Skip to content

[stack 5/8] fix(coding-agent): repair queued and archived session lifecycle - #1162

Open
sethkarten wants to merge 7 commits into
stack/external-04-daemon-foundationsfrom
stack/external-05-lifecycle
Open

[stack 5/8] fix(coding-agent): repair queued and archived session lifecycle#1162
sethkarten wants to merge 7 commits into
stack/external-04-daemon-foundationsfrom
stack/external-05-lifecycle

Conversation

@sethkarten

@sethkarten sethkarten commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Stack 5/8 — fix(coding-agent): repair queued and archived session lifecycle

Active review snapshot — do not merge yet. The complete stack is open for architecture/design review, while final cumulative audit, CI, Cursor Bug Bot, and Macroscope findings are being remediated. Branches will be force-updated after validation.

Base: stack/external-04-daemon-foundations
Review order: merge only after the preceding stack layer is accepted. This PR is not intended to merge independently out of order.

Stack navigation

  1. #1158 — ci: harden verification and release compatibility
  2. #1159 — fix(security): harden session and autonomous execution boundaries
  3. #1160 — fix(coding-agent): make persisted state crash-safe
  4. #1161 — fix(daemon): fence worker and supervisor lifecycle state
  5. #1162 — fix(coding-agent): repair queued and archived session lifecycle
  6. #1163 — fix(coding-agent): complete Windows kernel and daemon startup
  7. #1164 — fix(providers): harden MCP OAuth and Codex transports
  8. #1165 — fix(runtime): bound transcript and autonomous recovery

Summary

  • Wake idle programmatic prompts without puncturing update-restart suspension.
  • Batch child usage attribution per turn while preserving in-memory accounting.
  • Terminate POSIX bash process groups with cooperative grace.
  • Revive archived sessions once and retry late concurrent prompts against the revived ID.

Validation

Provenance

  • Authored independently from upstream/main using issue reports and PR descriptions/comments only.
  • No external contributor branch, diff, commit, implementation code, or test code was fetched, inspected, copied, or reused.
  • The implementation and regression tests in this stack are maintainer-owned.

Linked-item disposition

Fixed on merge

Independently superseded pull requests

Partially addressed — remains open

Reviewer notes

  • Please review this layer against its immediate stack base, not against main, to avoid cumulative duplicate diffs.
  • No merge is requested; the complete stack is being left for human review.

lifecycle: "resident",
env: this.options.sendClientEnv ? collectDaemonClientEnv() : undefined,
});
if (

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium agent-connection/daemon-agent-connection.ts:839

reviveArchivedSession creates a resident daemon session via the create request, and if dispose() or a concurrent session switch occurs while that request is in flight, the function throws "Archived-session revival was superseded" without detaching or otherwise cleaning up the newly created resident session. The daemon keeps that resident worker running indefinitely with no owner.

The guard at line 840 checks disposed/disposing/activeSessionId/attachedSessionFile after create already succeeded, so when the condition is true it discards summary and throws instead of detaching the new session. Consider detaching (or completing) targetActiveSessionId in that branch before throwing.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts around line 839:

`reviveArchivedSession` creates a resident daemon session via the `create` request, and if `dispose()` or a concurrent session switch occurs while that request is in flight, the function throws `"Archived-session revival was superseded"` without detaching or otherwise cleaning up the newly created resident session. The daemon keeps that resident worker running indefinitely with no owner.

The guard at line 840 checks `disposed`/`disposing`/`activeSessionId`/`attachedSessionFile` *after* `create` already succeeded, so when the condition is true it discards `summary` and throws instead of detaching the new session. Consider detaching (or completing) `targetActiveSessionId` in that branch before throwing.

@sethkarten
sethkarten force-pushed the stack/external-05-lifecycle branch from 91643f5 to bf5e9fa Compare August 10, 2026 19:23
options?: AgentConnectionPromptOptions,
): Promise<void> {
const pendingRevival = this.revival;
if (pendingRevival) await pendingRevival.promise.catch(() => undefined);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium agent-connection/daemon-agent-connection.ts:752

promptWithAdmissionCancellation awaits a pending revival before checking options.signal, so a concurrent prompt whose signal is already aborted (or aborts during a slow revival) hangs until the unrelated revival finishes instead of promptly rejecting with AgentConnectionPromptAdmissionError. Check the signal before awaiting the pending revival so aborted prompts reject immediately.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts around line 752:

`promptWithAdmissionCancellation` awaits a pending revival before checking `options.signal`, so a concurrent prompt whose signal is already aborted (or aborts during a slow revival) hangs until the unrelated revival finishes instead of promptly rejecting with `AgentConnectionPromptAdmissionError`. Check the signal before awaiting the pending revival so aborted prompts reject immediately.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bf5e9fa. Configure here.


private async _prompt(text: string, options?: InternalPromptOptions): Promise<void> {
if (!this.isStreaming) {
this._sessionInputPumpSuspended = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Injected prompts hang under update-restart

High Severity

_promptInjectedMessage can admit an immediately eligible turn while update_restart suspension keeps the input pump stopped, then await delivered/completed. Cancelled RLM children that fall back to this path during abortForUpdateRestart never finish, so their finally cleanup and usage flush do not run.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bf5e9fa. Configure here.

}
const targetActiveSessionId = summary.activeSessionId ?? summary.id;
await this.reattachSession(sourceActiveSessionId, targetActiveSessionId);
this.terminalCloseEmitted = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Superseded revival leaves resident worker

Medium Severity

reviveArchivedSession can successfully create a resident worker and then throw as superseded when the connection is disposing, without stopping or detaching that worker. dispose also does not cancel or await an in-flight revival, so the revived session can remain running unattached.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bf5e9fa. Configure here.

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

Labels

None yet

Projects

None yet

1 participant