Skip to content
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
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-ALERT-WAKE-AND-EMAIL-INTENT-PROMOTION-AND-ROUTER-LOOSEN-MEGABUCKET
May 24, 2026
Merged

feat(kora): KR-ALERT-WAKE-AND-EMAIL-INTENT-PROMOTION-AND-ROUTER-LOOSEN-MEGABUCKET — 3 deliverables#197
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-ALERT-WAKE-AND-EMAIL-INTENT-PROMOTION-AND-ROUTER-LOOSEN-MEGABUCKET

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

CC#1 megabucket completing two queued product threads + closing the #193 follow-on:

  • A: Alert wake consumer (substantial) — completes the unified-operator-interface for alerts; activates the alert_investigation cost-telemetry route end-to-end.
  • B: 6th promotion loop (email-intent) — Joshua's "Kora gets smarter naturally" thesis applied to email intent recognition.
  • C: Small feat(kora): KR-PROMOTE-LOOPS-COMPLETION-MEGABUCKET — 3 loops + debounce + audit batching #193 follow-on — adds the operator-override audit row that activates the router-tuning loop's dormant loosen path.

Per-deliverable status

ID Deliverable Status Notes
A KR-ALERT-INVESTIGATION-WAKE-CONSUMER ✅ shipped AlertWakeConsumer + listener; tails notification.dispatched; new alert.investigation_completed seam; 4-stream join via caller_session_id=alert:{category}:{severity}; alert_investigation route active end-to-end
B KR-PROMOTE-EMAIL-INTENT (6th loop) ✅ shipped Observer reads intent.email_to_sea_ticket action=logged_only rows; subject-only clustering via shared lexical embedder; new promotion.email_intent_pattern_proposed seam; endpoints under /api/promotions/email-intent/
C KR-PROMOTE-ROUTER-LOOSEN-AUDIT-ROW ✅ shipped Engine emits opus_override.applied on iter-1 opus_prefix/force_opus_env; router-tuning observer + proposer extended with collect_route_overrides + generate_loosen_proposals; cycle merges tighten+loosen into one batch

All 4 new audit seams added to SeamName Literal: alert.investigation_completed, promotion.email_intent_pattern_proposed, opus_override.applied, plus implicit reuse of promotion.approved / promotion.rejected for 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_attempted will land here when alert envelope auto-actions get built; autoaction_attempted field 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 into kora_cli/intent/email_to_sea_ticket.py using the persisted proposed_pattern as 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

  • ✅ Alert wake trigger uses existing notification.dispatched seam — no new wake-trigger seam needed. Consumer filters aggregate/non-ok rows.
  • ✅ Email-intent payload (subject-only) is sufficient for clustering — STOP-ASK §4 anticipated insufficient text but the existing audit shape is fine.
  • opus_override.applied slots cleanly into the engine's existing per-iteration loop with a single helper method; no structural plugin reshuffle needed.
  • ✅ Email-intent auto-apply: kept OFF per the email-intent risk profile (a bad regex could silently auto-Sea_Ticket emails). probe-fix-envelopes precedent.

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:

  1. Header band: severity emoji + category + alert_id + relative time.
  2. Investigation summary: investigation_summary_text verbatim from Stream 2.
  3. Cost footer: model_used + total_cost_usd + investigation_duration_ms.
  4. DM status pill: dm_status enum reused (sent / failed_send / engine_unavailable_fallback / engine_unavailable_failed_send).
  5. Reserved: autoaction_attempted badge — 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) for slack_message_ts to 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:

  • Tab: email-intent alongside the existing 5
  • Card layout: sample_subjects (chip cluster) + proposed_pattern (mono font + regex-test-link to the operator's regex tester if any) + proposed_action_kind (dropdown: save_note | log_only | save_with_reply at approve-time) + confidence + Approve/Reject
  • Pending badge rollup: extend the sidebar nav badge to sum across all 6 endpoint groups
  • Status enum drift-guard: same _PROMOTION_STATUS_VALUES pin already used by the other loops

Recommended 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 new override_count / sample_message_texts / by_override_source fields).

Test plan

  • 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)
  • 706 pass across snapshot / promote / reasoning / probes / audit / alerts / hermes plugin suites locally + 327 listener / web_server tests pass. Remaining failures across the wider suite are missing local dev-deps (aiosmtplib) unrelated to this PR.

🤖 Generated with Claude Code

…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>
@rafe-walker rafe-walker merged commit 95b8298 into feature/phase2-upgrades May 24, 2026
2 of 4 checks passed
@rafe-walker rafe-walker deleted the feat/kora-KR-ALERT-WAKE-AND-EMAIL-INTENT-PROMOTION-AND-ROUTER-LOOSEN-MEGABUCKET branch May 24, 2026 08:11
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>
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
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