Files
Maxim 0dd43f2d36 fix(react-core): guarantee row-key uniqueness for pathological tc:-prefixed message ids
buildRowRenderKeys previously fell back to message.id without consulting
the claimed set. A message whose literal id happened to begin with "tc:"
and matched an earlier-claimed tool-call key would produce duplicate
React keys — React then reconciles a row against the wrong DOM node and
inherits stale state. The docblock's "unique by construction" claim was
also wrong: it relied on a precondition (no raw id begins with "tc:")
that the function did not enforce.

Make uniqueness structural: every assigned key is checked against the
claimed set, and a deterministic numeric suffix (":2", ":3", ...) is
appended when a collision is detected. Normal-path behavior is byte-
identical (no claimed.has(candidate) miss, no claimed.has(message.id)
hit → still assigns candidate-or-id).

Also:
- Correct the docblock; add explicit precondition (caller must
  deduplicate) and an order-sensitivity caveat for shared-anchor cases.
- Add a regression test for the pathological tc:-prefixed-id collision.
- Strengthen the existing shared-anchor test to pin first-claimant-wins
  precedence via input-order textContent assertions.
- Fix an inaccurate comment that claimed duplicate keys "silently drop"
  a row — the real failure mode is wrong-node reconciliation.
- Note the limitations in the changeset prose.

Call-site enumeration: buildRowRenderKeys has a single call site in
CopilotChatMessageView.tsx (inside the rowRenderKeys useMemo). The
input is always deduplicatedMessages, so the precondition holds.

Red-green evidence: with the claimed.has(assigned) else-if removed,
the new pathological-collision test fails with 3 "two children with
the same key" warnings; restoring the guard returns to green.
2026-06-10 16:09:24 +02:00
..
2026-06-05 05:21:08 +00:00
2026-06-05 05:21:08 +00:00