Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 48 additions & 60 deletions .github/required-contexts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
# "nothing pending" would have reported green without ever waiting for a test leg, because with one
# required context there was nothing to wait for. Count what SHOULD gate the merge, not what does.
#
# The set then moved four more times the same day (1 -> 13 -> 12 -> 15 -> 12), and it moved again on
# 2026-08-31: `a reviewer has read this` was armed, and the two CodeQL matrix contexts were seen
# required earlier that day and are no longer. THE LIST BELOW IS SET-EQUAL TO THE SERVER -- fourteen
# contexts, nothing extra on either side -- read from the API at 2026-08-31 20:57 CDT. A set-equal
# read is the only one worth writing down: a count alone cannot tell a matching set from two
# offsetting errors. Two non-context settings also moved and are recorded because they change merge
# semantics:
# The set then moved four more times the same day (1 -> 13 -> 12 -> 15 -> 12); it moved on 2026-08-31,
# when `a reviewer has read this` was armed and the two CodeQL matrix contexts stopped being required;
# and it moved again on 2026-09-04, when the owner DE-REQUIRED `a reviewer has read this`. That last
# one is recorded with its cost in the review-gate.yml entry at the foot of this file. THE LIST BELOW
# IS SET-EQUAL TO THE SERVER -- thirteen contexts, nothing extra on either side -- read from the API at
# 2026-09-04 18:48 CDT. A set-equal read is the only one worth writing down: a count alone cannot tell
# a matching set from two offsetting errors. Two non-context settings also moved and are recorded
# because they change merge semantics:
#
# strict = TRUE -- a PR must be up to date with `main` before it can merge. This closes the
# stale-green hole: previously a PR validated against an older base could merge
Expand All @@ -30,7 +31,8 @@
# enforce_admins = TRUE -- an admin's direct push to `main` is refused by the server, not merely by
# the local hook. It was ON from 2026-07-28, turned OFF on 2026-07-29 through the
# escape hatch in scripts/hooks/push_guard.py (for when a permanently red required
# check blocks every merge), and READ BACK AS TRUE on 2026-08-31.
# check blocks every merge), READ BACK AS TRUE on 2026-08-31, and TRUE again in
# the 2026-09-04 read above. `strict` re-read TRUE in that same call.
#
# THE HOOK ITSELF IS ALREADY CORRECTED. scripts/hooks/push_guard.py's module
# docstring and its user-facing warning were rewritten in this same change, and
Expand Down Expand Up @@ -152,59 +154,45 @@ a PR that implements BACKLOG #N must update BACKLOG.md
# prevent. Adding to protection is all-or-nothing: the REST endpoint 422s with `already_exists` if any
# context in the request is already required, and then adds NONE of them, so send only the missing ones.

