feat(replay): the replay tails the session; the now line replaces the state diagram; clock axis, veil, thread focus - #103
Merged
Merged
Conversation
The six-node diagram modelled the wrong machine: reply is an outcome, not a state; waiting read 0 on every trace; the counts restated the convo header's time chip verbatim. In its place one row — nowAt: the observed state at the cursor, what is running, how long it has held (only where the extent is a wire fact), and the absolute clock it began at. soFar keeps the one figure nothing else states, the per-tool call tally. beatAt gains the loop's head, so a step always names the task it serves. axisTicks lands with them for the strip's clock ruler. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d in focus The strip could not say WHEN: no axis, every thread's spans drawn on top of each other, and a 2px accent playhead over an accent-tinted past over accent-hued model spans — invisible in any dense region. - a clock row (axisTicks) above the human lane, labelled in local time, major ticks dropping a rule through every lane - the veil: the FUTURE dims from the playhead to the right edge. The accent-tinted past (#rp-fill) is gone — it cost the model spans their contrast exactly where the reader looks - the playhead gets a surface-color halo and a flag on the clock row - thread focus: the rail's selection draws full, every other thread ghosts - transport: ⏭ / End seek the end of the tape (the live edge on a live run), a live chip states whether the page is tailing or offers the snap back, the clock reads absolute local time before the tape offset, and ✕ exit means exit — nothing else Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ursor Replay claimed live and was a snapshot: a landed pair redrew the strip but never moved the cursor, so a reader parked at the edge fell behind in silence while the strip grew. - a pair frame measures wasAtEdge/wasAtBottom BEFORE ingest; at the edge the cursor moves to the new one, the now line and the beat follow, and the convo sticks to its bottom only if the reader was there. Behind the edge nothing moves and the chip flips to the snap-back - history frames never move the cursor: the edge did not change - playback reaching the end of a live tape parks at the edge instead of just stopping — from there the tail rule applies - every other cursor change (seek, step, chapter, tick) scrolls the convo to its bottom instantly: the bottom IS the moment - the beat gets the page's 160ms live-arrived fade on a tail advance only Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gelog The spec's "Revision 2" section is the brief this branch implemented; the rest of the doc is now the current truth. web-ui.md, the SKILL, the README and CLAUDE.md drop the diagram and pick up the now line, the clock axis, the veil, thread focus and the tail; ui.md's replay rule says the future is what dims, never the past. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…us; the spec names the edge, the instant, the ruler step - a subagent selected in the rail drew its own agent span ghosted (the lane keyed off parentKey only); it now stays full - axisTicks picks the FINEST step that clears 72px — the comment and the spec said coarsest, the code and its test always did finest - the spec states what the harness had to guess: the transport's <length> is the strip's axis (stretched by an open start) while 'at the edge' is measured against the newest completed pair; a tools gap overlapping a running child reads agents; spans are half-open so the gap owns the instant at a pair's end; reading pages leave the live chip's skeleton span empty - changelog: ascii separators, no UI glyphs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1. The strip's measured frame width is part of its cache KEY. Entering replay from the requests tab renders once while #session-view is still display:none (the hash route is async): axisTicks(0) drew no clock and no span label got .w24, and the key-guard froze that draw forever. The route's own render now repairs it; a bounded rAF re-render backs it up. 2. The ruler's zone offset is measured on the DATA (new Date(span.t0)), not on today — a July trace read in January no longer rules an hour off its own tips. The comment claiming otherwise is corrected; a mid-span DST transition is named in the spec's "Not done". 3. A history frame re-reads the bar on the new axis: the playhead, the veil and the tape length were left on the pre-merge one. 4. The live-arrived fade fires only when the beat actually moved — telemetry, count_tokens probes and usage polls land at the edge too. 5. A tail advance renders the session view ONCE, at the new cursor, instead of once at the old cursor and again at the new one. 6. nowAt states no `since` for the idle before the first pair: stateAt bounds that hole by a clock the cursor has not reached. 7. axisTicks holds the 72px floor past the ladder's top rung — 30 days at 900px drew 31 day-ticks 29px apart. 8. Tests: a bare expression now asserts; the history test merges a real earlier pair and checks the absolute clock held while the tape grew; the child-thread focus case is covered. 9. Nits: the live chip rewrites only when its state flips (it was destroying the button mid-hover); seekEnd's unreachable enterReplay branch is gone; the agents-lane comment is one sentence again; the duplicated focus test folds into oth(k, k2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lroolle
force-pushed
the
feat/replay-tail
branch
from
August 29, 2026 14:18
73d3903 to
5abb988
Compare
…in the bar Rev 2 deleted the state diagram on the argument that the strip already carried the loop's shape. Eric's read: the strip shows the loop unrolled; the picture of the machine was the thing worth keeping — "redesign it accurately, live and horizontal, in the replay bar". The loop row (#rp-now) sits between the strip and the transport, aligned to the strip's gutter: Claude Code's machine — human -> model -> one hand-off slot that reads tools / agents / waiting -> model ... -> human — as fixed-pixel inline SVG, the state at the cursor lit with the edge it came in by (prompt, calls, results, answer; a failed request is the model chip in red with no edge), and beside it what is running, how long it has held where that is a wire fact, and the absolute clock it began at. No counts on it. Click seeks to the step that opened the state; at the live edge the model chip beats while a request is in flight. loopAt (src/replay.ts) builds on nowAt/stateAt: adjacency for a landed request's edge, the protocol's edge for a live one, the answer edge only when the reply actually landed. The stage's #stage-now row is gone — the state is stated once. Spec: docs/design/replay-stage.md "Revision 2.1". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d's own time with idle folded
Rev 2.1's three 16px chips read as a legend, not a diagram. The loop row
is now Claude Code's loop as a flowchart: boxes human / model / the
hand-off slot (tools, agents or waiting), a `calls?` decision diamond —
the reply's tool_use blocks, a wire fact — and five labelled edges
(prompt, yes, results over the row, no · answer under it). The state at
the cursor lights its box, the edge it came in by lights and FLOWS (an
animated dash: the transition in progress, a deliberate second motion
owner while replaying), the model box beats only for a request in
flight. Fixed pixel geometry; prefers-reduced-motion drops both.
The strip's axis was the whole capture: on a 10h38m trace the selected
1h34m session sat in the left quarter and three quarters drew nothing.
The axis is the selected thread's own extent now (threadExtent), and a
gap in its busy time over five minutes folds to a 28px hatched break
with the skipped duration in the clock row (timeScale / scaleX / scaleT
in src/replay.ts — the one x<->t mapping every strip surface uses:
spans, ticks, veil, playhead, slice, drag, wheel zoom). The ruler rules
per busy segment, so a folded 8h never coarsens the ticks beside it;
break labels anchor inside the track. The transport's clock and length
stay real wall-clock.
Implemented by an Opus 5 worker against docs/design/replay-stage.md
("Revision 2.2"); verified in Chrome on the 2026-08-28 trace.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…replay tail Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replay rev 2: the replay tails the session, the now line replaces the state diagram
Eric's read of 0.45.0's stage: "the replay should tail the session; the transition stage is inaccurate and a bad representation of Claude Code agent work; refine the layout, the design, the live, the motion." Verified on a real 4h trace (1209 pairs, 25 sessions, 2 subagents) before changing anything:
replay.cursor— a reader parked at the live edge fell behind silently while the beat, the convo and the "state" froze at entry time.prompt -> [model -> tools]* -> model -> answer.replyis an outcome not a state,waitingread 0 on every trace,humannever lit, the counts were redundant (tools 160 = model>tools 160) or inconsistent (model>agents 1 vs agents>model 2), andmodel 164 . 33m 12s / tools 160 . 17m 31srestated the convo header'stimechip verbatim (ui.md: a number is stated once).What changed
pairframe the page measures where the reader was BEFORE ingest; at the edge the cursor follows, the now line and beat move, the convo sticks to its bottom only if it was there. Behind the edge nothing moves and the live chip flips to a⤓ livesnap-back.historyframes never move the cursor. Playback reaching the end of a live tape parks at the edge.nowAt, built onstateAt): dot in the lane color, the state, what is running (tool names with repeats folded / running children by name / the failed status), held time only where the extent is a wire fact, absolute clock it began at. The dot beats only for a live in-flight request. The diagram,stateCountsand its transitions table are gone;soFarkeeps the one figure nothing else states (the call tally).axisTicks, local time, day-major ticks drop a rule), the FUTURE is veiled instead of the past being tinted, playhead halo + flag, thread focus (selected thread full, others.other).● live/⤓ livechip on live pages,✕ exitonly exits.so fartally under it.Spec rewritten in place: docs/design/replay-stage.md (rev 2 section explains each change against the three findings). Docs: web-ui.md, ui.md, SKILL.md, README, CLAUDE.md, CHANGELOG under Unreleased.
Verification
bun test: 847 pass / 0 fail. tsc clean.make buildOK.test-output/replay-tail/check.sh(static rev-2 surface, frozen fixture): 19 PASS / 0 FAIL.test-output/replay-tail/check-live.sh— a tracedclaude -prun with a headless browser attached MID-RUN in replay: 17 PASS / 0 FAIL — a landed pair advanced the cursor at the edge, the convo stuck,● livewhile tailing,model . thinkingwith the live class while a request was in flight, a pair landing while scrubbed back did NOT move the cursor,⤓ livesnapped back.sincein the future before the first pair, no tick floor on multi-day spans.Not in this PR (spec "Not done"): folding the context overview and the strip into one component, a compressed-time axis for multi-day sessions, a mid-span DST shift on the ruler, per-call durations (P3 chunk timing).
🤖 Generated with Claude Code