Explorar o código

fix(ci): stabilize native Windows coverage

imccyu hai 3 semanas
pai
achega
5ba9e50bb0

+ 2 - 2
.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md
-2026-08-08-native-windows-pull-request-ci.md: 113193bcc05dae132b045382bea822b4296b9ff0
-2026-08-08-native-windows-pull-request-ci.zh.md: b038f11da5cbf7d5278b8600c9691879c93a5231
+2026-08-08-native-windows-pull-request-ci.md: 7bcdfa7a3e560f247b3041ddf6dd214031c540fc
+2026-08-08-native-windows-pull-request-ci.zh.md: 12c853364cbfb191e3bf7c06734559dcdd498ab3

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md


+ 2 - 2
.agents/notes/implemented/process/2026-08-18-in-job-partitioned-coverage.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-18-in-job-partitioned-coverage.md
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-18-in-job-partitioned-coverage.md
-2026-08-18-in-job-partitioned-coverage.md: 5cbec688a9967bcb23a2277e11a119c7d278d7ee
-2026-08-18-in-job-partitioned-coverage.zh.md: b5d7db566b3883f26ec5528084a05a97b6e97b6a
+2026-08-18-in-job-partitioned-coverage.md: d6b8f98095ebb77c6caf88ce67999e683c71f74c
+2026-08-18-in-job-partitioned-coverage.zh.md: 36a49b91b2544c611bf77350bda66b06a2708ba6

+ 1 - 1
.agents/notes/implemented/process/2026-08-18-in-job-partitioned-coverage.md