# --- review-gate.yml --------------------------------------------------------------------------------
# ARMED 2026-08-31 (BACKLOG #1404), and this line is the second half of that arming -- protection moved
# first, this file followed, which is the order the paragraph directly above prescribes.
#
# THIS ONE CONTEXT IS THE REPOSITORY'S ENTIRE REVIEW REQUIREMENT, AND THERE IS NOTHING BEHIND IT.
# `required_approving_review_count` is 0 and has to stay 0: every session on this machine pushes as ONE
# GitHub identity (`gh` auth lives at AppData\Roaming\GitHub CLI\hosts.yml, machine-wide rather than per
# config root), CODEOWNERS assigns every path to that same account, and GitHub refuses to let an author
# approve their own pull request -- so raising the count to 1 wedges every pull request permanently
# instead of reviewing any of them. review-gate.yml's header carries that measurement. With approvals
# pinned at 0, dropping this context from protection does not weaken review, it REMOVES it: nothing
# else anywhere reports that a green pull request was never read.
#
# What it enforces is a STEP, not an identity. `gh pr edit <N> --add-label reviewed` is the whole
# protocol; nothing automated ever adds the label, and a `synchronize` event REMOVES it, so commits
# nobody has read are unread again. It does not establish that an independent party looked, and no
# prose here or anywhere else may describe it as if it does.
#
# SAFE TO REQUIRE, which for this file means one thing: the required-but-absent trap. A required check
# that never reports blocks every pull request forever, so three separate ways it could fail to report
# were checked before arming, and all three came back clean:
#
# * IT ALWAYS DISPATCHES. The trigger is `pull_request` with NO paths filter, and the `reviewed` job
# carries no `if:` of its own. The `if:`s in that workflow sit on STEPS, inside a job that always
# runs -- and a skipped step still leaves the job reporting a conclusion, which is what branch
# protection reads.
# * IT REPORTS IN THE QUEUE. review-gate.yml declares `merge_group:`. Omitting that is the total
# failure codeql.yml's own header records under BACKLOG #340: a required context whose workflow has
# no merge_group trigger never reports on a queue entry, so NOTHING MERGES. Measured there on the
# first entry the queue ever held -- 32 check-runs green and three contexts simply absent.
# * IT REPORTS ON PULL REQUESTS OLDER THAN ITSELF. GitHub runs a `pull_request` workflow from the
# MERGE commit, not from the head, so a branch that predates the workflow still gets the check.
# VERIFIED on PR 713: its head 5cb51e46 returns 404 for .github/workflows/review-gate.yml, and the
# context reported on it anyway.
#
# SO ARMING IT STRANDED NOTHING, and the remedy is not a rebase. Every open pull request goes red on
# this one check until a reviewer labels it; `labeled` is in the trigger list, so the label alone
# re-runs the job and clears it. That distinction is the one worth keeping: a reader who assumes a
# stranded check needs a rebase will rebase, which on `synchronize` STRIPS the label and moves the pull
# request further from green.
#
# THAT SENTENCE IS ONLY TRUE WHILE `labeled` IS IN THE WORKFLOW'S `types:` LIST, so it is held by a
# test rather than by this paragraph:
#
# tests/test_merge_gate_controls.py::test_the_review_gate_reruns_when_a_reviewer_adds_the_label
#
# Deleting that action reddens nothing on its own and leaves a gate no reviewer action can clear: the
# label fires no run, and the only trigger that still re-runs the job is `synchronize`, whose first
# step REMOVES the label. Measured 2026-08-31 -- before the test above existed, dropping `labeled`
# passed 65 tests.
a reviewer has read this

# DELIBERATELY NOT REQUIRED (do not add without the owner's decision; each has a recorded reason):
# review-gate.yml -- DE-REQUIRED 2026-09-04 by the owner, having been armed on 2026-08-31
# (BACKLOG #1404). The workflow is untouched: it still dispatches, and
# it still reports `a reviewer has read this`. It no longer BLOCKS, so
# a red one on a pull request is not a merge problem.
#
# WHAT THAT COSTS, recorded because nothing else on the merge path now
# records it. `required_approving_review_count` is 0 and has to stay 0
# -- every session here pushes as ONE GitHub identity and GitHub
# refuses to let an author approve their own pull request, so raising
# it to 1 wedges every pull request instead of reviewing any;
# review-gate.yml's header carries that measurement. This context was
# therefore the repository's ENTIRE review requirement. With it
# de-required, NOTHING on the merge path reports that a green pull
# request was never read. That is the owner's call, recorded here
# rather than argued.
#
# The `reviewed` label protocol is correspondingly unenforced. `gh pr
# edit <N> --add-label reviewed` still works and still means what it
# meant -- a STEP happened, never that an independent party looked --
# but no gate reads it any more.
#
# THE WORKFLOW'S OWN PROPERTIES ARE STILL HELD BY TESTS, in
# tests/test_merge_gate_controls.py: it reports under this exact
# context string, it declares `merge_group:`, and `labeled` is in its
# `types:` so a reviewer's label re-runs the job. Those tests stay.
# What they are no longer is NEGATIVE CONTROLS: the registry at
# tests/negative_controls.toml indexes controls by REQUIRED context
# and its reconciliation fails on a control naming a context nobody
# requires, so that entry came out in this same change and the tests
# themselves were kept.
#
# RE-ARMING IS AN OWNER DECISION, and the three ways it could have hit
# the required-but-absent trap were measured clean before 2026-08-31
# and are unchanged: no paths filter and no job-level `if:`, a
# `merge_group:` trigger (whose absence is the total failure
# codeql.yml's header records under BACKLOG #340), and it reports on
# branches older than itself -- verified on PR 713, whose head
# 5cb51e46 404s for the workflow file and got the check anyway.
# codeql.yml, scorecard.yml -- their SARIF upload needs `security-events: write`, which fork-PR
# tokens lack, so requiring them would block every fork PR.
# `CodeQL (python)` and `CodeQL (javascript-typescript)` were read as
Expand Down
31 changes: 31 additions & 0 deletions docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22560,6 +22560,7 @@ So `test_the_script_prefers_its_own_repo_over_an_earlier_path_entry` supplies th

**Adjacent and NOT fixed here, named rather than numbered.** `docs/WEBCONSOLE-PACKAGE.md`'s seam-refresh procedure is stale in three steps left behind by #1220: it says to bump `ENGINE_UI_SEAM` by hand (`1` to `2`) when the value is a derived digest, it says to update curated lists in this script that #1220 retired, and its step 5 prescribes `python scripts/webconsole_seam_snapshot.py > tests/golden/...`, the shell redirect this script's own docstring forbids because PowerShell's `>` writes UTF-16LE with a BOM into a file the test reads as UTF-8. That is doc drift with its own cause and it wants its own item; folding a documentation rewrite into a `sys.path` fix would make both harder to review.


## 1434. the tooling-partition gate names the file it rejects and not the remedy, so the Builder who trips it has already exited

> 🚧 **Filed 2026-09-03. The failure message is fixed on this branch. Five open pull requests still carry unregistered test files, and only their own branches can fix them -- they are named below.** `tests/test_tooling_partition.py::test_every_non_engine_test_is_classified` fails when a file matching `tests/test_*.py` sits in neither `tests/tooling_manifest.txt` nor `_STAYS_WITHOUT_IMPORTING`. It is not deselected by `-m 'not tooling'`, so it reds **all three required `test` legs at once**. PR 774 hit exactly that, and its Builder's process had exited before any leg reported.
Expand Down Expand Up @@ -22627,3 +22628,33 @@ All 137 listed entries were swept for a repo-rooted read of `messagefoundry/**`.

1. **The five pull requests above.** A Builder must not push to another seat's branch, so each is fixed by whoever next touches it: append `tests/<name>.py` to `tests/tooling_manifest.txt`, keeping the list alphabetical. **The gate is passable and two pull requests that night passed it correctly -- nothing here asks for it to be weakened.**
2. **Three copies of the manifest parser, pinned against nothing.** This file, `_tooling_basenames` in `tests/conftest.py` (the copy that actually applies the marker), and `_manifest_paths` in `tests/test_ci_tooling_gate.py` all implement the same rule. Extracting one `tests/_tooling_manifest.py` is the real fix. Related: `test_every_manifest_entry_trips_its_own_gate` in `tests/test_ci_tooling_gate.py` feeds each manifest entry back as its own changed path, so on the manifest arm every entry matches itself unconditionally.

## 1452. required-contexts.txt and its pin still claim the retired reviewer context is required

> 🔢 **Filed 2026-09-04 - FIXED IN THIS PULL REQUEST, not yet landed.** The owner removed `a reviewer has read this` from `main`'s branch protection earlier the same day. The checked-in claim did not follow it, so the repository's own answer to "does this check block a merge" over-reported the required set by exactly one context.

**Cluster:** repository tooling. **Priority:** P3. **Verdict:** build.
**Severity:** no engine effect, no PHI axis, and **no deployment axis (sec. 0)** -- none of these files ship in a wheel. The cost is a merge-path claim that was wrong, in the one file whose entire purpose is to be that answer readable from a clone.

**MEASURED 2026-09-04 18:48 CDT** against `gh api repos/MEFORORG/MessageFoundry/branches/main/protection`: the server requires **13** contexts, `.github/required-contexts.txt` named **14**, and the difference is exactly `a reviewer has read this`. The other twelve matched, both directions. `strict`, `enforce_admins` and `required_approving_review_count` re-read TRUE, TRUE and 0 in the same call, unchanged.

**THE DIRECTION OF THE ERROR IS THE UNUSUAL PART, AND IT IS THE SAFER ONE.** The failure this file was built against is the file naming FEWER contexts than the server, because a context the file omits reads as not-blocking -- the reassuring answer rather than the true one. This drift ran the other way: the file claimed a gate that nothing enforced. That still misdirects, and it does so about review specifically, which is the one gate that never tested the code.

**ONE INSTRUMENT SAW IT, AND IT IS DELIBERATELY NOT A REQUIRED ONE.** `tests/test_required_contexts.py` compares the file against prose, workflow job names and a hand-written count, so all nine of its tests stayed green throughout while the claim was false. That is by construction rather than a defect in it: the `gh api` line beside its count pin is a COMMENT recording a past manual read, not a call. `scripts/ci/check_required_contexts_drift.py` does read the server and fails closed, and it was RED on `main` for this drift -- it is not in the required 13, so it reported and blocked nothing. Watched fail 2026-09-04: exit 1 against the pre-fix file, naming that context, and exit 0 against the corrected file at 13 against 13.

**WHAT THE CORRECTION HAD TO TOUCH, which is wider than the two lines it looks like.** Removing one context from the canonical file moves five in-repo claims that are reconciled against it:

| File | What moved |
|---|---|
| `.github/required-contexts.txt` | the context line, the set-equal header read, and a new DELIBERATELY NOT REQUIRED entry recording the de-requiring and its cost |
| `tests/test_required_contexts.py` | the pinned count, 14 to 13, plus the module docstring |
| `docs/CI.md` | the required-checks bullet and the review-gate paragraph |
| `tests/test_security_posture.py` | 13 contexts resolving to 11 distinct jobs, was 14 over 12 |
| `tests/negative_controls.toml` | the review-gate control entry, because the registry refuses a control naming a context nobody requires |

**THE NEGATIVE CONTROLS WERE DE-REGISTERED, NOT DELETED.** `review-gate.yml` still exists and still runs, so the nine test nodes that entry named still hold its real behaviour inside the required `test` legs. What ended is their status as controls for a merge gate. One assertion did have to go: `test_the_review_gate_still_reports_under_the_required_context_string` asserted the context was required, which is now false; it kept its three structural assertions, was renamed to `..._under_its_declared_context_string`, and its docstring records that a re-arm is caught by the registry reconciliation rather than duplicated there.

**RESIDUE, NAMED RATHER THAN NUMBERED, because retiring any of it is an owner decision this seat cannot take.** `CLAUDE.md` section 5 still describes the Reviewer seat and still states that the `reviewed` label is what blocks a merge. `.github/workflows/unread-signal.yml` and `scripts/ci/check_unread_prs.py` exist to notify a reviewer that a pull request is waiting on a gate that now blocks nothing. `review-gate.yml` itself still reddens an unlabelled pull request, which is expected and harmless but reads as a failure. Whether any of that is retired, and whether the context is re-armed, is the owner's call.

**TWO NUMBERS WERE BURNED ON THIS SUBJECT BEFORE THIS ONE, AND NEITHER IS FILED.** A peer seat allocated 1449 for the same drift and left it unfiled. This seat then allocated 1451 from the PRIMARY checkout by mistake: ledger ownership keys on the allocating worktree or its branch, both non-transferable, so 1451 is claimed by `main` in a tree that must never commit it and is unusable here. 1452 was re-allocated from this worktree and is the only one of the three that names this work. Recorded so a later reader does not read three numbers as three defects; `scripts/coord/alloc_strand_sweep.py` is the tool that already exists for stranded allocations.

14 changes: 7 additions & 7 deletions docs/CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ The stable contexts required on `main` are — mirroring
- `forbidden-content (customer/PHI leak guard)`
- `a PR that implements BACKLOG #N must update BACKLOG.md`
- `cla`
- `a reviewer has read this`

`cla` is the **job key** in `cla.yml`, whose job declares no `name:`. Branch protection
matches the job name, never the workflow name — so the context is `cla`, not "CLA Assistant". Every
Expand All @@ -69,12 +68,13 @@ the same reason and additionally **does not run on PRs at all** (`scorecard.yml`
trigger — it runs on push-to-main, a schedule, and branch-protection changes). Nightly / path-gated
legs (service-smoke, load, SQL/Postgres store) are deliberately **not** required.

`a reviewer has read this` (`review-gate.yml`) is the required check that is **not a test of the code**,
and the one with nothing behind it. `required_approving_review_count` is 0 and stays 0 — every session
pushes as one GitHub identity, so a human-approval rule would wedge every PR rather than review any —
which makes this single context the repository's whole review requirement. A PR clears it with
`gh pr edit <N> --add-label reviewed`; a new commit removes the label, so re-review is automatic. It
proves a **step happened**, not that an independent party looked.
`a reviewer has read this` (`review-gate.yml`) was **de-required by the owner on 2026-09-04**, having
been required since 2026-08-31. **The workflow still runs**, so a PR with no `reviewed` label still
shows that check red — it just does not block a merge any more, and it is not something to chase.
`required_approving_review_count` is 0 and stays 0, because every session pushes as one GitHub identity
and a human-approval rule would wedge every PR rather than review any. That made this one context the
repository's whole review requirement, so **nothing on the merge path now reports that a green PR was
never read**. `.github/required-contexts.txt` records that call and its cost; do not restate it here.

The `quality-advisory.yml` jobs create **no code-scanning category** and **no _required_ check context** —
they do report as ordinary advisory checks, and they **must never be added to the required list**. Two
Expand Down
Loading
Loading