Skip to content

fix(server): recover Codex sessions after process exits - #12922

Open
matheustimbo wants to merge 4 commits into
pingdotgg:mainfrom
matheustimbo:fix/codex-dead-session-recovery
Open

matheustimbo wants to merge 4 commits into
pingdotgg:mainfrom
matheustimbo:fix/codex-dead-session-recovery

Conversation

@matheustimbo

@matheustimbo matheustimbo commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #12904. A Codex App Server killed by SIGKILL left the T3 thread bound to a closed runtime. Every subsequent send failed with ProviderAdapterSessionClosedError until the T3 server was restarted or the session was otherwise replaced.

This PR combines two complementary fixes already proposed upstream:

The original authors and commits are preserved. This branch also closes lifecycle races: observers see the session removed before its terminal event; an explicit stop emits one graceful terminal event; a process exit during startup fails the start; and pending teardown remains covered during adapter shutdown.

A real-process integration regression kills the Codex peer with SIGKILL, checks that hasSession is false and listSessions is empty, then resumes the same native thread and sends a new turn. The interrupted turn is not replayed. A separate test closes the adapter as the terminal event arrives and verifies cleanup.

Related: #10798.

Validation

  • Focused Codex adapter and runtime integration tests: 71 passed.
  • bun run fmt: passed.
  • bun run lint: passed, with existing repository warnings outside these files.
  • bun run typecheck: passed across 15 workspaces.
  • git diff --check: passed.

No live server update is included.

Summary by CodeRabbit

  • Bug Fixes
    • Improved recovery when a Codex session exits unexpectedly, including resuming sessions with saved progress.
    • Prevented stale or duplicate exit notifications during session replacement and cleanup.
    • Ensured replacement sessions can start without being blocked by a previously failed session.
    • Improved exit status reporting for normal closures, unexpected terminations, and non-zero exit codes.
    • Ensured intentional stops report a graceful session exit consistently.

khaneliman and others added 4 commits September 21, 2026 09:51
Handle failed exit-status effects so signal termination emits the session exit event needed by the existing resume path. Cover killed-process recovery, numeric exit statuses, and intentional shutdown with process fixtures.

(cherry picked from commit 2faee12)
Wait for piped responses to flush before the fixture exits so numeric-exit coverage cannot hang on a truncated response.

(cherry picked from commit b986d37)
The Codex adapter forwarded a runtime's session.exited event but left the dead session in its map, so hasSession and listSessions kept reporting the thread as live. Startup reconciliation trusts listSessions and the session reaper skips sessions holding an activeTurnId, so a thread whose Codex process died mid-turn stayed running and showed Working forever.

(cherry picked from commit 95c96c1)
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 21, 2026
Comment on lines +2407 to +2413
onFailure: (cause) => {
const diagnostic = cause instanceof Error ? cause.message : String(cause);
return {
status: "error" as const,
message: `Codex App Server exited unexpectedly: ${diagnostic}.`,
};
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exposes arbitrary failure text through the provider event, which can leak command output, paths, or other unbounded defect details to downstream UI/RPC consumers. Keep the event message normalized and bounded; the underlying failure remains available in the Effect cause for diagnostics.

Suggested change
onFailure: (cause) => {
const diagnostic = cause instanceof Error ? cause.message : String(cause);
return {
status: "error" as const,
message: `Codex App Server exited unexpectedly: ${diagnostic}.`,
};
},
onFailure: () => ({
status: "error" as const,
message: "Codex App Server exited unexpectedly.",
}),

Posted via Macroscope — Effect Service Conventions

@macroscopeapp

macroscopeapp Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes production session lifecycle behavior across process-exit recovery, teardown, replacement, and event publication rather than making a narrowly isolated fix. Its new exit diagnostic can expose arbitrary process failure text to downstream consumers, requiring human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Understand this PR’s impact

Explore downstream dependencies and potential security impact with Blast Radius.

View blast radius →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 0c6df8bb-120f-4759-8957-b0f88065bc13

📥 Commits

Reviewing files that changed from the base of the PR and between 1de563c and 67b5747.

📒 Files selected for processing (4)
  • apps/server/src/provider/Layers/CodexAdapter.test.ts
  • apps/server/src/provider/Layers/CodexAdapter.ts
  • apps/server/src/provider/Layers/CodexCollabRuntime.integration.test.ts
  • apps/server/src/provider/Layers/CodexSessionRuntime.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The Codex runtime now reports unexpected process exits. The adapter removes exited sessions, separates terminal events from resource teardown, and waits for pending teardown. Tests cover startup exits, process recovery, exit statuses, and intentional closes.

Changes

Codex exit recovery

Layer / File(s) Summary
Runtime exit status handling
apps/server/src/provider/Layers/CodexSessionRuntime.ts
Failed child exits now produce error status and diagnostic messages. Numeric exit codes retain their closed or error mappings.
Adapter session teardown
apps/server/src/provider/Layers/CodexAdapter.ts
The adapter tracks teardown state, filters stale events, removes exited sessions, publishes graceful exits, and releases resources through an idempotent teardown path.
Lifecycle and recovery validation
apps/server/src/provider/Layers/CodexAdapter.test.ts, apps/server/src/provider/Layers/CodexCollabRuntime.integration.test.ts
Tests cover startup exits, replacement sessions, delayed stopAll teardown, SIGKILL recovery, resume requests, numeric exit statuses, and intentional close behavior.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant CodexAppServer
  participant CodexSessionRuntime
  participant CodexAdapter
  participant ResumedRuntime
  CodexAppServer->>CodexSessionRuntime: exit unexpectedly
  CodexSessionRuntime->>CodexAdapter: emit session/exited with error status
  CodexAdapter->>CodexAdapter: remove session and release resources
  ResumedRuntime->>CodexAdapter: resume thread with saved cursor
  CodexAdapter->>CodexAppServer: send thread/resume with excludeTurns true
Loading

Suggested reviewers: t3dotgg, juliusmarminge

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: recovering Codex sessions after the App Server process exits.
Description check ✅ Passed The description is detailed, on-topic, and explains the problem, implementation, validation, and scope. It uses Summary and Validation headings instead of the template's What Changed, Why, and Checkli…
Linked Issues check ✅ Passed The changes satisfy the coding requirements in issue #12904. CodexSessionRuntime now handles failed exit-status retrieval and emits session/exited for unexpected process termination, including `SI…
Out of Scope Changes check ✅ Passed The reported changes stay within issue #12904. Runtime exit handling, adapter cleanup, startup-failure handling, teardown ordering, and shutdown behavior directly support reliable recovery and resourc…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Codex turn retries stay closed after App Server SIGKILL

3 participants