Egress approval settlement survives a stream restart
Status summary#
Complete. Keyed root appends now get one bounded availability replay, exact approval submissions are replay-safe without blocking a corrected decision, and a fetch cannot report success until its settlement fact is durable. Focused preview proofs and the full preview suite passed without retries at the product head. A later docs-only CI run exposed a separate Stream Facet wake cycle, fixed in this PR; its release gate is green and PR #2467 is ready for review.
Problem#
Preview 8 worker version 6291b7de-419a-4ba1-92d6-32c9b9e48951 reproduced
this sequence on 2026-08-10:
- the stream restart was injected at
14:14:49.966Z; - the approval decision append completed at
14:14:50.993Z; - the held Script Execution recovered and returned HTTP 200 at
14:14:51.689Z; - the worker logged
egress approval: settle append failedfor projectprj_dc2de56d94ab423391cb047faae7c420, approval offset 41, index 0 at14:14:51.459Z; - the public
waitForEventthen expired after 30 seconds because nohuman-approval-settledfact existed.
The settlement append already has an idempotency key, so retrying a retryable Durable Object availability failure is safe. A successful approved fetch must not return before that durable outcome is recorded. Non-retryable append failures must still fail loudly instead of becoming a successful but divergent result.
Checklist#
- Add one regression through the Project Egress public behavior: a held request is approved, the first settlement append gets a retryable stream reset, the caller receives the upstream response, and exactly one settlement fact exists. The root-append unit test covers the reset and one replay; the production-shaped restart e2e proves the end-to-end outcome.
- Confirm the regression fails because the current code swallows the settlement append failure. A public collision on the deterministic settlement key first reproduced a false HTTP 200 with no settlement.
- Retry the keyed settlement append through the existing bounded, observable idempotent-operation policy. Keyed root appends now get one explicit replay; they do not inherit the orphan deadline used by non-root processor paths.
- Keep non-retryable settlement failures visible to the caller. The Project DO now rejects the held fetch if success or error settlement cannot be journalled.
- Run the focused unit/integration checks, then the forced-restart e2e against a preview deployment with no retry layer. Stream RPC 35/35, approve-core 17/17, both package typechecks, settlement-collision e2e, and forced-restart e2e passed; the latter two passed on their first attempts against preview 1.
- Audit the preview trace/log window for one decision, one settlement,
no swallowed append warning, and no unexplained errors. The restart
window had no settlement warning or attributable retry. The deliberate
collision trace
ee9193f23c9f92b54d06953904d9e098records the expected egress error, no worker error log, and no settlement fact.
Implementation log#
- 2026-08-10: PR #2460 was squash-merged as
f83499aa. This follow-up was split out after its final docs-only preview's retry was traced to the settlement append, not the mobile restoration paths or the parked Script Execution recovery itself. - 2026-08-10: Added deterministic decision idempotency keys so the bounded append replay cannot duplicate an approval decision after an ambiguous reset.
- 2026-08-11: Cursor Bugbot found that keying only by request offset made an ignored invalid decision collide with a corrected retry. Decision keys are now content-addressed: an exact append replay dedupes, while a changed verdict, key, reason, or signature is a distinct submission.
- 2026-08-10: The first follow-up preview exposed a merge-integration gap: #2460 contained the Notifications screen and specs, while its drawer link existed only in that branch's old base history. Restored the link alongside the current integrations/repos/media entries. Both affected mobile specs then passed locally and in canonical preview CI without retries.
- 2026-08-10: Final preview CI on
67168d04passed every check: 199 OS Vitest tests, 73 Playwright tests, and no retries. Its 190.9s OS lane is below the preceding failed run's 210.0s, but still trips the repo's existing 100s performance warning; this PR did not raise that baseline. - 2026-08-10: The later docs-only head retried during
Project.create, before the tested source recreation began. The separate source-alarm/facet-wake actor cycle is a release blocker, but does not reopen the completed approval settlement behavior.