You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Surfaced during Step 3.4 phase-executor full-path import audit. The Step 3.4 spec (#729) treated `getMessage` and `getReply` as obsolete read helpers after Steps 3.1–3.3 flipped the GET handlers to D1. The audit found these helpers are still live in WRITE-path authorization reads (PATCH mark-read, POST reply):
`app/api/outbox/[address]/route.ts:198` — POST handler: `getMessage(kv, messageId)` to fetch original message for auth
`app/api/outbox/[address]/route.ts:318` — POST handler: `getReply(kv, messageId)` to check for duplicate replies
`app/api/outbox/[address]/route.ts:343` — POST handler: `getMessage(kv, messageId)` in partial-write recovery path
`app/api/inbox/[address]/[messageId]/route.ts:203` — PATCH handler: `getMessage(kv, messageId)` to verify ownership before mark-read
These are authorization reads embedded in write flows, not display reads. Step 3.2 (#731) flipped the GET path only.
Step 4 removes KV writes on POST/PATCH handlers. Once writes are gone, KV is no longer kept in sync — KV reads on those same handlers would race against stale data. Step 4's cutover requires the entire POST/PATCH path (read + write) to be on D1.
Doing the auth-read flip as a separate step also isolates the variable: this PR is reversible (D1 already has the data via dual-write since Step 1; flipping reads doesn't impact writes), whereas Step 4 is the irreversible write removal.
Flip POST `/api/outbox/[address]` to use D1 for the duplicate-reply check (needs new helper or use `fetchRepliesForMessages` with single-element array)
#730 is already the irreversible cutover with a 60min smoke window. Bundling the auth-read flip would conflate two cutovers into one PR and a single smoke. Splitting them lets each smoke isolate one variable (LOOP_PROMPT PR-scoping discipline).
Authorized under whoabuddy's 2026-05-11T01:40Z directive ("go all the way; Step 4 is important to reducing the bill"). Step 4 (#730) still requires the explicit double-checkpoint per LOOP_PROMPT; this Step 3.5 is incremental and inherits the series authorization.
Context
Surfaced during Step 3.4 phase-executor full-path import audit. The Step 3.4 spec (#729) treated `getMessage` and `getReply` as obsolete read helpers after Steps 3.1–3.3 flipped the GET handlers to D1. The audit found these helpers are still live in WRITE-path authorization reads (PATCH mark-read, POST reply):
These are authorization reads embedded in write flows, not display reads. Step 3.2 (#731) flipped the GET path only.
Why this is a prerequisite for #730 (Step 4)
Step 4 removes KV writes on POST/PATCH handlers. Once writes are gone, KV is no longer kept in sync — KV reads on those same handlers would race against stale data. Step 4's cutover requires the entire POST/PATCH path (read + write) to be on D1.
Doing the auth-read flip as a separate step also isolates the variable: this PR is reversible (D1 already has the data via dual-write since Step 1; flipping reads doesn't impact writes), whereas Step 4 is the irreversible write removal.
Scope
In:
Out:
Why not roll this into #730
#730 is already the irreversible cutover with a 60min smoke window. Bundling the auth-read flip would conflate two cutovers into one PR and a single smoke. Splitting them lets each smoke isolate one variable (LOOP_PROMPT PR-scoping discipline).
Acceptance criteria
References
Sign-off context
Authorized under whoabuddy's 2026-05-11T01:40Z directive ("go all the way; Step 4 is important to reducing the bill"). Step 4 (#730) still requires the explicit double-checkpoint per LOOP_PROMPT; this Step 3.5 is incremental and inherits the series authorization.