This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(kora): KR-FE-PANEL-KIT-AND-MUTATING-ACTIONS-MEGABUCKET — kit + autofix + kora-actions (#180/#183 retrofit)#187
Merged
rafe-walker merged 1 commit intoMay 24, 2026
Conversation
…utofix + kora-actions (#180/#183 retrofit) Four deliverables in one PR per the new batched-dispatch discipline. CC#2-flagged "3rd-consumer threshold" from PR #183 crossed — kit extraction landed alongside the 3rd consumer (AutofixLogPage) + the 4th consumer (KoraActionsPage, apex operator-trust view). ================================================================ Deliverable A — AuditPanelKit extracted ================================================================ New module: web/src/components/AuditPanelKit/ Sparkline.tsx — 14-day daily-count bars (plain SVG) SummaryChips.tsx — 24h count band (skip zero-counts) FilterChips.tsx — All + per-category buttons EmptyFilteredMessage.tsx — calm green empty-state w/ All-reset BadgeTone.ts — type pin to @nous-research/ui Badge types.ts — CategoryDef<K> + DailyCountPoint formatters.ts — formatTimestamp / formatRelative / truncate / formatBytes / formatChars / formatDurationMs (new) index.ts — public API exports README.md — props contract + theming notes + "adding a new consumer" runbook Generic over per-panel enum (CategoryDef<K extends string>) so the kit's FilterChips type-checks onChange exhaustively per consumer. ================================================================ Deliverable B — #180 + #183 retrofitted to use kit ================================================================ EmailIntentLogPage.tsx + OutboundEmailLogPage.tsx now import Sparkline / SummaryChips / FilterChips / formatters / EmptyFilteredMessage / BadgeTone / CategoryDef / FilterValue from the kit. Local copies removed. Each panel still defines its own CategoryDef[] array (with {key, label, tone, Icon} per enum value) — that's panel-specific. Tests updated: * test_filter_chips_iterate_*: now verify CategoryDef[] keys include every canonical action/status value + the kit- sourced FE constant is still imported (drift-guard greps it) * test_sparkline_uses_plain_svg: belt+suspenders — pin both page imports from kit AND kit's Sparkline.tsx uses plain SVG Both pages' existing test suites pass unchanged (24 #180 + 23 #183 = 47/47) after retrofit. Visual diff is zero (kit IS the source-of-truth shape). ================================================================ Deliverable C — KR-FE-AUTOFIX-LOG-PANEL (3rd kit consumer) ================================================================ Surfaces tool.probe_autofix_attempted audit seam (PR #182). Backend GET /api/probe-autofix/recent: * _PROBE_AUTOFIX_STATUS_VALUES drift-guard allow-list * _project_probe_autofix_audit per-status field whitelist * SECURITY: before_state / after_state dicts NOT propagated whole — only `state` field exposed as before_state_label / after_state_label. Test injects hostile fields (region, instance_id, fly_api_key) and asserts none leak. * reason_from_reasoning truncated to 300 chars (longer than other truncations because operator uses this for "why?" triage) * rejection_detail JSON-serialized + 200-char truncate * Daily-attempted 14d sparkline (status=attempted only) * by_status_24h aggregation across 3 known statuses + unknown Frontend web/src/pages/AutofixLogPage.tsx: * 3rd consumer of AuditPanelKit (validates the kit's API across 3 different enums) * Per-row: probe + action + target + status badge + before→after state transition + executor duration + reason_from_reasoning snippet * Wrench icon for the page (mirrored in card row + sidebar nav) * /probe-autofix-log route + sidebar nav entry ================================================================ Deliverable D — KR-FE-KORA-ACTIONS-AGGREGATED-PANEL (apex) ================================================================ Apex "what did Kora do today" timeline. Joins 4 mutating-action audit seams into one chronological view. Operator-trust surface that answers "did Kora do anything worth my attention today?" Backend GET /api/kora-actions/recent: * Joins 4 seams via read_audit_entries — orchestration only, no new audit/JSONL plumbing: - tool.email_to_operator_sent → email_sent - intent.email_to_sea_ticket (action=created only) → sea_ticket_created - tool.probe_autofix_attempted (status=attempted only) → autofix_attempted - phrasebook.updated (actor != "operator") → phrasebook_proposal_approved (v1: yields zero — see below) - probe.investigation_completed (NousResearch#406 pending; forward- compat: read attempt silently returns [] until seam lands) → investigation_completed * Merged + sorted by emitted_at desc * Per-row summary composed per category — privacy-preserved whitelisted fields only (no operator PII / SMTP headers etc; pinned by test_per_category_summaries_dont_leak_arbitrary_fields) * Deep-link target per category (sea-ticket → /sea-tickets?focus=X, autofix → /probe-autofix-log, email → /outbound-email-log, phrasebook → /phrasebook) * _KORA_ACTION_CATEGORIES drift-guarded canonical list (6 values including "other" forward-compat catch-all) * Daily-actions 14d sparkline (all categories combined) * by_category_24h aggregation Frontend web/src/pages/KoraActionsPage.tsx: * 4th consumer of AuditPanelKit * Activity-icon header "What Kora Did" (apex framing) * Per-row card: timestamp + category chip + status chip + composed summary + deep-link "detail" link * Calm empty state: "Kora has been quiet today" * /kora-actions route + prominent sidebar nav entry v1 behavior: * email_sent + sea_ticket_created + autofix_attempted populate normally * phrasebook_proposal_approved yields zero rows (ALL existing phrasebook.updated entries have actor="operator"; KR-PROMOTE- PHRASEBOOK bucket will emit actor="kora_proposal_approved" and this category begins to populate) * investigation_completed yields zero rows pending NousResearch#406 ================================================================ Drift-guard pin summary (all new endpoints) ================================================================ C — Autofix status (test_status_values_drift_guard): 3 sources × 3 values {attempted, rejected, execution_failed} 1. BE _PROBE_AUTOFIX_STATUS_VALUES in kora_cli/web_server.py 2. BE STATUS_* constants in kora_cli/tools/probe_autofix.py 3. FE PROBE_AUTOFIX_STATUS_VALUES in web/src/lib/api.ts D — Kora-action categories (test_action_categories_drift_guard): 2 sources × 6 values {email_sent, sea_ticket_created, autofix_attempted, investigation_completed, phrasebook_proposal_approved, other} 1. BE _KORA_ACTION_CATEGORIES in kora_cli/web_server.py 2. FE KORA_ACTION_CATEGORIES in web/src/lib/api.ts (No emitter constants — these are FE-defined cross-seam categories, not per-tool emit-time values.) Plus the existing drift guards from #180 + #183 still pass unchanged (action_values for intent, status_values for outbound). ================================================================ STOP-ASKs (none triggered) — design choices noted inline ================================================================ Spec §4 flagged 4 possible STOP-ASKs. All resolved inline: [A] AuditPanelKit visual deviation → none surfaced (kit copies were verbatim across #180 + #183; CategoryDef parameterization handles per-enum differences cleanly) [D] Aggregated endpoint perf → not currently a concern; each per-seam read_audit_entries is bounded by JSONL file size, merge is in-memory + bounded by limit. Pre-aggregation cache / cursor-pagination deferred until operator reports actual perf issue under realistic load. [D] phrasebook actor field filter → confirmed field exists per PR #177's emitter; filter `actor != "operator"` works cleanly. v1 yields zero (no kora-proposal loop yet) which is the correct semantic. [C,D] Deep-link routing — used /sea-tickets?focus=<id> + /probe-autofix-log + /outbound-email-log forward-compat params; no URL-builder helper needed for v1. SeaTicketsPage doesn't currently consume focus; same forward-compat posture as PR #180. ================================================================ Tests (98 panel-suite tests pass; 51 new) ================================================================ test_audit_panel_kit.py (8 NEW) — kit file shape, exports, plain-SVG, BadgeTone matches lib, README docs every export, all 4 consumers import from kit, no residual local Sparkline/SummaryChips/FilterChips in retrofitted pages test_autofix_log_panel.py (21 NEW) — backend (12) + drift guard (2) + FE source-pins (8) including SECURITY pin that before/after state dicts don't leak test_kora_actions_panel.py (22 NEW) — backend (14) + drift guard (2) + FE source-pins (8) including cross-seam category filters + forward-compat investigation seam + privacy whitelist test_email_intent_panel.py (24 existing, 2 updated after retrofit) — still pass test_outbound_email_panel.py (23 existing, 2 updated after retrofit) — still pass 98/98 panel tests pass. tsc -b clean. vite build clean. ================================================================ Screenshots ================================================================ web/docs/panel-kit-megabucket/kit_storybook.png — AuditPanelKit components rendered in isolation (Sparkline + SummaryChips + FilterChips + EmptyFilteredMessage) web/docs/panel-kit-megabucket/autofix_log.png — 5 events covering all 3 statuses (3 attempted with state transitions, 1 rejected with envelope-gate detail, 1 execution_failed with error) web/docs/panel-kit-megabucket/kora_actions.png — 8-event apex timeline with category-color-coded chips, deep-link icons, cross-seam chronological order #180 + #183 visually unchanged (the kit IS their components — retrofitted pages render identically; existing screenshots in web/docs/email-intent-log-panel/ + web/docs/outbound-email- log-panel/ remain accurate). ================================================================ Recommendation for follow-on additions to KoraActionsPage ================================================================ When new mutating-action seams ship, add them by: 1. Adding the seam to the BE endpoint's read_audit_entries calls (1 line each) 2. Adding a per-category summary composer 3. Adding to KORA_ACTION_CATEGORIES enum + drift-guard pin 4. Adding CategoryDef + visual to KORA_ACTION_CATEGORIES_DEFS Highest-value next additions: * probe.investigation_completed once NousResearch#406 lands (already wired forward-compat — just need the seam in SeamName Literal) * Future KR-PROMOTE-PHRASEBOOK actor="kora_proposal_approved" rows will auto-populate phrasebook_proposal_approved (already wired; zero changes needed when the loop ships) * mcp.tool_called rows where caller_actor_kind != "operator" — i.e., agent-driven mutating calls (would need a new category "agent_mutation") Refs: * rafe-walker/kora-docs 17_cc_bucket_prompts/KR-FE-PANEL-KIT-AND-MUTATING-ACTIONS-MEGABUCKET.md * PR #155 — KR-AUDIT-PANEL-ENDPOINTS (per-seam endpoint pattern) * PR #164 — CostTelemetryPage (plain-SVG charts discipline) * PR #180 — KR-FE-EMAIL-INTENT-LOG-PANEL (retrofitted in this PR) * PR #182 — tool.probe_autofix_attempted (audit source for Deliverable C) * PR #183 — KR-FE-OUTBOUND-EMAIL-LOG-PANEL (retrofitted in this PR) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Four deliverables in one PR per the new batched-dispatch discipline. CC#2-flagged "3rd-consumer threshold" from PR #183 crossed — kit extraction landed alongside the 3rd consumer (AutofixLogPage) + the 4th consumer (KoraActionsPage, apex operator-trust view).
AuditPanelKitfrom #180/#183 duplicationKR-FE-AUTOFIX-LOG-PANEL(3rd kit consumer)KR-FE-KORA-ACTIONS-AGGREGATED-PANEL(apex)98/98 panel-suite tests pass (51 new + 47 existing). tsc + vite build clean.
Screenshots
A. AuditPanelKit storybook (4 components in isolation)
B. #180 + #183 retrofit — visually unchanged
The kit IS the source-of-truth shape these pages used; retrofitted pages render identically. Existing screenshots in
web/docs/email-intent-log-panel/+web/docs/outbound-email-log-panel/remain accurate.C. Probe Autofix Log (3rd kit consumer)
5 events covering all 3 statuses (3 attempted with state transitions, 1 rejected with envelope-gate detail, 1 execution_failed).
D. Kora Actions — apex "what did Kora do" timeline (4th kit consumer)
8-event apex timeline with category-color-coded chips, deep-link icons, cross-seam chronological order.
Drift-guard pin summary across all new endpoints
test_status_values_drift_guard(3 values:attempted/rejected/execution_failed)_PROBE_AUTOFIX_STATUS_VALUESinweb_server.py(2)STATUS_*constants intools/probe_autofix.py(3)PROBE_AUTOFIX_STATUS_VALUESinapi.tstest_action_categories_drift_guard(6 values:email_sent/sea_ticket_created/autofix_attempted/investigation_completed/phrasebook_proposal_approved/other)_KORA_ACTION_CATEGORIESinweb_server.py(2)KORA_ACTION_CATEGORIESinapi.ts. No emitter constants — these are FE-defined cross-seam categories, not per-tool emit-time values.test_seam_literal_includes_all_source_seamstool.email_to_operator_sent+intent.email_to_sea_ticket+tool.probe_autofix_attempted+phrasebook.updated(the 4 seams the apex panel reads)test_badge_tone_matches_libraryBadgeTone.tspinned to@nous-research/uiBadge's tone unionPlus existing drift guards from #180 + #183 still pass unchanged.
STOP-ASKs (none triggered) — design choices resolved inline
Spec §4 flagged 4 possible STOP-ASKs:
CategoryDef<K>parameterization handles per-enum differences cleanly.read_audit_entriesis bounded by JSONL file size, merge is in-memory + bounded bylimit. Pre-aggregation cache / cursor-pagination deferred until operator reports actual perf issue.phrasebook.updatedactorfield shapeactor != \"operator\"works cleanly. v1 yields zero (no kora-proposal loop yet) — correct semantic; future KR-PROMOTE-PHRASEBOOK withactor=\"kora_proposal_approved\"auto-populates./sea-tickets?focus=<id>+/probe-autofix-log+/outbound-email-logforward-compat params; no new helper. SeaTicketsPage doesn't currently consumefocus; same forward-compat posture as PR #180.What ships in the kit
Components:
Sparkline(plain SVG, parameterizable totalSuffix) ·SummaryChips<K>(zero-count categories skipped) ·FilterChips<K>(All + per-category buttons) ·EmptyFilteredMessage(calm reassurance copy with inline All-reset link)Types:
BadgeTone(pinned to@nous-research/ui) ·CategoryDef<K extends string>·DailyCountPoint·FilterValue<K>Helpers:
formatTimestamp/formatRelative/truncate/formatBytes/formatChars/formatDurationMs(new — used by autofix executor-duration rendering)See
web/src/components/AuditPanelKit/README.mdfor the full props contract + theming notes + "adding a new consumer" runbook.SECURITY notes
C):before_state/after_statedicts NOT propagated whole — only thestatefield exposed asbefore_state_label/after_state_label. Test injects hostile fields (region, instance_id, fly_api_key) + asserts none leak.D): Per-category summary composers whitelist fields. Hostile-field injection test (test_per_category_summaries_dont_leak_arbitrary_fields) covers all 4 source seams.email_sentsummary.Test plan
pytest tests/kora_cli/test_audit_panel_kit.py tests/kora_cli/test_email_intent_panel.py tests/kora_cli/test_outbound_email_panel.py tests/kora_cli/test_autofix_log_panel.py tests/kora_cli/test_kora_actions_panel.py)pnpm tsc -bcleanpnpm buildclean/kora-actionsagainst a daemon with mixed audit-log rows → all categories render with correct chips + summaries + deep-links work → switch filter chips → counts narrow correctly → switch toInvestigation completed(zero-count v1) → empty state renders. Then/probe-autofix-logagainst a daemon with at least one KR-PROBE-AUTOFIX-EXECUTION — Kora attempts the fix (vision completion) #182 audit row → before→after state transition rendered + reason snippet visible.Follow-on recommendation
When new mutating-action seams ship, add to KoraActionsPage by:
read_audit_entriescalls (1 line)KORA_ACTION_CATEGORIESenum + drift-guardCategoryDef+ visual toKORA_ACTION_CATEGORIES_DEFSHighest-value next additions:
probe.investigation_completedonce Feature: Independent Code Verification & Quality Gates — Fail-Closed Review, Baseline Regression Detection, and Auto-Fix Loop (inspired by Nightwire) NousResearch/hermes-agent#406 lands (already wired forward-compat — just needs the seam in SeamName Literal)KR-PROMOTE-PHRASEBOOKactor=\"kora_proposal_approved\"rows auto-populatephrasebook_proposal_approved(already wired; zero changes needed)mcp.tool_calledrows wherecaller_actor_kind != \"operator\"— agent-driven mutating calls (would need a newagent_mutationcategory)Refs
rafe-walker/kora-docs→17_cc_bucket_prompts/KR-FE-PANEL-KIT-AND-MUTATING-ACTIONS-MEGABUCKET.mdtool.probe_autofix_attemptedaudit source for Deliverable C🤖 Generated with Claude Code