fix(session-persistence-jsonl): reject empty zstd artifacts

A present zero-byte .jsonl.zstd file was treated as though no artifact existed because readRaw returned undefined when frame scanning found nothing. That contradicted both the plaintext path and the logical zstd reader, and it made the export endpoint answer 404 for on-disk corruption.

Treat a present artifact without a complete header frame as corruption and reuse the zstd reader's existing diagnostic. The regression test now distinguishes an existing empty file from an absent path, and the bilingual JSONL storage contract records that zero-frame artifacts reject alongside other header and frame failures.
This commit is contained in:
Tianyi Cui
2026-08-11 15:05:54 +08:00
parent e58cc13de4
commit 904c3f2c35
5 changed files with 9 additions and 9 deletions

View File

@@ -377,16 +377,16 @@ describe('SessionPersistenceJsonl: default Zstandard encoding', () => {
expect(scanned.events.map(event => event.type)).toEqual(oneTurnLog().map(event => event.type))
})
it('readRaw is undefined for a zstd artifact that carries no frame', async () => {
it('readRaw rejects a present zstd artifact that carries no frame', async () => {
const root = await freshRoot()
const ctx = await mount(root)
const header = meta('raw-zero-frame', '/work')
await ctx.sessionPersistence.create(header)
await ctx.sessionPersistence.append(header.id, oneTurnLog())
// Overwrite the physical artifact with a short buffer: frame scanning
// answers zero frames before any magic check, so readRaw reports no artifact.
// The path still exists, so zero frames is corruption rather than absence.
await writeFile(logPath(root, '/work', header.id, 'zstd'), Buffer.alloc(0))
expect(await ctx.sessionPersistence.readRaw(header.id)).toBeUndefined()
await expect(ctx.sessionPersistence.readRaw(header.id))
.rejects.toThrow('empty or header-less Zstandard session log')
})
it('resolves the default when a programmatic wrapper bypasses Loader schema normalization', async () => {