feat(acp): harden resident session lifecycle - #1494
Conversation
…fiers # Conflicts: # packages/coding-agent/CHANGELOG.md
…fiers # Conflicts: # packages/coding-agent/CHANGELOG.md
…fiers # Conflicts: # packages/coding-agent/CHANGELOG.md
…fiers # Conflicts: # packages/coding-agent/CHANGELOG.md # packages/coding-agent/src/core/agent-session.ts
|
@alexzhang13 PR #1494 is ready for final human review at
The final review rounds also closed the supervisor pause-owner reconnect, detach/reacquire, detach-all, cleanup-timeout, and attach-failure races. |
…fiers # Conflicts: # packages/coding-agent/CHANGELOG.md # packages/coding-agent/src/modes/daemon/daemon-supervisor.ts # packages/coding-agent/test/daemon-supervisor-monitor.test.ts
|
Final lifecycle follow-up is ready at The latest commits resolve the validated restart-quiescence, failed-close/cancel serialization, and stale initial-roster reconciliation findings. Response boundaries now explicitly declare whether they owe a later Validation: @alexzhang13 this is ready for final human review. |
# Conflicts: # packages/coding-agent/CHANGELOG.md
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d3516c6. Configure here.
|
Final exact-stack validation after the two lifecycle fixes:
The live rollout did not spawn RLM children; the recursive-quiescence, close-fenced terminal-notice, update-checkpoint, pre-admission demotion, and cancellation paths are covered by the deterministic regressions in this PR. Benchmark reward and lifecycle status remain reported separately. |
Conflict resolution (3 files, all CHANGELOG):
- packages/{ai,coding-agent,tui}/CHANGELOG.md — keep fork [Unreleased]
bullets (Z.AI reasoning_effort; mermaid/selection/statusline/cwd/ctrl+c/
config-scope panes/agents-view fixes), take upstream's finalized
[0.7.4] sections verbatim
Upstream payload: model search intent ranking (PrimeIntellect-ai#539), ACP resident
session lifecycle hardening (PrimeIntellect-ai#1494), ACP follow-up prompt queueing
(PrimeIntellect-ai#800), v0.7.4 release prep (version bumps, catalogs).
Fork features verified intact after merge: mermaid transform + settings
toggle, tui Markdown transform hook, config scope panes, cwd statusline,
grok-mermaid dependency, Z.AI supportsReasoningEffort catalog entries.
…n continuation cannot start (#1583) * fix(coding-agent): reject headless idle waiters when a post-compaction continuation cannot start A continuation that fails to start settled headless idle as a clean finish, so ACP and print-mode callers reported a turn as completed that never ran. The settlement is now one-shot with reject support: non-retryable start failures reject waiters, cancellation and the benign nothing-to-continue race still resolve, a settled failure is never re-exposed to later waiters, and interactive waitForIdle is unchanged. Ports the failure semantics from #881 onto the resident-lifecycle settlement from #1494. Co-authored-by: Parker Pettit <parkerpettit@users.noreply.github.com> * docs: cut comments down to single-line load-bearing invariants * test: keep only the two tests that pin new behavior

Summary
--no-session, RPC, and print invocations client-ownedsessionDirand monotonictelemetryDisabled, and require a fresh client launch environment before replacing a failed residentRelated Linear: ENG-4600, ENG-4603, ENG-4685.
Recovery and security contract
Live residents remain reattachable from their worker identity and socket. If a worker is dead or unreachable after supervisor recovery, it remains failed until a new client supplies fresh transient launch context. A verified-current failed resident is stopped only when its stored process-start identity still matches; replaced PIDs are never signaled, and unknown identities fail closed.
Durable worker state contains routing/session identity, local worker authentication, lifecycle markers, and the two typed host-policy fields above. It excludes
launchEnv,apiKey, provider/model selection, headers, extension values, runtime metadata, and the rest ofcreateCommand.config.Validation
npm run checkmaingit diff --checkThis standalone PR supersedes the broader #1236 / #1239 stack once its own baseline checks and review complete. It intentionally does not include relay IDs/replay machinery, intercept retries, daemon discovery or shutdown CLI changes, or release cleanup behavior.
Note
High Risk
Changes span ACP completion semantics, concurrent session input admission, multi-layer daemon fencing, and persisted worker recovery—any ordering bug could mis-report turn completion or admit input during teardown.
Overview
ACP session-backed workers stay resident for normal ACP mode; only
--no-session(and non-ACP clients) use client-owned workers viaisClientOwnedDaemonSession.ACP updates are now producer-ordered and causally tagged.
AcpUpdateProducerstamps every notification withpromptTurnId, monotoniceventSequence,phase(event/responseBoundary/terminalQuiescence), andoutcome. Prompt handling emits a response boundary withterminalQuiescenceExpected, then a terminal quiescence update only after headless completion withwaitForRlmQuiescenceand an authoritative child roster with no outstanding subagents.session/newadmission is gated until the JSON-RPC response is written so buffered events cannot race ahead of the reply.Session input is fail-closed during stop/close/cancel.
acquireSessionInputPauseleases fence new turns through the session, daemon, supervisor, andDaemonAgentConnection; disconnect invalidates pauses and closes the connection.RLM child lifecycle is settlement-aware. Child runs track
settlement, quiescence abandonment, and recursivewaitForRlmQuiescence; headless completion can opt into the strong barrier. Daemon addsget_rlm_children, schema revision 19 capabilities, and always includeschildrenon attach snapshots.Recovery persistence is narrowed. Worker descriptors migrate to v2 with
durableDaemonWorkerDescriptoranddurableAgentSessionRuntimeConfig—only host routing/policy fields (e.g.sessionDir,telemetryDisabled), not models, credentials, orlaunchEnv. Failed owned workers wait for freshrecoveryConfigand launch env on reattach before relaunch; stale failed residents can be reclaimed when process identity is verified.Reviewed by Cursor Bugbot for commit 095ba1e. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Harden resident session lifecycle with input fencing, RLM quiescence, and descriptor v2 migration
waitForRlmQuiescenceblocks until all descendant child runs settle, deletion cleanup completes (or records retry), and deferred terminal notices flushsessionDir/telemetryDisabledto top level, stripping secrets fromcreateCommand/config/lastError, and redacting on both load and persistAcpUpdateProducerin acp-mode.ts that serializes session updates with producer-stampedpromptTurnId,eventSequence, and phase/outcome classification; session/new response acts as the admission barrier before any session-scoped update publishesDAEMON_SCHEMA_REVISIONto 19 in daemon-protocol.ts with new capabilities:authoritative_child_roster,owned_session_recovery_context,rlm_quiescence_barrier,session_input_pauselifecycle: 'failed'awaiting a freshrecoveryConfigon attach instead of auto-relaunching;launchEnvis always collected (not just for client-owned);isClientOwnedDaemonSessionreturns false for ACP sessions withoutnoSession; snapshot responses always include achildrenarray (possibly empty) instead of eliding the field;getRlmChildSnapshotsreturns authoritative rosters gated byauthoritative_child_rostercapability;waitForHeadlessCompletiondefaults towaitForHeadlessIdle(not fullwaitForIdle)Macroscope summarized f18de4b.