ci: keep required status aggregator portable

This commit is contained in:
Tianyi Cui
2026-07-27 14:05:32 +08:00
parent 79eb3a9035
commit 7ca13198de
4 changed files with 78 additions and 2 deletions

View File

@@ -0,0 +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 .agents/notes/implemented/process/2026-07-27-portable-required-status-aggregation.md
2026-07-27-portable-required-status-aggregation.md: 081d841cfb939c97f189c46fc0985f9ff2d1987d
2026-07-27-portable-required-status-aggregation.zh.md: 896e9500d2ad6e2e0ef6c6cc7a37373c6d28b303

View File

@@ -0,0 +1,35 @@
# Agent Note: Portable required-status aggregation
Status: implemented
English | [中文](2026-07-27-portable-required-status-aggregation.zh.md)
## Problem
Branch protection consumes one stable `all checks passed` job instead of tracking the changing names of matrix legs and execution lanes. This job performs no repository work: after its blocking dependencies finish, it only reduces their results into the required verdict.
Assigning that bookkeeping job to a custom runner pool adds an external allocation dependency without using the pool's additional CPU or memory. A provisioning failure can therefore leave the final required status queued even after every substantive check has produced its evidence.
## Decision
The `all-checks-passed` job in [CI](../../../../.github/workflows/ci.yml) runs on standard GitHub-hosted `ubuntu-latest`. It keeps every blocking job in `needs`, retains its load-bearing `if: always()` condition, fails when any dependency is failed, cancelled, or skipped, and succeeds only when every dependency succeeds. It performs no checkout, toolchain setup, dependency installation, or repository gate.
The aggregate depends only on production standard-hosted capacity; it does not use organization-defined, enterprise-defined, or self-hosted labels. Substantive jobs choose their own runner topology independently. Moving this verdict does not change their commands, weaken their evidence, or make an unresolved dependency pass: the aggregate waits for unfinished dependencies and fails on non-success terminal results.
This decision supersedes only the aggregate-placement clause in the [portable pull-request CI recovery boundary](2026-07-23-portable-required-pull-request-ci.md), which continues to own the substantive jobs' recovery topology. The final bookkeeping status remains separately owned so runner-topology changes and branch-protection aggregation can evolve independently.
## Alternatives considered
**Run the aggregate beside substantive jobs on a custom enterprise pool.** This avoids one short standard-hosted allocation, but gives the bookkeeping job a provisioning failure mode without using the larger machine's capacity.
**Use a standby self-hosted runner.** This replaces one external readiness dependency with another and makes a required verdict depend on a separately operated machine. Managed standard-hosted capacity is the production path for this bookkeeping work.
**Require every substantive job directly in branch protection.** This removes the aggregate allocation, but couples repository settings to matrix and lane names that change as the CI topology evolves.
**Treat missing or non-success dependencies as success.** This would produce a green status by discarding required evidence rather than by completing it.
## Consequences
Each pull request allocates one short standard-hosted job after its substantive dependencies settle. Because the job performs no checkout or setup, it adds little active runtime, but its scheduling and billing remain separate from custom pools.
A custom-pool outage can still keep a substantive dependency queued, and the aggregate correctly waits in that case. Once the dependencies reach terminal results, the final required verdict no longer needs custom-pool or self-hosted allocation. Future changes can move substantive jobs between standard and larger runners without reintroducing that dependency into the branch-protection status.

View File

@@ -0,0 +1,35 @@
# Agent Note: 必需状态的可移植聚合
Status: implemented
[English](2026-07-27-portable-required-status-aggregation.md) | 中文
## 问题
分支保护只使用一项稳定的 `all checks passed` 作业,无需跟踪持续变化的矩阵分支名和执行通道名。该作业不执行任何仓库工作:会阻塞判定的依赖项结束后,它只将这些依赖项的结果归并为必需判定。
将这项结果汇总作业分配给自定义运行器池,会在不使用该池额外 CPU 或内存的情况下增加一项外部运行器分配依赖。因此,即使所有实质性检查都已产出证据,预配失败仍可能让最终的必需状态持续排队。
## 决策
[CI](../../../../.github/workflows/ci.yml) 中的 `all-checks-passed` 作业在 GitHub 标准托管的 `ubuntu-latest` 上运行。它在 `needs` 中保留所有会阻塞判定的作业,保留承重的 `if: always()` 条件;任何依赖项失败、被取消或被跳过时,该作业都会失败,只有所有依赖项都成功时才会成功。它不执行代码检出、工具链设置、依赖安装或仓库门禁。
聚合作业只依赖生产环境的标准托管容量;它不使用组织定义的、企业定义的或自托管的运行器标签。实质性作业各自独立选择运行器拓扑。调整这项判定作业的运行位置,不会改变实质性作业的命令、削弱其证据或使未完成的依赖项通过:聚合作业会等待尚未结束的依赖项,并在依赖项产生非成功的终态结果时失败。
本决策仅取代[拉取请求 CI 的可移植恢复边界](2026-07-23-portable-required-pull-request-ci.md)中关于聚合作业运行位置的条款;该记录继续规定实质性作业的恢复拓扑。最终的结果汇总状态仍由本决策单独规定,使运行器拓扑变更与分支保护聚合可以独立演进。
## 曾考虑的替代方案
**让聚合作业与实质性作业一同在自定义企业级运行器池上运行。** 此方案可以避免一次短暂的标准托管运行器分配,但会在未使用大型机器容量的情况下,为结果汇总作业引入预配失败的故障模式。
**使用备用自托管运行器。** 此方案只是用另一项外就绪状态依赖替换原有依赖,并使必需判定依赖一台单独运维的机器。由平台管理的标准托管容量是这项结果汇总工作的生产路径。
**在分支保护中直接要求每项实质性作业。** 此方案不再需要为聚合作业分配运行器,但会将仓库设置与随 CI 拓扑演进而变化的矩阵分支名和通道名耦合。
**将缺失或非成功的依赖项视为成功。** 这种做法不是通过完成相应检查来产出必需证据,而是丢弃这些证据以产出绿色状态。
## 后果
每个拉取请求都会在实质性依赖项的结果确定后分配一项短时运行的标准托管作业。由于该作业不执行代码检出或设置,它只增加少量活跃运行时间,但其调度和计费仍独立于自定义运行器池。
自定义运行器池不可用仍可能让实质性依赖项持续排队,聚合作业在这种情况下会按设计等待。依赖项产生终态结果后,最终的必需判定不再需要自定义运行器池或自托管运行器分配。未来可以在标准运行器与大型运行器之间迁移实质性作业,而不会将这项依赖重新引入分支保护状态。

View File

@@ -693,8 +693,8 @@ jobs:
# 'cancelled' and 'skipped'.
all-checks-passed:
name: all checks passed
# The required verdict must not add a separate standard-hosted billing dependency.
runs-on: dsh-enterprise-ubuntu-latest-32core-test
# This bookkeeping-only verdict must not depend on custom-pool provisioning.
runs-on: ubuntu-latest
needs: [node-24, node-24-coverage, node-24-consumers, node-compat, python-sdk, windows]
if: always() && github.event_name == 'pull_request'
steps: