From 761eeb7c55c3e34902c1dfa1acee33345d8202d5 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Mon, 27 Jul 2026 14:15:46 +0800 Subject: [PATCH] ci: restore standard runners for primary checks --- ...rial-cross-platform-ci-reference.i18n.yaml | 6 ++--- ...7-21-serial-cross-platform-ci-reference.md | 6 ++--- ...1-serial-cross-platform-ci-reference.zh.md | 6 ++--- ...ence-based-larger-hosted-runners.i18n.yaml | 6 ++--- ...22-evidence-based-larger-hosted-runners.md | 20 ++++++++--------- ...evidence-based-larger-hosted-runners.zh.md | 20 ++++++++--------- ...ortable-required-pull-request-ci.i18n.yaml | 6 ++--- ...07-23-portable-required-pull-request-ci.md | 16 +++++++------- ...23-portable-required-pull-request-ci.zh.md | 16 +++++++------- .github/workflows/ci.yml | 22 +++++++++---------- 10 files changed, 62 insertions(+), 62 deletions(-) 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 17edb300cc..8cd2a0f7c8 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 @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # 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: -# pnpm run verify-translation-pairing --write -2026-07-21-serial-cross-platform-ci-reference.md: 5433d2c51831ce61d06a16ee0b0ed982911f9218 -2026-07-21-serial-cross-platform-ci-reference.zh.md: 041d53d13e14354c995e4b65defce94a97646b0a +# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md +2026-07-21-serial-cross-platform-ci-reference.md: 220c4b2a092ec1907482edc60a12f981fdf986a4 +2026-07-21-serial-cross-platform-ci-reference.zh.md: 70e4c40f0f64fef4b1de05a7603ece25aaf5bea2 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 5433d2c518..220c4b2a09 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 @@ -14,7 +14,7 @@ Reviewers also need a direct answer to a simpler question: what happens when the ## Decision -[CI](../../../../.github/workflows/ci.yml) gives pull-request and master-push events complementary responsibilities. Pull requests run consolidated Linux and Windows jobs plus the Node compatibility and Python contracts on standard GitHub-hosted capacity. A push to `master` skips those jobs and runs three explicit references named `serial / linux`, `serial / macos`, and `serial / windows`. They intentionally duplicate their short checkout, runtime setup, and immutable install sequences instead of hiding the operating systems behind a matrix or reusable workflow. `workflow_dispatch` is reserved for runner benchmarks. +[CI](../../../../.github/workflows/ci.yml) gives pull-request and master-push events complementary responsibilities. Pull requests run three primary Linux jobs, one complete Windows job, and the Node compatibility and Python contracts on standard GitHub-hosted capacity. A push to `master` skips those jobs and runs three explicit references named `serial / linux`, `serial / macos`, and `serial / windows`. They intentionally duplicate their short checkout, runtime setup, and immutable install sequences instead of hiding the operating systems behind a matrix or reusable workflow. `workflow_dispatch` is reserved for runner benchmarks. Each reference job runs `pnpm run check:ci` without any shard selector. `DSH_GATE_CONCURRENCY=1` makes the top-level aggregate execute one ready gate at a time; coverage, snapshot replay, built-bin smoke, and publication validation also receive worker counts of one. The three operating-system jobs may run beside one another, but each host's repository gates are serial and complete. Linux installs bubblewrap before replaying snapshots, and Windows enables Developer Mode before installing the symlinked workspace. @@ -24,7 +24,7 @@ The macOS reference runs the ordinary Vitest project in forked processes. Node 2 Master reference jobs are diagnostic and do not participate in the pull request's required `all checks passed` result. A pull request runs only its required jobs; a master push runs only the three serial references. Performance is evaluated from completed hosted-job timestamps and reported as a measurement; it is not encoded as a `timeout-minutes` value. -The portable reference uses GitHub's standard `ubuntu-latest`, `macos-latest`, and `windows-2025` labels. Required pull-request jobs use the same portable Linux and Windows capacity under the [required-CI decision](2026-07-23-portable-required-pull-request-ci.md). Higher-core hosted runners remain manual benchmarks because a correctness path must remain runnable without repository-external runner configuration. +The portable reference uses GitHub's standard `ubuntu-latest`, `macos-latest`, and `windows-2025` labels. Substantive required pull-request jobs use the same portable Linux and Windows capacity under the [required-CI decision](2026-07-23-portable-required-pull-request-ci.md). Higher-core hosted runners remain manual benchmarks because a correctness path must remain runnable without repository-external runner configuration. ## Alternatives considered @@ -32,7 +32,7 @@ The portable reference uses GitHub's standard `ubuntu-latest`, `macos-latest`, a - **Trust only the concurrent primary inventory** - rejected because scheduling and validation share implementation assumptions; a serial aggregate is an independent completeness check. - **Run the serial references on every pull request** - rejected because they duplicate complete cross-platform aggregates and add macOS work to every change; the required jobs already execute the blocking Linux and Windows contracts. - **Use one operating-system matrix** - rejected because three named jobs make the reference surface visible without another selection mechanism. -- **Run the serial reference on larger runners** - rejected because both required CI and its independent reference must remain runnable when organization-owned pools cannot allocate jobs. +- **Run the serial reference on larger runners** - rejected because substantive required CI and its independent reference must remain runnable when organization-owned pools cannot allocate jobs. ## Consequences 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 041d53d13e..70e4c40f0f 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 @@ -14,7 +14,7 @@ Status: implemented ## 决策 -[CI](../../../../.github/workflows/ci.yml) 为拉取请求事件与 master 推送事件赋予互补的职责。拉取请求在 GitHub 标准托管容量上运行合并后的 Linux 和 Windows 作业,以及 Node 兼容性与 Python 契约。向 `master` 推送时会跳过这些作业,改为运行三个显式参考作业,名称分别为 `serial / linux`、`serial / macos` 和 `serial / windows`。这些作业有意分别重复简短的代码检出、运行时设置和依赖锁定的安装步骤,不用矩阵或可复用工作流把操作系统差异隐藏起来。`workflow_dispatch` 仅用于运行器基准测试。 +[CI](../../../../.github/workflows/ci.yml) 为拉取请求事件与 master 推送事件赋予互补的职责。拉取请求在 GitHub 标准托管容量上运行 3 项 Linux 主作业、1 项完整的 Windows 作业,以及 Node 兼容性与 Python 契约。向 `master` 推送时会跳过这些作业,改为运行三个显式参考作业,名称分别为 `serial / linux`、`serial / macos` 和 `serial / windows`。这些作业有意分别重复简短的代码检出、运行时设置和依赖锁定的安装步骤,不用矩阵或可复用工作流把操作系统差异隐藏起来。`workflow_dispatch` 仅用于运行器基准测试。 每个参考作业均在不设置任何分片选择器的情况下运行 `pnpm run check:ci`。`DSH_GATE_CONCURRENCY=1` 使顶层聚合每次只执行一个已经就绪的门禁;覆盖率、快照回放、built-bin 冒烟测试和发布验证的并发数也设为 1。三种操作系统的作业可以彼此并行,但每台主机上的仓库门禁都串行运行且完整执行。Linux 在回放快照前安装 bubblewrap,Windows 则在安装采用符号链接的工作区前启用开发人员模式。 @@ -24,7 +24,7 @@ macOS 参考流程使用 fork 进程运行常规 Vitest 项目。macOS arm64 上 master 分支的参考作业仅用于诊断,不参与拉取请求所要求的 `all checks passed` 结果。拉取请求只运行其必需作业;向 master 推送时只运行三个串行参考作业。系统根据已完成托管作业的时间戳评估性能,并将其报告为测量结果,而不是写成 `timeout-minutes` 值。 -可移植的参考流程使用 GitHub 标准的 `ubuntu-latest`、`macos-latest` 和 `windows-2025` 标签。依据[必需 CI 决策](2026-07-23-portable-required-pull-request-ci.md),拉取请求必需作业使用相同的可移植 Linux 和 Windows 容量。更高核心数的托管运行器仍仅用于手动基准测试,因为正确性路径必须无需仓库外部的运行器配置即可运行。 +可移植的参考流程使用 GitHub 标准的 `ubuntu-latest`、`macos-latest` 和 `windows-2025` 标签。依据[必需 CI 决策](2026-07-23-portable-required-pull-request-ci.md),拉取请求中的实质性必需作业使用相同的可移植 Linux 和 Windows 容量。更高核心数的托管运行器仍仅用于手动基准测试,因为正确性路径必须无需仓库外部的运行器配置即可运行。 ## 曾考虑的替代方案 @@ -32,7 +32,7 @@ master 分支的参考作业仅用于诊断,不参与拉取请求所要求的 - **仅信任并发执行的主门禁清单**:不予采纳,因为调度逻辑与校验逻辑共享实现假设;串行聚合流程是一项独立的完整性检查。 - **在每个拉取请求上运行串行参考作业**:不予采纳,因为这些作业会重复完整的跨平台聚合流程,并为每项改动增加 macOS 工作;必需作业已经执行阻塞性的 Linux 和 Windows 契约。 - **使用一个操作系统矩阵**:不予采纳,因为三个具名作业无需另一套选择机制,就能让参考流程的构成清晰可见。 -- **在大型运行器上运行串行参考流程**:不予采纳,因为当组织自有运行器池无法分配作业时,必需 CI 及其独立参考流程都必须仍可运行。 +- **在大型运行器上运行串行参考流程**:不予采纳,因为当组织自有运行器池无法分配作业时,承担实质性检查的必需 CI 及其独立参考流程都必须仍可运行。 ## 后果 diff --git a/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.i18n.yaml b/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.i18n.yaml index 3d8e6fc395..eeaa689fd8 100644 --- a/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.i18n.yaml @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # 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: -# pnpm run verify-translation-pairing --write -2026-07-22-evidence-based-larger-hosted-runners.md: fe11e6929545923d27fbf41f5a39f7dd2b9c3fbf -2026-07-22-evidence-based-larger-hosted-runners.zh.md: 47879284532a537cbe7e78aa2c495c4ef0be26c4 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.md +2026-07-22-evidence-based-larger-hosted-runners.md: 8a3ca991accd5bbe71b6f92cffff4c9a420b1f25 +2026-07-22-evidence-based-larger-hosted-runners.zh.md: 870c4301eed4793d3ac6801c310288abf1d46c3b diff --git a/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.md b/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.md index fe11e69295..8a3ca991ac 100644 --- a/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.md +++ b/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.md @@ -12,19 +12,19 @@ Larger runners make it possible to pay setup once and parallelize inside the rep ## Decision -The enterprise keeps repo-restricted x64 larger-runner pools for Ubuntu and Windows. Ordinary pull requests name three 32-core pools directly: Ubuntu 24.04 for exhaustive coverage, Ubuntu latest for the remaining primary Node 24 inventory, and Windows 2025 for blocking Windows contracts. Public IPs are disabled, and workflow concurrency remains bounded because an autoscaling ceiling neither allocates idle machines nor makes repository work scale without limit. +The enterprise keeps repo-restricted x64 larger-runner pools for Ubuntu and Windows as measurement infrastructure. Public IPs are disabled, and benchmark concurrency remains bounded because an autoscaling ceiling neither allocates idle machines nor makes repository work scale without limit. -The required primary path depends on those enterprise pools. Standard GitHub-hosted jobs retain the Node 22.19, Node 26, and Python SDK compatibility contracts, while the [portable recovery boundary](2026-07-23-portable-required-pull-request-ci.md) and [serial reference](2026-07-21-serial-cross-platform-ci-reference.md) keep complete standard-runner evidence available on `master`. `suite=larger-runner-benchmark` compares isolated critical lanes across provisioned sizes, and `suite=consolidated-runner-benchmark` compares whole aggregates. Each benchmark reports its observed processor and memory capacity before running repository work. +Ordinary pull requests use the standard-hosted primary path owned by the [portable recovery boundary](2026-07-23-portable-required-pull-request-ci.md). `suite=larger-runner-benchmark` compares isolated critical lanes across provisioned sizes, and `suite=consolidated-runner-benchmark` compares whole aggregates. Each benchmark reports its observed processor and memory capacity before running repository work. The [serial reference](2026-07-21-serial-cross-platform-ci-reference.md) keeps an independent complete standard-runner oracle on `master`. The former gate-level and coarse primary shard jobs are absent from the workflow. Their static, lint, coverage, snapshot, and scenario shard selectors are also absent from the repository, so an unused diagnostic path cannot preserve a second CI architecture. -Linux primary work uses three independent 32-core jobs. Coverage runs alone with its own worker bound, and the static scheduler runs alone so its result has no post-build consumer tail. After static gates finish, that job publishes its emitted `apps/*/lib`, `packages/*/*/lib`, and `vendor/*/lib` tree as a run-scoped artifact. The third job restores that exact tree, then starts lint, Node 24 runtime compatibility, build-backed snapshots, and all artifact consumers without repeating the build. Generated NodeNext consumer directories are excluded from ESLint discovery because the artifact check removes them while these processes overlap. The pnpm store and ESLint cache are restored without putting cache uploads on the pull-request critical path. Performance reports use each job's `startedAt` to `completedAt` interval; runner queue delay is capacity evidence, not repository execution time. +Linux primary work uses three independent standard-hosted jobs with single-worker inner bounds. Coverage runs alone, and the static scheduler runs alone so its result has no post-build consumer tail. After static gates finish, that job publishes its emitted `apps/*/lib`, `packages/*/*/lib`, and `vendor/*/lib` tree as a run-scoped artifact. The third job restores that exact tree, then starts lint, Node 24 runtime compatibility, build-backed snapshots, and all artifact consumers without repeating the build. Generated NodeNext consumer directories are excluded from ESLint discovery because the artifact check removes them while these processes overlap. The pnpm store and ESLint cache are restored without putting cache uploads on the pull-request critical path. Performance reports use each job's `startedAt` to `completedAt` interval; runner queue delay is capacity evidence, not repository execution time. The gate dependencies remain explicit. Coverage consumes source and does not wait for build. Documentation typechecking builds its complete project-reference graph once. Snapshot replay and publication consumers wait for emitted output, while Node-version compatibility jobs exercise runtime-sensitive source loading without repeating the primary source-graph typecheck. PTY and subprocess suites keep their bounded inner concurrency rather than inheriting the runner's core count. The artifact boundary remains explicit. `scripts/publint-all.ts` calls publint's supported API against an in-memory publication view formed from each manifest's declared files plus npm's mandatory metadata, avoiding one package-manager pack process per package. `scripts/verify-built-package-invariants.mjs` stages the declared `lib/` files below the real package and imports its compiled self-reference through plain Node and Cordis Loader normalization; a runtime chunk omitted from the publication contract still fails. -Windows shares one 32-core setup across the blocking build and production site plus observational built-artifact contracts. Linux owns the duplicate lint, coverage, and snapshot inventories because running those observational copies on Windows extends the paid critical path without adding a blocking platform claim. +Windows shares one standard-hosted setup across the blocking build and production site plus observational built-artifact contracts, with single-worker bounds. Linux owns the duplicate lint, coverage, and snapshot inventories because running those observational copies on Windows extends the critical path without adding a blocking platform claim. An [exact-head all-size benchmark](https://github.com/deepseek-harness/deepseek-harness/actions/runs/29908491351) ran the complete unsharded primary Node aggregate on every Linux pool before the eager-build correction: @@ -50,11 +50,11 @@ Inner and outer worker limits are separate controls. An [exact-head 32-worker ES The process-bound coverage project contains exactly five suite files. Thirty-two forks crashed Node 24's CJS lexer twice, and a later 16-fork run reproduced the worker loss and invalid coverage result. The single Vitest invocation therefore uses threads for the broad inventory and reserves forks for suites that exercise process-global state, `process` APIs, or timing-sensitive process I/O. That narrow fork inventory includes the local bash process-plumbing suite and the pi-ai adapter suite because aggregate contention changed timing observations in both. These failures make deterministic coverage, not advertised cores, the upper bound on worker selection. -Complete serial Linux, macOS, and Windows references run only when `master` moves. Pull requests use the enterprise required path plus standard-hosted compatibility jobs, while other larger-runner sizes run only by manual dispatch. +Complete serial Linux, macOS, and Windows references run only when `master` moves. Pull requests use the standard-hosted required path, while larger-runner sizes run only by manual dispatch. ## Alternatives considered -**Keep the three coarse primary Linux lanes.** The core, CPU, and production-site jobs met the latency targets, but they paid three setup waves and left primary Node work sharded after larger runners were available. The all-size trace showed that one unnecessary dependency, not a lack of host capacity, kept the single-box aggregate above one minute. +**Restore the former core, CPU, and production-site lanes.** Those jobs met the latency targets, but they paid three setup waves and left primary Node work sharded after larger runners were available. The all-size trace showed that one unnecessary dependency, not a lack of host capacity, kept the single-box aggregate above one minute. **Keep the former gate-level shard topology as a manual reference.** A dormant second topology kept hundreds of workflow lines, selector modules, and scenario-partition behavior alive. The all-size and serial suites provide timing and completeness controls without preserving production code that no required job exercises. @@ -68,7 +68,7 @@ Complete serial Linux, macOS, and Windows references run only when `master` move **Keep static gates and post-build consumers on one runner.** Reusing one workspace avoids a setup wave and artifact transfer, but build-duration variance delays every consumer and leaves their lint and snapshot tails after the static result. A run-scoped built tree preserves one exact build while independent jobs keep both complete paths within the observed target. -**Keep the complete required path on standard GitHub-hosted capacity.** This avoids repository-external runner configuration, but exact-head standard-runner runs remain materially slower and can spend longer queued behind shared capacity. Standard-hosted compatibility and serial references preserve portable evidence without making that slower topology the ordinary primary path. +**Use larger-runner pools as the required default.** This offers lower measured latency when allocation works, but a missing entitlement or delayed enterprise transfer leaves required jobs queued without repository diagnostics. The portable path accepts longer runtime, and manual suites preserve the performance experiment. **Keep required and observational Windows checks in separate jobs.** The split preserves status semantics at the workflow level but pays setup twice. `run-gates` preserves the same required versus non-blocking distinction inside one process. @@ -76,10 +76,10 @@ Complete serial Linux, macOS, and Windows references run only when `master` move ## Consequences -The required topology pays one setup wave per 32-core lane and retains no shard selectors. Every ordinary pull request consumes paid enterprise Linux and Windows minutes; manual benchmarks add other sizes only when remeasurement is useful. +The required topology pays one setup wave per standard-hosted lane and retains no shard selectors. The substantive CI inventory consumes enterprise larger-runner minutes only when a benchmark is dispatched; the lightweight aggregate's separate runner choice is outside this decision. -GitHub rounds each larger-runner execution up to a whole minute, so complete-job measurement exposes both billed time and workflow complexity. Splitting Linux repeats setup twice and transfers one built tree, but isolates coverage, static gates, and post-build consumers from each other's critical paths without repeating the build; consolidating Windows avoids repeating its slower setup. +Splitting Linux repeats setup twice and transfers one built tree, but isolates coverage, static gates, and post-build consumers from each other's critical paths without repeating the build. Consolidating Windows avoids repeating its slower setup. The trade-off is longer elapsed time than the measured larger-runner topology. Performance targets are observations, not cancellation deadlines or correctness requirements. Manual all-size and serial suites remain available when image, dependency, scheduler, or pricing changes need remeasurement. -Missing or renamed enterprise labels leave required primary jobs queued. Standard-hosted compatibility jobs and `master` references still report useful evidence, but they do not substitute for the required aggregate; runner assignment is therefore an operational dependency that repository CI cannot repair. +Missing or renamed enterprise labels leave manual benchmarks unavailable without queueing a substantive primary job. The retained pools can compare sizes after allocation recovers without making runner assignment an operational dependency of repository gate execution. diff --git a/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.zh.md b/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.zh.md index 4787928453..870c4301ee 100644 --- a/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.zh.md +++ b/.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.zh.md @@ -12,19 +12,19 @@ Status: implemented ## 决策 -企业保留仅限本仓库使用的 Ubuntu 和 Windows x64 大型运行器池。普通拉取请求直接指定 3 个 32 核运行器池:Ubuntu 24.04 用于完整覆盖率,Ubuntu latest 用于其余主 Node 24 清单,Windows 2025 用于阻塞性 Windows 契约。公网 IP 已禁用;工作流并发仍设有边界,因为自动扩缩容上限既不会分配闲置机器,也不意味着仓库工作可以无限扩展。 +企业保留仅限本仓库使用的 Ubuntu 和 Windows x64 大型运行器池,作为测量基础设施。公网 IP 已禁用;基准测试并发仍设有边界,因为自动扩缩容上限既不会分配闲置机器,也不意味着仓库工作可以无限扩展。 -必需主路径依赖这些企业级运行器池。GitHub 标准托管作业保留 Node 22.19、Node 26 和 Python SDK 兼容性契约,而[可移植恢复边界](2026-07-23-portable-required-pull-request-ci.md)与[串行参考流程](2026-07-21-serial-cross-platform-ci-reference.md)则在 `master` 上持续提供完整的标准运行器证据。`suite=larger-runner-benchmark` 比较已预配规格上相互独立的关键通道,`suite=consolidated-runner-benchmark` 则比较完整聚合流程。每项基准测试都会先报告实测的处理器和内存容量,再运行仓库工作。 +普通拉取请求使用由[可移植恢复边界](2026-07-23-portable-required-pull-request-ci.md)规定的标准托管主路径。`suite=larger-runner-benchmark` 比较已预配规格上相互独立的关键通道,`suite=consolidated-runner-benchmark` 则比较完整聚合流程。每项基准测试都会先报告实测的处理器和内存容量,再运行仓库工作。[串行参考流程](2026-07-21-serial-cross-platform-ci-reference.md)在 `master` 上保留一套独立、完整的标准运行器判定基准。 原有的门禁级和粗粒度主流程分片作业已从工作流中移除。相应的静态、lint、覆盖率、快照和场景分片选择器也已从仓库中移除,因此未使用的诊断路径无法继续维系第二套 CI 架构。 -Linux 主流程使用 3 个相互独立的 32 核作业。覆盖率单独运行,并设有自己的工作线程上限;静态调度器也单独运行,因此构建后的消费方不会拖延其结果。静态门禁完成后,该作业将其生成的 `apps/*/lib`、`packages/*/*/lib` 和 `vendor/*/lib` 目录树作为仅供本次运行使用的产物发布。第三个作业恢复完全相同的目录树,再让 lint、Node 24 运行时兼容性、依赖构建产物的快照和所有产物消费方基于构建完成后的工作树启动,而不重复构建。生成的 NodeNext 消费方目录不会纳入 ESLint 的文件发现范围,因为这些进程重叠执行时,产物检查会删除这些目录。pnpm store 和 ESLint 缓存会得到恢复,但缓存上传不会进入拉取请求关键路径。性能报告采用每个作业从 `startedAt` 到 `completedAt` 的区间;运行器排队延迟是容量证据,而非仓库执行时间。 +Linux 主流程使用 3 项相互独立的标准托管作业,内部均采用单工作线程上限。覆盖率单独运行;静态调度器也单独运行,因此构建后的消费方不会拖延其结果。静态门禁完成后,该作业将其生成的 `apps/*/lib`、`packages/*/*/lib` 和 `vendor/*/lib` 目录树作为仅供本次运行使用的产物发布。第三个作业恢复完全相同的目录树,再让 lint、Node 24 运行时兼容性、依赖构建产物的快照和所有产物消费方基于构建完成后的工作树启动,而不重复构建。生成的 NodeNext 消费方目录不会纳入 ESLint 的文件发现范围,因为这些进程重叠执行时,产物检查会删除这些目录。pnpm store 和 ESLint 缓存会得到恢复,但缓存上传不会进入拉取请求关键路径。性能报告采用每个作业从 `startedAt` 到 `completedAt` 的区间;运行器排队延迟是容量证据,而非仓库执行时间。 门禁依赖关系保持显式。覆盖率消费源码,不等待构建。文档类型检查只构建一次完整的 project-reference 图。快照回放和发布消费方等待生成的输出,而 Node 版本兼容性作业会验证对运行时敏感的源码加载,且不重复主源码项目图的类型检查。PTY 和子进程套件继续使用自身有界的内部并发,不继承运行器的核心数。 产物边界保持显式。`scripts/publint-all.ts` 对内存中的发布视图调用 publint 支持的 API;该视图由每个 manifest(元数据清单)声明的文件和 npm 强制要求的元数据组成,从而避免为每个包启动一次包管理器 pack 进程。`scripts/verify-built-package-invariants.mjs` 将已声明的 `lib/` 文件暂存到真实包下,并通过普通 Node 和 Cordis Loader 规范化导入其已编译的自身引用;发布契约只要遗漏一个运行时分片,检查仍会失败。 -Windows 以一次 32 核环境设置同时承载阻塞性构建、生产网站和观测性的构建产物契约。重复的 lint、覆盖率和快照清单由 Linux 承担,因为在 Windows 上运行这些观测性副本会延长付费关键路径,却不会新增任何阻塞性平台契约。 +Windows 以一次标准托管环境设置同时承载阻塞性构建、生产网站和观测性的构建产物契约,并采用单工作线程上限。重复的 lint、覆盖率和快照清单由 Linux 承担,因为在 Windows 上运行这些观测性副本会延长关键路径,却不会新增任何阻塞性平台契约。 一次[分支头精确的全规格基准测试](https://github.com/deepseek-harness/deepseek-harness/actions/runs/29908491351)在修正构建尽早启动逻辑前,对每种 Linux 池都运行了完整且未分片的主 Node 聚合流程: @@ -50,11 +50,11 @@ Windows 仓库工作在超过 16 核后收益很小,但 32 核池可以让完 进程约束的覆盖率项目恰好包含 5 个套件文件。32 个 fork 曾两次导致 Node 24 的 CJS 词法分析器崩溃,后来一次使用 16 个 fork 的运行又复现了工作进程丢失和无效的覆盖率结果。因此,单次 Vitest 调用会对大范围测试清单使用线程,只为涉及进程全局状态、`process` API 或对时间敏感的进程 I/O 的套件保留 fork。这份有限的 fork 清单包括本地 bash 进程通路套件和 pi-ai 适配器套件,因为聚合争用改变了二者的时序观测结果。这些故障表明,选择工作线程数量时,上限取决于能否得到确定的覆盖率结果,而非标称核心数。 -只有在 `master` 移动时,才运行完整的 Linux、macOS 和 Windows 串行参考。拉取请求使用企业级运行器必需路径和标准托管兼容性作业,其他大型运行器规格仅通过手动触发运行。 +只有在 `master` 移动时,才运行完整的 Linux、macOS 和 Windows 串行参考。拉取请求使用标准托管的必需路径,大型运行器规格仅通过手动触发运行。 ## 曾考虑的替代方案 -**保留 3 个粗粒度 Linux 主流程通道。** 核心、CPU 和生产网站作业均达到延迟目标,但它们需要 3 轮设置,而且在大型运行器已经可用后仍对主 Node 工作进行分片。全规格运行轨迹表明,让单机聚合流程超过 1 分钟的是一项不必要的依赖,而非主机容量不足。 +**恢复原有的核心、CPU 和生产网站通道。** 这些作业均达到延迟目标,但它们需要 3 轮设置,而且在大型运行器已经可用后仍对主 Node 工作进行分片。全规格运行轨迹表明,让单机聚合流程超过 1 分钟的是一项不必要的依赖,而非主机容量不足。 **将原有的门禁级分片拓扑保留为手动参考。** 一套闲置的第二拓扑会让数百行工作流、选择器模块和场景分区行为继续存活。全规格和串行套件无需保留任何必需作业都不执行的生产代码,也能提供计时与完整性对照。 @@ -68,7 +68,7 @@ Windows 仓库工作在超过 16 核后收益很小,但 32 核池可以让完 **将静态门禁和构建后消费方保留在同一台运行器上。** 复用同一个工作区可以省去一轮设置和一次产物传输,但构建耗时的波动会延迟每个消费方,并使消费方的 lint 和快照尾段延续到静态结果之后。仅供本次运行使用的已构建目录树可以保留同一份构建结果,而相互独立的作业能让两条完整路径都保持在实测目标内。 -**将完整必需路径保留在 GitHub 标准托管容量上。** 此方案可以避免依赖仓库外部的运行器配置,但标准运行器上的分支头精确运行仍明显更慢,也可能因共享容量而排队更久。标准托管兼容性作业和串行参考流程保留可移植证据,无需让这套较慢的拓扑成为普通主路径。 +**将大型运行器池作为必需作业的默认运行环境。** 当运行器能够分配时,此方案可提供实测更低的延迟;但若未获得相应使用权限或企业转移延迟,必需作业会持续排队,且不会发出仓库诊断。可移植路径接受更长的运行时间,手动套件则保留性能实验。 **将必需的 Windows 检查和观测性 Windows 检查保留在不同作业中。** 这种拆分在工作流层保留状态语义,却需要支付两次设置开销。`run-gates` 在一个进程内保留了相同的必需与非阻塞区别。 @@ -76,10 +76,10 @@ Windows 仓库工作在超过 16 核后收益很小,但 32 核池可以让完 ## 后果 -必需拓扑中的每个 32 核通道只承担 1 轮设置开销,且不保留分片选择器。每个普通拉取请求都会消耗付费的企业级 Linux 和 Windows 运行器分钟数;只有在重新测量有价值时,手动基准测试才会加入其他规格。 +必需拓扑中的每个标准托管通道只承担 1 轮设置开销,且不保留分片选择器。只有在触发基准测试时,实质性 CI 清单才会消耗企业级大型运行器分钟数;轻量级聚合流程单独选择运行器,不属于本决策范围。 -GitHub 会把每次大型运行器执行向上取整到整分钟计费,因此完整作业测量能同时呈现计费时长与工作流复杂度。拆分 Linux 会重复两轮设置并传输一份已构建目录树,但能使覆盖率、静态门禁与构建后消费方不再相互进入关键路径,且无需重复构建;合并 Windows 则避免重复其耗时更长的设置。 +拆分 Linux 会重复两轮设置并传输一份已构建目录树,但能使覆盖率、静态门禁与构建后消费方不再相互进入关键路径,且无需重复构建。合并 Windows 可避免重复其耗时更长的设置。代价是总耗时长于经测量的大型运行器拓扑。 性能目标是观测结果,而非取消截止时间或正确性要求。当映像、依赖、调度器或定价发生变化而需要重新测量时,仍可使用手动全规格和串行套件。 -企业级运行器标签缺失或改名时,必需主作业会持续排队。标准托管兼容性作业与 `master` 参考流程仍会报告有用证据,但不能替代必需聚合流程;因此,运行器分配是一项仓库 CI 无法修复的运维依赖。 +企业级运行器标签缺失或改名时,手动基准测试会不可用,但不会让实质性主作业排队。运行器分配能力恢复后,保留的运行器池仍可比较不同规格,同时不会让运行器分配成为仓库门禁执行的运维依赖。 diff --git a/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.i18n.yaml b/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.i18n.yaml index 05147cd54a..34ea2f4a90 100644 --- a/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.i18n.yaml @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # 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: -# pnpm run verify-translation-pairing --write -2026-07-23-portable-required-pull-request-ci.md: d1002c7d9db7cd8bbed3bdfda8a773a4b124bf16 -2026-07-23-portable-required-pull-request-ci.zh.md: fedfc6b9c982ace5ece430c52db23c22ec5119d4 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.md +2026-07-23-portable-required-pull-request-ci.md: 4fd915a00300922d7318c78d16e1e8078b5170ed +2026-07-23-portable-required-pull-request-ci.zh.md: 9d489970a46279de8033cb82af64489d86b20d2c diff --git a/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.md b/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.md index d1002c7d9d..4fd915a003 100644 --- a/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.md +++ b/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.md @@ -12,24 +12,24 @@ Billing health, a runner definition's `Ready` state, and a large autoscaling cei ## Decision -[CI](../../../../.github/workflows/ci.yml) runs the required primary Node 24 jobs, plus the stable `all checks passed` aggregate, on repo-restricted enterprise 32-core pools. The aggregate performs no checkout or repository gate, but sharing the enterprise pool prevents the required verdict from introducing a separate standard-hosted billing dependency after its substantive jobs have already succeeded. The required Windows job runs on standard `windows-2025` with single-worker bounds, keeping the complete Windows contract independent of enterprise Windows allocation. Standard `ubuntu-latest` jobs retain Node 22.19, Node 26, and Python SDK compatibility, and `master` runs complete serial Linux, macOS, and Windows references. Those standard-hosted jobs keep the portable execution boundary observable without duplicating the primary inventory on every pull request. +[CI](../../../../.github/workflows/ci.yml) runs the three required primary Node 24 jobs on standard `ubuntu-latest` and the complete required Windows job on standard `windows-2025`. Static gates publish their exact built tree for the snapshot and artifact job, while coverage remains independent. Top-level gates, coverage, ESLint, publint, and snapshot replay use single-worker bounds on these smaller hosts. Node 22.19, Node 26, and Python SDK compatibility also use standard capacity. The lightweight `all checks passed` aggregate remains a separate scheduling decision because it performs no checkout or repository gate. -The two Linux primary jobs, Node compatibility, Python SDK, and `windows node 24 / complete` remain dependencies of `all checks passed`; branch protection continues to require `e2e` and `all checks passed`. There is no automatic fallback when a remaining enterprise Linux label cannot allocate: the standard jobs continue to report their own contracts, but they cannot manufacture the missing required result. +The three Linux primary jobs, Node compatibility, Python SDK, and `windows node 24 / complete` remain dependencies of `all checks passed`; no gate is removed or made observational to recover availability. Branch protection continues to require `e2e` and `all checks passed`. -The [larger-runner decision](2026-07-22-evidence-based-larger-hosted-runners.md) owns the current primary topology and its measurements. The [serial cross-platform reference](2026-07-21-serial-cross-platform-ci-reference.md) remains the independent standard-hosted completeness check, and the manual larger-runner suites retain size comparisons without expanding the ordinary required matrix. +The [larger-runner decision](2026-07-22-evidence-based-larger-hosted-runners.md) owns the retained performance measurements and manual suites. The [serial cross-platform reference](2026-07-21-serial-cross-platform-ci-reference.md) remains the independent standard-hosted completeness check. ## Alternatives considered -**Keep the Linux primary jobs and aggregate on standard capacity.** This removes the remaining enterprise allocation dependency, but complete standard-runner jobs give materially slower feedback and still experience shared-capacity queues. The current split retains portable compatibility and serial evidence while spending enterprise capacity on the Linux primary critical path. +**Wait for enterprise allocation to recover.** A queue with no assigned runner emits no repository diagnostic and can block every pull request indefinitely, so external recovery is not a correctness path. -**Select enterprise size from advertised core count.** Benchmarks show non-monotonic scaling and setup variance, so exact complete-job measurements choose the required pools instead. +**Use only the smallest enterprise pools.** Every named pool crosses the same enterprise allocation boundary; reducing core count does not remove the dependency that caused the queue. **Skip or demote checks while capacity is unavailable.** This would make the status green by dropping evidence rather than by running the repository's required contracts. -**Use one worker policy on every host.** Outer gate concurrency and inner tool workers contend differently on Linux, Windows, and standard runners; measured host-specific bounds avoid turning additional cores into slower execution. +**Keep larger-runner worker limits on standard runners.** Concurrent repository gates and their inner worker pools can oversubscribe the smaller memory and CPU allocation, turning an availability repair into contention failures. ## Consequences -Ordinary pull requests spend enterprise capacity on the Linux critical path while standard Windows trades longer runtime for independent allocation. A live exact-head run proves the same commands that branch protection consumes; queue delay is reported separately from each job's `startedAt` to `completedAt` execution interval. +Ordinary pull requests can acquire every substantive runner without enterprise-specific configuration. A live exact-head run proves the same commands that branch protection consumes, at the cost of longer elapsed time on smaller hosts. -Standard compatibility and required Windows jobs remain useful when enterprise allocation is degraded, but they do not make a blocked required Linux job or aggregate green. Recovering Linux availability may require restoring the complete standard-hosted topology; changing a pool definition's status alone is insufficient evidence that it can receive work. +Manual larger-runner benchmarks can remain queued without blocking pull requests. Restoring larger runners to the required path needs a separate evidence-based decision after exact-head jobs receive nonzero runner IDs and complete reliably; changing a pool definition's status alone is insufficient. diff --git a/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.zh.md b/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.zh.md index fedfc6b9c9..9d489970a4 100644 --- a/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.zh.md +++ b/.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.zh.md @@ -12,24 +12,24 @@ Status: implemented ## 决策 -[CI](../../../../.github/workflows/ci.yml) 在仅限本仓库使用的企业级 32 核运行器池上运行必需的主 Node 24 作业,以及稳定的 `all checks passed` 聚合流程。该聚合流程不执行代码检出或仓库门禁;但让它与所依赖的实质性作业共用企业级运行器池,可以避免这些作业已经成功后,必需判定结果又引入一项单独的标准托管计费依赖。必需的 Windows 作业在标准 `windows-2025` 上运行,并采用单工作线程上限,使完整的 Windows 契约不依赖企业级 Windows 运行器分配。标准 `ubuntu-latest` 作业保留 Node 22.19、Node 26 和 Python SDK 兼容性,`master` 则运行完整的 Linux、macOS 和 Windows 串行参考流程。这些标准托管作业让可移植执行边界保持可观测,而不必在每个拉取请求中重复主清单。 +[CI](../../../../.github/workflows/ci.yml) 在标准 `ubuntu-latest` 上运行 3 项必需的主 Node 24 作业,并在标准 `windows-2025` 上运行完整的必需 Windows 作业。静态门禁发布其完全一致的已构建目录树,供快照与产物作业使用;覆盖率作业则保持独立。这些较小主机上的顶层门禁、覆盖率、ESLint、publint 和快照回放均采用单工作线程上限。Node 22.19、Node 26 和 Python SDK 兼容性也使用标准容量。轻量级 `all checks passed` 聚合流程仍由单独的调度决策管理,因为它不执行代码检出或仓库门禁。 -两项 Linux 主作业、Node 兼容性、Python SDK 和 `windows node 24 / complete` 继续作为 `all checks passed` 的依赖项;分支保护继续要求 `e2e` 和 `all checks passed`。剩余的企业级 Linux 运行器标签无法分配运行器时没有自动后备机制:标准作业会继续报告各自的契约,但无法产出缺失的必需结果。 +3 项 Linux 主作业、Node 兼容性、Python SDK 和 `windows node 24 / complete` 继续作为 `all checks passed` 的依赖项;为恢复可用性,没有移除任何门禁,也没有将任何门禁改为仅供观测。分支保护继续要求 `e2e` 和 `all checks passed`。 -当前主拓扑及其测量结果由[大型运行器决策](2026-07-22-evidence-based-larger-hosted-runners.md)记录。[跨平台串行参考流程](2026-07-21-serial-cross-platform-ci-reference.md)继续作为独立的标准托管完整性检查,手动大型运行器套件则保留规格比较,同时不扩大普通必需矩阵。 +保留的性能测量结果与手动套件由[大型运行器决策](2026-07-22-evidence-based-larger-hosted-runners.md)记录。[跨平台串行参考流程](2026-07-21-serial-cross-platform-ci-reference.md)继续作为独立的标准托管完整性检查。 ## 曾考虑的替代方案 -**将 Linux 主作业和聚合流程保留在标准容量上。** 此方案消除了剩余的企业级运行器分配依赖,但标准运行器上的完整作业反馈明显更慢,仍会遇到共享容量排队。当前拆分既保留可移植兼容性和串行证据,又将企业级运行器容量用于 Linux 主关键路径。 +**等待企业级运行器分配恢复。** 未分配运行器的队列不会发出任何仓库诊断,并且可能无限期阻塞所有拉取请求,因此外部恢复不能作为正确性路径。 -**根据标称核心数选择企业规格。** 基准测试表明扩展效果不呈单调变化,设置耗时也存在波动,因此必需运行器池改由完整作业的精确测量结果选定。 +**仅使用最小的企业级运行器池。** 无论指定哪个运行器池,都要经过同一个企业级分配边界;减少核心数并不能消除导致排队的依赖。 **在容量不可用时跳过检查或降低其级别。** 这种方式通过丢弃证据而非执行仓库的必需契约来使状态变绿。 -**在每台主机上使用同一工作线程策略。** 外层门禁并发与内层工具工作线程在 Linux、Windows 和标准运行器上的争用方式不同;按主机实测的上限可以避免新增核心反而拖慢执行。 +**在标准运行器上沿用大型运行器的工作线程上限。** 并发运行的仓库门禁及其内部工作线程池,可能让并发需求超过较小的内存和 CPU 配额,使可用性修复反而引发资源争用故障。 ## 后果 -普通拉取请求会将企业级运行器容量用于 Linux 关键路径,而标准托管 Windows 作业则以更长的运行时间换取不依赖企业池的运行器分配。一次实际的分支头精确运行能够证明分支保护使用的同一组命令;排队延迟与每个作业从 `startedAt` 到 `completedAt` 的执行区间分开报告。 +普通拉取请求无需企业专用配置,即可为每项实质性作业获得运行器。一次实际的分支头精确运行能够证明分支保护使用的同一组命令,代价是在较小主机上耗时更长。 -企业级运行器分配能力下降时,标准兼容性作业和必需的 Windows 作业仍能提供有用证据,但无法让受阻的必需 Linux 作业或聚合流程变绿。恢复 Linux 可用性时,可能需要恢复完整的标准托管拓扑;仅改变运行器池定义的状态,不足以证明它可以接收作业。 +手动大型运行器基准测试即使持续排队,也不会阻塞拉取请求。只有在分支头精确作业获得非零运行器 ID 并稳定完成后,才能另行作出基于证据的决策,将大型运行器恢复到必需路径;仅改变运行器池定义的状态仍然不够。 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f02d30a563..dd49680c6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,15 +27,15 @@ env: jobs: - # Three enterprise jobs isolate coverage, static analysis, and the + # Three standard Linux jobs isolate coverage, static analysis, and the # build-backed consumer tail. The static job publishes its exact build so # consumers do not repeat the longest part of their critical path. node-24: if: github.event_name == 'pull_request' - runs-on: dsh-enterprise-ubuntu-latest-32core-test + runs-on: ubuntu-latest name: node 24 / static env: - DSH_GATE_CONCURRENCY: '8' + DSH_GATE_CONCURRENCY: '1' steps: # Fetch complete history so the archive gate can read the trusted PR base from a reused shallow checkout. - uses: actions/checkout@v6 @@ -81,11 +81,11 @@ jobs: node-24-coverage: if: github.event_name == 'pull_request' - runs-on: dsh-enterprise-ubuntu-24-04-32core-test + runs-on: ubuntu-latest name: node 24 / coverage env: - DSH_COVERAGE_MAX_WORKERS: '24' - DSH_GATE_CONCURRENCY: '8' + DSH_COVERAGE_MAX_WORKERS: '1' + DSH_GATE_CONCURRENCY: '1' steps: - uses: actions/checkout@v6 with: @@ -122,15 +122,15 @@ jobs: node-24-consumers: needs: node-24 if: github.event_name == 'pull_request' - runs-on: dsh-enterprise-ubuntu-latest-32core-test + runs-on: ubuntu-latest name: node 24 / snapshots and artifacts env: DSH_ESLINT_CACHE: '1' - DSH_ESLINT_CONCURRENCY: '8' - DSH_GATE_CONCURRENCY: '8' + DSH_ESLINT_CONCURRENCY: '1' + DSH_GATE_CONCURRENCY: '1' DSH_NODE_COMPAT_SKIP_TYPECHECK: '1' - DSH_PUBLINT_CONCURRENCY: '8' - DSH_SNAPSHOT_MAX_CONCURRENCY: '32' + DSH_PUBLINT_CONCURRENCY: '1' + DSH_SNAPSHOT_MAX_CONCURRENCY: '1' steps: - uses: actions/checkout@v6 with: