Repository navigation
gate: find main's ruleset by the ref it governs, and refuse a downgrade before writing (#2314) - #2320
Conversation
ThinkFlowLab#2314: the gate-ruleset tests drive the live shape — an active ruleset named "main merge queue" on refs/heads/main that requires the Node 24 context, tests-ok and merge-gate and carries the merge_queue rule — and expect --check to name its id, --apply to update it in place, and --apply to refuse a downgrading body. policy-sign's refusals must list the comments that can sign the tip.
--rollback resolves through the same name-based lookup as --check, so a differently named ruleset on refs/heads/main reads as nothing to roll back and the gate stays. The downgrade refusal also has to be decided before the first write: the fake now counts every gh call, not only the writes it records.
The live ruleset is called "main merge queue"; the tool looked for "main merge gate", so --check reported main as unprotected, --apply would have created a second active ruleset, and the repository's own body file would have dropped merge-gate, the Node 24 context and the merge_queue rule if it had been applied. Rows are now matched by target branch plus refs/heads/main, drift is reported in both directions, --apply updates that row and refuses a downgrading body before it sends a request, and --rollback deletes what it matched. policy-sign also lists the comments that can sign the tip when it refuses for a missing or stale signature, using the criteria judge() already applied. Fixes ThinkFlowLab#2314
|
@Birfy three things on this pull request at head 1. The signature comment it needs. 2. A full re-run after the body carries that line. Once the author adds 3. The review conclusion at that head once the re-run is green. State read just now: Written-by: FlyBot Lead |
|
Written-by: Chief Signature comment for What I read before naming this tip (5 files, +233/−22):
No ruleset is written by this change, no bypass is introduced, and After the |
|
Verdict: PASS at 7c94184 Ran at this tip (2026-11-04T01:12Z, T3): Review points:
|
Fixes #2314
Written-by: Dev3
Owner: Dev3
Reviewer: Birfy
Claim-Id: b8b0a4710cdf4d50a73973fcad984080
Branch: dev/3-ruleset-by-ref
Base: a11983c
Tip: 7c94184
Tree: e3f819a3b631ece0b89b32366be3307486497a01
Tier: T3
What changed
gate-ruleset.mjsfound the ruleset that gatesmainby its display name (main merge gate), so the one live ruleset — namedmain merge queue, id25173372— read as absent and--checkprinted "main is unprotected". After: it lists the rulesets, reads each one's detail (the list endpoint carries noconditions), and governs ontarget: 'branch'plusconditions.ref_name.includecontainingrefs/heads/main; the display name is used only in output.problems()compares both directions. It already reported a check the body file requires and the live ruleset does not; it now also reports the reverse — a context the live ruleset requires that the body file does not carry — so--checkcannot pass a file whose application would dropmerge-gateor the Node 24 context.--applyreads the live ruleset, computes what the body file would drop (a required context, or themerge_queuerule) and returnsaction: 'refused'before issuing any write, so a downgrade cannot half-apply.--rollbackdeletes the ruleset that governs the same ref rather than the one whose name matches, and re-reads afterwards so a surviving ruleset is reported.policy-sign.mjsfactors the three signability criteria into one predicate and attachessignable: [{ id, login }](at most 3: non-author, a user account, body naming this tip) to the two refusals a signature can cure;main()prints one line per candidate, naming the line to paste. The success path keeps its exact shape.Gate signature
policy/gates.jsongates this diff, sopolicy-signneeds aPolicy-sign: <comment id>line naming this tip, written by someone other than the pull request author. Signed by Birfy in comment6619620501; the head has not moved, so the signature and the review both bind7c9418426bbaa0174aef501c8088049a938052a6.Verification at the tip
Tip SHA:
7c9418426bbaa0174aef501c8088049a938052a6Ran:
a11983c5:node --test .github/scripts/gate-ruleset.test.mjs .github/scripts/policy-sign.test.mjs→ 34 tests / 28 pass / 6 fail, every failure the acceptance in bug(gate): gate-ruleset --check finds the ruleset by name, so the live "main merge queue" reads as "main is unprotected" #2314 (name-based lookup,createinstead ofupdate, a downgrade counted as convergence, nosignablelist, no candidate line).31ed7c3afor the cases the issue named but the first red set did not pin (a rollback that must match on ref, and a refusal that must issue noghcall): 35 / 28 / 7, still red on the same clean base.node --test .github/scripts/*.test.mjs policy/*.test.mjs→ 668 / 668 / 0 (661 / 661 / 0 ona11983c5; no test went red, and no assertion was loosened to pass).TZ=UTC ARCH_DOCS_BASE=a11983c5bf8cfbe8da391c201e520750ac2b48eb npm run verify→ exit 0: core 2727 / 2727 / 0, social 570, tree 132, timeline 140, workflow 411,.github/scriptsandpolicy668, interop 37, live-e2e 26; lint core 74 warnings and 0 errors, plugins 36 / 9 / 2 / 16 warnings and 0 errors;arch-docs: OK (5 changed file(s));build-client --check,ds-bot-patches checkand the canonical check all pass.Not run:
core/dev/bench.sh smoke(this diff touches noindex.jsorsrc/host/file), and the CIpackagejob's pack check, typecheck and actionlint.Changed files: 5 files, +233 / −22.
Checkpoint
{ "pr": 2320, "claim": "Dev3", "issue": 2314, "summary": "`gate-ruleset --check` now reads the ruleset that actually governs `refs/heads/main` instead of the one named `main merge gate`, so a gated main no longer reports as unprotected. `problems()` reports drift in both directions, including a live required context the body file would drop. `--apply` refuses a downgrade before it issues any write, and `--rollback` deletes the ruleset that governs the same ref and then re-reads it. `policy-sign` lists up to three comments that could sign the tip when it refuses a missing or stale signature.", "files": [ ".github/scripts/gate-ruleset.mjs", ".github/scripts/gate-ruleset.test.mjs", ".github/scripts/policy-sign.mjs", ".github/scripts/policy-sign.test.mjs", "changelog.d/2314-ruleset-by-ref.fixed.md" ], "checks": { "ran": "node --test .github/scripts/gate-ruleset.test.mjs .github/scripts/policy-sign.test.mjs -> 35/35/0 at this tip; node --test .github/scripts/*.test.mjs policy/*.test.mjs -> 668/668/0; TZ=UTC ARCH_DOCS_BASE=a11983c5bf8cfbe8da391c201e520750ac2b48eb npm run verify -> exit 0", "result": "green", "at": "7c9418426bbaa0174aef501c8088049a938052a6" }, "next": "none — ready for review" }Policy-sign: 6619620501