Skip to content

feat(email): route write leases through UserMeter - #1197

Merged
kody-bot merged 9 commits into
mainfrom
cursor/meter-do-38c8
Aug 4, 2026
Merged

kody-bot merged 9 commits into
mainfrom
cursor/meter-do-38c8

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Aug 4, 2026 •

Copy link
Copy Markdown
Owner

Intent

Complete the expand step for account write-lease authority by moving the final four email call sites onto UserMeter before deleting the legacy D1 path in a follow-up deployment.

Summary

  • pass the existing worker env to inbound, inbound-effects, outbound, and inbound-reconciliation lease boundaries
  • preserve all email behavior and the legacy D1 lease read/write path during the mixed-version drain
  • defer legacy-path deletion until this deploy is verified and D1 active leases drain

Testing

  • npm run typecheck β€” passed
  • email workers suites β€” 3 files, 21 tests passed
  • inbound-effects node suite β€” 1 test passed
  • local E2E with fresh disposable D1 β€” 15/15 passed
  • CI rerun after a workerd broken-pipe failure β€” green
  • Cursor Bugbot + CodeRabbit β€” passed, no actionable comments

System changes

System recap β€” composes existing primitives (low risk)

Mode: recap Β· Base: main @ ffb84630 Β· Head: 8ba23da2

Classification: composes β€” call-site wiring routes existing email mutations through the existing UserMeter lease authority; no primitive contract changes.

Primitives touched

Primitive Group Impact
email assistant composes β€” supplies USER_METER to four existing lease boundaries

System map

Email mutation paths now select the UserMeter branch of the existing write-lease helper while D1 remains a rollout compatibility fence.

Legend: green = composes (wiring only) Β· amber = extended by this PR Β· red = new primitive Β· gray = context (unchanged, included only when an edge crosses it).

flowchart LR
  email["email<br/>Email"]:::touched
  userMeter["user-meter<br/>Per-user quota meter"]:::untouched
  d1["d1-app-db<br/>Application database"]:::untouched
  email -->|"pass env to withAccountWriteLease"| userMeter
  email -->|"retain deleting_at and rollout lease compatibility"| d1
  classDef touched fill:#1a7f37,color:#fff
  classDef extended fill:#9a6700,color:#fff
  classDef added fill:#cf222e,color:#fff
  classDef untouched fill:#57606a,color:#fff
Loading

Invariants

Per-user isolation and account-deletion fencing remain unchanged; this PR only changes which already-existing authority branch the email paths select.

Conductor report

  • STATUS: merged and deployed in main 95f2150e at 2026-08-04 01:13Z
  • Mailbox coordination: mailbox legacy graph retirement was complete (#1174 / #1189); these were call-site-only changes.
  • Drain evidence: at 01:18Z, no D1 lease was acquired after this deploy. The one remaining pre-cutover row dated 2026-08-02 was audited and repaired (e72aac17-b95c-4b3a-8afd-08e3bb9d8893). Follow-up D1 active lease count: 0.
  • Parity evidence: repaired user had d1Only=0, legacyWithoutD1=0, deletion tombstone parity true. UserMeter remains authoritative and currently reports active DO leases independently.
  • Next step: remove the legacy D1 path and optional-env API from a fresh main-based branch; D1 schema drop remains a separate destructive review PR.
  • Destructive work: none.
Open in WebΒ Open in CursorΒ 

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability when processing inbound and outbound email delivery operations.
    • Ensured email processing retains the correct runtime environment while account updates are performed.

cursoragent and others added 9 commits August 4, 2026 00:34
All four email paths (inbound, inbound-effects, outbound,
reconcile-inbound-deliveries) now supply env to withAccountWriteLease.
This is call-site coordination only; no behavior changes beyond
env/holder plumbing. Mailbox legacy graph is already dropped
(#1174/#1189).

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
…only

- withAccountWriteLease: env required; remove D1 acquire/release path,
  D1/DO union, waitUntil param, and active_write_count plumbing
- markAccountDeleting: env required; D1 deleting_at set first (gate),
  then UserMeter markDeleting; no D1 lease snapshot or loading
- listActiveAccountWriteLeases: (env, userId) only; UserMeter page walk;
  no D1 union
- repairAccountWriteLease: env required; DO-only prepare/finalize; D1
  audit row kept; no stale D1 clear
- Remove dead waitUntil params from all call sites
- D1 users.deleting_at remains the permanent point gate

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
- Remove shadow types: UserMeterWriteLeaseShadow (replaced by
  UserMeterWriteLeaseEntry without authority field)
- Remove listDoAuthorityWriteLeases, replaceLegacyWriteLeases, and
  assertWriteLeaseAuthority
- Remove authority discriminated union behavior from acquireWriteLease,
  releaseWriteLease, prepareWriteLeaseRepair, finalizeWriteLeaseRepair
- Keep warm authority column/shim for schema compatibility; code treats
  every row as authoritative DO; will drop after schema_version >= 7
- Simplify test-support/user-meter.ts to match: remove authority field
  from WriteLeaseRow, remove finalizeWriteLeaseRepair authority guard

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
…ease query

- DeletionParity: drop d1ActiveLeaseCount/doAuthorityLeaseCount/doLegacyLeaseCount/
  tokenSetMismatches/temporaryMirrorRetired/mirrorLeaseParity; keep d1DeletingAt,
  meterDeletingAt, deletingAtParity, activeLeaseCount, truncated
- readDeletionParity: read D1 deleting_at + UserMeter deletingAt/countActiveWriteLeases;
  no D1 account_write_leases query
- admin-user-meter-parity: update deletionParitySchema, description, and keywords
  to match new DeletionParity type
- Tests: remove bootstrapDeletionState/UserMeterWriteLeaseShadow, rewrite to
  use meter.markDeleting and new parity shape; remove split-authority tests

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
- deletion-state.node.test.ts: rewrite for meter-only mark/list/repair;
  remove D1-only lease paths and waitUntil; add env-required tests; verify
  D1 deleting_at gate and races; add export/purge tombstone preservation test
- account-deletion.node.test.ts: acquire UserMeter lease to simulate active
  writer; verify deletion is blocked then proceeds after lease release
- user-meter.workers.test.ts: remove shadowAcquireWriteLease,
  listDoAuthorityWriteLeases, bootstrapDeletionState, authority field
- service.node.test.ts files: remove writeLeaseDb mock hooks; batch mock
  runs statements directly (no D1 account_write_leases queries on runtime path)

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
- account-write-lease-repair.md: remove legacy email / D1 lease paths;
  describe DO-only repair flow; note D1 account_write_leases quiescent
- data-storage.md: note authority column warm/ignored; all callers supply env;
  D1 account_write_leases quiescent; write-lease rows clear on release/repair/purge
- entitlements.md: rewrite Account-deletion write fencing section; mark contract
  complete 2026-08-03; remove split-authority/Phase-B/mirror-retired prose;
  update primitives table (activeLeaseCount replaces mirrorLeaseParity/doOnly)
- primitives.yaml: update User meter summary to reflect authoritative DO leases

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 4, 2026 •

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

Email inbound, outbound, and reconciliation flows now pass their worker environment to withAccountWriteLease.

Changes

Email lease environment propagation

Layer / File(s) Summary
Update email lease call sites
packages/worker/src/email/inbound.ts, packages/worker/src/email/inbound-effects.ts, packages/worker/src/email/reconcile-inbound-deliveries.ts, packages/worker/src/email/outbound.ts
Each email-related withAccountWriteLease call now receives the corresponding worker environment.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Possibly related PRs

πŸš₯ 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.
Title check βœ… Passed The title clearly summarizes routing email write leases through UserMeter, which is the main change.
Description check βœ… Passed The description covers intent, changes, testing, system impact, rollout safety, and deferred legacy-path removal.
✨ 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/meter-do-38c8

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.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

πŸ”Ž Preview deployed: https://kody-pr-1197.kody-a99.workers.dev

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

Mocks:

@kody-bot
kody-bot merged commit 69db99c into main Aug 4, 2026
14 of 16 checks passed
@kody-bot
kody-bot deleted the cursor/meter-do-38c8 branch August 4, 2026 01:05
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