From f34259923efcc5dced7082294d69caa2975d6f30 Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Thu, 3 Sep 2026 15:23:43 -0500 Subject: [PATCH 1/3] docs(backlog): correct #340's merge-queue record and the four workflow comments that call the trigger inert (BACKLOG #340) The item says half B is unbuilt and the queue does not exist. Both are false at HEAD, and a peer's PR merged through the queue the item denies. Measured at 2b8bccb4 on the indented trigger KEY, not the bare string: six of twenty-seven files under .github/workflows/ carry merge_group, against a control of thirteen carrying an indented pull_request key. The bare string returns seven, because failure-signal.yml reads a merge_group ref without triggering on it. repository.mergeQueue is non-null and PR 754 merged through the queue. The item STAYS OPEN. The correction records state, not authorisation: the 2026-08-14 amendment rules that half B must not be built speculatively, no later amendment retracts it, and who enabled the queue is recorded nowhere. Superseded claims are marked in place rather than overwritten, per the file's convention. The workflow comments were the more corrosive half. Four files, not the two first noticed, told the next reader "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today" while those triggers now govern the merge path. cla.yml also records the measured option (i) shape: its CLA Assistant step is skipped on merge_group and the job still reports cla success. Whether that green is merely decorative is recorded as UNESTABLISHED, not guessed. No trigger was removed, narrowed or disabled. Co-Authored-By: Claude Opus 5 --- .github/workflows/backlog-hygiene.yml | 22 +++++++++++++----- .github/workflows/ci.yml | 16 +++++++++----- .github/workflows/cla.yml | 32 ++++++++++++++++++++++----- .github/workflows/security.yml | 16 +++++++++----- docs/BACKLOG.md | 13 ++++++++--- 5 files changed, 76 insertions(+), 23 deletions(-) diff --git a/.github/workflows/backlog-hygiene.yml b/.github/workflows/backlog-hygiene.yml index fcaeaaa29..590998e3e 100644 --- a/.github/workflows/backlog-hygiene.yml +++ b/.github/workflows/backlog-hygiene.yml @@ -28,11 +28,23 @@ name: backlog-hygiene on: - # BACKLOG #340 step 1. INERT UNTIL A MERGE QUEUE EXISTS: with no queue configured GitHub never - # emits merge_group, so this workflow behaves identically today. It is added FIRST and separately - # because the failure mode of the reverse order is total -- enable a queue while a required - # context's workflow has no merge_group trigger and that check never reports in the queue, so - # NOTHING MERGES. + # BACKLOG #340 step 1. THE QUEUE IS LIVE, SO THIS TRIGGER IS LOAD-BEARING -- DO NOT REMOVE IT. + # This job's name is a REQUIRED context, and branch protection evaluates required contexts on the + # MERGE-GROUP commit, so removing this trigger means the context never reports in the queue and + # NOTHING MERGES. That is not hypothetical: codeql.yml's header records PR 619 sitting + # AWAITING_CHECKS on the queue's first entry with three contexts simply absent. + # + # WHAT THIS JOB CHECKS ON merge_group IS NOT WHAT IT CHECKS ON A PULL REQUEST. Its question -- + # "does THIS pull request update BACKLOG.md" -- has no subject in a merge group, where every + # `github.event.pull_request.*` field is null. The enforcement that matters therefore happens on + # the `pull_request` run; the queue-time run is what keeps the required context reporting. The + # concurrency note below is the other half of that story, and it was measured the hard way. + # + # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". + # That was true when the trigger landed on 2026-08-26 and became false once a queue was + # configured; corrected 2026-09-03, after PR 754 merged through the queue. BACKLOG #340 carries + # the measurements and STAYS OPEN -- a live queue is not that item being finished, and who + # enabled the queue is recorded nowhere. merge_group: pull_request: branches: [main] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad60a6bdc..b19c00016 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,11 +1,17 @@ name: CI on: - # BACKLOG #340 step 1. INERT UNTIL A MERGE QUEUE EXISTS: with no queue configured GitHub never - # emits merge_group, so this workflow behaves identically today. It is added FIRST and separately - # because the failure mode of the reverse order is total -- enable a queue while a required - # context's workflow has no merge_group trigger and that check never reports in the queue, so - # NOTHING MERGES. + # BACKLOG #340 step 1. THE QUEUE IS LIVE, SO THIS TRIGGER IS LOAD-BEARING -- DO NOT REMOVE IT. + # Branch protection evaluates required contexts on the MERGE-GROUP commit, so a required context + # whose workflow has no merge_group trigger never reports in the queue and NOTHING MERGES. That + # is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on the queue's + # first entry with three contexts simply absent. + # + # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". + # That was true when the trigger landed on 2026-08-26 and became false once a queue was + # configured; corrected 2026-09-03, after PR 754 merged through the queue. BACKLOG #340 carries + # the measurements and STAYS OPEN -- a live queue is not that item being finished, and who + # enabled the queue is recorded nowhere. merge_group: push: branches: [main] diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 18aa28f15..e55988059 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -12,11 +12,33 @@ name: CLA Assistant # See .github/required-contexts.txt. on: - # BACKLOG #340 step 1. INERT UNTIL A MERGE QUEUE EXISTS: with no queue configured GitHub never - # emits merge_group, so this workflow behaves identically today. It is added FIRST and separately - # because the failure mode of the reverse order is total -- enable a queue while a required - # context's workflow has no merge_group trigger and that check never reports in the queue, so - # NOTHING MERGES. + # BACKLOG #340 step 1. THE QUEUE IS LIVE, SO THIS TRIGGER IS LOAD-BEARING -- DO NOT REMOVE IT. + # `cla` is a REQUIRED context, and branch protection evaluates required contexts on the + # MERGE-GROUP commit, so removing this trigger means `cla` never reports in the queue and NOTHING + # MERGES. That is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on + # the queue's first entry with three contexts simply absent. + # + # THIS JOB'S GREEN MEANS TWO DIFFERENT THINGS UNDER ONE CONTEXT NAME, AND THE NAME CANNOT SHOW + # THE DIFFERENCE. The `CLA Assistant` step below is gated to the comment triggers and to + # `pull_request_target`, so on a merge_group event it is SKIPPED and the job still reports `cla` + # success. Measured 2026-09-03 on PR 754, a paired run on one change: run 33796353619 + # (pull_request_target) RAN the step, run 33797809984 (merge_group) SKIPPED it, and both jobs + # were green. That is BACKLOG #340's option (i), whose own 2026-08-14 amendment warns it + # manufactures a permanent green-that-means-not-applicable on the merge path -- the silent-control + # decay ADR 0158 names. + # + # WHETHER THAT QUEUE-TIME GREEN IS MERELY DECORATIVE IS UNESTABLISHED. DO NOT READ IT EITHER WAY. + # PR 754 did carry a green PR-time `cla` before it was queued (check-run success 19:25:55Z, the + # only `cla` among 41 check-runs on head 1e9f1cb3), which is consistent with the PR-time check + # being the one that does the work. But nobody has established that GitHub REQUIRES that PR-time + # green before an entry may join the queue, and no negative case was manufactured to find out. It + # is recorded as open on BACKLOG #340. Signing enforcement is NOT weakened by anything written + # here; it is also not proven by it. + # + # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". + # That was true when the trigger landed on 2026-08-26 and became false once a queue was + # configured; corrected 2026-09-03. BACKLOG #340 carries the measurements and STAYS OPEN -- a + # live queue is not that item being finished, and who enabled the queue is recorded nowhere. merge_group: issue_comment: types: [created] diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 6144c9335..a2fa58b2a 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -29,11 +29,17 @@ name: Security # who finds one paragraph of it demonstrably false has no way to tell which of the others still hold. # tests/test_security_posture.py refuses the return of a header claim that denies a declared trigger. on: - # BACKLOG #340 step 1. INERT UNTIL A MERGE QUEUE EXISTS: with no queue configured GitHub never - # emits merge_group, so this workflow behaves identically today. It is added FIRST and separately - # because the failure mode of the reverse order is total -- enable a queue while a required - # context's workflow has no merge_group trigger and that check never reports in the queue, so - # NOTHING MERGES. + # BACKLOG #340 step 1. THE QUEUE IS LIVE, SO THIS TRIGGER IS LOAD-BEARING -- DO NOT REMOVE IT. + # Branch protection evaluates required contexts on the MERGE-GROUP commit, so a required context + # whose workflow has no merge_group trigger never reports in the queue and NOTHING MERGES. That + # is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on the queue's + # first entry with three contexts simply absent. Seven of this file's jobs are required contexts. + # + # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". + # That was true when the trigger landed on 2026-08-26 and became false once a queue was + # configured; corrected 2026-09-03, after PR 754 merged through the queue. BACKLOG #340 carries + # the measurements and STAYS OPEN -- a live queue is not that item being finished, and who + # enabled the queue is recorded nowhere. merge_group: pull_request: # Post-merge re-scan (main only). A fork PR is scanned STRUCTURAL-ONLY by design -- the secret is diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 603526405..275df3254 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -3477,7 +3477,13 @@ Honestly bounded: **this is build-time only.** No PHI path, no running-engine su ## 340. Enable a GitHub merge queue: strict + no queue makes every merge a race that fails silently -> 🔢 **Re-scored 2026-08-20 -> DEMAND-GATE.** Value **6/10** · Difficulty **4/10** · _quick win_. Zero of the 24 workflow files carries a merge_group trigger, verified with a positive control (18 files match pull_request), so half B is entirely unbuilt and step 1 taken first would wedge every open PR. Value 6 is the awkward-workaround rung, with gh pr update-branch exercised and scripts/ci/check_stalled_prs.py already reporting the stalled set; difficulty 4 prices the actual remainder -- merge_group triggers on the four required-context workflows, two short-circuit shims, and the paired pinning-test edit -- none of which goes through mypy or a store backend. _(was 6/10 · 4/10.)_ +> 🔢 **RECORD CORRECTED 2026-09-03 -- HALF B IS BUILT, THE QUEUE IS LIVE, AND THE ITEM STAYS OPEN.** Every build-state claim below predates the queue; **at least** those marked `[SUPERSEDED 2026-09-03]` are false at HEAD. They are kept and marked rather than overwritten, so the decay stays visible, and the marked set is a floor rather than an enumeration. **Re-measured at `2b8bccb4` on the trigger KEY, not the string: SIX of TWENTY-SEVEN files under `.github/workflows/` carry an indented `merge_group:` trigger** -- `backlog-hygiene.yml:36`, `ci.yml:9`, `cla.yml:20`, `codeql.yml:45`, `review-gate.yml:58`, `security.yml:37` -- against a positive control of **THIRTEEN** files carrying an indented `pull_request:` key. **The instrument matters, and the superseded numbers show why:** a bare `grep -l merge_group` returns **seven**, because `failure-signal.yml` reads a merge_group ref without triggering on it, and `ci.yml` and `review-gate.yml` also carry `github.event_name == 'merge_group'` step guards. A bare `grep -l pull_request` returns **twenty-two** against the key's thirteen -- so the old control, *"18 files match pull_request"*, counted matches of a string while the claim it was guarding was about triggers. Half B landed 2026-08-26 in `080fb235b` (four workflows, PR 616) and `ccdd557b3` (`codeql.yml`, PR 629). +> +> **HALF A IS DONE TOO, AND RECORDING THAT IS NOT ENDORSING IT.** `repository.mergeQueue` is non-null -- `MQ_kwDOS5JJRs4AA9_8`, SQUASH, ALLGREEN, read from the GraphQL API on 2026-09-03 -- where the **What** section below still says it is null. The Actions API reports **1365** `merge_group` runs, and **PR 754 merged through the queue** at 2026-09-03T19:50:50Z with its five queue-time workflows green on `gh-readonly-queue/main/pr-754-c2237d78`. Required contexts are evaluated on the merge-group commit, and all sixteen reported on `2b8bccb4`, so these triggers now govern the merge path instead of sitting inert. The earliest queue entry the record names is PR 619 on 2026-08-27 (`codeql.yml`'s header). **WHO ENABLED THE QUEUE, AND WHEN, IS RECORDED NOWHERE** -- not in this item, not in an ADR, not in a commit -- and the 2026-08-14 amendment below **RULES** that half B must not be built speculatively, with no later amendment retracting it. That question is open and belongs to the owner. A live queue is not evidence that anyone authorised one. +> +> **STILL OPEN, WHICH IS WHY THIS IS A CORRECTION AND NOT A CLOSE.** Proposal 3 is undecided; `strict` still reads `true` on the server. And the amendment's option (i) is the shape that got built for `cla`. Measured 2026-09-03 on PR 754: the `CLA Assistant` step is gated to `pull_request_target`, so run `33796353619` (pull_request_target) RAN it and run `33797809984` (merge_group) SKIPPED it, and **both jobs reported `cla` success under the same context name**. That is the permanent green-that-means-not-applicable the amendment warned about, and the silent-control decay ADR 0158 names. **Whether it is merely decorative is UNESTABLISHED, and must not be guessed in either direction:** PR 754 did carry a green PR-time `cla` before it was queued (check-run success at 2026-09-03T19:25:55Z, exactly one `cla` among 41 check-runs on head `1e9f1cb3`), but nobody has established that GitHub REQUIRES that PR-time green before an entry may join the queue, and no negative case was manufactured to find out. +> +> 🔢 **Re-scored 2026-08-20 -> DEMAND-GATE.** Value **6/10** · Difficulty **4/10** · _quick win_. Zero of the 24 workflow files carries a merge_group trigger, verified with a positive control (18 files match pull_request), so half B is entirely unbuilt and step 1 taken first would wedge every open PR. **[SUPERSEDED 2026-09-03 -- false at HEAD; see the correction banner above. Six of twenty-seven files carry the trigger key and the queue is live. Kept because the sentence held its shape and lost its truth, and because its control counted string matches while its claim was about triggers.]** Value 6 is the awkward-workaround rung, with gh pr update-branch exercised and scripts/ci/check_stalled_prs.py already reporting the stalled set; difficulty 4 prices the actual remainder -- merge_group triggers on the four required-context workflows, two short-circuit shims, and the paired pinning-test edit -- none of which goes through mypy or a store backend. _(was 6/10 · 4/10.)_ > > **Filed 2026-08-01 — not started.** Build state confirmed: zero of the 21 files under `.github/workflows/` carries a `merge_group:` trigger, so difficulty 4 and the step-2-is-a-precondition reasoning are right. Value 8 is not. The rubric's `8` is "an ASVS L3 Partial on defaults, or a production blind spot with no workaround" — this is neither. It is a repo-workflow blind spot, and a workaround demonstrably exists and is exercised: `gh pr update-branch` (#74 landed via three merges from main, #119 landed via re-sync), plus a detector the project already BUILT for exactly this condition and which the item itself cites — `scripts/ci/check_stalled_prs.py` + `.github/workflows/stalled-prs.yml`. So the readiness signal is not in fact unfalsifiable from outside: a scheduled job reports the stalled set. That makes it "real gap, awkward workaround" = 6, one rung above the rubric's `4` for DX (the item's own cluster is Developer Experience & CI), and 6 is generous for a cluster the ladder caps at 4. At value 6, difficulty 4: quadrant stays quick win, but tier is P2 (P1 needs value >= 8, or value >= 6 at difficulty <= 2 — and this one is 4). _(was 8/10 · 3/10.)_ > **AMENDED 2026-08-14 (dispatcher, from a builder's pre-build read). THIS ITEM IS NOT BUILDABLE AS WRITTEN, AND THE OBSTACLE IS STRUCTURAL RATHER THAN AN OVERSIGHT. HELD PENDING AN OWNER DECISION -- see the fork at the end.** @@ -3491,6 +3497,7 @@ Honestly bounded: **this is build-time only.** No PHI path, no running-engine su > -- all null in a merge_group event. Its question ("does THIS PR update > BACKLOG.md") has no meaning for a merge group. > ``` +> **[SUPERSEDED 2026-09-03 -- the two-line block above is false at HEAD; see the correction banner. Both workflows now declare `merge_group:` (`cla.yml:20`, `backlog-hygiene.yml:36`) and both report in the queue. The amendment's REASONING survives its measurement: a merge group still has no pull request, so what changed is that each job now returns green with its PR-subject work skipped, which is option (i) below and not a refutation of the objection to it.]** > **SO ADDING `merge_group:` TO FOUR FILES PRODUCES A QUEUE THAT HANGS ON `cla` FOREVER** -- the **required-but-absent trap that `required-contexts.txt` documents in its own header**, and which this repo has already been bitten by. **Half B done naively creates the exact failure its own source of record warns about.** > **THE FORK, and it is an owner decision because every branch touches half A.** > - **(i) SHIM** -- give both workflows a `merge_group` trigger that short-circuits to success. **Delivers the queue, and manufactures a permanent green-that-means-not-applicable ON THE MERGE PATH.** Even written honestly -- the job stating in its own output that it is not-applicable and why -- **the honesty is not durable**: the next person to touch `cla.yml` inherits a job that reports success on `merge_group` and must re-derive why. That decay is the silent-control defect **ADR 0158** exists to name. @@ -3502,7 +3509,7 @@ Honestly bounded: **this is build-time only.** No PHI path, no running-engine su **Cluster:** Developer Experience & CI. **Priority:** P2. **Verdict:** build. **Severity:** medium. -**What:** branch protection on `main` sets `required_status_checks.strict = true` — a PR must be up to date with the base to merge — and the repo has **no merge queue** (`repository.mergeQueue` is null; `allow_auto_merge` is true). The slowest required leg runs ~20–25 minutes. Those three facts compose into a race: a PR is mergeable only in the window between its checks going green and the next thing landing on `main`. +**What:** branch protection on `main` sets `required_status_checks.strict = true` — a PR must be up to date with the base to merge — and the repo has **no merge queue** (`repository.mergeQueue` is null; `allow_auto_merge` is true). **[SUPERSEDED 2026-09-03: `repository.mergeQueue` is non-null and the queue is live -- see the correction banner. `strict` is still `true`, so the rest of this paragraph's mechanism still reads correctly for anything merging outside the queue.]** The slowest required leg runs ~20–25 minutes. Those three facts compose into a race: a PR is mergeable only in the window between its checks going green and the next thing landing on `main`. Losing that race is **silent**. Armed auto-merge does *not* update a `BEHIND` branch — it waits on checks that already passed — so the PR sits armed and stalled with no failing check, no notification, and no run in flight. Measured 2026-08-01: @@ -3540,7 +3547,7 @@ Two worked instances the same day. **#74** went green on 2026-07-30 and sat unme - The overnight run of eight merges was strictly serialized (min gap 26m06s, mean 35m16s over 7 gaps) — but **serialization is not evidence that hand coordination worked.** It is entailed by `strict = true` plus a full-suite cycle, human or no human. `strict` also does not always serialize: #110 and #111 merged **24 seconds apart** on 2026-08-01, #111's squash commit parented directly on #110's. That mechanism is **not established** — only the timestamps and the parentage are. - A queue does not shorten the suite. It reorders the same cycles; the wall-clock bounds tracked in #344 are untouched by it. -- **A queue would not report at all today.** Measured 2026-08-02: **no workflow under `.github/workflows/` carries a `merge_group:` trigger**, against 13 required contexts in branch protection — so by the mechanism step 2 describes, zero of them would report. Enabling the queue before step 2 lands would wedge every open PR. Step 2 is a precondition, not a follow-up. +- **A queue would not report at all today.** Measured 2026-08-02: **no workflow under `.github/workflows/` carries a `merge_group:` trigger**, against 13 required contexts in branch protection — so by the mechanism step 2 describes, zero of them would report. Enabling the queue before step 2 lands would wedge every open PR. Step 2 is a precondition, not a follow-up. **[SUPERSEDED 2026-09-03 -- see the correction banner. Six workflows now carry the trigger, the required set is sixteen on the server, and the queue reports. The mechanism this bullet states was never wrong: it fired for real on the queue's first entry, where PR 619 sat AWAITING_CHECKS with three contexts simply absent, which is why `codeql.yml` got its trigger afterwards.]** **Proposed:** 1. Enable a merge queue on `main` (branch protection → *Require merge queue*), squash method to match the existing history. From d06bf1eddd1df16077942b0839b6230b1ff986f5 Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Thu, 3 Sep 2026 17:38:23 -0500 Subject: [PATCH 2/3] fix(ci): drop the required-context counts this branch wrote into the tree (BACKLOG #340) CLAUDE.md forbids writing the required-context count into a document: .github/required-contexts.txt is a checked-in claim that can lag the server, so the live set must be read from branch protection instead. This branch wrote one into security.yml and one into docs/BACKLOG.md, and a third sat inside a superseded marker. One was already stale by the time it was written. The counts are DELETED, not corrected. Every sentence stands without a total, and each site now says to read branch protection. Two PRE-EXISTING counts also rode into the diff, because a supersession marker was appended to the same line that carried them. Those lines are restored byte-for-byte and each marker moved onto its own line, so the dated history is preserved unchanged and the diff no longer writes those numbers. No trigger, measurement, or supersession record changed otherwise. Co-Authored-By: Claude Opus 5 --- .github/workflows/security.yml | 3 ++- docs/BACKLOG.md | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index a2fa58b2a..b078ab4ef 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -33,7 +33,8 @@ on: # Branch protection evaluates required contexts on the MERGE-GROUP commit, so a required context # whose workflow has no merge_group trigger never reports in the queue and NOTHING MERGES. That # is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on the queue's - # first entry with three contexts simply absent. Seven of this file's jobs are required contexts. + # first entry with three contexts simply absent. Jobs in this file are among the required + # contexts; read branch protection for the live set, never a count written down here. # # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". # That was true when the trigger landed on 2026-08-26 and became false once a queue was diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 275df3254..ff03e9f6e 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -3479,11 +3479,13 @@ Honestly bounded: **this is build-time only.** No PHI path, no running-engine su > 🔢 **RECORD CORRECTED 2026-09-03 -- HALF B IS BUILT, THE QUEUE IS LIVE, AND THE ITEM STAYS OPEN.** Every build-state claim below predates the queue; **at least** those marked `[SUPERSEDED 2026-09-03]` are false at HEAD. They are kept and marked rather than overwritten, so the decay stays visible, and the marked set is a floor rather than an enumeration. **Re-measured at `2b8bccb4` on the trigger KEY, not the string: SIX of TWENTY-SEVEN files under `.github/workflows/` carry an indented `merge_group:` trigger** -- `backlog-hygiene.yml:36`, `ci.yml:9`, `cla.yml:20`, `codeql.yml:45`, `review-gate.yml:58`, `security.yml:37` -- against a positive control of **THIRTEEN** files carrying an indented `pull_request:` key. **The instrument matters, and the superseded numbers show why:** a bare `grep -l merge_group` returns **seven**, because `failure-signal.yml` reads a merge_group ref without triggering on it, and `ci.yml` and `review-gate.yml` also carry `github.event_name == 'merge_group'` step guards. A bare `grep -l pull_request` returns **twenty-two** against the key's thirteen -- so the old control, *"18 files match pull_request"*, counted matches of a string while the claim it was guarding was about triggers. Half B landed 2026-08-26 in `080fb235b` (four workflows, PR 616) and `ccdd557b3` (`codeql.yml`, PR 629). > -> **HALF A IS DONE TOO, AND RECORDING THAT IS NOT ENDORSING IT.** `repository.mergeQueue` is non-null -- `MQ_kwDOS5JJRs4AA9_8`, SQUASH, ALLGREEN, read from the GraphQL API on 2026-09-03 -- where the **What** section below still says it is null. The Actions API reports **1365** `merge_group` runs, and **PR 754 merged through the queue** at 2026-09-03T19:50:50Z with its five queue-time workflows green on `gh-readonly-queue/main/pr-754-c2237d78`. Required contexts are evaluated on the merge-group commit, and all sixteen reported on `2b8bccb4`, so these triggers now govern the merge path instead of sitting inert. The earliest queue entry the record names is PR 619 on 2026-08-27 (`codeql.yml`'s header). **WHO ENABLED THE QUEUE, AND WHEN, IS RECORDED NOWHERE** -- not in this item, not in an ADR, not in a commit -- and the 2026-08-14 amendment below **RULES** that half B must not be built speculatively, with no later amendment retracting it. That question is open and belongs to the owner. A live queue is not evidence that anyone authorised one. +> **HALF A IS DONE TOO, AND RECORDING THAT IS NOT ENDORSING IT.** `repository.mergeQueue` is non-null -- `MQ_kwDOS5JJRs4AA9_8`, SQUASH, ALLGREEN, read from the GraphQL API on 2026-09-03 -- where the **What** section below still says it is null. The Actions API reports **1365** `merge_group` runs, and **PR 754 merged through the queue** at 2026-09-03T19:50:50Z with its five queue-time workflows green on `gh-readonly-queue/main/pr-754-c2237d78`. Required contexts are evaluated on the merge-group commit, and every one of them reported on `2b8bccb4`, so these triggers now govern the merge path instead of sitting inert. **No count of that set is written down here, deliberately** -- it has moved repeatedly, so read it from branch protection. The earliest queue entry the record names is PR 619 on 2026-08-27 (`codeql.yml`'s header). **WHO ENABLED THE QUEUE, AND WHEN, IS RECORDED NOWHERE** -- not in this item, not in an ADR, not in a commit -- and the 2026-08-14 amendment below **RULES** that half B must not be built speculatively, with no later amendment retracting it. That question is open and belongs to the owner. A live queue is not evidence that anyone authorised one. > > **STILL OPEN, WHICH IS WHY THIS IS A CORRECTION AND NOT A CLOSE.** Proposal 3 is undecided; `strict` still reads `true` on the server. And the amendment's option (i) is the shape that got built for `cla`. Measured 2026-09-03 on PR 754: the `CLA Assistant` step is gated to `pull_request_target`, so run `33796353619` (pull_request_target) RAN it and run `33797809984` (merge_group) SKIPPED it, and **both jobs reported `cla` success under the same context name**. That is the permanent green-that-means-not-applicable the amendment warned about, and the silent-control decay ADR 0158 names. **Whether it is merely decorative is UNESTABLISHED, and must not be guessed in either direction:** PR 754 did carry a green PR-time `cla` before it was queued (check-run success at 2026-09-03T19:25:55Z, exactly one `cla` among 41 check-runs on head `1e9f1cb3`), but nobody has established that GitHub REQUIRES that PR-time green before an entry may join the queue, and no negative case was manufactured to find out. > -> 🔢 **Re-scored 2026-08-20 -> DEMAND-GATE.** Value **6/10** · Difficulty **4/10** · _quick win_. Zero of the 24 workflow files carries a merge_group trigger, verified with a positive control (18 files match pull_request), so half B is entirely unbuilt and step 1 taken first would wedge every open PR. **[SUPERSEDED 2026-09-03 -- false at HEAD; see the correction banner above. Six of twenty-seven files carry the trigger key and the queue is live. Kept because the sentence held its shape and lost its truth, and because its control counted string matches while its claim was about triggers.]** Value 6 is the awkward-workaround rung, with gh pr update-branch exercised and scripts/ci/check_stalled_prs.py already reporting the stalled set; difficulty 4 prices the actual remainder -- merge_group triggers on the four required-context workflows, two short-circuit shims, and the paired pinning-test edit -- none of which goes through mypy or a store backend. _(was 6/10 · 4/10.)_ +> 🔢 **Re-scored 2026-08-20 -> DEMAND-GATE.** Value **6/10** · Difficulty **4/10** · _quick win_. Zero of the 24 workflow files carries a merge_group trigger, verified with a positive control (18 files match pull_request), so half B is entirely unbuilt and step 1 taken first would wedge every open PR. Value 6 is the awkward-workaround rung, with gh pr update-branch exercised and scripts/ci/check_stalled_prs.py already reporting the stalled set; difficulty 4 prices the actual remainder -- merge_group triggers on the four required-context workflows, two short-circuit shims, and the paired pinning-test edit -- none of which goes through mypy or a store backend. _(was 6/10 · 4/10.)_ +> +> **[SUPERSEDED 2026-09-03 -- the re-score banner directly above is false at HEAD; see the correction banner. Six of twenty-seven files carry the trigger key and the queue is live. It is kept because the sentence held its shape and lost its truth, and because its control counted string matches while its claim was about triggers. Its other figures are left as the dated 2026-08-20 reading they were, and none of them should be copied forward -- for anything describing the required set, read branch protection.]** > > **Filed 2026-08-01 — not started.** Build state confirmed: zero of the 21 files under `.github/workflows/` carries a `merge_group:` trigger, so difficulty 4 and the step-2-is-a-precondition reasoning are right. Value 8 is not. The rubric's `8` is "an ASVS L3 Partial on defaults, or a production blind spot with no workaround" — this is neither. It is a repo-workflow blind spot, and a workaround demonstrably exists and is exercised: `gh pr update-branch` (#74 landed via three merges from main, #119 landed via re-sync), plus a detector the project already BUILT for exactly this condition and which the item itself cites — `scripts/ci/check_stalled_prs.py` + `.github/workflows/stalled-prs.yml`. So the readiness signal is not in fact unfalsifiable from outside: a scheduled job reports the stalled set. That makes it "real gap, awkward workaround" = 6, one rung above the rubric's `4` for DX (the item's own cluster is Developer Experience & CI), and 6 is generous for a cluster the ladder caps at 4. At value 6, difficulty 4: quadrant stays quick win, but tier is P2 (P1 needs value >= 8, or value >= 6 at difficulty <= 2 — and this one is 4). _(was 8/10 · 3/10.)_ > **AMENDED 2026-08-14 (dispatcher, from a builder's pre-build read). THIS ITEM IS NOT BUILDABLE AS WRITTEN, AND THE OBSTACLE IS STRUCTURAL RATHER THAN AN OVERSIGHT. HELD PENDING AN OWNER DECISION -- see the fork at the end.** @@ -3547,7 +3549,9 @@ Two worked instances the same day. **#74** went green on 2026-07-30 and sat unme - The overnight run of eight merges was strictly serialized (min gap 26m06s, mean 35m16s over 7 gaps) — but **serialization is not evidence that hand coordination worked.** It is entailed by `strict = true` plus a full-suite cycle, human or no human. `strict` also does not always serialize: #110 and #111 merged **24 seconds apart** on 2026-08-01, #111's squash commit parented directly on #110's. That mechanism is **not established** — only the timestamps and the parentage are. - A queue does not shorten the suite. It reorders the same cycles; the wall-clock bounds tracked in #344 are untouched by it. -- **A queue would not report at all today.** Measured 2026-08-02: **no workflow under `.github/workflows/` carries a `merge_group:` trigger**, against 13 required contexts in branch protection — so by the mechanism step 2 describes, zero of them would report. Enabling the queue before step 2 lands would wedge every open PR. Step 2 is a precondition, not a follow-up. **[SUPERSEDED 2026-09-03 -- see the correction banner. Six workflows now carry the trigger, the required set is sixteen on the server, and the queue reports. The mechanism this bullet states was never wrong: it fired for real on the queue's first entry, where PR 619 sat AWAITING_CHECKS with three contexts simply absent, which is why `codeql.yml` got its trigger afterwards.]** +- **A queue would not report at all today.** Measured 2026-08-02: **no workflow under `.github/workflows/` carries a `merge_group:` trigger**, against 13 required contexts in branch protection — so by the mechanism step 2 describes, zero of them would report. Enabling the queue before step 2 lands would wedge every open PR. Step 2 is a precondition, not a follow-up. + + **[SUPERSEDED 2026-09-03 -- see the correction banner. Six workflows now carry the trigger and the queue reports. The count above is left as the dated 2026-08-02 reading it was; the required set has moved since, and this file is not where you learn its size -- read branch protection. The mechanism this bullet states was never wrong: it fired for real on the queue's first entry, where PR 619 sat AWAITING_CHECKS with three contexts simply absent, which is why `codeql.yml` got its trigger afterwards.]** **Proposed:** 1. Enable a merge queue on `main` (branch protection → *Require merge queue*), squash method to match the existing history. From e83d84714a12a70cab0855d3697f835bb694793f Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Thu, 3 Sep 2026 17:49:29 -0500 Subject: [PATCH 3/3] fix(ci): delete the last required-context counts on this branch (BACKLOG #340) Reviewer finding, second pass. CLAUDE.md forbids writing the required-context count into a document: .github/required-contexts.txt is a checked-in claim that can lag the server, so the live set must be read from branch protection. Deleted, not updated: * the count in the "A queue would not report at all today" bullet, which was the worse of the two -- it presented a stale figure as a measurement inside a sentence about what the queue would report; * a count of contexts absent on one historical queue entry, in four workflow headers and one ledger marker. Those contexts are now NAMED instead, which is more precise than counting them and cannot drift. The supersession marker that referred to the deleted count is reworded to say the count was removed and why, so the record still shows the decay. Swept the whole diff for bare numerals and spelled-out numbers near "context", "required" and "jobs". What remains near those words is a run id, a commit sha, a CI step duration, and "one context name" describing semantics -- no count of the required set. Co-Authored-By: Claude Opus 5 --- .github/workflows/backlog-hygiene.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/cla.yml | 2 +- .github/workflows/security.yml | 2 +- docs/BACKLOG.md | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/backlog-hygiene.yml b/.github/workflows/backlog-hygiene.yml index 590998e3e..381af1ae3 100644 --- a/.github/workflows/backlog-hygiene.yml +++ b/.github/workflows/backlog-hygiene.yml @@ -32,7 +32,7 @@ on: # This job's name is a REQUIRED context, and branch protection evaluates required contexts on the # MERGE-GROUP commit, so removing this trigger means the context never reports in the queue and # NOTHING MERGES. That is not hypothetical: codeql.yml's header records PR 619 sitting - # AWAITING_CHECKS on the queue's first entry with three contexts simply absent. + # AWAITING_CHECKS on the queue's first entry with its CodeQL contexts simply absent. # # WHAT THIS JOB CHECKS ON merge_group IS NOT WHAT IT CHECKS ON A PULL REQUEST. Its question -- # "does THIS pull request update BACKLOG.md" -- has no subject in a merge group, where every diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b19c00016..3a3bcbe5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: # Branch protection evaluates required contexts on the MERGE-GROUP commit, so a required context # whose workflow has no merge_group trigger never reports in the queue and NOTHING MERGES. That # is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on the queue's - # first entry with three contexts simply absent. + # first entry with its CodeQL contexts simply absent. # # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". # That was true when the trigger landed on 2026-08-26 and became false once a queue was diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index e55988059..a4d4e1e98 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -16,7 +16,7 @@ on: # `cla` is a REQUIRED context, and branch protection evaluates required contexts on the # MERGE-GROUP commit, so removing this trigger means `cla` never reports in the queue and NOTHING # MERGES. That is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on - # the queue's first entry with three contexts simply absent. + # the queue's first entry with its CodeQL contexts simply absent. # # THIS JOB'S GREEN MEANS TWO DIFFERENT THINGS UNDER ONE CONTEXT NAME, AND THE NAME CANNOT SHOW # THE DIFFERENCE. The `CLA Assistant` step below is gated to the comment triggers and to diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index b078ab4ef..43d0db1a8 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -33,7 +33,7 @@ on: # Branch protection evaluates required contexts on the MERGE-GROUP commit, so a required context # whose workflow has no merge_group trigger never reports in the queue and NOTHING MERGES. That # is not hypothetical: codeql.yml's header records PR 619 sitting AWAITING_CHECKS on the queue's - # first entry with three contexts simply absent. Jobs in this file are among the required + # first entry with its CodeQL contexts simply absent. Jobs in this file are among the required # contexts; read branch protection for the live set, never a count written down here. # # THIS COMMENT USED TO SAY "INERT UNTIL A MERGE QUEUE EXISTS ... behaves identically today". diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 284f934ae..58bb59cca 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -3549,9 +3549,9 @@ Two worked instances the same day. **#74** went green on 2026-07-30 and sat unme - The overnight run of eight merges was strictly serialized (min gap 26m06s, mean 35m16s over 7 gaps) — but **serialization is not evidence that hand coordination worked.** It is entailed by `strict = true` plus a full-suite cycle, human or no human. `strict` also does not always serialize: #110 and #111 merged **24 seconds apart** on 2026-08-01, #111's squash commit parented directly on #110's. That mechanism is **not established** — only the timestamps and the parentage are. - A queue does not shorten the suite. It reorders the same cycles; the wall-clock bounds tracked in #344 are untouched by it. -- **A queue would not report at all today.** Measured 2026-08-02: **no workflow under `.github/workflows/` carries a `merge_group:` trigger**, against 13 required contexts in branch protection — so by the mechanism step 2 describes, zero of them would report. Enabling the queue before step 2 lands would wedge every open PR. Step 2 is a precondition, not a follow-up. +- **A queue would not report at all today.** Measured 2026-08-02: **no workflow under `.github/workflows/` carries a `merge_group:` trigger**, against the required contexts in branch protection — so by the mechanism step 2 describes, zero of them would report. Enabling the queue before step 2 lands would wedge every open PR. Step 2 is a precondition, not a follow-up. - **[SUPERSEDED 2026-09-03 -- see the correction banner. Six workflows now carry the trigger and the queue reports. The count above is left as the dated 2026-08-02 reading it was; the required set has moved since, and this file is not where you learn its size -- read branch protection. The mechanism this bullet states was never wrong: it fired for real on the queue's first entry, where PR 619 sat AWAITING_CHECKS with three contexts simply absent, which is why `codeql.yml` got its trigger afterwards.]** + **[SUPERSEDED 2026-09-03 -- see the correction banner. Six workflows now carry the trigger and the queue reports. The sentence above carried a count of the required set; it is deleted rather than updated, because that set has moved repeatedly and this file is not where anyone should learn its size -- read branch protection. The mechanism this bullet states was never wrong: it fired for real on the queue's first entry, where PR 619 sat AWAITING_CHECKS with its CodeQL contexts simply absent, which is why `codeql.yml` got its trigger afterwards.]** **Proposed:** 1. Enable a merge queue on `main` (branch protection → *Require merge queue*), squash method to match the existing history.