Skip to content

Commit a6b0fd1

Browse files
os-steveclaude
andauthored
merge-queue triage: excerpt the failure REASON, and aggregate same-signature ejections into one anchor issue (#10140)
* feat(ci): merge-queue triage excerpts the failure REASON, and aggregates same-signature ejections into one anchor issue Two limbs on the #4859 merge-queue-triage bot, plus the gate that exercises it. Limb 1 — the excerpt now prints the deciding line beside the FAIL line. A timeout and an assertion produce byte-identical FAIL lines and opposite diagnoses; on 2026-08-20 that ambiguity produced a confidently wrong card (#10112) and cost a full dispatch to falsify. Limb 2 — each ejection is keyed by the failing test file path and records the sighting in its own comment. When one key has ejected >= 2 distinct PRs inside 24h the bot files ONE anchor issue for it, or refreshes the open one, and links it from every later victim's comment. The bot still decides nothing: no requeue, no quarantine, no label on anybody's PR. Also: the cross marks in the FAIL matcher must now sit at line start, so a multiplication sign inside a test TITLE stops spending excerpt budget. Fixes #10128 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja * fix(ci): a line reported as a failure reason is not excerpted twice `AssertionError` qualifies under both the FAIL matcher and the reason matcher, so without a consumed-line guard the assertion case reports every failure twice and spends half the excerpt budget saying the same thing. Measured on the real captured assertion log: 12 excerpt lines before, 9 after. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 5a2ce6c commit a6b0fd1

7 files changed

Lines changed: 1709 additions & 19 deletions

File tree

.github/workflows/lint.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,46 @@ jobs:
10431043
node scripts/check-cross-repo-closer-outcome.mjs --self-test
10441044
node scripts/check-cross-repo-closer-outcome.mjs
10451045
1046+
# Merge-queue triage outcome contract (#10128, over the #4859 bot).
1047+
# merge-queue-triage.yml carries ~450 lines of inline github-script that
1048+
# only ever runs on a RED merge_group build — a condition nobody can
1049+
# produce on demand, so its two 2026-08-20 limbs would otherwise be
1050+
# unexercised code. This step is the exercise, on the same method as the
1051+
# cross-repo closer step above: the shipped script is extracted from the
1052+
# YAML with a real parser (never retyped) and run under doubles the way
1053+
# actions/github-script runs it, as one AsyncFunction body. No network.
1054+
#
1055+
# What it holds: (1) the excerpt names the failure REASON beside the FAIL
1056+
# line, driven against REAL captured vitest logs of the incident's own
1057+
# test file — one timeout, one assertion, byte-identical FAIL lines and
1058+
# opposite diagnoses, which is the confusion that produced a confidently
1059+
# wrong card (#10112) and cost a whole dispatch; and (2) the cross-PR
1060+
# aggregation files exactly ONE anchor issue at >= 2 DISTINCT PRs,
1061+
# REFRESHES it on the next ejection instead of filing a second, and files
1062+
# none for two different keys or for one PR ejecting twice. The refresh
1063+
# leg is driven as a PAIR — run 2's world is built from run 1's output —
1064+
# because idempotency is a property of the pair and a hand-written marker
1065+
# would prove each half while leaving the two runs free to disagree.
1066+
#
1067+
# Its --self-test runs first and is the half that stops the battery
1068+
# rotting into decoration: it mutates the shipped script fourteen ways —
1069+
# drop the reason lookahead, test the FAIL pattern before the reason
1070+
# pattern (which silently loses every assertion), count runs instead of
1071+
# distinct PRs, always create instead of refreshing, drop the sighting
1072+
# markers, downgrade each anti-no-op announcement to an info line, and
1073+
# more — and requires the battery to go RED for each, naming the scenario
1074+
# that catches it. A mutation whose anchor no longer exists is a failure
1075+
# too, so a rewrite of the workflow cannot leave the mutations silently
1076+
# matching nothing.
1077+
#
1078+
# Invoked as `node` rather than through a `pnpm check:*` alias, same
1079+
# reason as the step above: root package.json is declared territory of
1080+
# the @changesets/cli v3 migration lane (#9465) while it runs.
1081+
- name: Merge-queue triage outcome contract
1082+
run: |
1083+
node scripts/check-merge-queue-triage-outcome.mjs --self-test
1084+
node scripts/check-merge-queue-triage-outcome.mjs
1085+
10461086
# Shard positive-attestation gate (#6082). ci.yml's two aggregate gates
10471087
# used to decide from one `needs.<matrix>.result` word, which cannot carry
10481088
# three shards' verdicts: run 31120902911 read the undocumented

.github/workflows/merge-queue-triage.yml

Lines changed: 346 additions & 19 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)