Skip to content
Merged
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
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ What this buys is presence and a name from a closed list, not truth: with one sh
- **The label awaiting-approval is retired.** A PASS at the tip goes straight to the queue through the enqueue guard (#687); no pull request waits for an approval click and the label is not set again.
- **A pull request enters the queue with its issue and its `agent-pr` label.** On a branch this repository owns, the enqueue guard also refuses one whose body names no issue (`Fixes #<n>` / `Closes #<n>`) and one without the `agent-pr` label (#718), so "one issue, one pull request" is checked rather than remembered. It refuses a **live, non-draft** request whose body carries no `Owner:` line or no `Reviewer:` line in its first 20 lines, or a `Reviewer:` that is neither a `reviewers` login nor a `writers` Bot name, or that names nobody who can record a PASS — a Bot name counts only through the one identity every Bot writes as, `Birfy`, so it names nobody while that account is outside `reviewers` (#947); a `Reviewer:` that names the same Bot as the `Owner:` is refused too, compared name by name after commas, a leading `@` and case are normalised, because one Bot owning and reviewing the same pull request is the shape #940 had with no lines at all (#951); both lines also need a value the policy knows — a `Reviewer:` outside both vocabularies and an `Owner:` outside `writers` are refused, and a line with no value is the missing line, so an empty `Owner:` cannot clear the comparison (#951); the refusal names the missing line, or the word and the list it missed (#943, #947, #951; #940 merged in about seven minutes with the largest diff of the day and neither line). A **merged** pull request is never re-judged: this check also runs on every comment, and history is not a request. Two exemptions: a mechanical release PR, which carries neither by design, and a **fork** (`pull.head.repo.full_name` is not this repository), whose head we cannot push to and where the contributor keeps their own workflow.

**On the code fork `Birfy/FlyBot`, where this team's pull requests actually merge, the gate is a ruleset, not a queue** (#812). Once the ruleset from `--apply` is on that repository, its `main` requires two checks, `tests-ok` and `enqueue-guard`, with `bypass_actors: []`, so `PUT /pulls/<n>/merge` is refused — 405/422 — while the head carries a `hold`, no PASS naming that exact tip, a PASS that lists no `Ran:`, no `agent-pr`, or a body naming no issue. The required check is written by [`enqueue-guard.yml`](.github/workflows/enqueue-guard.yml), from code taken from `main` and never from the pull request, on every event that can change the answer for a fixed head: a push, a label added or removed, a comment, a review body, or a manual run. It calls [`enqueue-guard.mjs`](.github/scripts/enqueue-guard.mjs)'s own decision — the same function that prints the command — so the check and the command cannot disagree; a new commit is a new head and a new check run, and a green check never carries over. The ruleset is [`merge-gate-ruleset.json`](.github/agent/merge-gate-ruleset.json): `node .github/scripts/gate-ruleset.mjs --check` reads the live state and writes nothing, while `--apply` and `--rollback` change repository protection and are the owner's call, not a Bot's. The order is not optional: the check must already report on the open pull requests **before** the ruleset goes on, or every one of them reads "Expected — waiting for status" and cannot merge.
**`enqueue-guard` writes a check on the head, and the queue's ruleset does not require it** (#812, re-read 2026-10-24). Team pull requests merge upstream in `ThinkFlowLab/FlyBot` through the `main merge queue`, whose ruleset requires three contexts — `Node 24 · DSH 0.2.0-rc.2`, `tests-ok` and `merge-gate`; the paragraph below (#960) is how `merge-gate` reads the body the queue does not read. `enqueue-guard` still runs on that head, and on the queue entry: [`enqueue-guard.yml`](.github/workflows/enqueue-guard.yml) takes its code from `main` and never from the pull request, on every event that can change the answer for a fixed head — a push, a label added or removed, a comment, a review body, or a manual run — and calls [`enqueue-guard.mjs`](.github/scripts/enqueue-guard.mjs)'s own decision, the same function that prints the command, so the check and the command cannot disagree. It refuses a head that carries a `hold`, that has no PASS naming that exact tip, a PASS that lists no `Ran:`, a pull request with no `agent-pr`, or a body that names no issue; a new commit is a new head and a new check run, and a green check never carries over.

**Historical: the fork's own ruleset (#812, used until 2026-10-23).** While the team's pull requests merged on the code fork `Birfy/FlyBot`, that repository's `main` required two contexts — `tests-ok` and `enqueue-guard` — with `bypass_actors: []`, so `PUT /pulls/<n>/merge` was refused (405/422); [`merge-gate-ruleset.json`](.github/agent/merge-gate-ruleset.json) is that protection, and `node .github/scripts/gate-ruleset.mjs --check` still reads a repository's live state and writes nothing. The fork is an archive now — nothing merges into it — so those two contexts are not this repository's gate, and `--apply` / `--rollback` are not part of any routine — no Bot runs them — and the ordering instruction that came with them (the check had to report on every open pull request before the ruleset went on) described that fork alone.

**The queue does not read the `enqueue-guard` context here, so the required `merge-gate` reads the body too** (#960). On `merge_group` the queue entry is judged by `merge-gate.mjs`, which now also calls the guard's own `guard()` for the pull request behind the entry: the `Fixes #<n>` line, the `Owner:`/`Reviewer:` lines and the `agent-pr` label are refused there with the guard's own reasons, and `fork` is read from `pull.head.repo.full_name` so an external pull request keeps the exemption #711/#713 gives it. It is **best effort by design**: when the queue branch names no pull request, or the API no longer returns it, the run logs one line and lets the entry through — a wedged queue is worse than a missed judgement. `enqueue-guard.yml` also runs on `merge_group` and writes its check on the entry commit the queue merges, so the context exists where a queue rule would look for it; the `main merge queue` ruleset is **not** changed by this — it still requires three contexts (`Node 24 · DSH 0.2.0-rc.2`, `tests-ok`, `merge-gate`), and adding `enqueue-guard` stays the separate decision #960 describes.

Expand Down
Loading