This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(kora): KR-PANEL-USE-INSTRUMENTATION — panel-view event emit (data-driven cut prerequisite)#159
Merged
rafe-walker merged 1 commit intoMay 24, 2026
Conversation
…a-driven cut prerequisite)
Per Council R3 lock + sub-cut (c): every top-level *Page.tsx /
*Panel.tsx emits a panel_view event on mount to a backend sink
that accretes operator-UX telemetry. Builds the data needed for
any future panel-shape decisions — no cuts happen blind.
Zero LLM cost per emit. Fire-and-forget POST with silent failure
(instrumentation MUST NEVER break operator UX).
PM-confirmed Path B (separate panel_views.jsonl, not SeamName
extension)
=========================================================
Separate panel_views.jsonl chosen over SeamName extension; audit
log preserved as forensic surface, panel_views as UX telemetry
surface.
STOP-ASK surfaced + answered before drafting: extending
kora_cli/audit/jsonl_sink.py's SeamName Literal would mix
operator-UX telemetry into the forensic/compliance audit log
(Pydantic extra="forbid" + tight Literal kept intentionally
narrow). A future read_audit_entries(seam=None) query would
surface panel-views unexpectedly — latent contract violation.
PM endorsed Path B's separate-stream design.
Backend (kora_cli/web_server.py)
=================================
New ``POST /api/panel_view`` endpoint writing to
``${KORA_HOME}/panel_views.jsonl``. Write discipline mirrors
``audit/jsonl_sink.py``:
* mkdir(parents=True, exist_ok=True) — fresh KORA_HOME
* Atomic single-line append per request
* Best-effort: OSError → WARN-log + return ``{ok:True,
warning:"write_failed"}`` so FE caller stays green
(instrumentation must never break UX)
Validation:
* panel_name required + non-empty (stripped) → else 400
* panel_name truncated to _PANEL_NAME_MAX (128 chars)
* session_id missing/empty → "unknown" (cold tabs still
produce countable rows)
* session_id truncated to _SESSION_ID_MAX (64 chars)
* Hardcoded kind="panel_view" — FE can't override (test pin)
Reader OUT OF SCOPE for this bucket per PM direction — we just
write; consumers come later when we have data to act on.
Frontend hook (web/src/hooks/usePanelView.ts)
==============================================
export function usePanelView(panelName: string): void
Usage in every top-level Page/Panel (NOT internal components):
export default function AlertsPanel() {
usePanelView("AlertsPanel");
// ... component body ...
}
Implementation:
* useEffect with [panelName] deps — emit once per mount, not
on re-render (React 18 strict-mode dev double-emit is a
documented dev-only quirk; production analysis unaffected)
* getOrCreateSessionId(): reads sessionStorage "kora_session_id";
generates per-tab UUID via crypto.randomUUID() if missing;
fallback to Math.random base36 on older browsers;
fallback to "unknown" if sessionStorage throws (private
browsing / strict cookie modes)
* fetchJSON POST with .catch() silencing — instrumentation
must never break UX
panelName matches component name verbatim so downstream queries
against panel_views.jsonl can group by component without mapping.
Instrumentation pass: 34 panels
================================
All top-level web/src/pages/*.tsx instrumented via mechanical
sweep + ChatPage manual fix (multi-line destructured-param
signature). Inventory:
Panels (8): AgentActivityPanel, AlertsPanel, EmailPanel,
HeartbeatPanel, MCPClientsPanel, ReasoningPanel,
SlackDMPanel, WebhookEventsPanel
Pages (26): AnalyticsPage, BootStatusPage, CapabilitiesPage,
ChainEventsPage, CharterPage, ChatPage, ConfigPage,
CostStatePage, CronPage, DashboardPage, DocsPage,
DRStatePage, EnvPage, HealthRollupPage, IdentityPage,
KoraControlPage, LogsPage, MCPPage, ModelsPage,
OperationalStatePage, PluginsPage, ProfilesPage,
RunbooksPage, SeaTicketsPage, SessionsPage,
SkillsPage
NO internal components or web/src/components/ui/* instrumented
per spec scope (only top-level pages/panels rendered as routes).
Tests (tests/kora_cli/test_web_server_panel_view.py — 18 tests)
================================================================
Backend endpoint:
* Happy path appends correct JSONL row
* Empty/missing/whitespace panel_name → 400
* Oversized panel_name truncated to 128
* Missing/empty session_id → "unknown"
* Oversized session_id truncated to 64
* Multiple POSTs append separately
* Entry shape pin (4 keys + Z-suffixed UTC ISO)
* Fresh KORA_HOME mkdirs before append
* Read-only KORA_HOME → graceful warning, ok:true
* SECURITY: FE-supplied "kind" can't override hardcoded
"panel_view" (downstream queries protected)
Frontend pins:
* usePanelView hook source exists
* Posts to /api/panel_view via POST
* .catch() error-swallow present
* Every top-level page/panel imports + invokes usePanelView
with the matching component name (prevents future page
additions silently skipping instrumentation)
* Page-count pin: 34 (snapshot; update alongside any page
add/remove so the instrumentation audit stays accurate)
Verification:
* 18/18 panel_view tests pass
* 210/210 panel + audit regression (no breakage of existing
suites)
* pnpm tsc -b clean
* pnpm build clean
Refs:
* rafe-walker/kora-docs 17_cc_bucket_prompts/KR-PANEL-USE-INSTRUMENTATION_view_event_emit_no_llm_cost.md
* PM Path-B decision: STOP-ASK answered with rationale
endorsement
* Council R3 lock + sub-cut (c) — unified-operator-interface
lens prerequisite
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10e9273 to
d46476b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Per Council R3 lock + sub-cut (c): every top-level
*Page.tsx/*Panel.tsxemits apanel_viewevent on mount to a backend sink that accretes operator-UX telemetry. Builds the data needed for any future panel-shape decisions — no cuts happen blind. Zero LLM cost per emit. Fire-and-forget POST with silent failure (instrumentation MUST NEVER break operator UX).Separate panel_views.jsonl chosen over SeamName extension; audit log preserved as forensic surface, panel_views as UX telemetry surface.
STOP-ASK + PM endorsement
Surfaced before drafting: extending
kora_cli/audit/jsonl_sink.py'sSeamNameLiteral would mix operator-UX telemetry into the forensic/compliance audit log (Pydanticextra="forbid"+ tight Literal kept intentionally narrow). A futureread_audit_entries(seam=None)query would surface panel-views unexpectedly — latent contract violation. PM endorsed Path B's separate-stream design.Backend (
kora_cli/web_server.py)New
POST /api/panel_viewendpoint writing to${KORA_HOME}/panel_views.jsonl. Write discipline mirrorsaudit/jsonl_sink.py:mkdir(parents=True, exist_ok=True)— fresh KORA_HOME{ok:True, warning:"write_failed"}so FE caller stays greenValidation:
panel_namerequired + non-empty (else 400), truncated to 128 chars;session_idmissing/empty →"unknown", truncated to 64; hardcodedkind="panel_view"(FE can't override — tested).Reader OUT OF SCOPE per PM direction — we just write; consumers come later when there's data to act on.
Frontend hook (
web/src/hooks/usePanelView.ts)useEffectwith[panelName]deps emits once per mount.getOrCreateSessionId()readssessionStorage["kora_session_id"], generates per-tab UUID viacrypto.randomUUID()if missing, falls back toMath.randombase36 on older browsers, and to"unknown"if sessionStorage throws (private browsing / strict cookie modes)..catch()silences errors — instrumentation must never break UX.Instrumentation pass: 34 panels
All top-level
web/src/pages/*.tsxinstrumented via mechanical sweep + ChatPage manual fix (multi-line destructured-param signature). No internal components /web/src/components/ui/*touched per spec scope.Panels (8): AgentActivityPanel, AlertsPanel, EmailPanel, HeartbeatPanel, MCPClientsPanel, ReasoningPanel, SlackDMPanel, WebhookEventsPanel
Pages (26): AnalyticsPage, BootStatusPage, CapabilitiesPage, ChainEventsPage, CharterPage, ChatPage, ConfigPage, CostStatePage, CronPage, DashboardPage, DocsPage, DRStatePage, EnvPage, HealthRollupPage, IdentityPage, KoraControlPage, LogsPage, MCPPage, ModelsPage, OperationalStatePage, PluginsPage, ProfilesPage, RunbooksPage, SeaTicketsPage, SessionsPage, SkillsPage
Test plan
tests/kora_cli/test_web_server_panel_view.py— 18 tests covering: happy-path JSONL append, validation (empty/missing/whitespace/oversizedpanel_name),session_idsemantics (missing/empty → "unknown"; oversized → truncated), multi-POST append-only, entry shape pin, fresh KORA_HOME mkdir, read-only KORA_HOME graceful warning, SECURITY pin against FE-suppliedkindoverride, frontend source pins (hook exists / POSTs / catches), every-page-instrumented inventory pin, page-count snapshot pin.pnpm tsc -bclean.pnpm buildclean.panel_views.jsonlaccumulates one row per mount with the correctpanel_name.Refs
rafe-walker/kora-docs→17_cc_bucket_prompts/KR-PANEL-USE-INSTRUMENTATION_view_event_emit_no_llm_cost.md🤖 Generated with Claude Code