Skip to content

fix(server): recover Codex sessions after sharing rejection - #28962

Open
yelgabo wants to merge 6 commits into
pingdotgg:mainfrom
yelgabo:fix/codex-invalid-history-recovery
Open

yelgabo wants to merge 6 commits into
pingdotgg:mainfrom
yelgabo:fix/codex-invalid-history-recovery

Conversation

@yelgabo

@yelgabo yelgabo commented Nov 1, 2026 •

Copy link
Copy Markdown

A Codex turn rejected by ChatGPT sharing can leave its native conversation unable to answer any later prompt, including huh. Native thread/resume succeeds, so T3 keeps reusing history that the provider rejects.

On the next user turn, recognize the persisted subscription_sharing_unsupported_capability failure in the latest accepted root attempt and use the existing fresh-session/portable-history fallback. Keep the T3 thread, visible transcript, provider-thread identity, selected provider/model, and the original error. Do not automatically retry the failed action. Scope recovery to the affected native session; wait for pending background work before replacing it.

Related: #21061. This is a focused recovery fix for an obvious reliability defect; it does not change native-agent availability or sharing configuration.

Expected rejection versus the recovery bug

The initial unsupported-capability rejection is expected when the configured runtime emits input that the sharing route does not support. It should not permanently poison subsequent ordinary text turns.

The reproduced managed process already had features.multi_agent=false and features.multi_agent_v2=false, but native agents still ran. Closed/unmerged #20270 proposes adding agents.enabled=false to prevent that mismatch. There is no verified enable=true workaround here. Prevention/configuration and recovery of existing affected histories are separate; this PR addresses recovery.

Reproduction

Environment: Windows x64 10.0.26200, T3 0.1.6 (build 2359643cffa6), managed Codex 0.156.1, openai_token_sharing, gpt-6-astra / high.

  1. In a disposable thread, request no tools and exactly BASELINE_OK: succeeds.
  2. Request exactly one native collaboration.spawn_agent, whose worker replies WORKER_OK without tools, followed by collaboration.wait_agent.
  3. Worker and parent fail with invalid_request_error, param=input, code=subscription_sharing_unsupported_capability, willRetry=false.
  4. Send literal huh: the same rejection occurs without an assistant reply or tool call. Model changes did not rescue the original affected thread.

The parent and worker rollouts contain native agent_message records immediately before rejection. These support the invalid-history explanation; the exact outgoing Responses HTTP item was not captured.

Original reproduction and sanitized protocol evidence.

Before/after verification

Public evidence gist: logs, runtime transcript, script, and validation manifest. All 13 files and the gist page were verified accessible without authentication. The original private-repository links were a publication error and have been replaced.

  • Against base fa31b66bbb2a, the new recovery cases fail for live, detached, legacy, and pending-background-work histories. All 7 new cases pass with this patch, including unrelated-error/provider controls and an already-repaired native session. They use the real orchestrator, SQLite projections, and handoff delivery with a deterministic adapter that rejects every subsequent turn on the affected native ID.
  • Separate real-provider validation copied the broken rollout into an isolated CODEX_HOME: resuming it and sending huh still failed. A replacement native session carrying the conversation as text correctly recalled BASELINE_OK, then answered FOLLOWUP_OK in that same session. No live install/state was patched. This checks the recovery mechanism, not a deployed T3 UI end-to-end.
  • Selected test files: 88 passed, 4 failed. All four worktree-recreation failures reproduce unchanged against base. Full failure names and outputs are in the evidence.
  • Changed-file format/lint, server GraphQL generation, typechecks for t3, @t3tools/evals, and @t3tools/scripts, and both knip:check passes succeeded.
  • vp run check:changed was attempted but its ignored-file scan traversed Windows pnpm junctions and emitted “Filename too long”; it was interrupted before checks. Its selected check commands were run directly. The aggregate command is not reported as passing.

Focused command:

vp test run apps/server/src/orchestration-v2/testkit/ProviderSwitch.integration.test.ts -t "recovers rejected Codex history"

History transfer retains the existing context budget and omission behavior. Unsupported requests can still be rejected until the runtime/configuration is compatible.

Model: GPT-6 Astra. Harness: Codex in T3 Code.

@github-actions github-actions Bot added vouch:unvouched Author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 1, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 332447e

Macroscope's review found this PR approvable — Recovers affected Codex conversations on the next user turn using the existing fresh-session context handoff. Recovery is scoped to the rejected history and guarded against pending background work, without changing sharing configuration or retrying the failed action.

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

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

Codex startup detects eligible rejected native history from prior accepted runs. If background work is pending, startup fails. Otherwise, it uses fresh-session recovery with portable context. Integration tests cover recovery and exclusion cases.

Changes: Codex rejected-history recovery

Layer / File(s) Summary
Detect rejected history and route startup
apps/server/src/orchestration-v2/ProviderTurnStartService.ts
Startup checks prior accepted-run history for the rejected-history error. It excludes mismatched native threads and runs covered by a full-thread-summary handoff. Pending background work causes ContextHandoffBackgroundWorkError. Otherwise, rejected history triggers fresh-session recovery with a distinct reason.
Exercise recovery and exclusion cases
apps/server/src/orchestration-v2/testkit/ProviderSwitch.integration.test.ts, apps/server/src/orchestration-v2/ProviderTurnStartService.test.ts
The test adapter tracks native threads with rejected runs. Integration scenarios cover recovery, repaired-native reuse, other errors, other providers, and pending background work. Tests also check that follow-up turns reuse the recovery thread without reinjecting history. The history fixture returns empty history when no fallback read failure is configured.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: yash-singh1, juliusmarminge, maria-rcks

Merge Risk: Minimal · up to 29b73

Codex sessions rejected for sharing now recover on the next user turn through the existing fresh-session fallback. No concrete merge-blocking defect was established. One unconfirmed edge case remains: whether native background work could survive a reopened runtime and so go undetected before the thread is replaced.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title "fix(server): recover Codex sessions after sharing rejection" names the main change: recovery of Codex sessions whose persisted history was rejected for subscription sharing. The raw summary…
Description check Passed The description follows the template's main sections: Problem (rejected Codex history blocks later prompts), Change (recovery via existing fresh-session/portable-history fallback, with scope limits), …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "fix(server): recover Codex sessions after sharing rejection" names the main change: recovery of Codex sessions whose persisted history was rejected for subscription sharing. The raw summary confirms the change in ProviderTurnStartService (rejected-history detection, fresh-session recovery with rejected_native_history) and the integration test matrix. The title is a conventional commit in plain language and is specific enough for a teammate scanning history. It omits the background-work wait and the test additions, which is acceptable.

Full details: Description check

Explanation

The description follows the template's main sections: Problem (rejected Codex history blocks later prompts), Change (recovery via existing fresh-session/portable-history fallback, with scope limits), Scope (references related #21061 and calls it a focused reliability fix, though it does not link a specific bug issue or say a maintainer requested it), and Verification (detailed focused command, before/after results, the 88 passed / 4 failed test counts, and an unreported check:changed run). It names the model and harness at the end as the template asks. The Scope section is weaker because it does not clearly link the issue that shows the bug, and the author describes #21061 only as related. This is a minor gap, so the description is mostly complete.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 10f1d85 and 29b7322.

Files selected for processing: 3

  • apps/server/src/orchestration-v2/ProviderTurnStartService.test.ts
  • apps/server/src/orchestration-v2/ProviderTurnStartService.ts
  • apps/server/src/orchestration-v2/testkit/ProviderSwitch.integration.test.ts

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

@yelgabo
yelgabo force-pushed the fix/codex-invalid-history-recovery branch from 332447e to 471b4c2 Compare November 4, 2026 22:42
Extend the existing recovery in pingdotgg#28962 to interrupted or cancelled runs that already retain the root sharing-rejection item. Preserve native-session binding and the background-work fence. Ordinary interruptions without that error remain unchanged.
@yniknafs

yniknafs commented Nov 7, 2026

Copy link
Copy Markdown

Sent a small follow-up to your existing branch: yelgabo#1 (head 10c8d12c9faa13ee3d6c6506da9198039f43f784). It recognizes interrupted/cancelled accepted runs only when the same exact root sharing-rejection item was already persisted; native-ID and background-work guards stay intact. Ordinary Stop without that retained root error is unchanged. The two added tests synthesize persisted terminal states, not a live cancellation race. All nine rejected-history scenarios and check:changed (100 tests, pinned Node 26.12.1) pass. This is a 22-line supplemental amendment, not a replacement PR or a prevention/instruction/provider-switching change.

@yelgabo

yelgabo commented Nov 10, 2026

Copy link
Copy Markdown
Author

Resolved the test-helper conflict by merging upstream main 44ebb2fe57465d32f2bd07c5eb3d8e871bdf5ed5 into this branch (head 10f1d8514616fb9c1b7ed891fdf056b2211acd7e). Preserved both rejected-native-history tracking and upstream cancelledRunOrdinals handling, including failure/interruption/cancellation precedence. Production recovery logic is unchanged apart from the automatic upstream merge. No lockfile or unrelated changes remain in the PR diff.

Validation on Windows with Node 26.12.1: all 60 ProviderSwitch.integration.test.ts cases pass, including the nine rejected-history scenarios and upstream terminal-state handoff cases. Server typecheck exits 0 (existing Effect suggestions only); changed-file formatting/lint and the commit-hook knip checks pass; git diff origin/main --check passes. The aggregate check:changed command was attempted but stopped while its ignored-file scan traversed the Windows dependency tree, before check execution; it is not reported as passing. No real-provider inference or live-state changes. GitHub now reports mergeable=true (mergeable_state=blocked, not dirty); remaining review/CI gates are separate.

Model/harness: GPT-6.1 Sol through Codex.

@dotspace42

Copy link
Copy Markdown

Additional Linux verification of the recovery change.

Applied this PR’s production diff unchanged from 10f1d8514616 to main 5ccc65be0a2b. The integration test file conflicted in the adapter helper and adjacent test additions; a temporary resolution preserved upstream behavior/tests plus this PR’s rejected-history tracking and scenarios. The published branch was not changed.

Failing-first proof

vp test run apps/server/src/orchestration-v2/testkit/ProviderSwitch.integration.test.ts -t "recovers rejected Codex history" --maxWorkers=2

Without the production recovery change:

  • Failed: live, detached, legacy, interrupted, cancelled, and background.
  • Passed: other-error, other-provider, and repaired-native.

With the recovery change restored, all nine passed. The background scenario checks both blocking replacement while work is pending and successful recovery after it finishes.

These tests use T3’s orchestration/SQLite integration harness with a deterministic adapter, not the live provider.

Separate real-provider check

The three real-account reproductions described in #29992 left the parent history rejecting ordinary follow-ups. In each case, a fresh native session seeded with a small plaintext summary answered and completed another follow-up.

That shows a text-only replacement remains usable on the same connection. It does not verify full transcript restoration or this PR’s automatic recovery path end-to-end against the real provider.

Additional validation

With #28143 also applied, the complete two relevant test files passed 71 tests.

vp run --filter t3 typecheck

Server-only typechecking passed with Node 26.12.1, emitting existing Effect suggestions. git diff HEAD --check passed.

check:changed, repo-wide checks, and patched desktop-UI end-to-end testing were not run; no CI result is claimed.

Investigation assisted by GPT-6.1 Sol through Codex in T3 Code.

@github-actions

Copy link
Copy Markdown
Contributor

This PR conflicts with main. Rebase it or merge main into it. If it still conflicts after 7 days with no activity, it will be closed automatically.

See the conflict window.

@github-actions github-actions Bot added the needs-rebase Conflicts with its base branch. Closes after 7 days with no activity. label Nov 14, 2026
@maria-rcks

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Merged current main without rebasing and resolved the integration-helper conflict, preserving rejected-history tracking and main's held-tool and terminal-state behavior. Recovery now retains the native ownership check before creating a replacement session. Updated the existing history mock to return empty history unless a read failure is explicitly requested.

Blacksmith verification passed: all 72 ProviderSwitch integration cases, then vp run check:changed github/main with formatting, lint, knip, GraphQL, affected typechecks (3 packages), and 153 tests across 3 files. No actionable bot findings were present. The diff remains scoped to recovery and its existing tests.

Head: 29b7322ce2f63fbb0955ae4fc09b7ff69ea22156. GitHub reports no conflicts; new CI is running. Automatic recovery against a live Codex account through the client remains unverified.

@github-actions github-actions Bot removed the needs-rebase Conflicts with its base branch. Closes after 7 days with no activity. label Nov 15, 2026

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:M 30-99 changed lines (additions + deletions). vouch:unvouched Author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants