mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-14 04:01:35 +00:00
fix(scripts): validate historical fixture layout with source codecs
This commit is contained in:
@@ -106,6 +106,36 @@ describe('canonicalSessionFixture', () => {
|
||||
expect(canonicalSessionFixture(projected)).toBe(projected)
|
||||
})
|
||||
|
||||
it.each([0, 1, 2])('preserves physically valid v%i bytes without requiring migration to current', (version) => {
|
||||
const header = { type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version === 2 ? { isSeeded: false } : {}) }
|
||||
const content = [
|
||||
JSON.stringify(header),
|
||||
JSON.stringify({ type: 'user/message', data: { role: 'user', id: 'historical-user', source: { kind: 'user' }, content: [] }, surfaceOp: 'append' }),
|
||||
'',
|
||||
].join('\n')
|
||||
expect(canonicalSessionFixture(content)).toBe(content)
|
||||
})
|
||||
|
||||
it.each([0, 1, 2])('rejects v%i sequence gaps and invalid provenance ranges with source line diagnostics', (version) => {
|
||||
const header = JSON.stringify({ type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version === 2 ? { isSeeded: false } : {}) })
|
||||
expect(() => canonicalSessionFixture(`${header}\n{"type":"feedback/record","seq":3,"data":{"text":"gap"}}\n`, 'gap.jsonl'))
|
||||
.toThrow(/gap\.jsonl: session snapshot line 2:.*seq/)
|
||||
expect(() => canonicalSessionFixture(`${header}\n{"type":"feedback/record","data":{},"sourceEventSeqs":[[2,0]]}\n`, 'range.jsonl'))
|
||||
.toThrow(/range\.jsonl: session snapshot line 2:/)
|
||||
})
|
||||
|
||||
it.each([0, 1, 2])('finalizes the v%i source inherited cut', (version) => {
|
||||
const header = { type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version === 2 ? { isSeeded: true } : { seedLength: 1 }) }
|
||||
expect(() => canonicalSessionFixture(`${JSON.stringify(header)}\n`, 'cut.jsonl'))
|
||||
.toThrow(/cut\.jsonl: session snapshot line 1:.*(?:inherited|seed)/)
|
||||
})
|
||||
|
||||
it('refuses unsupported generation headers', () => {
|
||||
const header = { type: 'session', version: 99, id: 'future', createdAt: 1, isSeeded: false, delegationDepth: 0 }
|
||||
expect(() => canonicalSessionFixture(`${JSON.stringify(header)}\n`, 'future.jsonl'))
|
||||
.toThrow(/future\.jsonl: session snapshot line 1:.*99/)
|
||||
})
|
||||
|
||||
it('fails loud on malformed records after a session header', () => {
|
||||
expect(() => canonicalSessionFixture(`${HEADER}\n{not-json}\n`, 'broken.jsonl'))
|
||||
.toThrow(/broken\.jsonl: session snapshot line 2 contains invalid JSON/)
|
||||
|
||||
@@ -11,6 +11,13 @@ import {
|
||||
} from '@deepseek-ai/dsh-session'
|
||||
import type { SessionLogOffset as SessionLogOffsetType } from '@deepseek-ai/dsh-session'
|
||||
import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog'
|
||||
import { SessionFormatEventCollector, type SessionFormatArtifactDecoder, type SessionFormatCodec } from '@deepseek-ai/dsh-session-format'
|
||||
import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v0-to-v1'
|
||||
import { releasedV2SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v1-to-v2'
|
||||
|
||||
const historicalCodecs: readonly SessionFormatCodec[] = [
|
||||
releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, releasedV2SessionFormatCodec,
|
||||
]
|
||||
|
||||
/** Physical persistence artifacts validated by the WebWorker runtime fixture spec. */
|
||||
const WEBWORKER_PHYSICAL_SESSION_FIXTURE_ROOT =
|
||||
@@ -58,51 +65,6 @@ function validationHeader(value: unknown): unknown {
|
||||
return header
|
||||
}
|
||||
|
||||
function validationRow(source: Readonly<Record<string, unknown>>): Record<string, unknown> {
|
||||
if (source.type !== 'request/header') return { ...source }
|
||||
const data = source.data
|
||||
if (data === null || typeof data !== 'object' || Array.isArray(data)) return { ...source }
|
||||
const header = (data as Record<string, unknown>).header
|
||||
if (header === null || typeof header !== 'object' || Array.isArray(header)) return { ...source }
|
||||
if ((header as Record<string, unknown>).tools !== '{{tools}}') return { ...source }
|
||||
return {
|
||||
...source,
|
||||
data: {
|
||||
...data,
|
||||
header: { ...header, tools: [] },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function restoreRequestHeaderTokens(
|
||||
events: readonly SessionEvent[],
|
||||
rows: readonly Readonly<Record<string, unknown>>[],
|
||||
): SessionEvent[] {
|
||||
const sources = rows.filter(row => row.type === 'request/header')
|
||||
let sourceIndex = 0
|
||||
return events.map((event) => {
|
||||
if (event.type !== 'request/header') return event
|
||||
const source = sources[sourceIndex]
|
||||
sourceIndex += 1
|
||||
const sourceData = source?.data
|
||||
const sourceHeader = sourceData !== null && typeof sourceData === 'object' && !Array.isArray(sourceData)
|
||||
? (sourceData as Record<string, unknown>).header
|
||||
: undefined
|
||||
if (sourceHeader === null || typeof sourceHeader !== 'object' || Array.isArray(sourceHeader)
|
||||
|| (sourceHeader as Record<string, unknown>).tools !== '{{tools}}') return event
|
||||
return {
|
||||
...event,
|
||||
data: {
|
||||
...event.data,
|
||||
header: {
|
||||
...(event.data as unknown as { header: Record<string, unknown> }).header,
|
||||
tools: '{{tools}}',
|
||||
},
|
||||
},
|
||||
} as SessionEvent
|
||||
})
|
||||
}
|
||||
|
||||
function renderFixture(headerLine: string, events: readonly SessionEvent[]): string {
|
||||
return [
|
||||
headerLine,
|
||||
@@ -191,29 +153,28 @@ function parseFixtureRows(content: string, headerValue: unknown): SessionEvent[]
|
||||
}
|
||||
})
|
||||
}
|
||||
let restore: ReturnType<typeof sessionFormatCatalog.createRestore>
|
||||
const collector = new SessionFormatEventCollector()
|
||||
let decoder: SessionFormatArtifactDecoder
|
||||
try {
|
||||
restore = sessionFormatCatalog.createRestore(validationHeader(headerValue), {
|
||||
recovery: 'strict',
|
||||
validation: 'current',
|
||||
})
|
||||
const version = (headerValue as Record<string, unknown>).version
|
||||
const codec = historicalCodecs.find(candidate => candidate.version === version)
|
||||
if (codec === undefined) throw new Error(`unsupported session fixture version ${String(version)}`)
|
||||
decoder = codec.createDecoder(validationHeader(headerValue), 'strict')
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error)
|
||||
throw new Error(`session snapshot line 1: ${detail}`, { cause: error })
|
||||
}
|
||||
for (const [index, row] of rows.entries()) {
|
||||
try {
|
||||
restore.decodeRow(validationRow(row))
|
||||
decoder.decodeRow(row, collector)
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error)
|
||||
throw new Error(`session snapshot line ${rowLines[index] ?? 1}: ${detail}`, { cause: error })
|
||||
}
|
||||
}
|
||||
try {
|
||||
return restoreRequestHeaderTokens(
|
||||
[...restore.finish().events] as unknown as SessionEvent[],
|
||||
rows,
|
||||
)
|
||||
decoder.finish(collector)
|
||||
return [...collector.values] as unknown as SessionEvent[]
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error)
|
||||
const line = fixtureDiagnosticLine(error, rowLines, eventLines)
|
||||
@@ -246,8 +207,9 @@ function withoutEnvelope(events: readonly SessionEvent[]): Array<Omit<SessionEve
|
||||
|
||||
/**
|
||||
* Canonicalize one JSONL document when its first record is a session header.
|
||||
* The header line remains byte-identical; body records decode to logical events,
|
||||
* re-encode one event per row, and omit storage sequence/time envelopes.
|
||||
* Historical generations receive strict source-codec validation and remain byte-identical;
|
||||
* conversion to the current format is not required. Current body records re-encode
|
||||
* one event per row and omit storage sequence/time envelopes; their header is preserved.
|
||||
* Non-session JSONL returns undefined.
|
||||
*
|
||||
* @param content - JSONL source text.
|
||||
|
||||
Reference in New Issue
Block a user