Skip to content

fix(usage): pair in-memory call-log copies with persisted rows after #13481 - #18

Merged
claw-io merged 1 commit into
mainfrom
fix/call-log-inmemory-dedupe
Oct 5, 2026
Merged

claw-io merged 1 commit into
mainfrom
fix/call-log-inmemory-dedupe

Conversation

@claw-io

@claw-io claw-io commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

Problem

After #17 (importing upstream #13481), the request log shows a phantom · 2 attempts badge and a duplicate child row on every request, and a genuine 2-attempt retry reads 4 attempts.

Root cause

#13481 made persisted call_logs rows use the chatCore traceId as their id (per-attempt rows) instead of the pending-request id. But /api/usage/call-logs still deduped the finalized in-memory detail against persisted rows by id alone. The two id spaces are disjoint — ${now}-${uuid6} vs a 6-char trace id — so an in-memory copy could never match its own persisted row. Every request was rendered twice.

The same split made the detail modal lose its in-memory request/response payloads for persisted rows.

Fix

  • Carry the chatCore traceId onto the pending detail as callLogId, so the in-memory copy shares the persisted row's id space.
  • Match in-memory copies on callLogId, with a correlation-key fallback (correlationId + model + provider). connectionId is deliberately excluded: the in-memory copy keeps the starting account while the persisted row keeps the post-rotation one.
  • Only in-memory copies are ever skipped, so persisted rows sharing a correlationId — real retries — all survive.
  • /api/logs/[id] resolves a persisted row back to its in-memory detail by the same key.

The persisted write (id: traceId) is unchanged.

Verification

  • New unit suite tests/unit/call-logs-inmemory-dedupe.test.ts — 9/9 pass, covering: same-correlation drop with differing ids, connectionId rotation in the fallback, callLogId-carrying copy, real retries (both persisted rows kept), not-yet-persisted retry, null-correlation rows, in-flight rows, and the trackPendingRequest/findCompletedDetailForCallLog helpers.

  • npm run typecheck:core — exit 0.

  • Live A/B against the same endpoint and window (phantom group = >1 row sharing a correlationId with disjoint ids):

    Environment Rows sampled Phantom groups
    Before the fix 436 34
    After the fix 300 0
  • Post-fix detail modal still returns live requestBody/responseBody; retry semantics unchanged.

Notes

Reported and fixed downstream of #17; affects any tree carrying #13481.

…#13481

PR #17 (upstream #13481) keyed persisted call_logs rows on the chatCore
traceId instead of the pending-request id, but the list endpoint still
deduped the finalized in-memory detail against persisted rows by id only.
The two id spaces are disjoint (`${now}-${uuid6}` vs a 6-char trace id), so
every request emitted a duplicate row sharing its correlationId: the log UI
showed a bogus "· 2 attempts" badge, and a genuine 2-attempt retry showed
"4 attempts". The same split made the detail modal lose the in-memory
request/response payloads for persisted rows when detailed logging is off.

Carry the chatCore traceId onto the pending detail as `callLogId` so the
in-memory copy shares the persisted row's id space, and match in-memory
copies on `callLogId` with a correlation-key fallback
(correlationId + model + provider, deliberately excluding connectionId
because the in-memory copy keeps the starting account while the persisted
row keeps the post-rotation one). Only in-memory copies are ever skipped, so
persisted rows sharing a correlationId — real retries — all survive.

The persisted write (`id: traceId`) is unchanged.
@claw-io
claw-io force-pushed the fix/call-log-inmemory-dedupe branch from 836c973 to 956787f Compare October 4, 2026 21:58
@claw-io
claw-io merged commit 74f1ed4 into main Oct 5, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants