You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The root transcript has zero such lines. Enrichment already greps every transcript, so one more pattern yields a complete child → parent map. No heuristics, no content comparison.
Four consequences in CodeV
/branch copies the transcript but NOT history.jsonl. The child's prompts before the branch exist only in the transcript. CodeV's list is built from history.jsonl, so:
Deep search cannot see them. Searching for anything said before the branch finds the parent, never the child — search systematically points at the older generation.
messageCount is wrong. A child carrying a full conversation renders as "1 msgs" (observed: 5 msgs vs the parent's 38).
Pins do not follow. Verified in ~/.config/codev/session-marks.json: the pin sat on the parent while work continued in the child.
Ordering. Resuming a parent lifts it above the child that actually continues the work.
The sharper problem: identically-named live sessions
Because /branch moves you into the new session, the new name lands on the work you are continuing, while the original session keeps the old name — the wrong way round. The workaround in daily use is a three-step swap: branch with a temporary name, resume the parent and rename it <name>-2, then rename the child back to the original name.
Why the child gets the original name is the important part: /branch carries in-flight background subagents across, and their output lands in the child. So the unfinished task genuinely continues there, and the name follows the work. The parent is then resumed and repurposed for a different task, which is why it takes the -2.
That makes the rename dance a manual substitute for something CodeV does not provide: stable task identity across session ids. The user's mental model keys on name + task; CodeV keys on session id, and the two diverge every time a branch happens.
The result is that names are deliberately reused across generations. Measured right now:
pid=22290 id=b7f7c407 "agentic-fred harden again - pr2-1533-v7-readiness — deps ref…"
pid=20653 id=a96a4274 "agentic-fred harden again - pr2-1533-v7-readiness — deps ref…"
pid=27303 id=6fab4f73 "agentic-fred harden again - pr2-1533-v7-readiness — deps ref…"
Three distinct sessions, three live pids, identical names. CodeV is reporting this correctly — it is simply undisplayable, and scanning the terminals by eye does not separate them either.
And iTerm2 switching matches on the tab title, so all three rows switch to the same terminal. That is the "clicking any of them goes to the same session" report. Not a regression of the same-cwd work (activeStateRef is replaced wholesale each detection, and the direct pid→id mapping never reaches the cwd fallback) — it is the existing title-matching mechanism meeting a case where titles are intentionally not unique.
Proposed work, in priority order
C0 — make same-named live sessions distinguishable, and switch by TTY/pid rather than title. This is the one that hurts today. Display needs something unique per row (branch generation, divergence time, pid/tty).
C1 — surface the forkedFrom relation. Bind identity to the task, not blindly to the newest descendant. An earlier proposal here was to resolve pins to the tip of the chain. That is too crude: after the dance the child continues the original task while the parent is live under a different task, so both are meaningful and "newest" is not the same as "the thing you pinned". The relation should be shown, and any migration should follow the task — the signal for which is the name moving, not the chain advancing.
C2 — messageCount summed along the chain.
C3 — optional chain collapse in the list (plan §6's C3).
docs/session-finding-plan.md §6 states C3 chain collapse is "essentially defunct … no generation chains exist; only meaningful if --fork-session / copy-fork become common." Generation chains are a daily occurrence and 23.9% of the corpus.
§4.4 lists forking under "Edge cases (v1 ignores them; re-pin manually if hit)". Same false premise.
Both should be corrected regardless of which items above get built.
🤖 On behalf of @grimmerk — generated with Claude Code
What was measured (2026-09-05, live experiment)
/branch <name>copies the transcript to a new session id and lets the same process keep writing to the new file. Confirmed end to end on this machine:/branchb4feeab6a8f5603asessions/<pid>.jsonbranch-test-a/branchline lands under the parent, everything after under the childResuming the parent afterwards works (new pid, appends to the parent transcript). So the reported symptom is confusion, not failure.
This is not an edge case: 21 of 88 transcripts on disk (23.9%) carry
forkedFrom.The exact primitive
Claude Code records the link itself, on every copied line of the child:
The root transcript has zero such lines. Enrichment already greps every transcript, so one more pattern yields a complete child → parent map. No heuristics, no content comparison.
Four consequences in CodeV
/branchcopies the transcript but NOThistory.jsonl. The child's prompts before the branch exist only in the transcript. CodeV's list is built fromhistory.jsonl, so:messageCountis wrong. A child carrying a full conversation renders as "1 msgs" (observed: 5 msgs vs the parent's 38).~/.config/codev/session-marks.json: the pin sat on the parent while work continued in the child.The sharper problem: identically-named live sessions
Because
/branchmoves you into the new session, the new name lands on the work you are continuing, while the original session keeps the old name — the wrong way round. The workaround in daily use is a three-step swap: branch with a temporary name, resume the parent and rename it<name>-2, then rename the child back to the original name.Why the child gets the original name is the important part:
/branchcarries in-flight background subagents across, and their output lands in the child. So the unfinished task genuinely continues there, and the name follows the work. The parent is then resumed and repurposed for a different task, which is why it takes the-2.That makes the rename dance a manual substitute for something CodeV does not provide: stable task identity across session ids. The user's mental model keys on name + task; CodeV keys on session id, and the two diverge every time a branch happens.
The result is that names are deliberately reused across generations. Measured right now:
Three distinct sessions, three live pids, identical names. CodeV is reporting this correctly — it is simply undisplayable, and scanning the terminals by eye does not separate them either.
And iTerm2 switching matches on the tab title, so all three rows switch to the same terminal. That is the "clicking any of them goes to the same session" report. Not a regression of the same-cwd work (
activeStateRefis replaced wholesale each detection, and the direct pid→id mapping never reaches the cwd fallback) — it is the existing title-matching mechanism meeting a case where titles are intentionally not unique.Proposed work, in priority order
forkedFromrelation. Bind identity to the task, not blindly to the newest descendant. An earlier proposal here was to resolve pins to the tip of the chain. That is too crude: after the dance the child continues the original task while the parent is live under a different task, so both are meaningful and "newest" is not the same as "the thing you pinned". The relation should be shown, and any migration should follow the task — the signal for which is the name moving, not the chain advancing.messageCountsummed along the chain.Documentation this falsifies
docs/session-finding-plan.md§6 states C3 chain collapse is "essentially defunct … no generation chains exist; only meaningful if--fork-session/ copy-fork become common." Generation chains are a daily occurrence and 23.9% of the corpus.Both should be corrected regardless of which items above get built.
🤖 On behalf of @grimmerk — generated with Claude Code