-
Notifications
You must be signed in to change notification settings - Fork 409
fix(proxy): hold fenced hard turns through cooldown #1739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Soju06
merged 4 commits into
Soju06:main
from
kevinsslin:codex/upstream-hard-turn-cooldown-recovery
Aug 16, 2026
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
108aceb
fix(proxy): hold fenced hard turns through cooldown
kevinsslin 32247a0
docs: add @kevinsslin as a contributor
Komzpa 23a10ae
fix(proxy): harden operation-fenced cooldown wait
Komzpa 841cd35
fix(proxy): fail closed on cooldown lease renewal errors
kevinsslin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
openspec/changes/hold-operation-fenced-hard-turn-cooldown/.openspec.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-08-14 |
41 changes: 41 additions & 0 deletions
41
openspec/changes/hold-operation-fenced-hard-turn-cooldown/design.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| ## Context | ||
|
|
||
| Hard turn-state requests can omit `previous_response_id` while still carrying a | ||
| real Codex turn-state continuity anchor. Their replay identity is protected by | ||
| the durable operation ledger, but the startup cooldown guard runs before | ||
| operation registration. It therefore classifies the request as continuity-bound | ||
| without safe replay and returns 503 before the ledger can serialize recovery. | ||
|
|
||
| The HTTP response already includes `Retry-After`, and an already-started SSE | ||
| failure includes an SSE `retry:` directive. Production telemetry shows Codex | ||
| Desktop retrying in milliseconds anyway, so another client hint does not address | ||
| the observed failure mode. | ||
|
|
||
| ## Decision | ||
|
|
||
| Treat a turn-state-only hard request as eligible to wait through cooldown only | ||
| when all of the following hold: | ||
|
|
||
| - recovery mode is `server_anchored_replay_once` or | ||
| `server_indefinite_recovery`; | ||
| - the durable operation ledger is enabled; | ||
| - the request has a real hard continuity anchor; | ||
| - the bridge has both a durable session id and current owner epoch; | ||
| - no response id or upstream response event has been observed; and | ||
| - request budget remains. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| The wait is clamped to the smaller of cooldown remaining and request budget. | ||
| It does not reserve a replay, mutate the operation journal, or send upstream. | ||
| When the cooldown expires, normal submission performs the existing operation | ||
| fingerprint lookup and atomic recovery claim. One-shot mode keeps its existing | ||
| maximum of one recovery dispatch; indefinite mode retains its existing explicit | ||
| opt-in semantics. | ||
|
|
||
| ## Explicit exclusions | ||
|
|
||
| - No change to the default `fail_closed` mode. | ||
| - No transparent replay without a durable session and owner fence. | ||
| - No cross-account, file-pinned, image, soft-affinity, or eventful recovery. | ||
| - No weakening of operation fingerprint, ownership, or replay-count checks. | ||
| - No infinite retry added by this change; bounded one-shot mode is the | ||
| recommended deployment setting for this incident class. | ||
27 changes: 27 additions & 0 deletions
27
openspec/changes/hold-operation-fenced-hard-turn-cooldown/proposal.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| ## Why | ||
|
|
||
| When two eventless upstream attempts open the HTTP bridge retry circuit, Codex | ||
| Desktop immediately retries the same hard turn-state request. The bridge | ||
| currently returns a startup 503 before consulting the durable operation ledger. | ||
| Codex does not honor the full retry-circuit delay and can exhaust its client | ||
| retry budget during the cooldown, pausing the task even though the bridge and | ||
| VPS remain healthy. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - In an explicitly enabled server recovery mode, hold a turn-state-only hard | ||
| continuation through the active retry-circuit cooldown before submission. | ||
| - Require a live durable session id and owner epoch, zero response events, and | ||
| no response id before waiting. | ||
| - Dispatch nothing while waiting. After cooldown, use the existing durable | ||
| operation ledger and one-shot/indefinite recovery policy to arbitrate whether | ||
| the request may be created, claimed, replayed, or failed closed. | ||
| - Preserve the current immediate 503 for the default `fail_closed` mode, | ||
| in-memory fallback sessions, soft affinity, and eventful requests. | ||
| - Emit a low-cardinality bridge event when the operation-fenced wait begins. | ||
|
|
||
| ## Impact | ||
|
|
||
| - HTTP Responses bridge startup behavior during retry-circuit cooldown. | ||
| - No database schema, public API, account routing, or default configuration | ||
| change. |
67 changes: 67 additions & 0 deletions
67
...ges/hold-operation-fenced-hard-turn-cooldown/specs/responses-api-compat/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Operation-fenced hard turns preserve client retry budget during cooldown | ||
|
|
||
| A hard turn-state HTTP bridge request arriving during retry-circuit cooldown MUST remain pending until cooldown expires only if an explicit server recovery mode is enabled, the request has not observed a response id or response event, and the bridge has a live durable session and owner epoch. The proxy MUST NOT dispatch upstream while waiting. After the wait, the request MUST pass through the existing durable operation-ledger admission before any `response.create` is sent. | ||
|
|
||
| #### Scenario: One-shot hard turn waits before durable arbitration | ||
|
|
||
| - **GIVEN** `server_anchored_replay_once` is enabled | ||
| - **AND** a turn-state-only hard continuation has a live durable owner | ||
| - **AND** its retry circuit is cooling down before submission | ||
| - **WHEN** the request reaches bridge startup | ||
| - **THEN** the proxy waits for the bounded cooldown instead of returning 503 | ||
| - **AND** it sends no upstream request during the wait | ||
| - **AND** normal durable operation admission runs after cooldown | ||
|
|
||
| #### Scenario: Missing durable fence remains fail closed | ||
|
|
||
| - **GIVEN** a turn-state-only hard continuation has no durable session or owner | ||
| epoch | ||
| - **WHEN** its retry circuit is cooling down | ||
| - **THEN** the proxy does not wait or dispatch upstream | ||
| - **AND** it returns the existing cooldown failure with a retry hint | ||
|
|
||
| #### Scenario: Operation ledger disabled remains fail closed | ||
|
|
||
| - **GIVEN** ambiguous continuation recovery mode is enabled | ||
| - **AND** a turn-state-only hard continuation has a live durable session and | ||
| owner epoch | ||
| - **AND** the durable operation ledger is disabled | ||
| - **WHEN** its retry circuit is cooling down before submission | ||
| - **THEN** the proxy preserves the existing cooldown failure | ||
| - **AND** it does not wait or dispatch upstream | ||
|
|
||
| #### Scenario: Default mode remains fail closed | ||
|
|
||
| - **GIVEN** ambiguous continuation recovery mode is `fail_closed` | ||
| - **WHEN** any continuity-bound hard request arrives during cooldown | ||
| - **THEN** the proxy preserves the existing immediate cooldown failure | ||
| - **AND** it does not create or claim a durable recovery operation | ||
|
|
||
| #### Scenario: Request budget expires while waiting | ||
|
|
||
| - **GIVEN** an operation-fenced hard turn is allowed to wait through cooldown | ||
| - **AND** its request budget expires before the cooldown does | ||
| - **WHEN** the bounded wait reaches the request deadline | ||
| - **THEN** the proxy releases the request reservation and returns a terminal | ||
| timeout | ||
| - **AND** it does not submit `response.create` after the deadline | ||
|
|
||
| #### Scenario: Cooldown waiter stays within the per-session queue limit | ||
|
|
||
| - **GIVEN** an operation-fenced hard turn is eligible to wait through cooldown | ||
| - **AND** the bridge session is already at its configured queue limit | ||
| - **WHEN** the request reaches the cooldown wait point before submission | ||
| - **THEN** the proxy rejects the request with the existing bridge queue full | ||
| error | ||
| - **AND** it does not sleep or dispatch upstream | ||
|
|
||
| #### Scenario: Durable ownership is renewed while the cooldown wait is pending | ||
|
|
||
| - **GIVEN** an operation-fenced hard turn is waiting through startup cooldown | ||
| - **AND** the cooldown exceeds one durable lease refresh cadence | ||
| - **WHEN** the wait continues before submission | ||
| - **THEN** the proxy renews and revalidates the durable owner lease before the | ||
| wait completes | ||
| - **AND** it fails closed if durable ownership changes during the wait |
8 changes: 8 additions & 0 deletions
8
openspec/changes/hold-operation-fenced-hard-turn-cooldown/tasks.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| - [x] 1. Reproduce the production turn-state-only startup cooldown as a unit | ||
| regression that currently returns 503 before submission. | ||
| - [x] 2. Hold only explicitly enabled, zero-event, durable operation-fenced hard | ||
| turns through the bounded cooldown. | ||
| - [x] 3. Preserve fail-closed behavior when the durable session/owner proof is | ||
| absent and keep one-shot recovery bounded by the existing atomic claim. | ||
| - [x] 4. Run focused tests, relevant bridge suites, Ruff, type/architecture | ||
| checks, whitespace checks, and strict OpenSpec validation. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.