diff --git a/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.i18n.yaml b/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.i18n.yaml index 3cb0aae486..c8afbe8e53 100644 --- a/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.i18n.yaml @@ -9,8 +9,8 @@ en: 4fb1c27a631b32d3 zh: 9dbe9a4b9aadfca9 /agent-note-serial-cross-platform-ci-reference/decision: - en: de8d4ab11006cbdb - zh: 7e338f387244fcec + en: 6c682d0b7b2a03ca + zh: b75950853f45cccf /agent-note-serial-cross-platform-ci-reference/alternatives-considered: en: 3610152c5c4e93af zh: f4c09d327716f750 diff --git a/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md b/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md index d65ac05b08..abe34e58a4 100644 --- a/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md +++ b/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md @@ -24,7 +24,7 @@ Platform ownership remains explicit inside that complete aggregate. `terminal-ba The macOS reference runs the ordinary Vitest project in forked processes. Node 24 on macOS arm64 has aborted in its CJS lexer from a worker thread; the process boundary contains that external runtime failure without removing any test from the aggregate, while Linux and Windows retain the lower-overhead thread pool. Repository-owned races are fixed at their observation boundaries: dev bundle polling stages each candidate table, graph, and watch-baseline map before publishing a rescan, and a missing bundle remains dirty until a successful content hash. PTY readiness retains a prompt candidate while polling checks foreground ownership; the ordinary silence bound covers inherited markers from interactive children. Real PTY fixtures assemble synchronization tokens at runtime so the interactive shell's input echo cannot satisfy a child-readiness wait. The live-link package-manager e2e preserves the workflow-prepared Corepack home and pnpm metadata/store caches while isolating the other managers' mutable caches, so it does not discard reusable package-manager state before the install. -The standalone [Sandbox](../../../../.github/workflows/sandbox.yml) workflow belongs to the reference side of the same split. Its bwrap, Landlock x64/arm64, and Seatbelt real-kernel matrix runs only after a push to `master`. Those four jobs are diagnostic: they are not branch-protection requirements and do not feed `all checks passed` across workflow files. A fifth job, `unit-darwin`, runs the complete unit suite on `macos-latest` under its own budget, so the darwin-only unit expectations keep a platform oracle without holding the Seatbelt leg to the unit suite's duration. That job grants `DSH_COVERAGE_TEST_TIMEOUT_MS=90000`, the coverage and serial lanes' key and value, and runs the unit inventory through the `ci-unit` aggregate that consumes it, so cases that inherit Vitest's defaults keep those lanes' budget on the shared macOS runner; under the root config's inline projects only the per-test flag currently reaches the tests, while the hook and `expect.poll` flags stay at Vitest's defaults. Pull-request CI still checks sandbox source through its ordinary unit and coverage inventory; the host-kernel and packed-install proofs report after merge. +The standalone [Sandbox](../../../../.github/workflows/sandbox.yml) workflow belongs to the reference side of the same split. Its bwrap, Landlock x64/arm64, and Seatbelt real-kernel matrix runs only after a push to `master`. Those four jobs are diagnostic: they are not branch-protection requirements and do not feed `all checks passed` across workflow files. A fifth job, `unit-darwin`, runs the complete unit suite on `macos-latest` under its own budget, so the darwin-only unit expectations keep a platform oracle without holding the Seatbelt leg to the unit suite's duration. That job grants `DSH_COVERAGE_TEST_TIMEOUT_MS=90000`, the coverage and serial lanes' key and value, and runs the unit inventory through the `ci-unit` aggregate that consumes it, so cases that inherit Vitest's defaults keep those lanes' budget on the shared macOS runner. Pull-request CI still checks sandbox source through its ordinary unit and coverage inventory; the host-kernel and packed-install proofs report after merge. Master reference jobs are diagnostic and do not participate in the pull request's required `all checks passed` result. The ci-master and Sandbox workflows keep their cross-platform references on master pushes. Performance is evaluated from completed hosted-job timestamps and reported as a measurement; it is not encoded as a `timeout-minutes` value. diff --git a/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.zh.md b/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.zh.md index 5c105a271f..832af4e655 100644 --- a/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.zh.md +++ b/.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.zh.md @@ -24,7 +24,7 @@ Status: implemented macOS 参考流程使用 fork 进程运行常规 Vitest 项目。macOS arm64 上的 Node 24 曾在工作线程中执行 CJS 词法分析器时异常终止;进程边界能够隔离这一外部运行时故障,且无需从聚合流程中删除任何测试,而 Linux 与 Windows 仍使用开销更低的线程池。仓库自身引入的竞态均在相应的观测边界修复:开发构建产物的轮询逻辑每次发布重新扫描结果前,都会先暂存候选表、候选图和候选监视基线映射;构建产物缺失后会一直保持脏状态,直到成功计算内容哈希。PTY 就绪检测会在轮询检查前台进程组归属期间保留提示符候选项;常规静默时限也涵盖从交互式子进程继承而来的标记。真实 PTY fixture 会在运行时拼接同步标记,使就绪等待逻辑不会把交互式 shell 的输入回显误判为子进程已就绪。实时链接场景下的包管理器 e2e 会保留由工作流预先准备的 Corepack 主目录、pnpm 元数据缓存和 store 缓存,同时隔离其他包管理器的可变缓存,因此不会在安装前丢弃可复用的包管理器状态。 -独立的 [Sandbox](../../../../.github/workflows/sandbox.yml) 工作流属于同一职责划分中的参考侧。其 bwrap、Landlock x64/arm64 与 Seatbelt 真实内核矩阵只在向 `master` 推送后运行。这四个作业仅用于诊断:它们既不是分支保护的必需项,也不会跨工作流计入 `all checks passed`。第五个作业 `unit-darwin` 在 `macos-latest` 上以自己的预算运行完整单元测试套件,让只在 darwin 上生效的单元测试预期保有平台判据,同时不让 Seatbelt 作业受制于单元测试套件的时长。该作业授予与覆盖率、串行通道相同键值的 `DSH_COVERAGE_TEST_TIMEOUT_MS=90000`,并通过消费该变量的 `ci-unit` 聚合运行单元测试清单,因此继承 Vitest 默认值的用例在共享的 macOS 运行器上保有这些通道的预算;在根配置的内联 projects 下,目前只有单测试标志到达测试,hook 与 `expect.poll` 标志仍停留在 Vitest 默认值。拉取请求 CI 仍通过常规的单元测试与覆盖率清单检查沙箱源码;宿主内核与 packed-install 验证在合并后报告结果。 +独立的 [Sandbox](../../../../.github/workflows/sandbox.yml) 工作流属于同一职责划分中的参考侧。其 bwrap、Landlock x64/arm64 与 Seatbelt 真实内核矩阵只在向 `master` 推送后运行。这四个作业仅用于诊断:它们既不是分支保护的必需项,也不会跨工作流计入 `all checks passed`。第五个作业 `unit-darwin` 在 `macos-latest` 上以自己的预算运行完整单元测试套件,让只在 darwin 上生效的单元测试预期保有平台判据,同时不让 Seatbelt 作业受制于单元测试套件的时长。该作业授予与覆盖率、串行通道相同键值的 `DSH_COVERAGE_TEST_TIMEOUT_MS=90000`,并通过消费该变量的 `ci-unit` 聚合运行单元测试清单,因此继承 Vitest 默认值的用例在共享的 macOS 运行器上保有这些通道的预算。拉取请求 CI 仍通过常规的单元测试与覆盖率清单检查沙箱源码;宿主内核与 packed-install 验证在合并后报告结果。 master 分支的参考作业仅用于诊断,不参与拉取请求所要求的 `all checks passed` 结果。ci-master 与 Sandbox 工作流把跨平台参考流程保留在 master 推送上。系统根据已完成托管作业的时间戳评估性能,并将其报告为测量结果,而不是写成 `timeout-minutes` 值。 diff --git a/scripts/run-gates.spec.ts b/scripts/run-gates.spec.ts index 92aa0e4deb..c71e2ed045 100644 --- a/scripts/run-gates.spec.ts +++ b/scripts/run-gates.spec.ts @@ -15,8 +15,15 @@ import { type GateResult, } from './run-gates.ts' -// Graph fixtures select their own browser pool instead of inheriting the CI host's pool. -beforeEach(() => vi.stubEnv('DSH_WEB_SNAPSHOT_WORKERS', undefined)) +// Graph fixtures select their own browser pool instead of inheriting the CI +// host's pool, and coverage gates take their shape from the values each case +// sets, not from the lane that runs this file (a partitioned lane exports +// DSH_COVERAGE_PARTITIONS to every child). +beforeEach(() => { + vi.stubEnv('DSH_WEB_SNAPSHOT_WORKERS', undefined) + vi.stubEnv('DSH_COVERAGE_MAX_WORKERS', undefined) + vi.stubEnv('DSH_COVERAGE_PARTITIONS', undefined) +}) afterEach(() => vi.unstubAllEnvs()) /** @@ -565,7 +572,12 @@ describe('gate graph validation', () => { const gates = withEnv('DSH_COVERAGE_TEST_TIMEOUT_MS', '15000', () => withPnpmEntrypoint(() => gatesForMode('ci-unit'))) expect(gates.map(gate => gate.id)).toEqual(['native-system', 'unit']) - expect(gates[0]).toMatchObject({ displayCommand: 'pnpm run build:native-system' }) + // The aggregate is the `test` package script's two segments, in order, + // so a step added to one cannot silently leave the other. + const [nativeBuild, unitRun, ...rest] = (scripts.test ?? '').split(' && ') + expect(rest).toEqual([]) + expect(gates[0]).toMatchObject({ displayCommand: nativeBuild }) + expect(gates[1]?.displayCommand).toBe(`pnpm exec ${unitRun} --testTimeout=15000 --expect.poll.timeout=15000 --hookTimeout=15000`) expect(gates[1]).toMatchObject({ label: 'test', needs: ['native-system'], diff --git a/scripts/run-gates.ts b/scripts/run-gates.ts index 3fc0d6b1b3..b002510545 100644 --- a/scripts/run-gates.ts +++ b/scripts/run-gates.ts @@ -203,9 +203,10 @@ export function ciWorkerEnvironment( env: NodeJS.ProcessEnv, available = availableParallelism(), ): Record { - // ci-unit runs the plain Vitest inventory and nothing that reads these - // settings; the inventory's own run-gates tests build coverage gates from - // the ambient coverage variables, so it inherits the environment exactly as + // ci-unit's gates read none of these settings, while the inventory it runs + // reads the same variables (run-gates.spec.ts builds coverage gates from + // DSH_COVERAGE_PARTITIONS; the oxlint contract spawns run-oxlint, which + // reads DSH_OXLINT_THREADS), so the aggregate leaves the environment as // `pnpm run test` finds it. if (!mode.startsWith('ci-') || mode === 'ci-unit') return {} const additions: Record = {}