fix(resume): a replayed transcript had lost every tool result - #27
Merged
Conversation
Resuming a session redrew its tool calls with nothing under them:
⏺ Read(src/domain/usage.ts)
⏺ Bash(ls -1 src | head -12)
Every result the session had ever produced was gone. `rehydrate` folded
`tool/call` into a row and never looked at `tool/result` at all, and the
transcript builder discarded the row's text on purpose — reasonably, back
when that text was the model-facing payload nobody wants pasted into a
transcript.
It no longer is. The card projections now carry a real `⎿` summary, and
the harness persists each card's structured shape in the session log
precisely so `presentResult` reproduces the identical card from a stored
event. So replay presents its results the same way the live path does, and
the row's text IS that summary:
⏺ Read(src/domain/usage.ts)
⎿ Read 3 lines
⏺ Bash(ls -1 src | head -12)
⎿ __tests__
app
…
`presentResult` takes the call's name and arguments as parameters instead
of reading them off the live maps, which is what lets replay share it.
Results are matched to their call by id, not by arrival order, because
parallel calls interleave their results in the log.
A write or edit cannot draw its diff card on the flat replay trail, so it
gets the card's own header as text — `Wrote 3 lines to notes.txt`, `Added
1 line, removed 1 line` — rather than the "file has been updated
successfully" boilerplate addressed to the model.
Co-Authored-By: Claude Opus 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.
What
Resuming a session redrew its tool calls with nothing under them. Captured by running a session, killing it, and replaying it with
/sessions <id>:Every result the session had ever produced was gone.
Why
rehydratefoldedtool/callinto a row and never looked attool/resultat all, and the transcript builder discarded the row's text on purpose — reasonably, back when that text was the model-facing payload nobody wants pasted into a transcript.It no longer is. The card projections (#15, #17) now produce a real
⎿summary, and the harness persists each card's structured shape in the session log precisely sopresentResultreproduces the identical card from a stored event:So replay presents its results the same way the live path does, and the row's text is that summary.
Details
presentResulttakes the call's name and arguments as parameters instead of reading them off the live maps — that is what lets replay share it.Wrote 3 lines to notes.txt,Added 1 line, removed 1 line— rather than the "file has been updated successfully" boilerplate addressed to the model.Test
npm run typecheck,npm test— 150 files / 1953 passingnode scripts/verify-boundary.mjsharnessClient.test.ts: the stored log now carries atool/result, and the rehydrated row asserts its presented textmessages.test.ts: the tool row's text reaches the trail line (the fixture's'ignored raw result'was the old contract, now'Found 3 files')/sessions <id>— showing the replayed trail matching the live one🤖 Generated with Claude Code