fix(codex): ungate app-server terminal liveness and fan out poisoned-client retirement#102097
fix(codex): ungate app-server terminal liveness and fan out poisoned-client retirement#102097obviyus wants to merge 3 commits into
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 8, 2026, 8:22 AM ET / 12:22 UTC. Summary PR surface: Source +77, Tests +204. Total +281 across 10 files. Reproducibility: yes. source-reproducible: current main gates terminal-idle on activeAppServerTurnRequests, and the PR adds focused tests proving terminal-idle now fires with an in-flight request and resets on notifications. I did not run live or unit tests in this read-only review. Review metrics: 2 noteworthy metrics.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Keep this PR open as the B2 review record and land the behavior through #102160 after maintainers accept the Codex shared-client recovery tradeoff. Do we have a high-confidence way to reproduce the issue? Yes, source-reproducible: current main gates terminal-idle on activeAppServerTurnRequests, and the PR adds focused tests proving terminal-idle now fires with an in-flight request and resets on notifications. I did not run live or unit tests in this read-only review. Is this the best way to solve the issue? Yes for the B2 Codex liveness slice: removing only the terminal-idle request gate and making forced retirement opt-in is narrower than changing completion semantics or default cleanup. The best merge path is still the linked atomic integration PR, not standalone cleanup landing. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 4bf70be01a21. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +77, Tests +204. Total +281 across 10 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (3 earlier review cycles)
|
|
Landing plan update: this track lands atomically with its siblings via the integration PR #102160 (all commits preserved, rebase merge) — sequential landing would put untested intermediate states on main (e.g. the stale takeover without the quiet-tool floor). This PR stays open as the per-track review record and closes when #102160 lands. |
a43547d to
c66a2e5
Compare
What Problem This Solves
Track B2 of #101863 — the Codex app-server half of the liveness redesign (#89742, regression of #82681; also #85251, #90673).
One shared app-server client serves every session with the same auth profile + start options (
shared-client.tskeyed global map). Two verified defects:activeAppServerTurnRequests > 0suppresses the completion-idle (60s), assistant-completion (10s), and terminal-idle (30 min) watches. A client that goes silent with a request outstanding (the reported 429-burst shape:turn/started, then nothing) is exactly the state no watch can see; the only remaining bound is the whole run budget.Why This Change Was Made
Protocol proof (Codex gate). Inspected sibling
openai/codexsource directly: server→client requests register a oneshot callback and await the client's response (codex-rs/app-server/src/outgoing_message.rs:272-350), completely separate from fire-and-forget server notifications (outgoing_message.rs:589-629; envelope split inapp-server-transport/src/outgoing_message.rs:21-31; types inapp-server-protocol/src/protocol/common.rs:1199-1252, 1630-1658). An in-flight request therefore proves nothing about notification liveness in either direction — gating a notification-silence watchdog on the request counter is unsound.Changes (all in
extensions/codex/src/app-server/):attempt-turn-watches.ts): the 30-minute zero-notification backstop now fires regardless of in-flight requests. Its clock still resets on every real notification, so healthy turns — including ones legitimately waiting on approvals/elicitation — are untouched as long as the server emits anything within the window. The completion-idle and assistant-completion watches keep their request gates: they express turn-completion semantics, which are genuinely indeterminate while a request is being served. No timeout constants changed.shared-client.ts,attempt-client-cleanup.ts):retireSharedCodexAppServerClientIfCurrentgains an explicitfailActiveLeasesmode used only by the timed-out-turn path — it closes the physical client immediately (transport close SIGKILLs the child after 1s), so co-leased attempts hit the existing client-closed retry path and re-run on a fresh client, and pending acquires reject instead of leasing the poisoned process. Default retirement stays graceful (detach + close-when-idle): routine one-shot bundle-MCP cleanup and startup-failure paths keepmain's behavior — the initial implementation applied immediate-close to all callers, which would have yanked healthy clients from co-leased sessions at every one-shot run end; review caught it and scoped it, restoringmain's two graceful-retirement tests verbatim and adding a pin test for the default.Stated tradeoff: a healthy sibling turn co-leased on a client that another turn timed out gets aborted-and-retried. Intentional — a client suspect enough to deny future sessions should not keep serving current ones — and the failure is retryable, not user-terminal.
User Impact
Evidence
../codexinspection (f1affbac), verified independently by implementer and reviewer.extensions/codexsuite green (96 files / 2005 tests on Testbox; app-server subset 78 files / 1681 tests re-run green after review edits), extensions tsgo + extensions-test tsgo lanes exit 0, oxlint/oxfmt clean.Part of #101863 (Track B2). Fixes #89742; addresses #85251 / #90673 (same wedge class — will verify against each before closing).