Repository navigation
Commit df6dac8
fix(ci): merge-queue-triage stacksFor() walks the stack through green queue groups (#26294)
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi9KyXC7PqZzbzLfU36Sd9Xoo)_
Fixes #26265
Clause-②: no
Metadata-protocol: none
⛔ **Tier H (governed: `.github/workflows/**`).** This PR stays a draft.
Landing waits for an approved review from a `GOVERNED_APPROVERS`
account; no seat readies it, queues it or arms auto-merge.
## What changed
`stacksFor()` in `.github/workflows/merge-queue-triage.yml` used to
union two victims only when one victim's queue base was another victim's
queue head. A victim stacked on another victim **through green,
non-victim queue groups** therefore read as an independent hit. On
#26247 that turned one deterministic break (#26064's queued commit) into
"2 independent hits".
- **The walk.** From each victim's base, `stacksFor()` now walks base to
head through every `merge_group` run already indexed in `stackEdges`
(green groups included). It unions with any other victim whose head the
chain reaches. The index was already in hand, so this adds no API calls.
- **The two rules from before are unchanged.** Matching is still
full-sha equality only (no prefixes, no time ordering). A victim whose
own run is missing from the index is still counted as independent and
still counts toward `unresolved`.
- **Loops.** The walk keeps a `visited` set, so a loop in the index ends
the walk instead of hanging the job.
- **Anchor prose.** The anchor's "Queue depth is not evidence" paragraph
now says the chain may pass through green groups. The reading guidance
gains one line: a later queue build that went green on the same `main`
is a control only if its affected-only selection ran the failing
package.
- **Harness** (`scripts/check-merge-queue-triage-outcome.mjs`):
- New scenario **A18** re-scores the #26247 chain: victim #26064 ← green
#26158 ← green #26210 ← victim #26198. Expected: 2 PRs, **1 independent
hit**, #26064 as root and #26198 as inherited. It also carries a two-run
loop behind main's tip, which the walk must end on and must not fuse.
- New mutation **M29** stops the walk at its first hop. A18 must go red,
and A12 and A13 must stay green as controls.
- M16's anchor moved to the new lookup line.
- `queueRun()` takes an optional `conclusion`, so green groups are
spelled `success`.
## Evidence
- **Red before the fix.** Commit `f6efe203` adds A18 on top of
`origin/main` `be531f68`, with the workflow unchanged. `node
scripts/check-merge-queue-triage-outcome.mjs` exits 1 with 4 failed
assertions, all A18. The anchor reads `**2 pull requests** … **2
independent hits**`, and both rows show `independent`.
- **Green after the fix** (head `4394d310`):
- `node scripts/check-merge-queue-triage-outcome.mjs` exits 0: `OK (141
assertions over 35 scenarios …)`.
- `node scripts/check-merge-queue-triage-outcome.mjs --self-test` exits
0: `187 assertions, 33 mutations of the shipped script each driven to
red`. On main this was 34 scenarios and 32 mutations; every original
scenario is unchanged and still green.
## Gates
Local subset, measured at head `4394d310`:
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives **51 commands** for this diff (2
paths, +127/-19 changed lines, under the 3000-line threshold).
- **All 51 ran, and all 51 exited 0.** Each exit code was captured
before any pipe, with stdin set to `/dev/null`. That includes
`check-merge-queue-triage-outcome` with and without `--self-test`,
`check:nul-bytes`, `check:self-test-wired`,
`check:workflow-step-name-quoting`, `check:pm-governed-merges` and
`check:pm-dispatch-gates` (fast tier: 1899 cases, 575 s).
- `dispatch-gates --ran` reports: `51 derived, 51 run, 0 NOT-MEASURED, 0
UNRUN`. That zero is derived from the recorded exit codes.
- **Not measured locally:**
- 7 derived families take a value from the workflow (the
shard-attestation and test-completeness argvs, `--verify-required-set`)
and have no local invocation.
- The path-scheduled `Test Core` job and the type-check lanes run only
in CI.
- CI on this PR is the reading for all of these.
- **No package touched.** No build or typecheck is owed, and no dogfood
(the title has no `!` and there is no `(narrowing)` arm).
- **Changeset:** `skip-changeset`. This changes in-repo tooling only and
publishes nothing.
## Acceptance notes
- **The walk also passes through landed history.** A victim's base is
usually `main`'s tip, which is itself the head of the queue group that
landed it, so the walk keeps going into landed groups inside the 24 h
window. That fuses nothing as long as no victim's head ever landed. One
case can break that. A CI run that is red only on advisory
(non-required) jobs still lands. Its head then sits on `main`, and every
later victim with the same key would be read as stacked on it. The old
one-hop test already had this exposure for the PR directly behind such a
landing; the walk widens it to the rest of the window. I'm noting it
here rather than filing it: it is an inference from reading the code,
and no real queue run has been seen in that state. No owner is assigned.
- `stackEdges` is still not narrowed to the CI workflow, as before.
Other workflows' `merge_group` runs on the same commit share its base
and head, so they add the same edge twice and can never add a wrong one.
## 维护者速读(草稿)
- **改了什么**:合并队列分诊工作流里判断「两个被弹出的 PR
是否同一条投机栈」的函数,现在会沿着窗口内所有队列构建(包括中间变绿、没被弹出的那几组)从 base 一路追到 head,追到另一个被弹出 PR
的 head 就算同一栈。原来只看相邻一跳。锚卡阅读指引加了一句:同一 main 上后来变绿的队列构建,只有它的 affected-only
选择真跑到了失败包,才算对照。
- **为什么改**:#26247 上,一次确定性的断裂(#26064 排队提交)被读成了「2 次独立命中」,差点被当成 flaky
交给错的人。原因是中间两组队列构建没选中失败包所以是绿的,旧算法在那里断了链。
- **风险与代价(含回滚)**:只影响锚卡与分诊评论里「独立命中」的计数和 stack 列,不改触发条件(仍是 ≥2 个 PR
就立锚),不重排、不打标签、不碰任何门禁。不多调 API。可能的偏差方向见 Acceptance notes 第一条(非必需 job
红但落地的构建会让之后同签名的弹出被算成同栈)。回滚就是 revert 本 PR。
- **席位意见**:
- **你要做的**:审阅后用 GOVERNED_APPROVERS 账号批准;批准后由席位落地。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01TB4mXrHF2oa5RXawpKD7Rj)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent ab4e30a commit df6dac8
2 files changed
Lines changed: 127 additions & 19 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
554 | 554 | | |
555 | 555 | | |
556 | 556 | | |
557 | | - | |
558 | | - | |
559 | | - | |
560 | | - | |
561 | | - | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
562 | 570 | | |
563 | 571 | | |
564 | 572 | | |
| |||
582 | 590 | | |
583 | 591 | | |
584 | 592 | | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
585 | 601 | | |
586 | 602 | | |
587 | 603 | | |
| |||
590 | 606 | | |
591 | 607 | | |
592 | 608 | | |
593 | | - | |
594 | | - | |
595 | | - | |
596 | | - | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
597 | 621 | | |
598 | 622 | | |
599 | 623 | | |
| |||
839 | 863 | | |
840 | 864 | | |
841 | 865 | | |
842 | | - | |
843 | | - | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
844 | 869 | | |
845 | 870 | | |
846 | 871 | | |
| |||
867 | 892 | | |
868 | 893 | | |
869 | 894 | | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
870 | 899 | | |
871 | 900 | | |
872 | 901 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
126 | | - | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
127 | 129 | | |
128 | 130 | | |
129 | 131 | | |
| |||
567 | 569 | | |
568 | 570 | | |
569 | 571 | | |
570 | | - | |
571 | | - | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
572 | 575 | | |
573 | | - | |
| 576 | + | |
574 | 577 | | |
575 | 578 | | |
576 | | - | |
| 579 | + | |
577 | 580 | | |
578 | 581 | | |
579 | 582 | | |
| |||
596 | 599 | | |
597 | 600 | | |
598 | 601 | | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
599 | 620 | | |
600 | 621 | | |
601 | 622 | | |
| |||
1078 | 1099 | | |
1079 | 1100 | | |
1080 | 1101 | | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
| 1135 | + | |
| 1136 | + | |
| 1137 | + | |
| 1138 | + | |
| 1139 | + | |
| 1140 | + | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
1081 | 1148 | | |
1082 | 1149 | | |
1083 | 1150 | | |
| |||
1659 | 1726 | | |
1660 | 1727 | | |
1661 | 1728 | | |
1662 | | - | |
1663 | | - | |
| 1729 | + | |
| 1730 | + | |
1664 | 1731 | | |
1665 | 1732 | | |
1666 | 1733 | | |
| |||
1679 | 1746 | | |
1680 | 1747 | | |
1681 | 1748 | | |
| 1749 | + | |
| 1750 | + | |
| 1751 | + | |
| 1752 | + | |
| 1753 | + | |
| 1754 | + | |
| 1755 | + | |
| 1756 | + | |
| 1757 | + | |
| 1758 | + | |
| 1759 | + | |
| 1760 | + | |
1682 | 1761 | | |
1683 | 1762 | | |
1684 | 1763 | | |
| |||
0 commit comments