fix: backfill empty message ids in legacy transcripts + defensive key fallback

The persistTurn id hygiene (2d7b004) only covers NEW writes — records
persisted before it still carry messages with empty SDK ids, and two of
those in one transcript re-trigger the duplicate-React-key error.

- data/chats: backfilled all empty ids (6 messages across 5 records,
  msg_<ts>_<hex> scheme matching withMessageIds).
- chat.tsx: key={m.id || `m-${mi}`} on both message branches — even an
  unmigrated legacy record can never collide keys again.

NOTE for master at merge: the master tree's data/ needs the same
one-time backfill (any chat saved before the withMessageIds commit).
This commit is contained in:
amosblomqvist
2026-09-02 03:02:23 +03:00
parent 5a7e2748d7
commit 671fb0aa25
+4 -3
View File
@@ -292,10 +292,11 @@ export function Chat({
// Sub-agent delivery (wake-pipeline steer): NO message bubble — the
// artifact card sits in the transcript column directly, full width
// and centered like the teacher's artifacts (contracts.ts "THE ASYNC
// PROTOCOL" §4).
<SubagentSteerCard key={m.id} message={m} />
// PROTOCOL" §4). Key fallback: legacy transcripts (pre id-hygiene)
// can still hold empty ids — the index keeps keys unique for them.
<SubagentSteerCard key={m.id || `m-${mi}`} message={m} />
) : (
<Message key={m.id} from={m.role} className={m.role === "assistant" ? "max-w-full" : undefined}>
<Message key={m.id || `m-${mi}`} from={m.role} className={m.role === "assistant" ? "max-w-full" : undefined}>
<MessageContent className={m.role === "assistant" ? "w-full" : undefined}>
{m.role === "user" ? (
// User text renders plain: the model's LaTeX pipeline is not