Add assertNever with closed-vs-extensible exhaustiveness guidance

assertNever (dsh-llm) marks unreachable defaults on CLOSED unions:
adding a StreamChunk variant now breaks compilation at
BlockAssembler.push, and a value escaping its type at runtime throws
with diagnostics. The module doc and a new AGENTS.md convention spell
out the dividing line: merge-extensible unions (SessionEventMap,
ContentBlockMap, …) must NOT use assertNever — plugin-added variants
are valid unknown values there; handle known cases and fall through
with a comment.
This commit is contained in:
Tianyi Cui
2026-06-11 15:21:25 +08:00
parent 225ed051b1
commit 370b5d3aab
5 changed files with 60 additions and 0 deletions

View File

@@ -151,3 +151,18 @@ describe('BlockAssembler', () => {
expect('usage' in result).toBe(true)
})
})
describe('assertNever', () => {
it('throws with diagnostics when a value escapes a closed union at runtime', async () => {
const { assertNever } = await import('@deepseek-ai/dsh-llm')
expect(() => assertNever({ type: 'rogue' } as never, 'test-context'))
.toThrow('unreachable variant in test-context: {"type":"rogue"}')
expect(() => assertNever(undefined as never)).toThrow('unreachable variant: undefined')
})
it('BlockAssembler.push rejects chunks outside the closed StreamChunk union', () => {
const assembler = new BlockAssembler()
expect(() => assembler.push({ type: 'rogue-chunk' } as unknown as StreamChunk))
.toThrow('unreachable variant in BlockAssembler.push')
})
})