This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(kora): KR-EMAIL-PANEL-FLIP — endpoint reads from JSONLs#144
Merged
rafe-walker merged 1 commit intoMay 23, 2026
Merged
Conversation
Flips ``GET /api/email/recent`` from the v1 stub (PR #121) to a live read of both email JSONLs: * ``${KORA_HOME}/email_inbound_log.jsonl`` (PR #138 writer) * ``${KORA_HOME}/email_outbound_log.jsonl`` (PR #124 writer) Symmetric with CC#2's KR-SLACK-DM-PANEL-FLIP (#137). Backend endpoint swap only — no FE changes (EmailMessage TS interface in web/src/lib/api.ts already matches the projection per PR #121). Per-direction projection helpers: * ``_project_email_inbound`` — derives from_label (joshua / unknown_sender) by comparing ``entry.from`` against ``KORA_EMAIL_JOSHUA_ADDRESS``; derives to_label (kora / other) by checking ``KORA_EMAIL_KORA_ADDRESS`` against ``entry.to``; truncates body_text_truncated_2k → 400 chars; flips spoofing_check_skipped → spoofing_warning semantically; maps handler's HANDLED_* taxonomy to FE's EmailHandledStatus union (filtered_paused/stopped → dropped_paused; filtered_non_joshua → filtered_non_allowlist) * ``_project_email_outbound`` — from_label always "kora"; to_label derived from first recipient; body is placeholder (outbound JSONL never contains body per PR #124 security contract); derives sent_ok / sent_failed from send_status 4-layer SECURITY contract preserved + extended: 1. from_label / to_label are LABELS — never raw email addresses (walk-payload regex sweep verifies) 2. message_id passes through as RFC 5322 ``<id@<operator-domain>>`` — operator domain is NOT personal identification + FE needs it for threading. Walk-payload sweep EXCLUDES message_id + in_reply_to fields from the email-regex check (documented carve-out in module docstring) 3. body_text_truncated_400 is plain text (truncation at API edge; FE renders as JSX child per the existing PR #121 source-pin) 4. Walk-payload guards for Purelymail-token env-var-name hints + 32+-hex HMAC shapes + Bearer/Authorization headers catch future log-entry drift CC#2 #137 fixture-isolation lesson applied: tests monkeypatch ``get_kora_home`` in all 3 module namespaces (kora_constants + kora_cli.config + kora_cli.web_server) because the endpoint resolves it from its own module namespace via a ``from kora_cli.config import get_kora_home`` re-import. The existing PR #121 stub-test fixture only patched the upstream namespace; updated to apply the discipline (caught a real bleed where pytest-xdist parallel tests saw stale state from each other's KORA_HOME without the 3-namespace patch). 47 new tests pass (32 panel-flip + 15 preserved security/shape pins) + 185 cross-bucket regression (panel + slack-dm + email handler + Purelymail SMTP/IMAP clients). Ruff clean. 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
Flips `GET /api/email/recent` from the v1 stub to a live read of both email JSONLs. Symmetric with CC#2's KR-SLACK-DM-PANEL-FLIP (#137). Backend-only — EmailMessage TS interface already matches the projection shape per PR #121.
Bucket spec: `17_cc_bucket_prompts/KR-EMAIL-PANEL-FLIP_stub_to_real.md`
Source PRs cited:
Surface
Projection (per spec §2)
Inbound (`email_inbound_log.jsonl` → EmailMessage):
Outbound (`email_outbound_log.jsonl` → EmailMessage):
SECURITY — 4-layer + message_id carve-out
CC#2 #137 fixture-isolation lesson applied
The endpoint resolves `get_kora_home` from its OWN module namespace (`kora_cli.web_server`), not via a fresh import. Tests must monkeypatch all 3:
Caught a real bleed: the original PR #121 stub-test fixture only patched the upstream namespace; one test in the post-flip world was reading JSONLs from another parallel pytest-xdist worker's KORA_HOME because the web_server namespace wasn't patched. Fixed in this PR.
Test plan
Cascade
Standalone PR. Ship checklist §4 satisfied.
🤖 Generated with Claude Code