Skip to content

fix(sessions): guard the remaining in-flight-turn invalidation paths - #1173

Open
solidlime wants to merge 1 commit into
agegr:mainfrom
solidlime:fix/session-invalidation-guards
Open

solidlime wants to merge 1 commit into
agegr:mainfrom
solidlime:fix/session-invalidation-guards

Conversation

@solidlime

Copy link
Copy Markdown

Reuses the existing isSessionRunningForReplacement() guard (already used by clone/fork in lib/rpc-manager.ts) for the paths that could still tear down a session while it had an in-flight turn. That teardown is what leaves extension ctx objects stale mid-run (see #1172).

What was unguarded

  • Extension reload (lib/rpc-manager.ts) — the extension command API and the extension ctx callback object reloaded without checking isSessionRunningForReplacement(), unlike clone/fork.
  • cwd sweep (lib/rpc-manager.ts) — destroyRpcSessionsForCwd() shut down every session in the target cwd, including running ones.
  • DELETE /api/sessions/[id] (app/api/sessions/[id]/route.ts) — shut down the deleted session's subagent descendants, and the target, even while they were mid-turn.
  • Background subagent parents (lib/subagent-runtime.ts) — a background subagent outlives its parent's turn, so the parent was eligible for idle eviction while the run was still active. start()/resume() now register a session-liveness provider for the parent, released when the run's promise settles.

Verification

Built 0.11.1 locally and exercised:

  • a reload aimed at a session with an in-flight turn is now rejected and the turn completes (previously the runner was invalidated and the turn died)
  • idle sessions still reload and delete normally
  • a parent holding a long background subagent survives the idle window and receives the completion notification without a stale-ctx error

npm run typecheck and eslint are clean, and node --test lib/rpc-manager.test.mjs passes (the DELETE-route source assertion was updated to the guarded form).

Three failures in lib/mcp-test.test.mjs, lib/mcp-transport.test.mjs and lib/rotate-preview-secrets.test.mjs also reproduce on a clean 30af3b4 checkout in this container (running as root, so the read-only-dir case cannot behave as intended, plus process-reaping timing). They are unrelated to this change.

Reuses the existing isSessionRunningForReplacement() pattern (already
used by clone/fork in rpc-manager.ts) for the paths that can still
invalidate a live extension ctx mid-turn:

- `reload` via the extension command API and the extension ctx callback
  object (rpc-manager.ts) - previously unguarded, unlike clone/fork
- the cwd-scoped sweep destroyRpcSessionsForCwd() shut down every
  session in the target cwd, including running ones
- DELETE /api/sessions/[id] shut down the deleted session's subagent
  descendants and the target even while they were mid-turn
- a background subagent outlives its parent's turn, so the parent
  session could be idle-evicted while the run was still active;
  register a session-liveness provider for the parent for the run's
  lifetime (start()/resume() in subagent-runtime.ts), released when the
  run's promise settles

Also updates the source-assertion test for the DELETE route to the
guarded shutdown form.

Verified against a locally built 0.11.1: a reload aimed at a session
with an in-flight turn is now rejected and the turn completes; idle
sessions still reload/delete normally; a parent holding a long
background subagent survives the idle window and receives the
completion notification without a stale-ctx failure.

Refs agegr#1172

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant