Files
deepseek-harness/scripts/gen-cordis-catalog-record.spec.ts
T
Tianyi Cui f7323354bb docs: generate each subsystem's cordis surface into its own page; delete the flat catalogs
Rebuild of the region machinery (PR3) on the post-#904 Typert projection:
renderPageRegion/renderInheritedPage live in dsh-typert-generator beside the
projection; scripts/gen-cordis-catalog.ts owns the curated SERVICE_PAGE /
EVENT_SCOPE_PAGE / SERVICE_WALK_EXEMPTIONS / LINK_MAP partition (fail-loud in
both directions, with the independent Context-merge scan backstopping the
projection's blind spot), spliceRegion, and the guarded pair auto-record.
docs/cordis-catalog/ is deleted: the flat events/services catalogs dissolve
into per-page regions and docs/cordis-catalog/core moves to docs/cordis-api/
with the inherited tier as its own generated page. The partition absorbs the
post-regrouping surface: ctx.typert → invariants.md, ctx.directoryPicker →
workspace.md, skills/* events → skills.md, and the four launcher-provided tui
accessor values join the named exemptions.
2026-08-09 01:31:57 +08:00

145 lines
6.5 KiB
TypeScript

/**
* Negative-path coverage for the guarded pair auto-record
* (`maybeRecordPair`): the safety property is that regeneration re-records a
* pair's `.i18n.yaml` ONLY for a region-confined write over a well-formed,
* previously-consistent record — every other state is left for the pairing
* gate to report.
*/
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { maybeRecordPair, REGION_BEGIN, REGION_END, spliceRegion } from './gen-cordis-catalog.ts'
import { blobHash, renderPairMeta } from './translation-pairing.ts'
const PAGE = 'docs/subsystems/fix.md'
const ZH = 'docs/subsystems/fix.zh.md'
const META = 'docs/subsystems/fix.i18n.yaml'
function page(prose: string, region: string): string {
return `# Fix\n\n${prose}\n\n${REGION_BEGIN}\n${region}\n${REGION_END}\n`
}
const roots: string[] = []
afterEach(() => {
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
})
/** Lay out a pair on disk and return { root, before } for a regeneration that already wrote `current`. */
function setup(options: {
beforeEn: string
beforeZh: string
currentEn: string
currentZh: string
meta?: string | null
omitZhSnapshot?: boolean
}): { root: string; before: Map<string, Buffer> } {
const root = mkdtempSync(join(tmpdir(), 'record-guard-'))
roots.push(root)
mkdirSync(join(root, 'docs/subsystems'), { recursive: true })
writeFileSync(join(root, PAGE), options.currentEn)
writeFileSync(join(root, ZH), options.currentZh)
const meta = options.meta === undefined
? renderPairMeta(PAGE, blobHash(Buffer.from(options.beforeEn)), ZH, blobHash(Buffer.from(options.beforeZh)))
: options.meta
if (meta !== null) writeFileSync(join(root, META), meta)
const before = new Map<string, Buffer>([[PAGE, Buffer.from(options.beforeEn)]])
if (!options.omitZhSnapshot) before.set(ZH, Buffer.from(options.beforeZh))
return { root, before }
}
describe('maybeRecordPair', () => {
const beforeEn = page('prose.', 'old region')
const beforeZh = page('散文。', 'old region')
const currentEn = page('prose.', 'new region')
const currentZh = page('散文。', 'new region')
it('re-records a region-confined write over a consistent record', () => {
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh })
expect(maybeRecordPair(PAGE, before, root)).toBe(true)
expect(readFileSync(join(root, META), 'utf8'))
.toBe(renderPairMeta(PAGE, blobHash(Buffer.from(currentEn)), ZH, blobHash(Buffer.from(currentZh))))
})
it('refuses when the pair was already out of sync before the run', () => {
const stale = renderPairMeta(PAGE, blobHash(Buffer.from('drifted long ago\n')), ZH, blobHash(Buffer.from(beforeZh)))
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh, meta: stale })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
expect(readFileSync(join(root, META), 'utf8')).toBe(stale)
})
it('refuses a malformed record even when its hashes are current', () => {
// A renamed key with preserved hashes must stay the pairing gate's error,
// never become valid through regeneration.
const renamedKeys = [
'# comment',
`fixXmd: ${blobHash(Buffer.from(beforeEn))}`,
`fix.zh.md: ${blobHash(Buffer.from(beforeZh))}`,
'',
].join('\n')
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh, meta: renamedKeys })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
expect(readFileSync(join(root, META), 'utf8')).toBe(renamedKeys)
})
it('refuses a record with extra entries', () => {
const extra = renderPairMeta(PAGE, blobHash(Buffer.from(beforeEn)), ZH, blobHash(Buffer.from(beforeZh)))
+ `other.md: ${blobHash(Buffer.from(beforeEn))}\n`
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh, meta: extra })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
})
it('refuses a record with a duplicated expected key', () => {
// Map#set would collapse the duplicate back to size 2; the parser must
// reject the repeat instead of letting the guard accept the record.
const duplicated = [
`fix.md: ${blobHash(Buffer.from(beforeEn))}`,
`fix.md: ${blobHash(Buffer.from(beforeEn))}`,
`fix.zh.md: ${blobHash(Buffer.from(beforeZh))}`,
'',
].join('\n')
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh, meta: duplicated })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
expect(readFileSync(join(root, META), 'utf8')).toBe(duplicated)
})
it('refuses when prose drifted alongside the region write', () => {
const proseDrift = page('prose, edited by a human.', 'new region')
const { root, before } = setup({ beforeEn, beforeZh, currentEn: proseDrift, currentZh })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
})
it('refuses a brand-new pair with no record', () => {
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh, meta: null })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
})
it('refuses when a side has no pre-write snapshot', () => {
const { root, before } = setup({ beforeEn, beforeZh, currentEn, currentZh, omitZhSnapshot: true })
expect(maybeRecordPair(PAGE, before, root)).toBe(false)
})
})
describe('spliceRegion', () => {
it('replaces exactly the cordis-surface region', () => {
const doc = `# T\n\nprose\n\n${REGION_BEGIN}\nold\n${REGION_END}\ntail\n`
expect(spliceRegion(doc, `${REGION_BEGIN}\nnew\n${REGION_END}`))
.toBe(`# T\n\nprose\n\n${REGION_BEGIN}\nnew\n${REGION_END}\ntail\n`)
})
it('fails loud on a page carrying only some other generator\'s region', () => {
// Another generator's markers satisfy the generic region grammar but must
// never be overwritten by THIS generator's splice.
const foreign = '# T\n\n<!-- BEGIN GENERATED other-surface (other-gen.ts) — do not edit between markers -->\ntheirs\n<!-- END GENERATED other-surface -->\n'
expect(() => spliceRegion(foreign, `${REGION_BEGIN}\nnew\n${REGION_END}`))
.toThrow('expected exactly 1 cordis-surface region, found 0 BEGIN/0 END')
})
it('fails loud on duplicate cordis-surface markers', () => {
const doubled = `${REGION_BEGIN}\na\n${REGION_END}\n${REGION_BEGIN}\nb\n${REGION_END}\n`
expect(() => spliceRegion(doubled, `${REGION_BEGIN}\nnew\n${REGION_END}`))
.toThrow('found 2 BEGIN/2 END')
})
})