merge a /clear chain into one conversation

The list collapses each chain to its newest link — the only one that can be
resumed — carrying the root's title and start time, the summed message count
and a part badge. The detail splices the chain's transcripts oldest-first with
a divider between parts, server-side, so the client's index-window pagination
needed no change.

The divider says "context cleared — nothing above this is in memory", because
the whole risk of merging is that the history reads as continuous when the
agent's context is not. Delete cascades the chain and the confirm says how many.

Supersedes the "continues X" line from the previous commit: there is nowhere to
link to once the parent is scrolled up above you.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 00:44:33 +00:00
co-authored by Claude Opus 5
parent 3e01de100e
commit 47894702ac
10 changed files with 296 additions and 67 deletions
+52
View File
@@ -345,6 +345,58 @@ not been through a browser.
---
## 15. A cleared conversation is one conversation again
**Where:** `/chat`. Look at the session list for `officer.dev`. It has one row fewer than it did
yesterday, and “Platform Arch 2” is gone — there is a single **Platform Arch** carrying a `2 parts`
badge. Open it and scroll up past the point where you cleared: the earlier conversation is above,
with a line across the transcript reading **context cleared — nothing above this is in memory**.
**What changed.** Item 14 could tell that one conversation followed another, and said so in a meta
line. This takes the obvious next step and stops showing them as two things at all. A `/clear` chain
is now one row and one transcript.
**The list** collapses each chain to its **newest** link, not its oldest, because that is the only one
you can carry on — a cleared session is finished, and `--resume` on it would fork a second branch. So
the row's id, its link, its rename and its delete all address the head. Everything else on the row
belongs to the whole chain: the root's start time, the summed message count, and the root's title. That
last one is why the numbering disappeared from view — a conversation shouldn't rename itself every time
you clear it, and `Platform Arch 2` was only ever a way of saying "this is still Platform Arch". Rename
still wins over all of it, and it is the head that stores it. The numbered titles are still computed and
still show up if you open a middle part directly from an old link.
**The transcript** is spliced server-side, in `loadChainTranscript`. This mattered for a boring reason:
the chat client pages by index into whatever the server calls the transcript — `?before=` and `?limit=`
plus a `total` — so a longer transcript simply pages further back and the client needed no changes at
all. Only ancestors are spliced in, never descendants, which keeps the returned id resumable.
**The divider is the point, not a decoration.** The risk in merging is that the conversation now looks
unbroken to you and is emphatically not: ask the agent about anything above that line and it has never
seen it. So the seam says what was lost rather than just drawing a rule. It is a new `divider` variant
on the `ChatMessage` union — the existing `system` role renders as a collapsible "System prompt" block
and would have been the wrong thing entirely.
**Delete now takes the whole chain**, and the inline confirm says so — `Delete all 2?` rather than
`Delete?`. Deleting only the head would have resurrected its parent as a separate row the moment its
child was gone, which reads as the delete half working. The chain is resolved from the transcript's own
directory rather than the requested one, because those two disagree routinely and the wrong group would
find no chain and quietly delete one part of several.
**What this removed.** The "continues X" line in the row and the link back in the chat header, both
built yesterday. There is nowhere to link to now — the previous conversation is scrolled up above you.
The header shows `continued across 2 sessions` instead, which is a fact about the thing you are reading
rather than a destination.
**Measured, not estimated:** `officer.dev` goes from 11 rows to 10, `dev-platform` from 2 to 1, each
merged transcript carrying exactly one divider at the expected index. Still read-only — nothing is
written back into Claude's store, so if the parent inference is ever wrong the damage is a list that
looks odd until the next read, not a corrupted transcript.
**Not verified:** the browser. Everything above is measured against your real transcripts through the
server code, not clicked through.
---
## Things noticed and deliberately left alone
- **`useChatWebSocket` silently ignores unparseable frames.** That one is intentional and the comment