Conversation
buildCallLogListRows() merges three sources into one response: in-flight
("pending") requests tracked in memory, recently-completed in-memory
entries, and persisted call_logs rows. The completed-entries loop already
guarded against double-counting an id that had already landed in the
persisted rows or the pending map -- but the pending-entries loop itself
had no equivalent guard against an id that had already been persisted.
A request that just finished can be written to call_logs a moment before
its in-memory pending-tracker entry is removed. In that window, the same
id appeared in both `activeEntries` and `logs` in a single API response,
producing a duplicate React key in the request logger's table:
Encountered two children with the same key, `<id>`. Keys should be
unique so that components maintain their identity across updates.
Observed live on /dashboard/logs (RequestLoggerV2.tsx's <tr key={log.id}>).
Fix: mirror the same `persistedIds.has(detail.id)` guard already used for
completedEntries onto the pendingDetails loop.
New regression test (buildCallLogListRows: dedupes a pending in-memory
entry already persisted to the DB) proves the id appears exactly once
once both sources report it, and that the persisted row wins (no stale
`active: true` flag). Confirmed it fails against the pre-fix code (returns
2 rows for the same id) and passes after (1 row).
Evidence:
- node --test tests/unit/call-logs-correlation-sort.test.ts: 5/5 pass
- node --test tests/unit/call-log-provider-display.test.ts tests/unit/request-logger-endpoints.test.ts:
40/40 pass (unaffected)
- eslint: clean (3 pre-existing unrelated `any` lint errors in the test
file, confirmed present on unmodified release/v3.8.51 too, not touched)
- tsc --noEmit: no errors in touched files
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
|
Good catch on the asymmetry with the |
|
Confirmed — checked the current release/v3.8.51 tip and |
…y persisted to call_logs) into dev/omniroute-dev-combined
…y persisted to call_logs) into dev/omniroute-dev-combined
|
Thanks for this — the guard is correct in isolation, and it mirrors the one already applied to the completed entries. Closing because the collision it defends against can no longer happen on the current tip:
The two id spaces are generated independently and never meet, so |
What Problem This Solves
/dashboard/logsoccasionally threw a React console error:Root Cause
buildCallLogListRows()merges three sources into one API response:in-flight ("pending") requests tracked in memory, recently-completed
in-memory entries, and persisted
call_logsrows.The completed-entries loop already guards against double-counting an id
that had already landed in the persisted rows or the pending map:
The pending-entries loop had no equivalent guard. A request that just
finished can be written to
call_logsa moment before its in-memorypending-tracker entry is removed. In that window, the same id appeared in
both
activeEntriesandlogsin a single response -- the exactduplicate key React reported.
Fix
Mirror the same
persistedIds.has(detail.id)guard already used forcompletedEntriesonto thependingDetailsloop.Evidence
New regression test proves the id appears exactly once once both sources
report it, and that the persisted row wins (no stale
active: trueflag). Confirmed it fails against the pre-fix code (returns 2 rows for
the same id) and passes after (1 row).
eslint: clean (3 pre-existing, unrelatedanylint errors in the testfile, confirmed present on unmodified
release/v3.8.51too -- nottouched by this PR)
tsc --noEmit: no errors in touched files