agent pane peer snapshots (8t2/n): tests of the attach fixes
Lawrence's list item, word for word: "start new VMs from acp chat - decouple persistence of acp trajectories from the VM itself, in case the VM is resuming".
Part of the client-snapshot piece of manaflow-ai/cmuxterm-hq#4381 ("Persistence, pause and resume, and history hydration"): the Mac's acpmux keeps a durable, bounded copy of each peer session's events, so the app paints a paused or offline peer chat at once, marked possibly stale, and catches up from the host with afterSeq. The host's journal stays the authority; the copy is not a write lease, an execution checkpoint or a backup. The shared fenced-writer database from #4381 is not part of this work.
This replaces #25323 (store) and #25378 (hook and pane), split so each piece lands on its own under about 800 changed lines, tests included. The series:
- the on-disk form of a copy (#25448, landed)
- the store's thread: bounds, writes, removals (#25445)
2t. the store's tests (#25505) - what starts or grows a copy: generations, joins, links (#25446)
- purges, removed peers, the queue's bound (#25447)
- the hub's taps (wiring) (#25449)
- the read hook
_acpmux/peer_snapshot, which the VM start/resume work calls too (#25473) - the pane's offline banner and the reply's reading (#25474)
- the pane paints the copy, then catches up (#25475)
8t. the pane's tests (#25506)
8t2. tests of 8's attach fixes (this PR)
This PR (8t2): tests of the pane's attach fixes
Tests only, in webviews/test/agent-pane-peer-copy.test.ts, split from 8t so that one stays under the line cap. Each fails without its fix in 8 (#25475), and passes with it:
- an attach reply of the session before a recreation (its
createdAtolder than the row's now) is dropped, and the session listed now is attached instead (P39); - a select's attach over the Mac's copy that a reconnect took over (the attach token moved on) leaves the copy on screen when it fails (P40);
- the attach a redraw starts after the session moved to a machine that is back, refused as down, draws that machine's copy offline instead of being swallowed (P40);
- an attach reply that comes after the session moved to another machine is attached again from that one (P42);
- a session recreated and back at once takes the old copy off screen before the machine is read (P43);
- a live record of an attach that failed, coming late, is not shown above the offline copy (P46);
- an attach retried for a recreated session is held to the row again when it answers: a row changed twice while the attaches were out never shows the session between (P47);
- a session recreated with an earlier
createdAt(a machine back on an earlier clock) is not taken for the one before (P48); - a recovery attach that a reconnect took over changes nothing when it answers (P49);
- a row that named another session while the attach was out, then this one again, keeps none of the other's records (P50);
- an open that fails before its attach leaves the copy offline with no attach out (P51);
- a copy that covers past its newest record keeps it under a page that starts right after it (P52);
- a row recreated while the attach is out keeps none of the session before's live records (P53);
- a row recreated while the reads after the attach are out has the chat read again (P54);
- a tail kept of rows proven of no session names none, so it never joins the session a later row moved to (P55);
- a record a refused attach sent past the copy holds back no record once the machine is read: the cursor is the newest record kept (P56; fails if
rebuildkeeps the old cursor); - a machine back while an attach with no copy to fall back on is out is read once that attach fails (P60);
- an attach that fails after the row named another session keeps none of that one's records (P61);
- an attach of a chat already left never takes the watch of the attach out (P62);
- a chat read ahead while its row named another session is not kept (P64).
The test daemon gains three hooks and a hold: onAttach (runs once when the next attach is asked), staleReply (the next attach answered as the session before a recreation) and afterAttach (runs at the first request after an attach was answered), and hold with release(method) (requests of a method wait unanswered until released).
Tests
On the fleet: the file's 48 cases pass with 8's fixes (the pane's 176 tests pass, and the webview typecheck is clean). With each fix reverted on its own, its test fails: these twenty in all.
Review: Codex (gpt-6-astra, xhigh) SHIP at 3867013b526 (its ninth round, with 8's eighteenth SHIP); git patch-id --stable of the diff vs base matches at this head, rebased onto 8t as landed (f720ce9f3b1).
Timers, threads and loops
None: tests only. The test daemon answers each request once, on a microtask.
Base reds, not from this PR (they fail the same way on feat-cmux-next): bun run check exits 1 there too, and so does gallery-coverage.
Agent session: agent session
š¤ Generated with Claude Code