Skip to content

feat(acp): harden resident session lifecycle - #1494

Merged
snimu merged 48 commits into
mainfrom
v080/acp-minimal-verifiers
Aug 20, 2026
Merged

feat(acp): harden resident session lifecycle#1494
snimu merged 48 commits into
mainfrom
v080/acp-minimal-verifiers

Conversation

@sethkarten

@sethkarten sethkarten commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep session-backed ACP workers resident while leaving ACP --no-session, RPC, and print invocations client-owned
  • serialize ACP updates with monotonic event sequences and causal prompt-turn IDs, emit explicit response boundaries, and emit terminal quiescence only when the authoritative child roster has no outstanding work
  • publish the initial nested-child roster, preserve child origins across turns, and drain admitted updates across cancellation and close races
  • persist identity-only v2 worker descriptors and a typed host-only supervisor configuration; never persist launch environments or arbitrary runtime/model/provider configuration
  • migrate v1 descriptors by lifting only sessionDir and monotonic telemetryDisabled, and require a fresh client launch environment before replacing a failed resident

Related 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 of createCommand.config.

Validation

  • npm run check
  • 20 focused Vitest files: 626 tests passed after merging current main
  • git diff --check

This 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 via isClientOwnedDaemonSession.

ACP updates are now producer-ordered and causally tagged. AcpUpdateProducer stamps every notification with promptTurnId, monotonic eventSequence, phase (event / responseBoundary / terminalQuiescence), and outcome. Prompt handling emits a response boundary with terminalQuiescenceExpected, then a terminal quiescence update only after headless completion with waitForRlmQuiescence and an authoritative child roster with no outstanding subagents. session/new admission 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. acquireSessionInputPause leases fence new turns through the session, daemon, supervisor, and DaemonAgentConnection; disconnect invalidates pauses and closes the connection.

RLM child lifecycle is settlement-aware. Child runs track settlement, quiescence abandonment, and recursive waitForRlmQuiescence; headless completion can opt into the strong barrier. Daemon adds get_rlm_children, schema revision 19 capabilities, and always includes children on attach snapshots.

Recovery persistence is narrowed. Worker descriptors migrate to v2 with durableDaemonWorkerDescriptor and durableAgentSessionRuntimeConfig—only host routing/policy fields (e.g. sessionDir, telemetryDisabled), not models, credentials, or launchEnv. Failed owned workers wait for fresh recoveryConfig and 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

  • Adds per-session input pause leases scoped to client connections, with epoch-based fencing and automatic cleanup on disconnect/detach across daemon-mode.ts, daemon-supervisor.ts, and daemon-agent-connection.ts
  • Introduces strong RLM quiescence waiting in agent-session.ts: waitForRlmQuiescence blocks until all descendant child runs settle, deletion cleanup completes (or records retry), and deferred terminal notices flush
  • Reworks RLM child deletion into a detached flow with shared cleanup, retry-on-failure reporting, and durable terminal/failure notice admission via private parent channels
  • Migrates persisted worker descriptors to version 2 in daemon-worker-protocol.ts, lifting sessionDir/telemetryDisabled to top level, stripping secrets from createCommand/config/lastError, and redacting on both load and persist
  • Adds an AcpUpdateProducer in acp-mode.ts that serializes session updates with producer-stamped promptTurnId, eventSequence, and phase/outcome classification; session/new response acts as the admission barrier before any session-scoped update publishes
  • Bumps DAEMON_SCHEMA_REVISION to 19 in daemon-protocol.ts with new capabilities: authoritative_child_roster, owned_session_recovery_context, rlm_quiescence_barrier, session_input_pause
  • Behavioral Change: failed client-owned workers now park in lifecycle: 'failed' awaiting a fresh recoveryConfig on attach instead of auto-relaunching; launchEnv is always collected (not just for client-owned); isClientOwnedDaemonSession returns false for ACP sessions without noSession; snapshot responses always include a children array (possibly empty) instead of eliding the field; getRlmChildSnapshots returns authoritative rosters gated by authoritative_child_roster capability; waitForHeadlessCompletion defaults to waitForHeadlessIdle (not full waitForIdle)

Macroscope summarized f18de4b.

Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-worker-protocol.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session-config.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts
Comment thread packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts Outdated
Comment thread packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts Outdated
Comment thread packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-supervisor.ts
@sethkarten
sethkarten requested a review from alexzhang13 August 18, 2026 04:37
…fiers

# Conflicts:
#	packages/coding-agent/CHANGELOG.md
#	packages/coding-agent/src/core/agent-session.ts
@sethkarten

Copy link
Copy Markdown
Contributor Author

@alexzhang13 PR #1494 is ready for final human review at e791ff8fb:

  • all required CI checks are green
  • Cursor Bugbot and Macroscope are green
  • no unresolved review threads remain
  • npm run check passes locally
  • 13 focused Vitest files / 512 tests pass locally

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
Comment thread packages/coding-agent/src/cli/daemon-ps.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
@sethkarten

Copy link
Copy Markdown
Contributor Author

Final lifecycle follow-up is ready at 095ba1e5d.

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 terminalQuiescence, allowing rejected admissions to fail promptly without weakening settlement for accepted turns.

Validation: npm run check, focused ACP/recursion tests 126/126, full GitHub CI green, Cursor and Macroscope green, and zero unresolved review threads. The paired opt-in consumer is now on Verifiers #2355 at 547abf168, also green and review-clean.

@alexzhang13 this is ready for final human review.

Comment thread packages/coding-agent/src/core/agent-session.ts
# Conflicts:
#	packages/coding-agent/CHANGELOG.md

@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 d3516c6. Configure here.

Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts
@sethkarten

Copy link
Copy Markdown
Contributor Author

Final exact-stack validation after the two lifecycle fixes:

  • Prime code artifact: 90722ea8a (0.7.3-pr1494.90722ea8a); current head 1fc511c5e adds only the updated fix(coding-agent): preserve child attribution for terminal notices #617 regression.
  • Verifiers: local ccec7f25b on PR #2355.
  • Local canonical Yahoo/test/131072 non-numerical smoke: n=1, deepseek/deepseek-v4-flash, autonomous=false, require_terminal_quiescence=true, no retries.
  • Benchmark: reward 1.0; final answer Label: Sports.
  • Lifecycle: infrastructure_status=ok, correlated terminalQuiescence for prompt turn 1, response sequence 4708, terminal sequence 4710, outstandingSubagents=0, remainingAutonomousContinuations=0.
  • Teardown: rollout-owned container removed; unrelated containers unchanged.
  • Focused validation after the test-only follow-up: 7 files / 163 tests passed, npm run check passed, git diff --check passed.

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.

@snimu
snimu merged commit d98d076 into main Aug 20, 2026
20 checks passed
@snimu
snimu deleted the v080/acp-minimal-verifiers branch August 20, 2026 08:52
ruttybob added a commit to ruttybob/prime-agent that referenced this pull request Aug 20, 2026
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.
xeophon pushed a commit that referenced this pull request Aug 20, 2026
…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
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.

2 participants