fix(chat): follow transcript rotation on /clear so the chat keeps working (#34) #42
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!42
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/34"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fixes issue #34: using
/clearfrom the chat composer broke the session — the chat kept reading the pre-clear transcript and replies produced no visible response, and the only recovery was to stop and restart the instance.Claude Code's
/clear(and/rewind) rotates the sessionId → a new transcript file, freezing the old one on disk. lab pinnedruns.transcript_pathwrite-once to the old file. This change makes lab follow the rotation by its observable effect (the located transcript changing), so lab core never parses any agent's clear command — which also handles a clear run out-of-band (in claude.ai, or/rewind) for free.Changes
internal/chat— an ACTIVE run re-asksLocateTranscripteach read/tick and adopts a different, non-empty path (locateActive), re-pointingruns.transcript_path(single value — re-point & forget). Ended runs never re-locate (successor-safety); an empty locate never clobbers a set path; the persist is gated on a fresh liveness re-check so a since-ended run's tailer can't adopt a successor's transcript in a reused worktree. The tailer re-resolves each tick against its own cached path and resets its file-change bookkeeping on a rotation.transcript_id— an opaque hash-of-path token in the messages response (provider-neutral in the envelope, provider-derived in value); the SPA keys a stream reset on it, since the fresh transcript restartsseqat 1 and would otherwise collide with the accumulated messages in the seq-keyed merge.claudecode.PendingDialog— a dialog spool older than the current transcript is treated as stale (OR'd with the tool-id check), so a pre-clear spool can't keep the composer locked against the new session. Safe for a genuine pending dialog: the transcript is byte-frozen then (compat §5) and the spool is written after it, so the spool is always newer.web/RunChat— resets the accumulated stream + composer on atranscript_idchange; treats the""locating/gone sentinel as "no rotation".compat.md §5/§9— documents the new coupling./compactis unaffected (same sessionId, same file). Reply/interrupt is unchanged (the tmux session name is stable across/clear). No budget/claim/three-strikes effects; no new provider capability (issue #7 decision 12 / ADR-0016).Tests
internal/chat: re-locate-on-rotation, empty-locate-never-clobbers, ended-run-ignores-rotation,locateActivenever persists a successor onto an ended run, and the tailer follows a rotation + republishes.internal/httpapi:transcript_idis present and changes across a rotation.internal/provider/claudecode: a spool goes stale after a rotation; a byte-frozen (older) transcript still shows the dialog.web:RunChatresets the stream + unlocks the composer on atranscript_idchange, and the locating→available first-locate does not spuriously reset.Verification
Full Go suite (untagged +
ui-tagged) green; frontend eslint + prettier + 380 vitest tests +tsc+vite buildgreen. An adversarial multi-agent review of the diff surfaced 4 issues — a successor-adoption regression in the tailer, a""-vs-undefinedguard gap in the SPA rotation effect, and a filesystem-timestamp-granularity flake in a pre-existing spool test — all fixed and re-verified.Closes #34
🤖 Generated with Claude Code