@@ -18,7 +18,7 @@ When partitioning is enabled, `scripts/run-gates.ts` selects `pnpm run test:cove
 
 
 The coordinator waits for every child, validates that the blob directory contains exactly the expected files, and then runs one `vitest --merge-reports ... --coverage` command. Only that merged command applies the repository's per-file statement, branch, function, and line thresholds, so a partition is never judged against an intentionally partial inventory.
 The coordinator waits for every child, validates that the blob directory contains exactly the expected files, and then runs one `vitest --merge-reports ... --coverage` command. Only that merged command applies the repository's per-file statement, branch, function, and line thresholds, so a partition is never judged against an intentionally partial inventory.
 
 
-`DSH_COVERAGE_MAX_WORKERS` continues to size the uninstrumented exempt gate and the ordinary non-partitioned path; it does not resize partition children. Native Windows gives the exempt gate two workers and admits four concurrent outer gates: build, production-site validation, instrumented coverage, and exempt-heavy coverage start first, then the observational inventory enters as slots become available. Linux overlaps four instrumented partition processes with two exempt workers, restoring the ordinary path's former four-way instrumented concurrency while keeping every instrumented process single-worker.
+`DSH_COVERAGE_MAX_WORKERS` continues to size the uninstrumented exempt gate and the ordinary non-partitioned path; it does not resize partition children. Native Windows gives the exempt gate two workers and admits four concurrent outer gates: build, production-site validation, instrumented coverage, and exempt-heavy coverage start first, and the observational inventory waits for both coverage gates before entering the available slots. Linux overlaps four instrumented partition processes with two exempt workers, restoring the ordinary path's former four-way instrumented concurrency while keeping every instrumented process single-worker.
 
 
 ## Failure and output semantics
 ## Failure and output semantics
 
 

+ 1 - 1
.agents/notes/implemented/process/2026-08-18-in-job-partitioned-coverage.zh.md

@@ -18,7 +18,7 @@ Status: implemented
 
 
 协调器等待全部子进程结束,验证 blob 目录只包含预期文件,然后执行一次 `vitest --merge-reports ... --coverage`。只有这条合并命令应用仓库的逐文件语句、分支、函数与行阈值,因此系统不会拿有意不完整的测试清单单独判定任一分区。
 协调器等待全部子进程结束,验证 blob 目录只包含预期文件,然后执行一次 `vitest --merge-reports ... --coverage`。只有这条合并命令应用仓库的逐文件语句、分支、函数与行阈值,因此系统不会拿有意不完整的测试清单单独判定任一分区。
 
 
-`DSH_COVERAGE_MAX_WORKERS` 继续控制无插桩豁免门禁和普通非分区路径的规模,不会调整分区子进程。原生 Windows 为豁免门禁分配 2 个 worker,并允许 4 道外层门禁并发:构建、生产网站验证、插桩覆盖率与豁免重型覆盖率先启动,观测性清单随后在槽位释放时进入调度。Linux 让 4 个插桩分区进程与 2 个豁免 worker 重叠运行,在保持每个插桩进程只有 1 个 worker 的同时,恢复普通路径原有的 4 路插桩并发。
+`DSH_COVERAGE_MAX_WORKERS` 继续控制无插桩豁免门禁和普通非分区路径的规模,不会调整分区子进程。原生 Windows 为豁免门禁分配 2 个 worker,并允许 4 道外层门禁并发:构建、生产网站验证、插桩覆盖率与豁免重型覆盖率先启动,观测性清单等待两道覆盖率门禁完成后才进入可用槽位。Linux 让 4 个插桩分区进程与 2 个豁免 worker 重叠运行,在保持每个插桩进程只有 1 个 worker 的同时,恢复普通路径原有的 4 路插桩并发。
 
 
 ## 失败与输出语义
 ## 失败与输出语义
 
 

+ 0 - 2
packages/subprocess/subprocess-local/tests/fixtures/process-exit-host.ts

@@ -13,7 +13,6 @@ if ((kind !== 'ordinary' && kind !== 'terminal')
 }
 }
 
 
 const treeState = join(root, 'tree.json')
 const treeState = join(root, 'tree.json')
-const ready = join(root, 'ready')
 const proceed = join(root, 'proceed')
 const proceed = join(root, 'proceed')
 const managedTree = fileURLToPath(new URL('./managed-tree.ts', import.meta.url))
 const managedTree = fileURLToPath(new URL('./managed-tree.ts', import.meta.url))
 
 
@@ -58,7 +57,6 @@ const published = JSON.parse(await readFile(treeState, 'utf8')) as { root?: unkn
 if (!Number.isSafeInteger(published.root) || !Number.isSafeInteger(published.descendant)) {
 if (!Number.isSafeInteger(published.root) || !Number.isSafeInteger(published.descendant)) {
   throw new Error('managed tree published invalid process ids')
   throw new Error('managed tree published invalid process ids')
 }
 }
-await writeFile(ready, 'ready')
 await waitForFile(proceed)
 await waitForFile(proceed)
 
 
 if (trigger === 'dispose') {
 if (trigger === 'dispose') {

+ 0 - 4
packages/subprocess/subprocess-local/tests/process-exit.spec.ts

@@ -107,10 +107,6 @@ async function runScenario(kind: ManagedKind, trigger: ExitTrigger) {
   let treeGone = false
   let treeGone = false
   try {
   try {
     state = await readTree(join(root, 'tree.json'))
     state = await readTree(join(root, 'tree.json'))
-    await vi.waitFor(() => readFile(join(root, 'ready'), 'utf8'), {
-      interval: 10,
-      timeout: scenarioTimeoutMs,
-    })
     if (process.platform !== 'win32') identities = await captureIdentities(createProcessInspector(), state)
     if (process.platform !== 'win32') identities = await captureIdentities(createProcessInspector(), state)
     await writeFile(join(root, 'proceed'), 'proceed')
     await writeFile(join(root, 'proceed'), 'proceed')
     const outcome = await child
     const outcome = await child

+ 9 - 1
scripts/run-gates.spec.ts

@@ -110,7 +110,15 @@ describe('gate graph validation', () => {
     expect(byId.get('coverage')?.allowFailure).not.toBe(true)
     expect(byId.get('coverage')?.allowFailure).not.toBe(true)
     expect(byId.get('coverage-exempt-heavy')?.allowFailure).not.toBe(true)
     expect(byId.get('coverage-exempt-heavy')?.allowFailure).not.toBe(true)
     expect(observational).not.toHaveLength(0)
     expect(observational).not.toHaveLength(0)
-    for (const gate of observational) expect(byId.get(gate.id)?.allowFailure).toBe(true)
+    for (const gate of observational) {
+      const completeGate = byId.get(gate.id)
+      expect(completeGate?.allowFailure).toBe(true)
+      expect(completeGate?.needs).toEqual(expect.arrayContaining([
+        'coverage',
+        'coverage-exempt-heavy',
+        ...(gate.needs ?? []),
+      ]))
+    }
   })
   })
 
 
   it('applies one configured test and polling timeout to both coverage gates', () => {
   it('applies one configured test and polling timeout to both coverage gates', () => {

+ 8 - 2
scripts/run-gates.ts

@@ -454,15 +454,21 @@ function ciWindowsBlockingGates(): Gate[] {
 }
 }
 
 
 function ciWindowsCompleteGates(): Gate[] {
 function ciWindowsCompleteGates(): Gate[] {
+  const coverage = coverageGates()
+  const coverageNeeds = coverage.map(gate => gate.id)
   const observational = ciWindowsObservationalGates()
   const observational = ciWindowsObservationalGates()
     // The required production site replaces the observational MPA build; both
     // The required production site replaces the observational MPA build; both
     // VitePress modes write the same output directory and cannot overlap.
     // VitePress modes write the same output directory and cannot overlap.
     .filter(gate => gate.id !== 'build' && gate.id !== 'docs-site-build')
     .filter(gate => gate.id !== 'build' && gate.id !== 'docs-site-build')
-    .map(gate => ({ ...gate, allowFailure: true }))
+    .map(gate => ({
+      ...gate,
+      allowFailure: true,
+      needs: [...new Set([...coverageNeeds, ...(gate.needs ?? [])])],
+    }))
   return [
   return [
     pnpmScript('build', 'build'),
     pnpmScript('build', 'build'),
     pnpmScript('windows-site', 'docs:build', { label: 'production site' }),
     pnpmScript('windows-site', 'docs:build', { label: 'production site' }),
-    ...coverageGates(),
+    ...coverage,
     ...observational,
     ...observational,
   ]
   ]
 }
 }

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio