Skip to content

[orchestration] Clear stale active turn when session becomes inactive#3159

Open
Andrew-Forster wants to merge 1 commit into
pingdotgg:mainfrom
Andrew-Forster:codex/clear-active-turn-on-ready-session
Open

[orchestration] Clear stale active turn when session becomes inactive#3159
Andrew-Forster wants to merge 1 commit into
pingdotgg:mainfrom
Andrew-Forster:codex/clear-active-turn-on-ready-session

Conversation

@Andrew-Forster

@Andrew-Forster Andrew-Forster commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

This clears stale activeTurnId state when a provider reports that a session is inactive.

Concretely, session.state.changed now clears activeTurnId when it maps to:

  • ready
  • interrupted
  • stopped
  • error

It still preserves activeTurnId for starting and running.

Root Cause

The projection layer could previously write an impossible session state:

session.status = ready
session.activeTurnId = <old turn id>

That is inconsistent. A session that is ready, interrupted, stopped, or error should not also point at an active turn.

Codex exposes one concrete path into this state because T3 maps Codex session/ready into session.state.changed: ready, which is separate from turn.completed. This PR does not assume Codex normally omits turn/completed; the upstream app-server docs describe turn/completed as the normal terminal turn event. The fix is about making T3's projection invariant correct whenever an inactive session-state event is processed.

Why This Matters

A stale active turn can make the UI/sidebar keep treating old work as active after the provider has settled.

It can also affect cleanup. ProviderSessionReaper skips sessions when the projected thread still has activeTurnId != null, so preserving stale active-turn state can make a settled provider session look unreapable.

This does not try to solve every provider desync case. It fixes one small shared invariant: inactive sessions should not retain active turns.

Scope / Tradeoff

Low risk: this only changes session.state.changed handling for inactive statuses.

Shared orchestration fix: the behavior is not Codex-specific. Codex is just the clearest known path because of its separate session/ready event.

Preserved behavior: mid-turn session.started / thread.started updates still keep the active turn. There is an existing regression test for that path, and this PR keeps it passing.

Validation

  • pnpm --filter t3 exec vp test run src/orchestration/Layers/ProviderRuntimeIngestion.test.ts -t 'clears active turn when provider session becomes ready' --reporter=verbose
  • pnpm --filter t3 exec vp test run src/orchestration/Layers/ProviderRuntimeIngestion.test.ts -t 'does not clear active turn when session/thread started arrives mid-turn' --reporter=verbose
  • pnpm --filter t3 exec vp run typecheck
  • pnpm exec vp check (existing unrelated warnings only)
  • git diff --check

References

Related


Note

Low Risk
Narrow change to session lifecycle projection in ProviderRuntimeIngestion; existing mid-turn lifecycle test preserved.

Overview
Provider runtime ingestion now clears projected activeTurnId when a session.state.changed event maps to an inactive session status (ready, interrupted, stopped, or error). Only starting and running may retain an active turn, via new helper sessionStatusAllowsActiveTurn.

This fixes inconsistent projections such as status: ready with a non-null activeTurnId—notably when Codex emits session/ready separately from turn.completed—which could keep the UI treating old work as active and block ProviderSessionReaper cleanup.

Mid-turn session.started / thread.started behavior is unchanged (still preserves activeTurnId when a turn is running). Adds a regression test and extends waitForThread timeouts on related lifecycle tests.

Reviewed by Cursor Bugbot for commit b636c71. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Clear stale activeTurnId when provider session transitions to an inactive state

  • Adds a sessionStatusAllowsActiveTurn helper in ProviderRuntimeIngestion.ts that returns true only for starting or running statuses.
  • When a session.state.changed event produces a non-running/non-starting status (e.g. ready, error, stopped), session.activeTurnId is now set to null, preventing stale active turns from persisting.
  • Adds a test case in ProviderRuntimeIngestion.test.ts asserting that activeTurnId is cleared when the session returns to ready.

Macroscope summarized b636c71.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 99af93b0-ba0a-46e1-9cd4-b543454ece32

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jun 19, 2026
@Andrew-Forster Andrew-Forster force-pushed the codex/clear-active-turn-on-ready-session branch from a93024a to b636c71 Compare June 19, 2026 06:28
@Andrew-Forster Andrew-Forster changed the title [codex] Clear stale active turn on ready session [orchestration] Clear stale active turn when session becomes inactive Jun 19, 2026
@Andrew-Forster Andrew-Forster marked this pull request as ready for review June 19, 2026 21:26
@macroscopeapp

macroscopeapp Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

Straightforward bug fix that clears stale activeTurnId when a provider session transitions to an inactive state. The change is small, well-tested, and has no security or schema implications.

You can customize Macroscope's approvability policy. Learn more.

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

Labels

size:S 10-29 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.

1 participant