Skip to content

feat(email): dual-write finalized inbound Mailbox state - #1127

Merged
kody-bot merged 29 commits into
mainfrom
cursor/mailbox-do-810a
Aug 1, 2026
Merged

kody-bot merged 29 commits into
mainfrom
cursor/mailbox-do-810a

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Aug 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Completes high-risk inbound terminal Mailbox dual-write while preserving D1/R2 authority:

  • no Mailbox call before message/attachment storage and D1 received finalization
  • one ordered task: graph repair → D1 effects → final event mirror
  • finalization winner, already-received retry, and received storage-claim replay use the coordinator
  • post-claim rejection mirrors its event; pre-claim bounded rejects remain parity-backfilled
  • system:email remains D1-only; direct/retention deletes remain parity-repaired

Mailbox failure/timeout never changes reject/refund/retry/charge/finalization/ack behavior. Production-mode captured-waitUntil tests deliberately delay graph RPCs and prove finalized effects cannot be overwritten.

Shipping: high risk by policy; stop green + ready-for-review, do not self-merge.

System recap — extends existing primitives (high operational risk)

Mode: recap · Base: main @ e76b8c9 · Head: 8397c90

Classification: extends — inbound Email Routing composes its finalized D1/R2 boundary with one ordered post-commit Mailbox/effects task; authority does not move.

sequenceDiagram
	participant ER as Email Routing
	participant D1
	participant R2
	participant MB as Mailbox DO
	ER->>D1: claim lease
	ER->>R2: put MIME
	ER->>D1: message + attachments
	ER->>D1: finalize received
	ER-->>MB: waitUntil graph repair
	ER-->>D1: ordered effects
	ER-->>MB: final event mirror
	Note over ER,MB: mirror failures never change Routing semantics
Loading

Invariants

  • Pre-commit/finalization ordering unchanged.
  • Effects are serialized between graph and final event mirrors.
  • Retries repair without duplicate message or charge.
  • Effects failure skips final mirror and preserves reconcile behavior.
  • D1 remains authoritative; read cutover stays off.

Conductor report

  • STATUS: done
  • What shipped: ordered finalized inbound/replay/rejection/effects Mailbox shadow mirrors
  • Risk self-assessment: high — inbound terminal durability orchestration; independent reviews approved current ordering
  • Merged/deployed: no; intentionally stopped green + ready-for-review per policy
  • Sibling scope spill: none; no UserMeter/deletion-fence internals, scheduled lanes, delete ordering, or retention edits
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Inbound email deliveries now synchronize messages, threads, attachments, and delivery events with the mailbox.
    • Rejected deliveries now record delivery events for improved tracking.
    • Retry and replay handling improves recovery from temporary storage or synchronization failures.
    • Background processing helps complete mailbox updates without delaying email handling.
  • Documentation

    • Updated architecture documentation covering mailbox synchronization, retries, repair workflows, telemetry, and durability behavior.

cursoragent and others added 25 commits August 1, 2026 07:25
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Inbound email processing now schedules terminal Mailbox work. Received deliveries mirror graphs, apply effects, and mirror updated events. Rejected deliveries mirror only events. Retries, failures, replay repair, system mail, and D1 authority are covered by tests and documentation.

Changes

Inbound Mailbox mirroring

Layer / File(s) Summary
Terminal work coordination
packages/worker/src/email/inbound-mailbox.ts, packages/worker/src/email/inbound-mailbox.node.test.ts
Received work mirrors the graph, processes effects, then mirrors the delivery event. Rejected work mirrors only the event. Both paths support waitUntil, skip system mail, and log failures.
Inbound processing wiring
packages/worker/src/email/inbound.ts
User delivery paths dispatch terminal work for new, retried, already-received, and rejected deliveries. System-inbox effects keep the existing scheduler.
Mirror integration validation
packages/worker/src/email/inbound-mailbox-mirror.workers.test.ts
Tests cover successful mirroring, ordering, retries, pre-commit failures, RPC failures, replay repair, and rejected-event idempotency.
Storage contract documentation
docs/contributing/architecture/data-storage.md
Documentation describes inbound dual-write ordering, parity repair, deletion sequencing, phase status, and the unchanged D1 authority boundary.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InboundEmail
  participant TerminalWork
  participant Mailbox
  participant D1Effects
  participant EmailEvents
  InboundEmail->>TerminalWork: schedule received terminal work
  TerminalWork->>Mailbox: mirror message graph
  TerminalWork->>D1Effects: apply delivery effects
  D1Effects-->>TerminalWork: updated delivery state
  TerminalWork->>EmailEvents: mirror received delivery event
  EmailEvents->>Mailbox: persist delivery event
Loading

Possibly related PRs

  • kentcdodds/kody#1100: Covers inbound delivery-effect reconciliation and completion state used by this coordination.
  • kentcdodds/kody#1122: Adds Mailbox mirror helpers and parity primitives wired into inbound terminal processing.
  • kentcdodds/kody#1124: Extends the Mailbox dual-write system to inbound terminal delivery handling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's primary change: dual-writing finalized inbound Mailbox state.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/mailbox-do-810a

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

