This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(kora): KR-ALERT-WAKE-AND-EMAIL-INTENT-PROMOTION-AND-ROUTER-LOOSEN-MEGABUCKET — 3 deliverables#197
Merged
Conversation
…N-MEGABUCKET — 3 deliverables Deliverable A — KR-ALERT-INVESTIGATION-WAKE-CONSUMER: * New ``kora_cli/alerts/wake_consumer.py`` (AlertWakeConsumer) + ``kora_cli/listeners/alert_wake_listener.py``. Parallels probe wake consumer #166 + 4-stream join from #184. * Tails the existing ``notification.dispatched`` audit seam (#149 KR-ALERT-NOTIFY) — no new wake-trigger seam needed. Filters out aggregate burst_summary/digest_email rows + non-ok status rows at the consumer level. * New audit seam ``alert.investigation_completed`` extending the SeamName Literal with the per-investigation payload (alert_id / category / severity / model_used / tokens / total_cost_usd / investigation_duration_ms / investigation_summary_text / dm_status / autoaction_attempted reserved-false). * caller_session_id pattern ``alert:{category}:{severity}`` joins the 4 streams CC#2's KR-FE-ALERT-INVESTIGATIONS-VIEWER follow-on needs. * DM routed through the existing slack_dm_handler free function ``append_outbound_log_entry`` so the slack_dm_log entry carries the caller_session_id alongside reasoning meta. * Activates the ``alert_investigation`` cost-telemetry route literal end-to-end (the wire stub from #190 finally has a consumer). * Env: KORA_ALERT_WAKE_DEBOUNCE_SECONDS (default 600s), KORA_ALERT_WAKE_DEBOUNCE_BYPASS_CRITICAL (default false), KORA_ALERT_WAKE_POLL_SEC (default 30s). Deliverable B — KR-PROMOTE-EMAIL-INTENT (6th promotion loop): * New ``kora_cli/promote/email_intent/`` (observer / proposer / plugin). Observes ``intent.email_to_sea_ticket`` rows with ``action="logged_only"`` — Joshua-from emails that no existing intent pattern matched. * Subject-only clustering via the shared ``kora_cli/clustering/text_similarity`` helpers (PII discipline: body text intentionally NOT in the audit payload). Cohesion threshold default 0.65 — lower than phrasebook's 0.85 because subjects are inherently shorter / sparser. * Proposer derives a candidate regex from the cluster's common tokens (regex metacharacters escaped, same safety as the phrasebook proposer). Default ``proposed_action_kind = "save_note"`` (operator picks at approve-time). * New audit seam ``promotion.email_intent_pattern_proposed`` with source=``email``. * Endpoints ``GET /api/promotions/email-intent/pending`` + ``POST .../{id}/approve|reject`` via the shared _promotion_loop_pending / _promotion_loop_transition helpers from #193. * Default auto-apply OFF — operator scaffolds approved patterns into ``kora_cli/intent/email_to_sea_ticket.py`` manually (probe-fix-envelopes precedent from #193). * Cron + listener registered in kora_cli/listeners/__init__.py. Deliverable C — KR-PROMOTE-ROUTER-LOOSEN-AUDIT-ROW: * New audit seam ``opus_override.applied`` extending SeamName. * Engine emits the seam in ``anthropic_engine._tool_use_loop`` on iteration 1 when the router decision reason is ``opus_prefix`` or ``force_opus_env`` — i.e. operator manually forced Opus on a call the router would have left on Haiku. Skips on iteration ≥2 (that's the loop's own iteration-earning signal, not an override) and on decision_language / cost_clamp / etc. * Payload: original_message_text (truncated 240 chars) / pre_call_decision_reason (verbatim from router) / override_source (operator_prefix or force_env) / route. * Router-tuning observer (#193) extended with ``collect_route_overrides`` + ``RouteOverrideRollup``; reads the new seam over the rolling 24h window. * Router-tuning proposer (#193) extended with ``generate_loosen_proposals`` — emits ``loosen_review`` proposals for routes whose override_count crosses ``KORA_PROMOTE_ROUTER_TUNING_LOOSEN_OVERRIDE_THRESHOLD`` (default 3). Rationale surfaces the sample message texts the operator typed when they escalated. * Router-tuning cycle merges tighten + loosen proposals into one audit batch + persists both under the same loop directory. Cycle summary surfaces tighten/loosen counts separately for operator-grep parity. * RouterTuningProposal dataclass extended with optional override_count / sample_message_texts / by_override_source fields; tighten-path callers see 0/empty defaults so the change is backwards-compat. Tests: * 19 new tests for alert wake consumer (filter / debounce / engine paths / happy 4-stream join / source attribution / DM failure paths). * 12 new tests for email-intent loop (observer / proposer / cycle / regex safety / sample dedup). * 12 new tests for router-tuning loosen-path (override collector / per-source breakdown / sample-cap / loosen proposer threshold / end-to-end cycle). * 4 new tests for opus_override.applied engine emission (opus prefix / force env / default haiku doesn't emit / decision_language doesn't emit). * All 706 pass across snapshot / promote / reasoning / probes / audit / alerts / hermes plugin suites locally. Remaining failures across listener suite are missing local dev-deps (aiosmtplib) unrelated to this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
rafe-walker
pushed a commit
that referenced
this pull request
May 24, 2026
… promote CLI + alert fallback + envelope auto-approve
Deliverable A — Wider-suite test stability:
* Audited missing-deps blocker: all the deps CC#1 has been
flagging across the last several PRs (aiosmtplib, prompt_toolkit,
aioimaplib, fire, openai) are ALREADY declared in
``pyproject.toml`` core / dev extras. The gap was env-side, not
code-side — CC#1's dev environment hadn't been re-synced after
the dep additions across recent buckets.
* Resolution: ``uv pip install -e ".[all,dev]"`` (already
documented in CONTRIBUTING.md). With the deps installed:
- Collection: 7008 tests (was 7004 collected + 4 collection
errors on un-synced env)
- Full suite under hermetic env: **6905 passed / 94 failed /
10 skipped** in 83s
- Sub-suite excluding reasoning + gateway: **6605 passed /
24 failed / 10 skipped** in 80s
* Note: the 94 remaining failures are PRE-EXISTING (verified by
``git stash`` + re-run on the merge commit before this PR).
They cluster in:
- ``reasoning/test_anthropic_engine*.py`` (~53) — gateway-route-
through mock isolation issue introduced by CC#3's #196
daemon Phase 1 default-flip; tests call real Anthropic API
via the route-through path even though they pass a mock
client.
- ``test_backup.py`` / ``test_config.py`` / ``test_cron.py`` /
``test_web_server.py`` (~30) — HERMES_HOME → KORA_HOME
migration tests stamping legacy expectations.
- ``test_kanban*.py`` (~4) — separate flaky area.
Per the bucket spec STOP-ASK §4: these need a separate
stabilization bucket; this one completes with the deps-side
resolved. PR description carries the recommended bucket title.
Deliverable B — ``kora promote`` operator CLI commands:
* New module ``kora_cli/promote_cli.py`` with 4 subcommands:
- ``kora promote status`` — per-loop pending / approved /
rejected / expired counts + last activity timestamp across
all 6 loops.
- ``kora promote run-once <loop>`` — invoke one cycle ad-hoc;
returns the loop's cycle summary dict.
- ``kora promote history <loop> [--days N]`` — recent audit
rows for the loop, filtered to the per-loop seam vocabulary
and (where the seam is shared like ``promotion.approved``)
scoped via the ``promotion:<loop>:`` caller_session_id prefix.
- ``kora promote pending <loop>`` — JSON dump of currently-
pending proposals; ordered highest-confidence first.
* Snapshot-expand's audit-only layout (no pending/approved/
rejected) gets special-cased — ``pending`` errors with a clear
redirect to ``history``; ``status`` surfaces applied-record
counts only.
* Registered under main.py's existing subparser pattern; cycle
imports are LAZY so ``kora promote --help`` doesn't pull the
clustering / pricing chain.
Deliverable C — Alert investigation fallback DM polish:
* The mechanism shipped in #197 (fallback DM on reasoning failure
via ``append_outbound_log_entry`` + dm_status=
``engine_unavailable_fallback`` in the audit). KR-CC1-POLISH
improves the wording:
- Header now surfaces ``category (severity): alert id N
(via {channel})``
- Footer is explicit: "Kora is unavailable to investigate this
alert ... Review the alerts panel and act manually — Kora
will not retry this investigation."
* New test asserts dm_status exactly ==
``"engine_unavailable_fallback"`` on the engine-None path; CC#2's
KR-FE-ALERT-INVESTIGATIONS-VIEWER reads that enum value.
Deliverable D — Probe-fix-envelope auto-approve (low-risk):
* New env: ``KORA_PROMOTE_PROBE_FIX_AUTO_APPROVE_LOW_RISK``
(default ``false``; operator opts in).
* New env: ``KORA_PROMOTE_PROBE_FIX_AUTO_APPROVE_WAIT_HOURS``
(default ``1.0``).
* New module ``kora_cli/promote/probe_fix_envelopes/auto_approve.py``
with ``run_auto_approve_sweep`` — runs at end of each
probe-fix-envelope cycle, walks pending proposals, auto-
approves those whose ``blast_radius_level == "low"`` AND have
been pending ≥ wait_hours. Approval = transition to
``approved/`` + emit ``promotion.probe_envelope_action_auto_approved``
audit row.
* New ``ProbeEnvelopeProposal.blast_radius_level`` field
(``"low" | "medium" | "high"``); default ``"high"`` preserves
the existing operator-must-review posture. Backwards-compat:
legacy on-disk payloads without the field rehydrate to
``"high"`` via the new ``proposal_from_dict`` helper.
* Heuristic in ``_derive_blast_radius_level`` returns ``"low"``
ONLY for known-narrow envelope patterns
(``_KNOWN_LOW_RISK_PATTERNS`` — currently the fly
restart_unhealthy_machine envelope's (probe, issue_category)
pairs). Everything else defaults to ``"high"``. The heuristic
intentionally undershoots — false-low classifications would
let proposals slip through to operator's envelope without
review.
* CRITICAL — two-tier gating preserved (documented inline +
in the auto_approve module docstring):
1. Auto-approve → "this is in our envelope vocabulary"
2. Per-probe ``KORA_PROBE_AUTOFIX_<NAME>_ENABLED`` →
"Kora is permitted to invoke it at runtime"
The auto-approve flag DOES NOT cause Kora to execute the
fix — only adds it to the vocabulary; operator still enables
the per-probe ENABLED env separately to authorize execution.
* New audit seam ``promotion.probe_envelope_action_auto_approved``
extending SeamName Literal with the auto_approve_wait_hours +
auto_approved_at fields for operator timeline reconstruction.
Tests:
* 12 new tests for the probe-fix-envelope auto-approve sweep
(heuristic / fixture-backed rehydration / sweep disabled by
default / wait-window enforcement / high-risk never approves /
audit payload shape).
* 13 new tests for ``kora promote`` CLI commands (status / pending
/ history / run-once dispatch / loop allowlist / snapshot_expand
special-case error / cross-loop history caller_session_id
filtering).
* 2 new tests for alert fallback DM polish (wording assertion +
dm_status enum assertion).
* All 41 new tests pass; all relevant existing tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
rafe-walker
added a commit
that referenced
this pull request
May 24, 2026
…RESTRUCTURE-AND-ALERT-VIEWER-VERIFICATION-MEGABUCKET feat(kora): KR-FE-COCKPIT-NAV-RESTRUCTURE-AND-ALERT-VIEWER-VERIFICATION — sidebar groups + alert viewer aligned to real #197
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
CC#1 megabucket completing two queued product threads + closing the #193 follow-on:
alert_investigationcost-telemetry route end-to-end.Per-deliverable status
notification.dispatched; newalert.investigation_completedseam; 4-stream join viacaller_session_id=alert:{category}:{severity};alert_investigationroute active end-to-endintent.email_to_sea_ticketaction=logged_onlyrows; subject-only clustering via shared lexical embedder; newpromotion.email_intent_pattern_proposedseam; endpoints under/api/promotions/email-intent/opus_override.appliedon iter-1opus_prefix/force_opus_env; router-tuning observer + proposer extended withcollect_route_overrides+generate_loosen_proposals; cycle merges tighten+loosen into one batchAll 4 new audit seams added to SeamName Literal:
alert.investigation_completed,promotion.email_intent_pattern_proposed,opus_override.applied, plus implicit reuse ofpromotion.approved/promotion.rejectedfor the email-intent endpoints.Sample 4-stream alert investigation trace (caller_session_id =
alert:cost_ladder:warning)Stream 1 — alert notifier dispatches the alert (existing
notification.dispatched):{"emitted_at":"2026-05-24T08:00:00Z","seam":"notification.dispatched","details":{"channel":"slack","alert_id":"cost_warn_75","severity":"warning","category":"cost_ladder","status":"ok"}}Stream 2 — wake consumer investigates + emits
alert.investigation_completed(NEW):{"emitted_at":"2026-05-24T08:00:04Z","seam":"alert.investigation_completed","details":{"alert_id":"cost_warn_75","category":"cost_ladder","severity":"warning","model_used":"claude-haiku-4-5-20251001","input_tokens":420,"output_tokens":85,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"total_cost_usd":0.00034,"investigation_duration_ms":3421,"investigation_summary_text":"Daily burn rate is \$11.40/day, projecting \$342/mo against the \$200 pool. The cost-ladder hit the 75% warn rung 3 hours after the regular morning promotion-loop batch. Recommend reviewing whether yesterday's heavy Opus escalations were earned — see the router-tuning panel for the breakdown.","dm_status":"sent","autoaction_attempted":false},"caller_session_id":"alert:cost_ladder:warning","source":"reasoning"}Stream 3 — outbound DM lands in slack_dm_log.jsonl with the same caller_session_id (the 4-stream join key):
{"sent_at":"2026-05-24T08:00:04Z","channel_id":"U01JOSHUA","thread_ts":null,"text":"⚠️ Alert · cost_ladder\nDaily burn rate is \$11.40/day...","slack_message_ts":"1748067604.123","send_status":"ok","model_used":"claude-haiku-4-5-20251001","input_tokens":420,"output_tokens":85,"reasoning_duration_ms":3421,"caller_session_id":"alert:cost_ladder:warning"}Stream 4 (reserved) —
tool.alert_autoresolve_attemptedwill land here when alert envelope auto-actions get built;autoaction_attemptedfield in Stream 2 is the back-reference.Sample email-intent proposal (
promotion.email_intent_pattern_proposed){"emitted_at":"2026-05-24T11:00:00Z","seam":"promotion.email_intent_pattern_proposed","details":{"proposal_id":"p-email-001","cluster_size":4,"sample_subjects":["Quick idea: dashboard refresh","Quick idea about the new probe panel","Quick idea: rate limit shape"],"proposed_pattern":"(?i)(quick|idea|about)","proposed_action_kind":"save_note","confidence":0.6667,"created_at":"2026-05-24T11:00:00Z","status":"pending","review_notes":"","sample_caller_session_ids":["email:msg-101","email:msg-104","email:msg-118"],"action":"proposed"},"caller_session_id":"promotion:email_intent:p-email-001","source":"email"}Operator approves via
POST /api/promotions/email-intent/p-email-001/approve; v1 transitions status + emits audit, operator manually scaffolds a new pattern intokora_cli/intent/email_to_sea_ticket.pyusing the persistedproposed_patternas the spec.Sample router loosen-path proposal (
promotion.router_trigger_proposed){"emitted_at":"2026-05-24T08:00:00Z","seam":"promotion.router_trigger_proposed","details":{"proposal_id":"p-loosen-001","route":"slack_dm","calls_count":0,"escalation_count":0,"escalation_rate":0.0,"cost_estimate_usd_total":0.0,"recommendation_kind":"loosen_review","rationale":"Route 'slack_dm' saw 5 operator-driven Opus override(s) in the rolling 24h window (operator_prefix=5). The Haiku-router would otherwise have left these on Haiku — the trigger pattern likely needs loosening to auto-escalate similar messages. Sample message text(s) operator escalated: \"explain the cost migration tradeoff\"; \"what's the right call on supabase indexing\"; \"diagnose why probe wake stopped firing\".","confidence":0.5556,"created_at":"2026-05-24T08:00:00Z","status":"pending","review_notes":"","override_count":5,"sample_message_texts":["explain the cost migration tradeoff","what's the right call on supabase indexing","diagnose why probe wake stopped firing"],"by_override_source":{"operator_prefix":5}},"caller_session_id":"promotion:router_tuning:p-loosen-001","source":"reasoning"}Operator reviews the sample texts → identifies the pattern (here: cost/migration/diagnose tradeoff phrasing) → adds a decision-language pattern to the router selector via approve flow + manual scaffolding.
STOP-ASK posture
notification.dispatchedseam — no new wake-trigger seam needed. Consumer filters aggregate/non-ok rows.opus_override.appliedslots cleanly into the engine's existing per-iteration loop with a single helper method; no structural plugin reshuffle needed.CC#2 follow-on recommendations
KR-FE-ALERT-INVESTIGATIONS-VIEWER
Mirrors the existing ProbeInvestigationsPage (CC#2's #184 follow-on). The 4 streams + caller_session_id join key are identical in shape — most of the panel scaffolding ports 1:1.
Per-row view:
investigation_summary_textverbatim from Stream 2.dm_statusenum reused (sent / failed_send / engine_unavailable_fallback / engine_unavailable_failed_send).autoaction_attemptedbadge — false in v1, lights up when the future alert-envelope autoaction seam ships.Listing pattern: join Stream 2 (
alert.investigation_completed) as the primary; pull Stream 1 (notification.dispatched) for the dispatch timestamp; pull Stream 3 (slack_dm_log.jsonl) forslack_message_tsto deep-link into the operator's Slack history. The dm_status enum is byte-identical to the ProbeInvestigationsPage's so the same pill component renders.PromotionReviewPage extend for 6th loop
The KR-PROMOTE-LOOPS-COMPLETION-MEGABUCKET (#193) follow-on already plans extending the panel for 3 new loop types (router-tuning / tool-trimming / probe-fix-envelopes). Add the 6th tab + card renderer:
email-intentalongside the existing 5_PROMOTION_STATUS_VALUESpin already used by the other loopsRecommended title:
KR-FE-PROMOTION-REVIEW-PANEL-EXTEND-V2(extension of CC#2's first extend bucket; bundles 6th-loop support + any router-tuning loosen_review render improvements from this PR's newoverride_count/sample_message_texts/by_override_sourcefields).Test plan
opus_override.appliedengine emission (opus prefix / force env / default haiku doesn't emit / decision_language doesn't emit)🤖 Generated with Claude Code