Skip to content

ci(ui-merge): queue builds decide the four ui lanes from the merged diff against merge_group.base_sha - #25881

Merged
os-zhuang merged 2 commits into
mainfrom
claude/project-thread-8dceid
Oct 26, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/project-thread-8dceid

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #25867
Part of #25677 (post-cutover CI speed, item 1).

Clause-②: no
Metadata-protocol: none

What changed

ci.yml filter job, nothing else in the workflow:

  • The dorny/paths-filter step's allow-list gains merge_group. At the pinned v4.0.3 (ceb8a2b8) the action resolves that event itself: src/main.ts takes merge_group.base_sha / merge_group.head_sha from the payload when base / ref are unset, and src/git.ts fetches the base sha at depth 1 and diffs the two trees (base..head). So the queue build reads the same filter block, with the same globs, as the pull_request run. There is no second copy of the globs to keep in step.
  • On merge_group the step is continue-on-error, so a base that cannot be fetched leaves the outputs empty, || 'true' fills them in and every ui lane runs (fail-open). On pull_request / push a failure stays red, as before.
  • docs, core and crosspkg ignore the step on merge_group: they are spelled github.event_name != 'merge_group' && steps.changes.outputs.X || 'true', so Build Core, Build Docs and Test Core keep running on every queue entry exactly as today. Only ui and ui_consumers read the queue diff.
  • schedule / workflow_dispatch still skip the step and widen everything to 'true' (full battery, ruling Q6-b). push is unchanged.

The four ui lanes' if: lines are untouched.

scripts/pm/check-expected-skips.mjs: the header and the four ui roster reasons now say that a queue build skips the ui lanes when the merged diff touches no ui path, rather than "every output widens to 'true' on merge_group". scripts/pm/dispatch-gates.self-test.mjs: the marker-census row for that file moves 133 to 137 (the header grew four lines).

Resulting outputs per event (step value, then output):

event step ui ui step core core
pull_request / push from the diff as the step said from the diff as the step said
merge_group from base_sha..head_sha as the step said ignored 'true'
merge_group, step failed empty 'true' ignored 'true'
schedule / workflow_dispatch step skipped 'true' step skipped 'true'

Verification

Replayed the pinned action's dist/index.js locally with a synthetic merge_group event payload (GITHUB_EVENT_NAME=merge_group, base_sha / head_sha set, INPUT_FILTERS = the filter block read out of this branch's ci.yml):

entry base..head ui ui_consumers ui lanes
.claude/ + scripts/ only (abebc4e) 17f8217..abebc4e false false all four skip
spec + lint (b00fc55) abebc4e..b00fc55 false true Type Check UI and Build & E2E UI run; Test UI and Lint UI skip
ui/ scripts (1210544) 3fca599..1210544 true false all four run
three-commit group, ui + scripts 3fca599..c475b45 true false all four run
depth-1 checkout, base absent locally 1210544..5aa9fcb true false the action fetched the base by sha at depth 1, then diffed
unfetchable base 000…001..c475b45 (none) (none) action exits 1 with no outputs; with continue-on-error the 'true' fallback runs all four

This PR's own queue entry changes ci.yml, which is in the ui filter, so it runs all four ui lanes. The first non-ui entry after it lands is the live evidence the card asks for (four ui lanes skipped, Lint UI and Build & E2E UI reported as skipped, which a required check accepts). It will be posted on #25867.

Local gates at head be2cff5e: node scripts/pm/dispatch-gates.mjs --commands derives 67 commands; all 67 exit 0, and --ran reconciles 67 derived, 67 run, 0 NOT-MEASURED (a derived zero: every row carries its exit code). That includes check:pm-dispatch-gates (fast tier, 1917 cases) and the four dist/-reading Build Core guards, which ran after that battery's build. The gates the card names: check-ci-filter-parity (scan and --self-test), check:pm-expected-skips, check-step-collectors (scan and --self-test) all exit 0. The only failure on the way was the dispatch-gates marker census pinning check-expected-skips.mjs:133, fixed in the second commit.

Acceptance notes

  • Route differs from the card's wording: the card says git diff --name-only with the same globs. Running the action itself on the event gives the same globs by construction and keeps check-ci-filter-parity's one-step rule intact.
  • docs / core / crosspkg could read the queue diff the same way (Build Core and Build Docs would then skip on queue entries outside their paths). Not done here: the card scopes the ui outputs only, and the filter comment's "the queue build is the last validation before main" reasoning still governs those jobs. Carrier: none.

维护者速读(草稿)

改了什么: 合并队列里,ui 的四个作业(Test UI、Type Check UI、Build & E2E UI、Lint UI)改成按"这批改动相对队列基点到底动没动 ui"来决定跑不跑。判定用的是 PR 上同一套路径规则。core、docs 那几个作业在队列里照旧全跑。

为什么改: 合并 ui 之后,每个排队条目都会把四个 ui 作业跑一遍,哪怕只改了文档或脚本。小条目从 4–10 分钟变成 16–18 分钟,每条多花约 220 runner-min。

风险与代价(含回滚): 判定失败(比如取不到基点)时按"全跑"处理,不会因此漏跑。动了 ui 或那七个被 ui 使用的包,队列里照样会跑 ui 作业。回滚只需 revert 这一个 PR。

席位意见:

你要做的: 这个 PR 改了 .github/workflows/ci.yml,属于 Tier H,需要你批准后由席位落地。落地后第一个非 ui 条目进队时,席位会在 #25867 贴出前后耗时对比。


Generated by Claude Code

…iff against merge_group.base_sha

On merge_group the paths-filter step was skipped and the ui / ui_consumers
outputs fell back to 'true', so every queue entry ran Test UI, Type Check
UI, Build & E2E UI and Lint UI, docs-only entries included. dorny/paths-filter
v4.0.3 resolves merge_group itself (payload base_sha vs head_sha), so the
step now runs on that event too, continue-on-error there so a failed diff
fails open to 'true'. docs / core / crosspkg ignore the step on merge_group
and stay 'true', as before. schedule and workflow_dispatch are unchanged.

check-expected-skips' header and ui roster reasons now say what the queue
build does for the ui family.

Claude-Session: https://claude.ai/code/session_01Suqt7vsGh5kE2NhDZyqeh6
Co-authored-by: Claude <noreply@anthropic.com>
…ps' declaration to line 137

The header paragraph on the ui jobs' queue-diff outputs moved the
self-test-reads declaration down four lines.

Claude-Session: https://claude.ai/code/session_01Suqt7vsGh5kE2NhDZyqeh6
Co-authored-by: Claude <noreply@anthropic.com>
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit 487056b Oct 26, 2026
65 of 66 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-8dceid branch October 26, 2026 03:27
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 40263232770 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Test UI (11/16) — 失败步骤: Run the ui tests (shard 11/16)

    × finds no pre-install gate reaching a package 6ms
    FAIL   unit  scripts/__tests__/check-pre-install-import-graph.test.ts > the real tree — every step objectui#6148 measured is still derived > finds no pre-install gate reaching a package
      ↳ 失败原因: AssertionError: a script this repository runs before `pnpm install` needs `node_modules` to load: expected [ Array(1) ] to deeply equal []
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 11 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants