test(qwen): pin the orphaned-record dedup key shape

The pre-extraction decoder built dedup keys with template interpolation, so
a record missing sessionId or uuid produced the literal `qwen:undefined:<uuid>`.
Phase 8.1 changed the spelling to `qwen::<uuid>` by coalescing both fields to
an empty string. The intent was right — a missing identifier should contribute
nothing rather than a fake value — but the change shipped with nothing behind
it: no test, fixture or golden pinned either spelling, and the CLI parity
golden only exercises fully-formed records, where the two are byte-identical.
Nobody could tell the change from a defect.

This makes the corrected shape a tested contract. The test pins the orphan
spellings, asserts the collapsed key still dedups identical records, and fails
against the pre-migration spelling. The decode-site comment records why, so
nobody "restores" the old one.

Two caveats worth knowing rather than discovering. Records with an explicit
null coalesce the same way as missing ones, so two previously-distinct keys
now collapse into one. And keys persisted by pre-8.1 builds for orphaned
records will not match the new spelling, so such a record can be counted once
more across the upgrade — the qwen corpus is not in the frozen golden set, so
no shipped fixture moves.
This commit is contained in:
ozymandiashh 2026-08-05 12:51:00 +03:00
parent c49fa23590
commit 70be320af9
2 changed files with 48 additions and 0 deletions

View file

@ -128,6 +128,11 @@ export function decodeQwen({ records, seenKeys: liveSeen }: QwenDecodeInput): Qw
const candidatesTokenCount = usage.candidatesTokenCount ?? 0
if (promptTokenCount === 0 && candidatesTokenCount === 0) continue
// Deliberate shape: the pre-extraction decoder interpolated the raw fields
// (`qwen:${entry.sessionId}:${entry.uuid}`), so a record missing sessionId
// produced the literal 'qwen:undefined:<uuid>'. That spelling was a
// template-string artifact, never a contract; coalescing to '' is pinned by
// qwen-decode.test.ts ("pins the dedup-key shape ... no 'undefined' spelling").
const dedupKey = `qwen:${entry.sessionId ?? ''}:${entry.uuid ?? ''}`
if (seen.has(dedupKey)) continue
seen.add(dedupKey)

View file

@ -91,6 +91,49 @@ describe('qwen rich decode (moved to @codeburn/core)', () => {
expect(again).toEqual([])
})
it('pins the dedup-key shape for records missing sessionId/uuid — no "undefined" spelling', () => {
// The pre-extraction decoder interpolated the raw fields
// (`qwen:${entry.sessionId}:${entry.uuid}`), so a record missing sessionId
// produced the literal 'qwen:undefined:<uuid>'. That spelling was a
// template-string artifact of JS coercion, NOT a contract: no test, fixture,
// or golden ever pinned it (the CLI parity golden uses fully-formed records,
// where both shapes are byte-identical), and the sibling core decoders
// (kiro, openclaw, goose) resolve missing identifiers to real fallbacks
// rather than interpolating 'undefined'. The extraction deliberately
// coalesces to '' instead: the key keeps the uuid's entropy for dedup, never
// fabricates a fake value in a key persisted to the session cache, and
// matches the shape the CLI parity golden pins for well-formed records.
// Restoring the old spelling would be a behavior change with no contract
// behind it — this test exists so nobody flips it by accident.
const noSessionId = JSON.stringify({
uuid: 'a-orphan',
timestamp: '2026-05-16T10:02:05Z',
type: 'assistant',
message: { role: 'assistant', parts: [] },
usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 5, totalTokenCount: 15 },
})
const noUuid = JSON.stringify({
sessionId: 'sess-b',
timestamp: '2026-05-16T10:02:06Z',
type: 'assistant',
message: { role: 'assistant', parts: [] },
usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 5, totalTokenCount: 15 },
})
const { calls } = decodeQwen({ records: [noSessionId, noUuid], context })
expect(calls).toHaveLength(2)
expect(calls[0]!.deduplicationKey).toBe('qwen::a-orphan')
expect(calls[0]!.sessionId).toBe('')
expect(calls[1]!.deduplicationKey).toBe('qwen:sess-b:')
expect(calls[1]!.sessionId).toBe('sess-b')
// The pinned key must round-trip through the dedup set: two records that
// share a uuid and lack a sessionId still collapse to ONE call, exactly as
// the old key did for the same input.
const dup = decodeQwen({ records: [noSessionId, noSessionId], context })
expect(dup.calls).toHaveLength(1)
})
it('toObservations produces a schema-valid, content-free envelope', () => {
const { calls } = decodeQwen({ records: RECORDS, context })
const { sessions } = toObservations(