acpmux: restore older Claude chat history after restart

Merged
TE
7d ago
+1954-108

Leo asked: “I can't fing scroll up past the current fing turn after restarting, and I still don't see the fing left side session scroll prompts thing. ... the scroll up thing was because it still took thirty fing seconds to load anything.”

After a restart, adopted Claude chats now expose the transcript cursor recorded in acpmux and page older turns once the seeded session log is exhausted. Native transcript pages use bounded cursors, fold whole turns above the visible history, preserve the scroll anchor, and stop cleanly on older daemons or unsupported peers. This carries the implementation from draft #27982 into an owned lane because its owner is dead.

Before: the pane stopped at the newest log-seeded page, so older turns were unavailable after restart.
After: the pane reads older transcript pages on demand and shows every prior turn while keeping the reader's place.

Before/after synthetic Linux captures (same restarted adopted chat, newest answer visible):

No capture: the native Swift change only allows the history RPC and its parameters through the relay; it changes no native rendering. The web transcript behavior is captured below on revision 39aad1538d1bb96b529fb334b87b344749182b41 in the Linux harness.

BeforeAfter
BeforeAfter

I viewed the after image above: the transcript is readable, aligned, and leaves the composer unobstructed. The independent reviewer also opened it and accepted the layout alongside ChatGPT/Claude. This is the synthetic capture from revision 39aad153, not a new capture of the latest integration.

Performance

Same synthetic Linux Playwright harness and build, one sample per mode: 700 transcript turns, 200 seeded turns, 500,000 raw log records. Each sample starts a fresh browser after restarting its fixture daemon. Before omits waitLogs; after sends waitLogs:false.

metricbeforeafterdeltaharness
Navigation to newest answer in DOM1,806.9 ms256.5 ms−1,550.4 ms (−85.8%)restore fixture, run 41066566417

A repeated run of the same harness (five samples per mode) measured a median of about 1.87 s before and 0.27 s after (about 85% faster): head run 41068764032. At the merge base, both modes took 1,827–1,991 ms: base run 41068759544.

This isolates the attach wait on the same build. It measures DOM detection after navigation and daemon readiness, not pixel paint or full restart wall time. Both samples had no page errors; the captures use synthetic content.

Validation at 750f0ebaa233ba56903bb9a3590b0c702f9f271c: web passed all 10 history/scroll/queue/config regressions, typecheck, and lint; fast gates passed. The daemon library run passed 2,382 tests with zero failures and five ignored. Independent Codex integration review passed at this exact head, including both parent diffs and visual inspection of the accepted after image. Fleet Swift results are being checked against base per failing test.

Cursor marks use file identity, observed length, and a bounded boundary hash. Validation and paging share one open descriptor. Exact persisted unmarked seeds have an upgrade path; arbitrary unissued unmarked offsets are rejected. The sampled boundary does not fingerprint arbitrary rewrites elsewhere in the file. Restored held prompts publish a queue change to already attached clients. Native reply pages reduce their turn count to fit the RPC budget; an indivisible oversized turn uses explicit omission markers for payloads that cannot fit, while retaining the continuation cursor. No repeating timer was added; older-history reads stop at cursor zero and the existing selection-generation/epoch checks discard stale responses.

Agent session: agent session