mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Merge branch 'worktree/ci-native-windows-20260808' into worktree/ci-native-windows-coverage-20260808
This commit is contained in:
@@ -299,22 +299,55 @@ describe('docsPages locale routes', () => {
|
||||
})
|
||||
|
||||
it('publishes the Cordis core API under matching locale structures', () => {
|
||||
const files = ['context.md', 'events.md', 'fiber.md', 'registry.md', 'service.md', 'inherited.md']
|
||||
const files = ['context.md', 'events.md', 'fiber.md', 'registry.md', 'service.md']
|
||||
for (const file of files) {
|
||||
const root = docsPages.find(page => page.route === `reference/cordis-api/${file}`)
|
||||
const english = docsPages.find(page => page.route === `en/reference/cordis-api/${file}`)
|
||||
expect(root?.source).toBe(`docs/cordis-api/${file}`)
|
||||
expect(root?.source).toBe(`docs/cordis-api/${file.replace(/\.md$/, '.zh.md')}`)
|
||||
expect(root?.contentLocale).toBe('zh-CN')
|
||||
expect(root?.section).toBe('Cordis API')
|
||||
expect(english?.source).toBe(root?.source)
|
||||
expect(english?.source).toBe(`docs/cordis-api/${file}`)
|
||||
expect(english?.contentLocale).toBe('en-US')
|
||||
expect(english?.section).toBe('Cordis Core API')
|
||||
}
|
||||
})
|
||||
|
||||
it('includes persistence event headings in both locale outlines', () => {
|
||||
const pages = docsPages.filter(page => page.source === 'docs/persistence-catalog.md')
|
||||
it('keeps Cordis inherited on the English fallback in both locales', () => {
|
||||
const pages = docsPages.filter(page => page.route.endsWith('reference/cordis-api/inherited.md'))
|
||||
expect(pages).toHaveLength(2)
|
||||
expect(pages.every(page => page.source === 'docs/cordis-api/inherited.md')).toBe(true)
|
||||
expect(pages.every(page => page.contentLocale === 'en-US')).toBe(true)
|
||||
})
|
||||
|
||||
it('includes persistence event headings in both locale outlines', () => {
|
||||
const pages = docsPages.filter(page => page.route.endsWith('reference/persistence-catalog.md'))
|
||||
expect(pages).toHaveLength(2)
|
||||
expect(pages.map(page => page.source).sort()).toEqual([
|
||||
'docs/persistence-catalog.md',
|
||||
'docs/persistence-catalog.zh.md',
|
||||
])
|
||||
expect(pages.map(page => page.outline)).toEqual(['deep', 'deep'])
|
||||
})
|
||||
|
||||
it('projects reviewed generated counterparts into root locale routes', () => {
|
||||
// module-graph, event-producer-consumer, and graph-atlas are paired but intentionally unpublished.
|
||||
const routes = [
|
||||
'reference/capability-seams.md',
|
||||
'reference/agent-lifecycle.md',
|
||||
'reference/tool-execution-pipeline.md',
|
||||
'reference/config-catalog.md',
|
||||
'reference/tool-catalog.md',
|
||||
'reference/persistence-catalog.md',
|
||||
'reference/cordis-api/context.md',
|
||||
'reference/cordis-api/events.md',
|
||||
'reference/cordis-api/fiber.md',
|
||||
'reference/cordis-api/registry.md',
|
||||
'reference/cordis-api/service.md',
|
||||
]
|
||||
const pages = routes.map(route => docsPages.find(page => page.route === route))
|
||||
expect(pages.every(page => page?.contentLocale === 'zh-CN')).toBe(true)
|
||||
expect(pages.every(page => page?.source.endsWith('.zh.md'))).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addProjectionFrontmatter', () => {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -119,6 +119,12 @@ const otherSource = baseSource.replace('Beta base.', 'Beta other.')
|
||||
const otherZh = baseZh.replace('乙基础。', '乙对侧。')
|
||||
const mergedSource = currentSource.replace('Beta base.', 'Beta other.')
|
||||
const mergedZh = currentZh.replace('乙基础。', '乙对侧。')
|
||||
const generatedBaseSource = '# Module graph\n\nAlpha base.\n\nBeta base.\n'
|
||||
const generatedBaseZh = '# 模块图\n\n[English](module-graph.md) | 中文\n\n甲基础。\n\n乙基础。\n'
|
||||
const generatedCurrentSource = generatedBaseSource.replace('Alpha base.', 'Alpha current.')
|
||||
const generatedCurrentZh = generatedBaseZh.replace('甲基础。', '甲当前。')
|
||||
const generatedOtherSource = generatedBaseSource.replace('Beta base.', 'Beta other.')
|
||||
const generatedOtherZh = generatedBaseZh.replace('乙基础。', '乙对侧。')
|
||||
const manualBaseSource = baseSource.replace('guide.zh.md', 'manual.zh.md')
|
||||
const manualBaseZh = baseZh.replace('guide.md', 'manual.md')
|
||||
const manualCurrentSource = manualBaseSource.replace('Alpha base.', 'Alpha current.')
|
||||
@@ -257,6 +263,60 @@ describe('translation pairing merge composition', { timeout: 15_000 }, () => {
|
||||
expect(result.zhHash).toBe(gitBlobHash(Buffer.from(mergedZh)))
|
||||
})
|
||||
|
||||
it('merges a generated source without an English language switcher', () => {
|
||||
const fixture = createFixture(false)
|
||||
const ancestor = record(fixture.root, 'docs/module-graph.md', generatedBaseSource, generatedBaseZh)
|
||||
const current = record(fixture.root, 'docs/module-graph.md', generatedCurrentSource, generatedCurrentZh)
|
||||
const other = record(fixture.root, 'docs/module-graph.md', generatedOtherSource, generatedOtherZh)
|
||||
|
||||
const result = mergeTranslationPairingRecords(
|
||||
fixture.root,
|
||||
'docs/module-graph.i18n.yaml',
|
||||
ancestor,
|
||||
current,
|
||||
other,
|
||||
)
|
||||
|
||||
expect(result.sourceContent.toString('utf8')).toBe(
|
||||
generatedCurrentSource.replace('Beta base.', 'Beta other.'),
|
||||
)
|
||||
expect(result.zhContent.toString('utf8')).toBe(generatedCurrentZh.replace('乙基础。', '乙对侧。'))
|
||||
})
|
||||
|
||||
it('rejects an authored source without an English language switcher', () => {
|
||||
const fixture = createFixture(false)
|
||||
const source = baseSource.replace('English | [中文](guide.zh.md)\n\n', '')
|
||||
const ancestor = record(fixture.root, 'docs/guide.md', source, baseZh)
|
||||
const current = record(fixture.root, 'docs/guide.md', source, baseZh)
|
||||
const other = record(fixture.root, 'docs/guide.md', source, baseZh)
|
||||
|
||||
expect(() => mergeTranslationPairingRecords(
|
||||
fixture.root,
|
||||
'docs/guide.i18n.yaml',
|
||||
ancestor,
|
||||
current,
|
||||
other,
|
||||
)).toThrow('docs/guide.md clean merge lost its language-switcher link to guide.zh.md')
|
||||
})
|
||||
|
||||
it('rejects generated Chinese content without its English backlink', () => {
|
||||
const fixture = createFixture(false)
|
||||
const zh = generatedBaseZh.replace('[English](module-graph.md) | 中文\n\n', '')
|
||||
const ancestor = record(fixture.root, 'docs/module-graph.md', generatedBaseSource, zh)
|
||||
const current = record(fixture.root, 'docs/module-graph.md', generatedBaseSource, zh)
|
||||
const other = record(fixture.root, 'docs/module-graph.md', generatedBaseSource, zh)
|
||||
|
||||
expect(() => mergeTranslationPairingRecords(
|
||||
fixture.root,
|
||||
'docs/module-graph.i18n.yaml',
|
||||
ancestor,
|
||||
current,
|
||||
other,
|
||||
)).toThrow(
|
||||
'docs/module-graph.zh.md clean merge lost its language-switcher link to module-graph.md',
|
||||
)
|
||||
})
|
||||
|
||||
it('leaves owner-content conflicts for a human', () => {
|
||||
const fixture = createFixture(false)
|
||||
const ancestor = record(fixture.root, 'docs/guide.md', baseSource, baseZh)
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
linksTo,
|
||||
isTranslationScopeFile,
|
||||
parseTranslationMarkdown,
|
||||
requiresSourceLanguageSwitcher,
|
||||
translationStructureDiff,
|
||||
translationStructureSignature,
|
||||
} from './translation-pairing.ts'
|
||||
@@ -163,7 +164,7 @@ function loadRecordOwners(
|
||||
function assertMergedPairStructure(paths: TranslationPairPaths, source: Buffer, zh: Buffer): void {
|
||||
const sourceTree = parseTranslationMarkdown(source.toString('utf8'))
|
||||
const zhTree = parseTranslationMarkdown(zh.toString('utf8'))
|
||||
if (!linksTo(sourceTree, basename(paths.zh))) {
|
||||
if (requiresSourceLanguageSwitcher(paths.source) && !linksTo(sourceTree, basename(paths.zh))) {
|
||||
throw new Error(`${paths.source} clean merge lost its language-switcher link to ${basename(paths.zh)}`)
|
||||
}
|
||||
if (!linksTo(zhTree, basename(paths.source))) {
|
||||
|
||||
@@ -4,18 +4,9 @@
|
||||
".agents/notes/implemented/AGENTS.md",
|
||||
".agents/notes/implemented/CLAUDE.md",
|
||||
"docs/AGENTS.md",
|
||||
"docs/agent-lifecycle.md",
|
||||
"docs/capability-seams.md",
|
||||
"docs/config-catalog.md",
|
||||
"docs/cordis-api/",
|
||||
"docs/event-producer-consumer.md",
|
||||
"docs/graph-atlas.md",
|
||||
"docs/cordis-api/inherited.md",
|
||||
"docs/i18n/style-samples.md",
|
||||
"docs/i18n/terminology.md",
|
||||
"docs/i18n/translation-prompt.md",
|
||||
"docs/module-graph.md",
|
||||
"docs/persistence-catalog.md",
|
||||
"docs/tool-catalog.md",
|
||||
"docs/tool-execution-pipeline.md"
|
||||
"docs/i18n/translation-prompt.md"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
parseTranslationPairingCliArgs,
|
||||
parseTranslationPairingManifest,
|
||||
partitionGeneratedRegions,
|
||||
requiresSourceLanguageSwitcher,
|
||||
translationStructureDiff,
|
||||
translationStructureSignature,
|
||||
} from './translation-pairing.ts'
|
||||
@@ -142,6 +143,16 @@ describe('translation pairing manifest', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('translation pairing switchers', () => {
|
||||
it('exempts only paired generated English sources from reciprocal switchers', () => {
|
||||
expect(requiresSourceLanguageSwitcher('docs/config-catalog.md')).toBe(false)
|
||||
expect(requiresSourceLanguageSwitcher('docs/cordis-api/context.md')).toBe(false)
|
||||
expect(requiresSourceLanguageSwitcher('docs/cordis-api/inherited.md')).toBe(false)
|
||||
expect(requiresSourceLanguageSwitcher('docs/architecture.md')).toBe(true)
|
||||
expect(requiresSourceLanguageSwitcher('packages/core/session/README.md')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('translation pairing records', () => {
|
||||
const paths = translationPairPaths('docs/foo.md')
|
||||
const record = {
|
||||
|
||||
@@ -311,6 +311,28 @@ export function linksTo(tree: Nodes, target: string): boolean {
|
||||
return found
|
||||
}
|
||||
|
||||
/** Generated English sources cannot carry a switcher without making their generator stale. */
|
||||
export function requiresSourceLanguageSwitcher(source: string): boolean {
|
||||
return ![
|
||||
'docs/agent-lifecycle.md',
|
||||
'docs/capability-seams.md',
|
||||
'docs/config-catalog.md',
|
||||
'docs/cordis-api/context.md',
|
||||
'docs/cordis-api/events.md',
|
||||
'docs/cordis-api/fiber.md',
|
||||
// Excluded from pairing, but kept here for generated-category completeness and direct spec coverage.
|
||||
'docs/cordis-api/inherited.md',
|
||||
'docs/cordis-api/registry.md',
|
||||
'docs/cordis-api/service.md',
|
||||
'docs/event-producer-consumer.md',
|
||||
'docs/graph-atlas.md',
|
||||
'docs/module-graph.md',
|
||||
'docs/persistence-catalog.md',
|
||||
'docs/tool-catalog.md',
|
||||
'docs/tool-execution-pipeline.md',
|
||||
].includes(source)
|
||||
}
|
||||
|
||||
/** Collect the ordered structural signature, skipping one switcher target. */
|
||||
export function translationStructureSignature(tree: Nodes, switcherTarget: string): TranslationStructureSignature {
|
||||
const sig: TranslationStructureSignature = { headings: [], code: [], tables: [], lists: [], links: [] }
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
parseTranslationPairingCliArgs,
|
||||
parseTranslationPairingManifest,
|
||||
partitionGeneratedRegions,
|
||||
requiresSourceLanguageSwitcher,
|
||||
isTranslationScopeFile,
|
||||
TRANSLATION_SCOPE_GLOB_EXCLUDES,
|
||||
translationStructureDiff,
|
||||
@@ -254,7 +255,7 @@ for (const source of [...pairAnchors].sort()) {
|
||||
if (!linksTo(zhTree, basename(source))) {
|
||||
errors.push(`${zh}: missing language switcher — no link to ${basename(source)}`)
|
||||
}
|
||||
if (!linksTo(sourceTree, basename(zh))) {
|
||||
if (requiresSourceLanguageSwitcher(source) && !linksTo(sourceTree, basename(zh))) {
|
||||
errors.push(`${source}: missing language switcher — no link back to ${basename(zh)}`)
|
||||
}
|
||||
for (const divergence of translationStructureDiff(
|
||||
|
||||
Reference in New Issue
Block a user