Addresses the three review findings on the transcript presentation slice.
Finding B (merge blocker) — a reader's collapse survives ejection.
Grouping is re-derived every pass, so a group had no identity of its own
and was keyed by its first leaf. When the FIRST call failed,
isGroupingEligible ejected it, the next leaf became first, the key
churned, and the store found nothing under the new key — silently
reopening a group the reader had deliberately collapsed.
Identity is now resolved once per transcript pass: a group keeps the
identity of any leaf it still holds, an identity is claimed by at most
one group, and on a mid-run split the half holding the earlier leaves
inherits the reader's state. Identity is always content-derived from leaf
keys, never positional, so archive prepends cannot renumber anything.
The recognition table is scoped per transcript instance and retains only
leaves present in the current pass, so it stays bounded.
Fixing that surfaced a second, larger defect in the same seam: a
`<details>` fires `toggle` when React sets `open` on mount, not only when
a reader clicks, and the controlled row recorded that echo as a reader
action. Every group that mounted open immediately latched the sticky
userInteracted flag, which disabled automatic collapse entirely — the
auto-collapse policy was dead in the real app while passing at the unit
level. React also re-asserts the declared `open` before the async toggle
is delivered, which loses a genuine click. Controlled rows now drive
disclosure from the summary click and prevent the default, so the
caller's state is the single source of truth.
Finding A — history-certainty copy no longer drifts. getUncertainHistoryCopy
existed but the UI inlined its own wording. The certainty type now names
which check came up short rather than collapsing to a coarse "unknown",
and that helper is the only place the wording lives. Per the product
decision the uncertain message is correct when archive completeness
cannot be established, so the channel E2E expectation was updated to the
honest state instead of changing behavior.
Finding C — unreachable failure detail removed. No observer frame can put
a failed call inside a group, so the "N failed" plural badge was dead
presentation. The badge is now one plain word and the failure-leaning
fold is retained with a comment, so widening eligibility later cannot
silently hide a failure.
Verification (full desktop package, not scoped): 5428 unit tests pass /
0 fail, typecheck clean, pnpm check exit 0, transcript smoke spec 3/3,
and channels.spec.ts 87/87 — including the previously red
"shows and clears activity indicators" test. Both new browser tests were
mutation-checked: restoring the toggle mechanism fails them.
Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>