cursoragent and others added 3 commits August 1, 2026 13:35
Restore deleteEmailMessageById to D1 batch then immediate R2 cleanup with
no Mailbox env/waitUntil/mirror. Restore insertEmailMessageWithAttachments
signature without mirror forwarding. Drop PR-only delete mirror tests and
update data-storage.md: live explicit/retention deletes are repaired by
parity purge/rebuild; direct delete wiring remains pending.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kody-bot
kody-bot marked this pull request as ready for review August 1, 2026 13:49
@github-actions

github-actions Bot commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-1127.kody-a99.workers.dev

Worker: kody-pr-1127
D1: kody-pr-1127-db
KV: kody-pr-1127-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/worker/src/email/inbound.ts (1)

663-676: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Source all three delivery fields from storageClaim.delivery.

This block reads messageId from claimedDelivery but reads deliveryId and expectedFinalizationToken from storageClaim.delivery. Both objects describe the same delivery row today, so behavior is correct. Use the freshest row for all three fields to remove the drift risk if claimInboundDeliveryStorage ever returns a different stable delivery.

♻️ Proposed change
 			if (storageClaim.delivery?.state === 'received') {
 				await scheduleInboundReceivedTerminalWork({
 					env,
 					userId,
-					messageId: claimedDelivery.messageId,
+					messageId: storageClaim.delivery.messageId,
 					deliveryId: storageClaim.delivery.deliveryId,
 					expectedFinalizationToken: storageClaim.delivery.finalizationToken,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/email/inbound.ts` around lines 663 - 676, Update the
scheduleInboundReceivedTerminalWork call in the !storageClaim.claimed
received-delivery branch to source messageId from
storageClaim.delivery.messageId, matching deliveryId and
expectedFinalizationToken; stop using claimedDelivery for these fields.
packages/worker/src/email/inbound-mailbox.node.test.ts (1)

132-162: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case where the graph mirror rejects.

This test only covers a graph mirror that resolves with a degraded status (status: 'timeout'). The coordinator chains await mirrorMailboxMessageGraphFromD1(...) before processInboundDeliveryEffects(...), so a rejecting graph mirror skips the D1 effects entirely and logs once. That branch carries the real risk, because the delivery effects never run. Cover it explicitly.

♻️ Suggested additional test
test('graph mirror rejection skips D1 effects and logs once', async () => {
	resetMocks()
	consoleError.mockImplementation(() => {})
	mocks.mirrorMailboxMessageGraphFromD1.mockRejectedValueOnce(
		new Error('graph exploded'),
	)

	await scheduleInboundReceivedTerminalWork({
		env: { APP_DB: {} } as unknown as Parameters<
			typeof scheduleInboundReceivedTerminalWork
		>[0]['env'],
		userId: 'user-ddd',
		messageId: 'msg-1',
		deliveryId: 'delivery-4',
		logLabel: 'Inbound email effect dispatch failed',
	})

	expect(mocks.processInboundDeliveryEffects).not.toHaveBeenCalled()
	expect(mocks.mirrorMailboxDeliveryEventFromD1).not.toHaveBeenCalled()
	expect(consoleError).toHaveBeenCalledTimes(1)
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/email/inbound-mailbox.node.test.ts` around lines 132 -
162, Add a separate test alongside the existing terminal-work tests for a
rejected mirrorMailboxMessageGraphFromD1 call, configuring it to reject with an
error and invoking scheduleInboundReceivedTerminalWork. Assert
processInboundDeliveryEffects and mirrorMailboxDeliveryEventFromD1 are not
called, and consoleError is called exactly once.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/contributing/architecture/data-storage.md`:
- Around line 810-831: Update the inbound terminals documentation to use
scheduleInboundReceivedTerminalWork and scheduleInboundRejectedTerminalWork as
the coordinator names. Clarify that the received coordinator, after awaiting
processInboundDeliveryEffects, re-mirrors the updated delivery event via
mirrorMailboxDeliveryEventFromD1 rather than attributing this step to the
effects chain.

---

Nitpick comments:
In `@packages/worker/src/email/inbound-mailbox.node.test.ts`:
- Around line 132-162: Add a separate test alongside the existing terminal-work
tests for a rejected mirrorMailboxMessageGraphFromD1 call, configuring it to
reject with an error and invoking scheduleInboundReceivedTerminalWork. Assert
processInboundDeliveryEffects and mirrorMailboxDeliveryEventFromD1 are not
called, and consoleError is called exactly once.

In `@packages/worker/src/email/inbound.ts`:
- Around line 663-676: Update the scheduleInboundReceivedTerminalWork call in
the !storageClaim.claimed received-delivery branch to source messageId from
storageClaim.delivery.messageId, matching deliveryId and
expectedFinalizationToken; stop using claimedDelivery for these fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 734006fa-d4d7-4182-accb-240305d57df0

📥 Commits

Reviewing files that changed from the base of the PR and between e76b8c9 and 8c7c8fa.

📒 Files selected for processing (5)
  • docs/contributing/architecture/data-storage.md
  • packages/worker/src/email/inbound-mailbox-mirror.workers.test.ts
  • packages/worker/src/email/inbound-mailbox.node.test.ts
  • packages/worker/src/email/inbound-mailbox.ts
  • packages/worker/src/email/inbound.ts

Comment thread docs/contributing/architecture/data-storage.md
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants