Content-verified turn attribution + model sets; silent TUI, --continue preload, version hash#44
Content-verified turn attribution + model sets; silent TUI, --continue preload, version hash#44lroolle wants to merge 4 commits into
Conversation
…ty UX Session reconstruction (devlog 2026-07-17): - Per-turn attribution is index-first, content-verified against the pair's assembled response (turnContentSig), content-scan on mismatch. Claude Code repacks history with ephemeral notice turns, so raw indices land on the wrong turns — the 5-model test session had three silently unattributed replies and two attributed by luck. - Pairs matching nothing classify REWOUND (prefix-divergent: /rewind or an edited turn) or UNATTRIBUTED — marked in the conversation, never silently blank. Rewound exchanges mark their divergence point and link to the kept wire pair. - A thread's model is a set (per-model requests/tokens/cost); the face model is the one with the most output tokens. "fable-5 · 63 turns" for five models' work becomes "fable-5 +4 models · 63 turns". - compact rewind guard: a request whose final history message appears nowhere in the keeper's packing holds the only copy of an erased exchange — kept full, never stubbed. Verified pre/post-compact: identical turns and attribution on the real trace. - Regression fixture cut from the controlled 5-model + /rewind session, sanitized with equality-preserving hash tokens (10KB zst, leak-swept). Launch & continuity UX: - cctrace is silent while the traced client owns the terminal: all output funnels through src/termlog.ts, buffered from spawn to exit, flushed after — mid-session continuity merges and crash-guard notes no longer corrupt the TUI. - --continue/--resume preloads the resumed session speculatively (newest prior session id, or the explicit --resume id), so the UI opens populated; the first live request confirms the guess or evicts the preload with a client re-init. - --version and the banner print the commit hash: baked in by make build --define, git fallback on source runs (guarded so an npm install inside another repo never reports that repo's HEAD). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n tab The Session tab gains the third grouping level (session-tab.md decision 1): messages -> threads -> sessions -> project. - Threads are session-scoped: the grouping key is <sid>|<wire key>, so two sessions whose first message is identical (/clear mid-run) never merge into one thread. "" stays an honest no-session-id bucket. - Threads pane: >=2 session ids render collapsible per-session sections, newest activity first — header carries short sid (click = copy full), wall-clock range, request count, error rollup. Fold state survives live re-renders keyed by sid. Single-session traces render flat: zero new chrome, the common case pays nothing. - Routes: #/session/<sid8>[/<thread-key>] resolves sid-prefix after the thread-key back-compat check; old links keep working. [ / ] switch sessions from the keyboard. - Default focus is the newest session's main thread; a NEW session id appearing mid-run follows only while tailing — reading history is never yanked. - Request rows (the selected thread's list) mark rewound / compact-folded / failed requests inline; thread meta counts rewound exchanges; assistant turns that switch models prefix "→ model". - grok recap classification now reads the conv header instead of a key prefix (the sid prefix broke the old check — caught by tests). Verified through the dom-stub (the real page script executes): zero-chrome single-session, ordered sections, sid-prefix routing, grammar-clean markup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Third commit: the sessions layer (session-tab.md decision 1) — the Session tab is now the full hierarchy: Selection doubles as thread expand/collapse (the existing affordance); request rows gained rewound / folded / err markers. Thread keys are now session-scoped (sid|key) so /clear twins never merge — old #/session/ links still resolve, new #/session/[/] routes added, [ ] switches sessions. Single-session traces render byte-flat: zero new chrome. 430 tests green, including dom-stub renders of both paths. |
The default thread label was "fable-5 +4 models · 63 turns" — the model
occupied the identity slot, which read as "threads are grouped by model"
(they aren't; a thread is a conversation that can span models via
/model). Clean split:
- label names the conversation: "63 turns" / "[explore] search for..." /
"prewarm"; the kind badge already says chat/agent/utility
- the model becomes a quiet right-aligned chip on the card ("fable-5 +4"
after mid-thread switches, per-model split in the tooltip — one
modelTitle helper shared with the convo-pane chip)
- selection emphasis moves up to the SESSION container: a faint accent
wash on the section summary and the selected thread head, replacing
the accent border (edges read as chrome — same rule that fixed
user-turn emphasis)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The session card takes the bordered-box treatment threads used to have; threads flatten to divided rows inside it; the selected thread's request rows nest below. Containment is drawn by structure, not indentation. Header gets real hierarchy instead of a flat mid-dot line: identity left (short sid, strong, click-to-copy + conversation turns), quiet attributes right-aligned (HH:MM range — no seconds, no degenerate ranges — request count, errors). The word "session" is gone: the box is the session. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Superseded by #45 (v0.18.0): this branch was the base of sessions-layer-work — content-verified attribution, model sets, silent TUI, --continue preload, and the version hash all shipped in the 0.18.0 squash. Closing rather than merging a duplicate. |
Two cohesive chunks, both regression-tested (424 tests green).
Session attribution (devlog 2026-07-17, decisions 2/3/4)
The 5-model controlled session exposed three bugs: per-turn attribution
indexed by history length silently missed turns when Claude Code repacked
history (ephemeral notice turns -> non-monotonic hist lengths 2,4,5,10,9,
11,...), the thread model was last-write-wins ("fable-5" named for five
models' work), and /rewind erased captured exchanges from the
reconstruction with no trace.
pair's assembled response (new turnContentSig, capped compare per the
devlog CPU tradeoff), content-scan on mismatch. Verified claims beat
index-only ones; stubs/errored streams stay index-primary.
Real-trace result: 39/40 assistant turns attributed, 0 mismatches; the
one hole is a reply whose Bash command was edited client-side before
entering history — truthfully rendered "unattributed", never blank.
"Okay." exchange classifies rewound-not-lost at its divergence index,
gets a quiet dashed marker in the conversation linking to the kept wire
pair, and rewound/unplaced counts join the thread chips.
most output tokens; label "fable-5 +4 models · 63 turns"; split in the
model chip tooltip.
history message appears nowhere in the keeper's packing holds the only
copy of an erased exchange — kept full. Sound because every history
message was once some request's tail. Response-only rewinds still stub
safely (responses are never touched); their class softens to "unplaced".
Verified pre/post-compact on the real trace: identical turns, identical
attribution.
thread sanitized with equality-preserving hash tokens (10KB, leak-swept:
no paths/names/text). 9 new tests pin models, recovered holes,
no-misattribution, rewound classification, and retry-vs-branch-tip
compact behavior. Note: the fixture is strictly harsher than live on one
pair (an edit beyond the 160-char sig cap that live prefix-compare
attributes) — documented in the test.
Still open, sequenced after: sessions layer (session-tab.md design in
flight), OpenAI histLen audit (needs a real multi-model codex trace).
Launch & continuity UX (ideas 11/12/13)
from spawn to child exit, flushed after. Kills the mid-session
"session continued — merged N pairs" line, update-check status, and
crash-guard notes corrupting the TUI.
newest prior session (or the explicit --resume id) so the UI opens
populated; the first live request confirms or evicts (client re-init —
reuses the existing init full-replace, zero new ws protocol).
binaries, git fallback for source runs, guarded against reporting the
host repo's HEAD from an npm install.
🤖 Generated with Claude Code