Skip to content

Require durable R2 storage for inbound MIME - #853

Merged
kody-bot merged 2 commits into
mainfrom
cursor/legacy-purge-b-data-migrations-f449
Jul 22, 2026
Merged

kody-bot merged 2 commits into
mainfrom
cursor/legacy-purge-b-data-migrations-f449

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • require inbound raw MIME to reach EMAIL_BLOBS before inserting its D1 message row
  • remove all new inline raw_mime writes; R2 failures propagate for Email Routing retry
  • define an explicit durability commit point to avoid duplicate retries after post-commit bookkeeping failures
  • refund user/system daily receive quota only for typed pre-commit storage retries
  • keep the dual-read and deploy sweep temporarily for already-existing residuals

Durability policy

R2 is required for inbound MIME. A transient pre-commit R2/D1 failure is retried and does not consume receive quota. Once message+attachment rows are durable, bookkeeping failures are logged/acknowledged rather than retried, preventing duplicate mail.

Validation

  • complete unit suite: 1,082 tests passed
  • focused user/system inbound, R2 failure, D1/attachment cleanup, quota refund, and post-commit boundary tests passed
  • typecheck and formatting passed
System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ 1689cd0c · Head: 81899dbc

Classification: extends — makes R2 the required durability boundary for inbound email MIME.

Primitives touched

Primitive Group Impact
email assistant extends — typed pre/post commit delivery behavior
email-blobs-r2 storage extends — required write before D1 commit
entitlements auth extends — scoped receive-quota refunds on retry

Invariants

  • No new non-null email_messages.raw_mime writes.
  • Retryable pre-commit failures do not consume quota.
  • Post-commit failures do not cause duplicate delivery retries.
  • User and system counters remain separately scoped.
Open in Web Open in Cursor 

Summary by CodeRabbit

  • Improvements

    • Inbound email storage is now more reliable, with transient storage failures eligible for automatic retry.
    • Daily receive quotas are restored when a retryable storage failure prevents delivery, including system inboxes.
    • Successful inbound messages no longer depend on legacy inline raw-email storage.
    • Post-delivery bookkeeping issues no longer cause duplicate delivery attempts.
  • Documentation

    • Clarified email storage durability, quota refunds, retry behavior, and legacy data cleanup requirements.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 51b3e75b-9acb-4756-b8e3-a41515cefa62

📥 Commits

Reviewing files that changed from the base of the PR and between 1689cd0 and a5e1f9c.

📒 Files selected for processing (12)
  • docs/contributing/architecture/data-storage.md
  • docs/contributing/architecture/entitlements.md
  • docs/use/email-primitives.md
  • packages/worker/src/email/inbound.ts
  • packages/worker/src/email/inbound.workers.test.ts
  • packages/worker/src/email/repo.ts
  • packages/worker/src/email/system-email.ts
  • packages/worker/src/email/system-email.workers.test.ts
  • packages/worker/src/entitlements/entitlements.node.test.ts
  • packages/worker/src/entitlements/plans.ts
  • packages/worker/src/entitlements/service.ts
  • packages/worker/src/index.ts

📝 Walkthrough

Walkthrough

Inbound email persistence now requires R2-first MIME storage and typed retryable failures. Daily receive quotas are refunded for pre-commit storage failures using the original UTC day, while post-commit bookkeeping failures do not trigger retries or refunds. Tests and documentation cover these contracts.

Changes

Inbound storage and quota handling

Layer / File(s) Summary
R2-first MIME storage and cleanup
packages/worker/src/email/repo.ts, packages/worker/src/email/inbound.workers.test.ts, docs/contributing/architecture/data-storage.md
Inbound MIME is written to EMAIL_BLOBS before the D1 row, inline raw_mime fallback is removed, and attachment failures perform cleanup and durable-row probing.
Daily entitlement refund primitives
packages/worker/src/entitlements/service.ts, packages/worker/src/email/system-email.ts, packages/worker/src/entitlements/*.test.ts, packages/worker/src/email/system-email.workers.test.ts, docs/contributing/architecture/entitlements.md, packages/worker/src/entitlements/plans.ts
User and system daily counters support atomic refunds clamped at zero, using the same UTC timestamp as quota consumption.
Inbound commit boundary and retry handling
packages/worker/src/email/inbound.ts, packages/worker/src/email/inbound.workers.test.ts, packages/worker/src/email/system-email.workers.test.ts, packages/worker/src/index.ts, docs/use/email-primitives.md
Pre-commit storage failures become retryable and refund quota; post-commit bookkeeping failures are logged without refund or retry, with updated handler comments and quota documentation.

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

Sequence Diagram(s)

sequenceDiagram
  participant EmailRouting
  participant handleInboundEmail
  participant parseAndStoreInboundEmail
  participant EMAIL_BLOBS
  participant D1
  EmailRouting->>handleInboundEmail: deliver inbound email
  handleInboundEmail->>parseAndStoreInboundEmail: consume daily receive quota
  parseAndStoreInboundEmail->>EMAIL_BLOBS: store raw MIME
  parseAndStoreInboundEmail->>D1: insert message and attachments
  D1-->>parseAndStoreInboundEmail: commit result
  parseAndStoreInboundEmail-->>handleInboundEmail: return or throw storage error
  handleInboundEmail->>handleInboundEmail: refund quota for retryable pre-commit failure
  handleInboundEmail-->>EmailRouting: rethrow for retry
Loading

Possibly related PRs

  • kentcdodds/kody#619: Extends the same daily entitlement counter model with refund-on-retry behavior.
  • kentcdodds/kody#642: Adds related system-email daily counter plumbing used by the new system inbox refunds.
  • kentcdodds/kody#669: Modifies the same raw-email MIME R2 storage and loading paths.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: making durable R2 storage required for inbound MIME.
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.
✨ 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/legacy-purge-b-data-migrations-f449

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.

@cursor
cursor Bot force-pushed the cursor/legacy-purge-b-data-migrations-f449 branch from 51d8fa9 to a5e1f9c Compare July 22, 2026 07:30
@kody-bot
kody-bot marked this pull request as ready for review July 22, 2026 07:32
@github-actions

Copy link
Copy Markdown
Contributor

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

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

Mocks:

@kody-bot
kody-bot merged commit a25adea into main Jul 22, 2026
7 checks passed
@kody-bot
kody-bot deleted the cursor/legacy-purge-b-data-migrations-f449 branch July 22, 2026 07:39
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