Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

feat(KR-P2-CLEANUP ST4): BOOT-PANEL flip-to-real + BootGateRunner history ring#62

Merged
rafe-walker merged 2 commits into
mainfrom
feat/kora-KR-P2-CLEANUP-st4-boot-panel-flip
May 21, 2026
Merged

feat(KR-P2-CLEANUP ST4): BOOT-PANEL flip-to-real + BootGateRunner history ring#62
rafe-walker merged 2 commits into
mainfrom
feat/kora-KR-P2-CLEANUP-st4-boot-panel-flip

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

KR-P2-CLEANUP ST4 of 5. Flips /api/boot-status from the hardcoded stub to a live read of BootGateRunner.last_result() + recent_history(limit=20), with the same uninitialized → stub + error fallback shape established by ST2/ST3.

agent/boot_gates.py

  • BootHistoryEntry — new frozen dataclass: boot_id, started_at, completed_at, summary (BootSummary reference). elapsed_ms is a computed property.
  • Module-level _recent_history: deque[BootHistoryEntry] ring capped at 20. Wipes on process restart — durable boot history lives in the chain-event log (kora.boot.ready / kora.boot.failed via KR-P2-I-integration ST2's emit listener).
  • BootGateRunner classmethods:
    • record(entry) — append (called by boot_coordinator)
    • last_result() — newest entry or None
    • recent_history(limit) — oldest→newest, clamped to ring max
    • _reset_history_for_tests() — test-only ring clear

agent/boot_coordinator.py

run_boot_sequence now records every terminal outcome (READY / STOPPED, including diagnostic-mode runs) via BootGateRunner.record(). New _record_boot_history helper is fail-soft — recording errors don't break the boot path.

boot_id minted as boot_{uuid4-hex[:8]}; started_at captured at runner construction; completed_at at record time.

Endpoint flip — kora_cli/web_server.py

  • Live branch: real current (the newest BootHistoryEntry) + history (the rest, newest-first ordering for the panel) WITHOUT stub flag.
  • Empty-history branch: stub-shape with stub: True + error field naming the cause (panel renders distinct banner).

Two projection helpers (_project_boot_entry_current / _project_boot_entry_history) translate BootHistoryEntry / BootSummary / GateResult into panel-shaped dicts. Note: GateResult has no title field (title is a Gate ClassVar); projection falls back to gate_id when no title can be resolved — acceptable degradation from stub for ST4.

Stub body extracted into _boot_status_stub(error=...) for shape symmetry with ST2/ST3.

Tests — tests/kora_cli/test_web_server_boot_status.py (full rewrite, 282 LOC)

  • Empty-history branch: stub + stub:True + error + per-entry shape sanity (outcome / gate_outcome / gate_class enum membership)
  • Live branch single boot: current renders the recorded boot; history is empty; no stub flag
  • Live branch multiple boots: history rendered newest-first; failed entry surfaces failed_gate_id + detail
  • Ring max enforcement: record 25 → only last 20 visible
  • BootGateRunner.last_result() / recent_history() / limit=0 edge cases
  • Cron-regression sanity

Sub-task chain (this bucket — all independent off main)

ST PR Status
ST1 #55 open
ST2 #57 open
ST3 #60 open
ST4 this PR open (no dependency on ST2/ST3)
ST5 next independent test fix

Test plan

  • CI green on pytest tests/kora_cli/test_web_server_boot_status.py
  • Manual smoke after merge: boot the gateway; admin panel /api/boot-status shows the recorded boot with no STUB banner

🤖 Generated with Claude Code

CC#3 Kora Runtime and others added 2 commits May 21, 2026 23:32
…tory ring

Flips /api/boot-status from the hardcoded stub to a live read of
BootGateRunner.last_result() + recent_history(limit=20), with the
same uninitialized → stub + error fallback shape as ST2/ST3.

agent/boot_gates.py:
  - New BootHistoryEntry frozen dataclass (boot_id, started_at,
    completed_at, summary). ``elapsed_ms`` is a computed property.
  - Module-level ``_recent_history: deque[BootHistoryEntry]`` ring
    capped at 20. Wipes on process restart — durable history lives
    in the chain-event log (kora.boot.ready / kora.boot.failed via
    KR-P2-I-integration ST2's emit listener).
  - BootGateRunner classmethods:
      * record(entry)         — append (called by boot_coordinator)
      * last_result()         — newest entry or None
      * recent_history(limit) — oldest→newest, clamped to ring max
      * _reset_history_for_tests() — test-only ring clear

agent/boot_coordinator.py:
  - run_boot_sequence now records every terminal outcome (READY /
    STOPPED, including diagnostic-mode runs) via
    BootGateRunner.record(). New _record_boot_history helper is
    fail-soft — recording errors don't break the boot path.
  - boot_id minted as ``boot_{uuid4-hex[:8]}``; started_at captured
    at runner construction; completed_at at record time.

kora_cli/web_server.py:
  - GET /api/boot-status now reads BootGateRunner.last_result() +
    recent_history(limit=20). Live branch: returns real current +
    history (newest-first ordering for the panel) WITHOUT ``stub``;
    empty-history branch: returns stub-shape with stub:True +
    ``error`` naming the cause (panel renders distinct banner).
  - New _project_boot_entry_current / _project_boot_entry_history
    helpers translate BootHistoryEntry/BootSummary/GateResult into
    panel-shaped dicts. GateResult has no ``title`` field (title is
    a Gate ClassVar); projection falls back to gate_id when no
    title can be resolved — acceptable degradation from stub for ST4.
  - Stub body extracted into _boot_status_stub(error=...) for shape
    symmetry with ST2/ST3.

Tests (tests/kora_cli/test_web_server_boot_status.py): full rewrite
covering both branches:
  - Empty-history branch: stub + stub:True + error + per-entry
    shape sanity (outcome/gate_outcome/gate_class enum membership)
  - Live branch single boot: current renders the recorded boot;
    history is empty; no stub flag
  - Live branch multiple boots: history rendered newest-first;
    failed entry surfaces failed_gate_id + detail
  - Ring max enforcement (record 25 → only last 20 visible)
  - BootGateRunner.last_result() / recent_history() / limit=0
    edge cases

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…in test helper

GateResult dataclass has no defaults for started_at + completed_at
(they're required fields per agent/boot_gates.py:97-98). The test
helper omitted them, which would have failed at fixture
construction in CI. Added with sensible defaults the panel
projection doesn't use but the dataclass demands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker rafe-walker force-pushed the feat/kora-KR-P2-CLEANUP-st4-boot-panel-flip branch from b3dde75 to e2c8d82 Compare May 21, 2026 23:33
@rafe-walker rafe-walker merged commit d450908 into main May 21, 2026
@rafe-walker rafe-walker deleted the feat/kora-KR-P2-CLEANUP-st4-boot-panel-flip branch May 21, 2026 23:33
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant