Skip to content

fix(coding-agent): evict empty drafts when the last direct viewer detaches (ENG-5831) - #1946

Merged
xeophon merged 1 commit into
mainfrom
fix/direct-detach-eviction
Sep 1, 2026
Merged

xeophon merged 1 commit into
mainfrom
fix/direct-detach-eviction

Conversation

@snimu

@snimu snimu commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

Starting the TUI and quitting right away leaves the empty draft session behind as a zombie row in the agents view until an idle sweep catches it, if one ever runs (ENG-5831).

The empty-draft eviction from #1920 runs when the supervisor sees a client's last detach: on a supervisor socket close it walks that socket's attached sessions and evicts abandoned empty drafts. #1926 moved attach and detach onto the direct worker transport, so the session's viewer now attaches and detaches on the worker's own socket. The supervisor socket never records the attachment, its close-time walk finds nothing, and a clean quit does not touch the supervisor at all.

Fix

The worker already reports the exact signal: since #1926 it flushes a roster update when a direct viewer attaches or detaches, and that summary carries directAttachedClients. Both exit paths produce it — a clean detach command and an unclean socket drop share the worker's detach path.

The supervisor's roster write funnel now triggers the existing last-detach eviction when a worker-reported summary's directAttachedClients drops to zero. The eviction candidate check also counts direct viewers through the shared attachment sum, so with one routed and one direct client the session is evicted only when the last of both is gone, in either order.

No new wire frames, timers, or sweep changes: the fix reuses the roster signal and the eviction path that already exist.

Validation

  • New pins in daemon-supervisor-eviction.test.ts: a worker-reported drop to zero direct viewers evicts an empty draft; a mixed routed+direct session evicts only after the last of both detaches.
  • Existing fix(coding-agent): honest status and prompt eviction for empty sessions #1920 eviction pins, daemon-peer-transport, agent-connection-daemon, daemon-supervisor-monitor, and daemon-routed-client suites all green with sanitized env.
  • Root npm run check green.

Linear: ENG-5831

Note

Evict empty drafts when last direct-attached viewer detaches in DaemonSupervisor

  • Updates the evictable-empty-worker check to use attachedClientCount so it accounts for both supervisor-routed and direct-attached clients when deciding if a worker is evictable
  • In writeRosterEntry, detects when a worker's directAttachedClients transitions from >0 to 0 and triggers evictEmptySessionOnLastDetach, aligning direct-transport detach behavior with supervisor-routed clients
  • Adds tests covering eviction on last direct detach and the mixed client-kind case where eviction only fires after both routed and direct clients are gone

Macroscope summarized 2f879e6.


Note

Medium Risk
Touches daemon session eviction and roster-driven lifecycle, but reuses existing eviction helpers and is covered by new unit tests rather than new wire protocol.

Overview
Fixes empty draft sessions sticking around in the agents list after a user opens the TUI and quits immediately, because viewers on the direct worker transport no longer detach through the supervisor socket.

When a worker roster update shows directAttachedClients dropping from above zero to zero, writeRosterEntry now runs the same evictEmptySessionOnLastDetach path used for supervisor-routed clients (clean detach or socket drop both show up this way). The empty-worker eviction check uses attachedClientCount so routed and direct attachments are counted together—mixed sessions are only evicted after both kinds of viewer are gone.

Adds eviction tests for last direct detach and routed+direct ordering; changelog note for ENG-5831.

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

…aches

Direct-transport clients attach and detach on the worker socket, so the
supervisor-socket cleanup that owns empty-session eviction never saw their
last detach and empty drafts lingered until an idle sweep. The worker already
reports the drop: its peer attach/detach roster flush delivers a summary
whose directAttachedClients falls to zero, so the supervisor's roster write
funnel now triggers the existing last-detach eviction on that transition —
covering both clean detach and unclean socket drop, which share the worker's
detach path. The eviction candidate check counts direct viewers through the
shared attachment sum, so a remaining direct client blocks a routed client's
last detach and vice versa. Fixes ENG-5831.
@snimu
snimu requested a review from xeophon September 1, 2026 13:06
@xeophon
xeophon merged commit 23e5515 into main Sep 1, 2026
26 checks passed
@xeophon
xeophon deleted the fix/direct-detach-eviction branch September 1, 2026 13:06
olety added a commit to oneiron-dev/prime-agent that referenced this pull request Sep 1, 2026
Takes upstream's event-driven supervisor roster ledger + push (PrimeIntellect-ai#1897, PrimeIntellect-ai#1900),
direct TUI<->worker transport (ENG-5817), daemon startup/recovery hardening
(PrimeIntellect-ai#1929, PrimeIntellect-ai#1909), single-dump kernel snapshots (PrimeIntellect-ai#1945), empty-draft eviction
(PrimeIntellect-ai#1946), rlm_child_update suppression (PrimeIntellect-ai#1944), bash-skill preview (PrimeIntellect-ai#1911).

Fork laws re-expressed on the roster architecture:
- stable-target follow-up honesty kept (capability proof via worker hello,
  target_unavailable never not_found when ownership unproven)
- schema revision 26 (union of fork rev-24 stable-target + upstream
  rev-24/25 roster+transport); digest minted by the repo's own algorithm
- summary freshness reuse + single-flight + staleness + root-omission
  rejection restored on upstream's refresh pull
- adoption/recovery never fails a live worker on a slow or root-omitting
  catalog: get_state root seed + stale mark + bounded background rehydration
- repl.py keeps fork prune-on-aggregate-overflow
- delete handlers keep fork persistence reporting; eviction fence test keeps
  the stronger two-worker contention variant

Known test debt (deferred to post-Wave cleanup per owner): roster-era fixture
migrations in daemon-supervisor-monitor (2), plus un-triaged failures in
package-command-paths, agent-session-recursion, daemon-runtime-stress,
4600-supervisor-singleton, 4603-worker-recovery, 4606-update-restart-
coordinator, agents-view-roster. Production laws preserved; failures are
fixture-era artifacts or mechanism assertions to rewrite.
ketema added a commit to ketema/prime-agent that referenced this pull request Sep 1, 2026
- Direct session transport between TUI and worker (ENG-5817, PrimeIntellect-ai#1926)
- Event-driven supervisor agent roster with push subscriptions (PrimeIntellect-ai#1897, PrimeIntellect-ai#1900, PrimeIntellect-ai#1895)
- Hardened daemon startup, recovery ownership, and worker launch diagnostics (PrimeIntellect-ai#1929, PrimeIntellect-ai#1918)
- Python REPL runtime single-dump snapshots and bash preview tool (PrimeIntellect-ai#1945, PrimeIntellect-ai#1911)
- Non-blocking RLM subagent deletion and snapshot update suppression (PrimeIntellect-ai#1954, PrimeIntellect-ai#1944)
- Saved catalog loading on Agents View open (PrimeIntellect-ai#1960)
- Advanced Anthropic prompt caching marker across tool results (PrimeIntellect-ai#1927)
- TUI process replacement on update and empty draft eviction (PrimeIntellect-ai#1631, PrimeIntellect-ai#1946, PrimeIntellect-ai#1920)
paralin pushed a commit to paralin/prime-agent that referenced this pull request Sep 2, 2026
…aches (PrimeIntellect-ai#1946)

Direct-transport clients attach and detach on the worker socket, so the
supervisor-socket cleanup that owns empty-session eviction never saw their
last detach and empty drafts lingered until an idle sweep. The worker already
reports the drop: its peer attach/detach roster flush delivers a summary
whose directAttachedClients falls to zero, so the supervisor's roster write
funnel now triggers the existing last-detach eviction on that transition —
covering both clean detach and unclean socket drop, which share the worker's
detach path. The eviction candidate check counts direct viewers through the
shared attachment sum, so a remaining direct client blocks a routed client's
last detach and vice versa. Fixes ENG-5831.
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