Keep the turns a repair cuts, and hand them back to the session

Truncating the transcript is the mechanical fix, but the turns being cut are the
work itself. Losing the conversation that produced a morning's changes is most
of the damage, and a session that resumes with a hole in its memory is barely
resumed - it has no idea what it just did or what it was asked.

So --apply now writes the dropped turns out as <session>.recovered-<stamp>.md,
a readable record of what was asked, what was answered and what was run, and
appends the same text back to the truncated transcript as a single note. Tool
results are deliberately excluded: they are most of a transcript by volume and
the least useful part of a summary.

The note is a user entry marked isMeta - the marker Claude Code already uses for
its own local-command caveats, meaning context rather than something to answer -
and carries no message.id, so it cannot recreate the previous_message_id
condition being repaired. Verified on the real corrupted transcript: 1921 lines
in, 1813 kept plus the note, chained to the last good assistant uuid, no id on
the message, and the file reads back as healthy. The generated digest recovers
the actual instruction that was lost in the incident, which is the thing that
made this worth doing.

--no-reinject writes the markdown but leaves the session alone.
This commit is contained in:
smoido
2026-08-31 02:14:42 +03:00
parent a4afa55580
commit a14418b5d9
3 changed files with 168 additions and 14 deletions
+25 -4
View File
@@ -339,8 +339,8 @@ API Error: 400 diagnostics.previous_message_id: must be the `id` from a
prior /v1/messages response (starts with `msg_`)
```
There is no supported way back from that. The only fix is to truncate the
transcript to the last message Anthropic issued, losing every turn after it:
There is no supported way back from that. The transcript has to be rolled back
to the last message Anthropic issued:
```bash
claude-mode repair-session # list transcripts here and their state
@@ -348,8 +348,29 @@ claude-mode repair-session <session-id> # show what it would cut
claude-mode repair-session <session-id> --apply
```
It backs the original up first, and refuses to touch a transcript that was
written to in the last 90 seconds, since that belongs to a session still alive.
### The cut turns are not thrown away
Truncating is the mechanical fix, but the turns being cut are the work itself —
losing the conversation that produced a morning's changes is most of the damage,
and a session that resumes with a hole in its memory is barely resumed at all.
So `--apply` does three things before it deletes anything:
1. **Backs up** the original as `<session>.jsonl.pre-repair-backup-<stamp>`.
2. **Writes the dropped turns out** as `<session>.recovered-<stamp>.md` — a
readable record of what was asked, what was answered, and what was run. Tool
*results* are left out; they are most of a transcript by volume and the least
useful part of a summary.
3. **Hands them back to the session** as a single appended note, so the agent
that resumes knows what it just did.
That note is a `user` entry marked `isMeta` — the same marker Claude Code uses
for its own local-command caveats, meaning "context, not something to answer".
Critically it carries **no `message.id`**, so it cannot re-create the very
condition being repaired. `--no-reinject` writes the Markdown but leaves the
session untouched.
It refuses to touch a transcript written to in the last 90 seconds, since that
one belongs to a session still alive.
This is why a switch now asks before it writes rather than reporting afterwards.
So restart affected sessions — and `claude-mode sessions --restart` will do it