---
name: running-the-merge-queue
description: "Use when Sami asks a session to manage the open-PR queue, get PRs through review, tell him what's ready to approve, or act as the merge controller over PRs other agent sessions own. Also when a PR owner reports 'merge-ready' and someone has to decide whether that PR ships."
---

# Running the Merge Queue

You are the controller. Owners drive their PRs; you verify the gates and you ship. Sami, 2026-09-08, verbatim: "Your job is just to enforce certain CI requirements and review requirements and then approve PRs, and that's it. Stop inventing new roles for yourself." You are not a reviewer, a planner, a dispatcher for other sessions, a coach, or a relay for their questions. Do not ask owners to register plans with you, route their questions to Sami for them, assign them follow-up PRs, or broadcast rules of your own.

**Sami's rules (verbatim, 2026-09-04):** "Before anything can merge, the owner of the PR has to have CI passing. They have to have addressed all of the valid comments on their PRs... They have to have run thermonuclear on their PR and address those findings. And they also have to have actually tested end to end the way a user would all of the functionality of their PR. No shortcuts. No driving the internals of things. No claiming that they were infra blocked so that we should accept some kind of other substitute." And: "You're simply the person that makes sure that they have done all of the steps that I just outlined... don't turn yourself into a bottleneck."

**Sami's rules (verbatim, 2026-09-08, after a night where 23 PRs merged and the features he cared about did not):** "PRs have been taking way too long... Is it because we're applying an overly strict definition of what it means to reply to all review comments? I don't care about replying to every tiny little minor after every single push. We have to use some discretion here." And: "all correctness fixes need to be made in the same PR. Those cannot be deferred under any circumstances … We don't need to iterate endlessly against every minor finding on every push." And: "I don't need tiny little churn on CI — there's relatively little value."

## 0. Authority: one current record, never re-imposed

Your merge authority is **whatever Sami's current, explicitly recorded ruling permits**.
Record its source, timestamp and scope. Preserve standing approvals across handoffs until
they are superseded; do not ask for the same approval again. A dated example in this skill
is not a credential grant, an active hold or permission to bypass branch protection.
Use the ordinary protected squash-merge path; do not infer an admin/PAT exception from history.

Keep active priority holds, their release conditions and any approved merge windows in the
current queue record, not in a reusable skill. Re-read that record at each wake and before
merging. When a hold requires a conflict check, verify the actual three-way composition rather
than guessing from file overlap. Stacked work must identify its intended published parent. When
a coordinated batch of migration pull requests is packet-ready, assign and record their parent
order once, before individual migrations re-parent and re-gate; a later sibling does not by
itself reopen that batch decision. This applies to a defined coordinated migration batch, not
routine branch work.
Do not re-impose a lifted hold or invent a quiet window from an old incident.

**Registry and consumer contracts:** a runtime-selected package change can affect future launches without an infrastructure redeploy. For a task, solver or agent registry change, the owner's evidence must name the entries that supported launchers request and show them resolving in the actual intended runner environment. Migrate supported callers in the same change. Do not infer that every launch follows `main`, that an import proves registry availability, or that retaining an old alias is required without an explicit compatibility contract.

**Panes are located, never remembered (2026-09-09):** when Sami hands you a tmux pane carrying his `gh` identity, address it by *content* on every use (`tmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index} #{pane_current_command} #{pane_current_path}'`, match cwd + `bash`), never by the index he quoted hours ago. A server restart rebuilt the layout and an index-based `send-keys` typed a probe command into the controller's own session as a user message. If no pane matches, the pane is gone - ask for a new one; never type into a pane you have not just identified.

**Packet vs PR API (2026-09-09):** before every merge, compare the READY packet's file count and file list against `gh api repos/O/R/pulls/N/files` at the head SHA. A packet said "three files"; the PR had four - a rebase artifact reverting a just-merged sibling. The squash happened to compute against current main and the revert did not land, but the owner's retraction arrived 40 s after the merge. The check costs one API call; an owner's file list is a claim, the PR API is the fact.

**Verify a pushed branch from the remote's own state, never from a local `HEAD` (2026-09-22).** The same "a claim is not the fact" rule applies to your *own* PR. This controller cut a skill branch from a detached `HEAD` that happened to sit on another lane's unmerged commit, so a two-commit docs PR carried a third commit — six files including a 751-line rewrite handling a bearer credential — to review under a docs title. The local check that should have caught it, `git log origin/main..HEAD`, came back **empty and clean**, because co-tenants had reset the shared checkout underneath and it was answering a different question than "what is on the branch I pushed". The discriminator is `gh api repos/O/R/pulls/<n>/commits` or `git log origin/main..origin/<branch>`. Caught in review, by the reviewer reading the commit list this rule exists to make the author read.

**The reverting-rebase signature (2026-09-13):** a rebase built as `commit-tree <old-tree> -p <new-main-tip>` — a stale whole tree with a current parent — reads as a deliberate revert of everything main did in between. It passes every lane: CI has no opinion about a legitimate-looking revert, and the reviewer sees only the intended hunks in the PR's own diff view. The only tell is arithmetic on the file count: `changed files == (old-parent..new-parent diff) + (intended files)`. Twice in one night: 32 files nearly shipped that way, and 88 on another PR (93 changed instead of 5, caught pre-merge by its own owner). So: whenever a head moves after a rebase, compare the file count to the packet's; a count that jumped is a revert until proven otherwise, and the fix is to rematerialise on `main@origin` (`jj new main@origin` + re-apply), never to re-point a tree.

**A PR with an active coordinator gate lane does not merge without that lane's packet naming its head (2026-09-22).** Not the owner's word that it is settled, not your own verification, not a second reviewer's approval — the gate lane's packet. The latency is the price, and a PR that has taken six review rounds is exactly where it pays.

**No verdict cancels another verdict's open findings — read every artifact at the head, and read each one's scope before deciding what it answers (2026-09-22).** Two artifacts can sit at one head: a second reviewer's "Findings: none" about the last comment-only delta, and the gate review carrying a P1 and a P2 about the PR. Taking the agreeable one is the failure. What makes this insidious is that **both are true about their own subject** — the delta has no findings; the PR has two. The rule is symmetric and must stay so: a gate lane's ACCEPT does not cancel a second reviewer's open P1 either, and "whoever is senior wins" would produce exactly that mirror failure. The instrument is cheap, because **each artifact's first line names its own scope** ("Reviewed appended child X through Y", "Re-review at Z") — read that line first and you know which question it answered.

**Count unanchored findings explicitly, over EVERY surface a verdict can land on (2026-09-22).** `reviewThreads` reported **0 unresolved** on that PR at that head while two findings stood open, because findings posted in a verdict's prose are not threads. The same PR had been correctly held three hours earlier for an unanchored Major — the identical blindness produced the right call and then the wrong one, on one PR, in one evening. Two traps in the remedy itself: a census over **review objects alone is not enough**, because some reviewers post their verdicts as **issue comments** (claude's on that PR were), so enumerate both; and **read the verdicts rather than grepping them for markers** — a finding phrased without a severity token is still a finding, and a grep that finds none is the same false comfort as `unres=0`.

**Before classifying any delta, prove the verdict is an ANCESTOR of the head — a rewritten branch has no delta to classify (2026-09-22).** `git merge-base --is-ancestor <verdict-sha> <packet-sha>`. This comes first and costs one command, because every rule below it silently assumes the verdict sits on the head's history. When a branch is **rewritten** rather than appended to, the reviewed commit is not in the PR at all: there is no delta, and diffing the two is as meaningless as head-to-head diffing across a rebase. After a rewrite the owner's green signals can be TRUE AND STALE at once: the forge read and the approval each describe a head that no longer exists. A failed ancestry check ends the question: no carry, whatever the files look like.

**Take the verdict sha from what the review BODY names, never from the review object's `commit_id` (2026-09-22).** `commit_id` is the head **at post time**, not the commit the reviewer read — so on a rewritten branch it silently equals the current head and condition (0) degenerates into `--is-ancestor <head> <head>`, which passes and carries the stale verdict: precisely the failure (0) exists to stop. The body is the reviewer's claim about what they read; the field is metadata about when they pressed send. When the two disagree, the body governs and the disagreement is itself worth a question.

**A verdict carries across a rebase only after its behaviour proof is RE-EXECUTED at the new head (2026-09-22).** Put that clause first among the classification rules, because it is what makes the others worth anything: a rebase can drift semantics through the **base** rather than through the diff, and no amount of file classification detects that — only re-running the PR's own proof does. Text resolved is not behaviour preserved. The full condition, all required: (0) the verdict sha is an ancestor of the head; (1) every **conflicted** file is prose with zero code; (2) **the PR's own contribution is unchanged**; (3) the behaviour proof is re-executed, not re-asserted.

**Condition (2) is read from a diff-of-diffs, never from head-to-head, and never as "byte-identical" (2026-09-22).** Both of the obvious instruments are wrong. `git diff <old-head> <new-head>` measures **main's movement between two bases**. And "every non-conflicting file is byte-identical" is too strict to be a rule at all: any file the PR touches that main *also* changed differs after a clean rebase with no conflict. Diff each head against **its own base** (`<old-base>..<old-head>` against `<new-base>..<new-head>`) and compare the two file sets: a file that left the set because main's copy now carries its change in content is explained; any other difference is not. A file count that *drops* has the same burden of explanation as one that jumps.

**Scope arithmetic generalises past rebases: an unexplained file or line count is the tell (2026-09-13).** Same check, different cause: an owner fixing four prose citations ran the formatter over three *delivered* task graders and churned 45 unrelated lines. `tasks/` is not in the format lane's path list — the grep that "found" it matched `meta/trajectory_tasks`, which contains the substring — so CI would never have format-checked those files, the diff would have arrived looking like intentional authorship, and no lane or reviewer had a signal to question it. They caught it themselves and reverted to a one-line diff per file. So: **a PR whose file count or line count exceeds its stated scope is a revert-shaped artifact until proven otherwise**, whatever produced it; and before formatting anything, read the workflow's literal path list rather than grepping for a directory name. Delivered content under `tasks/` is the dangerous case precisely because nothing checks it.

**`jj rebase -r <bookmark> -d main` manufactures phantom deletion conflicts (2026-09-13).** `-r` reparents only the named revision and drops its real parent, so a two-commit chain shows every file the first commit added as a "deletion" conflict - which reads exactly like the reverting-rebase signature, on the night that signature was real twice. `jj rebase -b <bookmark> -d main` rebases the whole chain with zero conflicts. Before believing a rebase destroyed content, check which flag produced it.

**`gh pr create --body "$(cat <<'MD' ... MD)"` can truncate the body and still create the PR (2026-09-13).** A 3.3k body landed as 95 characters with exit 0. Write the body to a file and pass `--body-file`; read the body back from the API before treating the PR as described. The same read-back is how the queue checks a packet's file list against the PR - a created object is a claim until it is read. `gh api` has its own version of the trap: `-f body=@file` sends the literal string `@file`, because `-f`/`--raw-field` is a string parameter; only `-F`/`--field` reads `@<path>`. It returns 201 with a valid `html_url`, so nothing looks wrong - a lane posted a stray filename as a comment on an external maintainer's pull request that way (2026-09-26). Use `-F body=@file`, or `gh pr comment --body-file` / `gh issue comment --body-file`, which take a path by design, and read the posted body back (`gh api repos/<o>/<r>/issues/comments/<id> --jq .body`). Repair in place with `gh api -X PATCH .../issues/comments/<id> -F body=@file`, so the reader sees one comment rather than a deletion and a repost.

**A batched GraphQL mutation can half-succeed (2026-09-13).** `addPullRequestReviewThreadReply` 500'd on a 3.5 KB `-f b="$(cat file)"` body while the paired `resolveReviewThread` in the same call succeeded - the thread sat resolved with no explanation. Pass large bodies with `-F b=@file`, and read every mutation's result in the response, not the exit code or the last line. A resolved thread with no reply beneath it is this failure, not a reviewer's shortcut.

**Inferring absence from a source read is never grounds to reimplement (2026-09-13).** Ten times in one night an agent read a file, concluded a primitive did not exist, and hand-rolled a copy - four copies of one `seeded_ids` helper (one silently returning empty), a digest routine one line from duplicating a re-authoring flag on the evidence CLI at the time. Every instance traced to a stale checkout or a base-only read. The tell is the sentence "X does not exist in this codebase": before it is acted on, it needs `git show origin/main:<path>` and a grep of the callers, and if three sibling lanes used X in the last two hours it exists. A gate that depends on X existing (the stamp sweep on `auto`) is sound; a lane that reports X missing has a stale tree.

**A lane handed "X is broken, fix it" finds a story for why X is broken (2026-09-13).** Two rubrics were dispatched as "confirmed stale"; the fix lane did genuine git archaeology, found real historical renames, and built a coherent account of the staleness - of ids the rubrics already carried correctly. The flag was a bare prefix from a markdown line-wrap, item one on the census's own false-positive list, promoted to a defect by a confident framing. The fixer must re-verify the premise before fixing, and the dispatcher's brief must say so in a way the framing cannot override: "flagged, unverified - confirm the token in context against origin/main before changing anything". The controller states counts as verified + claimed, never as a total.

**A negative result must state where it looked (2026-09-13).** "There is no `.overlays/forrest-5` in the tree" was true and the conclusion drawn from it — a delivered, RfC-tagged arm whose content does not exist — was false: the content sat on an un-PR'd `dev/forrest/*` branch, one of 953, authored at the exact pvid timestamp. The check had asked `tasks/<base>/.overlays/<name>/` on main, which is the wrong place to ask whether content exists at all. That scare drove a costed "arms we cannot migrate" bucket into a migration plan and a phantom-debt class into a census before the wider search retired it (PHANTOM = 0). So: **absent from the place you checked is not absent**, and a report of absence carries its search scope or it is not a finding. The same night produced eleven sibling cases of an instrument reporting its own blind spot as a fact — a fidelity check that could not see loadability, a loader that warn-skips instead of raising, a grader whose missing lookup returned `False`, an unrunnable check indistinguishable from a failing one. The family rule, from three cases in one night: TREAT A SUSPICIOUSLY EMPTY OR SUSPICIOUSLY TIDY RESULT AS A BUG IN THE READER BEFORE A FACT ABOUT THE WORLD. A line-based filter stripping a wrapper's notice from single-line JSON deleted the whole payload and reported zero merged pull requests, which read as a quiet repository; a `grep | head -3` returned three stale hits and hid the verdict lines below them; a partial-range grep counted three migration heads where a full parse found one. Slice output from its first `{` or `[` rather than dropping matching lines, and re-run the reader against a case whose answer you already know. The false-positive half of the same shape, 2026-09-26: a gate checking whether a migration PR really was "docstring-only" grepped the PATCH for `revision|upgrade|op.` and reported two code-line changes that were one prose sentence rewritten inside the docstring - it would have held a clean PR, and been believed if it had said zero. Ask the question in the shape of the answer instead: fetch the file at the head and at the base, diff only the identity assignments (`^(revision|down_revision|branch_labels|depends_on)\s*=`) - byte-identical means the graph is untouched - and confirm nothing changed inside `def upgrade` or `def downgrade`.

**No rebases without a conflict (Sami, 2026-09-11 23:3xZ, verbatim):** "Please don't do unnecessary rebases (i.e. unless there are merge conflicts). The CI queue is too long and slow." Earlier that day: "Not everyone needs to rebase every time, e.g. if there are no merge conflicts." So: the controller never asks an owner to rebase or push "to pick up main" — not for a main-red fix, not for a runner-label change, not to refresh a stale run. A `gh run rerun <id>` replays the PR's original merge commit and therefore cannot see a main-side fix; that is a fact to state, not a reason to request a push. A PR that is red only on a main-red class **waits** until the owner's next real push (content, or `mergeable == CONFLICTING`); it does not merge on "known red" either — "do not admin override failing CI" stands. Reruns of a single failed job are still right for flakes. The controller that wrote this asked ~15 owners to "push once" in one evening and put ~60 jobs each back into a 40-slot queue.

**The `base_sha` corollary (2026-09-13) — this controller's own inference, not a sanctioned exception to Sami's verbatim 09-11 no-rebase ruling.** A re-run replays the cached test-merge with `base_sha` frozen at the branch's last *synchronize*, so a PR whose last push predates a main-side fix **cannot observe that fix, ever, however many times it re-fires**. Re-firing such a PR is a guaranteed no-op that still consumes a queue slot. Only a push refreshes the merge base. Sami's 09-11 ruling forbids a rebase absent a conflict; it does not carve out this case. So, as this controller's own judgment call and not a ruling Sami made: never ask for a rebase to "pick up main" on a *hypothesis*, and never ask for one even when a fix is on main and a whole class of PRs is red only on it — the controller does not ask owners to rebase-push to "pick up main" at all. Measured the hard way twice in one night: a re-fire sweep abandoned after 10 no-ops, and a "known red, re-fire it" instruction I issued that could not have worked. If a main-red class is blocking many PRs, the controller asks Sami once on dispatch — one ask on the queue's tracking issue — before treating a push as a lever; distinguish the buckets while waiting for that ruling: red-only-on-a-main-fix → wait, do not solicit pushes; a run that never completed (cancelled by a newer push, runner lost) → bare re-fire; a red the fix does not cover → neither.

**Review-model billing (Sami, 2026-09-09 16:35Z, verbatim):** "stop freaking out about the billing of the OpenAI models - they already naturally fall back to the API billing, and sometimes API billing bottoms out and then has to top up. Just chill." A thermo pair that dies on a credits/usage error is re-run later; it is not an incident, not a dispatch, and does not trigger a fleet-wide substitution broadcast. The controller broadcast three contradictory pair rules in one afternoon (substitute / lifted / substitute again) before he said this.

**A green required aggregate check answers a narrower question than "is this mergeable and addressed" (2026-09-22).** A green-and-unpacketed nudge went out on a check read alone to a PR that was `CONFLICTING` against a sibling and carried a self-declared hold for a design session; the same night a second PR read green with zero threads and was also `CONFLICTING`. Checks do not see mergeability, a stacked base, or a body that says "held". Nor do they see an **unanswered review**: a third PR read green, 0 failing, 0 pending, and was nudged as ready while an automated review round at its head carried three valid open findings that had never been filed as threads, so the unresolved-**thread** count could not see them. And they do not see a **head that is not the branch's tip**: on this controller's own skill PR, `gh pr view --json headRefOid` and `gh api .../pulls/<n>` both reported a sha one commit behind `git/ref/heads/<branch>`, stable across three reads over 68 seconds, because GitHub had not fired the synchronize event — a merge at that moment would have landed the PR *without* the commit it had been amended to add. So the sweep reads four things beside the checks: `mergeable_state`; the head's own review states; the branch ref compared against the PR's head association (`gh pr view --json headRefOid` is the PR's *association* with a sha, not the branch's tip, and when they disagree the PR merges something other than what you pushed); and the body, for a hold the author declared themselves.

**When the streaming job-log API returns nothing, read the run-level logs ZIP (2026-09-22).** `gh api repos/O/R/actions/jobs/<id>/logs` returned an empty body on one job and refused with "the response contains terminal escape sequences" on another, and `gh run view --log-failed` streamed 3,837 PASSED rows with no summary — which cost an hour and a refusal to classify a red. Two instruments recover it: `--allow-escape-sequences` piped through `sed 's/\x1b\[[0-9;]*m//g'`, and for a completed run the run-level ZIP (`gh api repos/O/R/actions/runs/<id>/logs`), whose per-job `.txt` carries the `short test summary` the stream dropped. Refusing to name a failing test from an empty log is right; staying unable to is not.

**Write merge bodies with a quoted heredoc, never a double-quoted `printf` (2026-09-22).** Backticks and `$` inside `printf "%s\n" "…"` are executed by the shell: four spans of a merge body were silently dropped with "command not found" while the merge itself succeeded. Use `cat > body.txt <<'EOF'` so the body is literal, and remember the merge message is the permanent record of why the gate was met.

**Do not infer which blocker is biting from a stalled symptom (2026-09-22, three times in one night, twice by this controller).** A stalled `wait-for-images` looks identical whether an ancestor run is unfinished or the needed image was never published, so "the gate image failed, therefore no apply can ever proceed" was asserted and disproved 30 minutes later by the wait succeeding. The same shape produced a wrong "four chains failed identically" claim built from two logs and two job conclusions — the other two had a different failing test and a different mechanism, split exactly at a merge boundary. And a builder diagnosis blamed daemon death, then a torn cache, then spot preemption, before the logs named an idle-watchdog. In each case the instrument that decides — the wait's own verdict, the four logs, the wrapper's retry lines — was available and unread. State the mechanism you have measured and name the one you have not.

**Removing a shared observation surface needs more than one announcement (2026-09-22).** After cancelling a scheduled run that three lanes were independently watching as their diagnostic datum, all three reasoned from it afterwards — each had it in flight when the cancel landed. Name the removed artifact again in the next status to every lane that referenced it, and say what was traded away for removing it.

Three failure modes, all observed:

- **Re-imposing a lifted hold.** Sami released a hold at 17:56; the controller acknowledged it at 17:57 and then told the owner at 20:26 that the hold stood, and put it back on his list at 23:41. Cost: 7h26 and another integration pass. **A hold is lifted the moment he says so. Never restore one from memory.**
- **Manufacturing a serial queue.** Bundling engineering calls into "decisions for Sami" stopped a green PR for 3h45. If it is an engineering judgment, make it and name it as yours.
- **Waiting to be asked.** Owners lose 60–90 min per PR waiting for a controller round that a 15-minute sweep would have started.

**Pre-merge proof on a production-like surface (Sami, 2026-09-13, verbatim):** "This should be obvious: the agent that developed it is responsible for testing, and they should be responsible for testing before it gets to production. There's this problem where we keep thinking that the proper way to develop things is to merge them and then test it, and that's obviously unacceptable. They need to test everything in a production-like environment before merging, and it is the agent that develops the feature that is responsible for doing that. If there's anything blocking that, we need to fix it: if it's infrastructure, we need to fix it; if it's tooling, we need to develop it; if it's skills, we need to fix the skills. Maybe using Legion will help with this, but it should not require deploying to production to realize your feature doesn't work. Also, the agent that developed it should be responsible for testing in production." Gate consequence for the controller: a PR that changes a user-facing surface is not approvable without a link to a pre-merge proof on a production-like surface — a run, screenshot, or e2e on a dev stack, staging, or a local stack with real migrations. A green unit suite is not it. What counts as that surface for each kind of change is the repo's own fact. Do not extend this into anything he did not say.

## 1. Priority: value, not readiness

Use the current recorded priorities. With no specific order in force, sequence by user value and dependencies rather than whichever PR reports READY first. Do not revive a dated category ranking as a standing rule.

Two corollaries:

- **Account for corpus-wide integration risk.** A large corpus merge can invalidate many peers; include that rebase cost in sequencing instead of letting it age behind unrelated small changes.
- **A stalled feature PR is your problem.** Sweep every open PR you own, including the ones nobody reported.

## 2. Blocking findings are fixed in the PR; non-blocking findings are follow-ups with a named destination

**Sami, 2026-09-23 04:28Z, verbatim:** "I'd like to start getting things merged faster. I want to keep thermonuclear and code-simplify reviews to the end, and non-blocking findings can be addressed in follow-ups and/or as part of implementing whatever's next on the agent's backlog (not allowed to just ignore it, of course)."

**Sami, 2026-09-23 17:12Z, answering the queue's ask on what "to the end" means:** **"Last thing before merge, once at the final head."** So the thermonuclear pair and the simplify pass ARE merge gates — run once, at the final code head, after every other round is closed, never per push. From 04:28Z to 17:12Z the queue applied "to the end" as after-merge (105 merges under that reading; the option he selected stated "today's merges are not re-gated", so they stand); that reading was the controller's, it was asked rather than assumed, and it was wrong. What the 04:28Z ruling still governs unchanged: non-blocking findings — from the pair included — go to follow-ups with a named destination.

This supersedes the 09-11 "no deferrals" rule for **non-blocking** findings only. What 09-11 still governs, verbatim: "all correctness fixes need to be made in the same PR. Those cannot be deferred under any circumstances." So:

- **Blocking** = a correctness or security defect in shipped behaviour, or a test that would pass on the very bug it is the PR's evidence against. Fixed in the PR, before merge, no exceptions. **Who decides: the owner, on the thread, and the independent reviewer whose verdict at the head confirms nothing blocking remains — never the controller** (§8: "you own the count"). The reviewer's marker is that reviewer's opinion of severity; the owner's disposition on the thread is the classification; the verdict at head is the check on it. A 🔴 whose body is about test quality can be dispositioned as a follow-up (a YAML test that string-matches instead of executing — #19868, 2026-09-23, dispositioned by its owner, confirmed by the reviewer's APPROVE at head, paid by #19893 the same morning); a 🟡 whose body is a fail-open in a delivery gate was dispositioned as blocking and fixed (same PR). What the controller does when a packet's blocking count and the GraphQL census disagree is bounce with the list of undispositioned threads — not rule on them. The controller read and classified #19868's threads itself in the bounce; the outcome held, the act was outside the role, and this sentence exists so it is not repeated.
- **Non-blocking** = everything else: test-strength, naming, docs polish, a TESTING.md §3 evidence request on a test that is not the PR's proof, a 🔵 of any kind. The owner replies on the thread with **where it goes** — a follow-up PR, a backlog item, or the next task in their lane — and resolves it. The controller names each follow-up in the merge body. A thread resolved with no destination named is ignoring the finding, which is the one thing the ruling forbids.
- **One push per review round, not per finding.** Fix the round's blockers, run the local lanes, push once. The controller never tells an owner to stop pushing a fix.
- Minors do not need a fresh verdict on their own — the verdict ran at the last *code* head with behaviour in it; a Minor-only round updates the head, not the verdict (controller's call, stated in the merge body).

History, so a reader can tell a ruling from drift: 09-11 was "no deferrals" ("Why are you telling agents not to fix their shit?" — to a controller that told an owner not to push a Minor). 09-23 relaxed it for non-blocking findings after a night of ~17 merges in which docs-only PRs waited hours on Minor threads. The 09-11 sentence about correctness fixes is unchanged.

## 3. The gates

| Gate | Passes when | Does not pass when |
|---|---|---|
| CI | the repo's required aggregate check succeeds and no required lane is non-green at the head being merged (the repo's CI docs name the aggregate job) | an in-progress lane; "green except the expected red" (list the reds — one is usually not the expected one). A cancelled lane that is a *superseded run* is fine; verify by run id, not by conclusion |
| Threads | 0 unresolved **blocking** threads (blocking as dispositioned by the owner and confirmed by the verdict at head, per §2; human threads count as blocking until the human resolves them); every non-blocking thread resolved with a named follow-up destination | a count from memory (three owners reported "0 unresolved" against a stale read in one night — require GraphQL `reviewThreads.isResolved` output, **every author**: one packet said "Blocking: 0" over five unanswered threads from a second reviewer); a non-blocking thread resolved with no destination |
| Verdict | an independent reviewer's verdict artifact **on the PR** (review body or issue comment) naming the exact head; or, across a rebase, the PR's own contribution proven identical at both heads by a check the controller can *run* — blob hashes when the surrounding file did not move, sorted +/- lines of `git diff` otherwise — with the pre-rebase head reachable (the owner pushes it as a tag if the force-push dropped it). A post-verdict commit that changes content is a new head and needs a re-cite; the controller does not read the delta to decide it is harmless | the owner's word; a verdict quoted in a packet but never posted; a verdict naming an older head that is not an ancestor of the current one (rewritten branch ⇒ verdict void); **a carry check that failed to run** (old head unreachable, empty left side) treated as a pass — #19911, 2026-09-23, merged on the owner's claim after the controller's comparison silently compared against nothing; "test-only delta, no production line moved" as a substitute for a re-cite (#19885, same day). *Attribution:* this row is the controller's standing practice (see "A verdict head is a fact about a sha" below), written into the table 2026-09-23 alongside the cadence ruling; it is not itself a Sami ruling | **`headRefOid` IS THE WRONG DISCRIMINATOR for whether a verdict survives a head move** (queue ruling, 2026-09-25): it changes on a CLEAN rebase and on a conflict-RESOLVING one alike, and only the second earns a re-dispatch. Compare the PR's OWN diff — against its base, per-file patch text — between the verdict's head and the current head. BYTE-IDENTICAL (a clean rebase) CARRIES: behaviour at the new base is covered by green CI at the new merge-ref, the same mechanism that covers every PR whose base advanced during its open window, and a clean rebase is only the explicit form of "main moved under me". CHANGED (a fix round, or a rebase that resolved conflicts and altered the contribution) re-dispatches, because the contribution the verdict described no longer exists. The residual — a reviewer's BASE-DEPENDENT reasoning invalidated by a base change with no CI-detectable effect — is real but not rebase-specific: it exists for every PR reviewed against an older base than its merge base, so a clean rebase adds no risk over that baseline. `pr-gate` already computes this comparison and prints "PR-own diff IDENTICAL … a confirmation, not a round", so the check is a read, not a judgement.
| E2E | the user path exercised on the real surface at the merged head, with ids — and an **oracle red-team of that plan and evidence** returned no unproven claim. The oracle's verdict is an artifact like any other: it counts when it is **posted on the PR** naming the head (or a tree the head shares, both shas and the tree stated), was run by a session that is not the PR's author lane (a coordinator or reviewer seat), and lists its gaps with each item's disposition; then the controller dispatches its own oracle only when the packet's e2e line names an artifact the posted oracle did not see (a re-run, a new head). An oracle claimed in a packet but not on the PR is testimony (#1321, 2026-09-25); a controller re-running an oracle a lane already posted is duplicate work (~25 min per PR, measured by the e2e lane the same night) | a unit test standing in; a proof 16 commits behind; "infra-blocked, accept a substitute"; an advisory lane presented as a gate; a Stage/e2e run whose harness does not exercise the changed path (one project's staged pods run a sleep stub and never launch the agent argv); a green pipeline gate that never scheduled onto the surface the change replaced — when a pin changes node userData, the gate to ask for is "did a gating cell land on a post-apply node", not "is staging-e2e green": on #20054 (2026-09-25) staging-e2e went green with 0 of 8 gVisor cells on the new runtime and production applied with 0 of 85, because do-not-disrupt sandboxes pin the drifted nodes; the runtime's only evidence was a node-level CRI probe, and the risk was time-shifted to the first replaced node, not retired |
| Thermonuclear | the **owner** ran deep + quality **once**, at the **final code head**, after every review round is closed, and the verdict is **posted on the PR** naming that head; its non-blocking findings carry a destination under §2 (Sami, 2026-09-23 17:12Z: "Last thing before merge, once at the final head") | run per push; run before the last review round; a docs-only PR gated on thermo at all (Sami: "we don't need thermonuclear review on a docs-only PR"); a Minor-only round after the pair treated as a new code head |
| Simplify | owner runs `ce-simplify-code` **once, before the pair**, at the head where every review round is closed, GPT reviewers, scoped to the PR's own diff. 0 applied → that head is the final head; applied → the applied head is the final head: CI runs on it, the pair runs once on it, and the E2E proof re-runs on it for the surface the simplify diff touched (Sami, 2026-09-13: test on the real surface before merging, no shortcuts — a refactor that "preserves behaviour" is a claim until it is executed). That cost is why 0-applied is the expected outcome and a pass that applies is spent sparingly. **Order: simplify is the last code change; the pair is the last review** (controller's sequencing call under Sami's 17:12Z "once at the final head", 2026-09-23; sdd.md and the worker skills of `core/reviewer.md` carry the same words). A docs-only PR gets neither pass: no code to simplify, no pair to run | a second pass; a pass that manufactures a new full-review campaign; the pair run before simplify and then carried across simplify's edits. Zero uniquely-attributed merge blockers came from this gate in a 14-hour window — keep it cheap |
**What the pair and simplify are gated on: runtime code.** Three classes, as the queue applied them on 2026-09-23/24. (a) Docs/prose only — including a docstring or comment-only delta — one reviewer, no pair (#19852, #19985, #20002). (b) Test-only — every changed file is a test module and no runtime line moves — one reviewer, no pair, *provided the reviewer's verdict shows the tests were exercised adversarially*: sabotage/mutants in both directions so no assertion went vacuous, and nothing deleted or loosened a gate (#20011, #20016, and one project's #1290: six gate sabotages per loop). A test-only PR that deletes or loosens assertions is not test-only in spirit and gets the pair. (c) Anything else — runtime code, CI config, Dockerfiles, scripts, IaC — simplify once, then the pair once, at the final head (a Dockerfile that changes what production builds on is code: #1280, 2026-09-24). Tests-only *deltas* on an already-paired PR carry the pair's verdict (the tests-only waiver), but the reviewer still re-cites the head.

**An APPROVE by login `sjawhar` may be the queue's own, and identity cannot tell you which.** The queue merges under an admin PAT that authenticates as Sami's login, so its approvals are indistinguishable from a human click except by BODY: the queue's carries its merge format ("Verified ... at head `<sha>`"). Two lanes read one as his in one night — a controller cited review 5324088494 on #20200 as "Sami's human APPROVE" (the authorization was intact anyway, standing on a fresh reviewer's MERGE at 36ae1e27), and platform reports made the same misread on #19837 hours earlier. `pr-gate` now excludes reviews by that login whose body matches the merge format, so a failed merge's leftover approval can never read as a verdict; when reading by hand, quote the body before attributing an approval to a person. The same file-it-anyway rule applies to your own earlier claims: both lanes corrected their record unprompted, which is why the gate could be fixed rather than the fact merely disputed.

**Migrations: two checks at merge time, neither visible from the PR's own green.** (1) `down_revision` must equal main's CURRENT alembic head at the moment you merge (read main's newest `migrations/versions/` file then, not from the packet); two PRs both parented on the same head each show one head against main and leave two heads once both land (platform PO's rule, 2026-09-24 17:52, applied on 0156/0161/0163/0157). (2) A migration that TIGHTENS a column (NOT NULL, a CHECK, a dropped default) can conflict semantically with a writer another PR added after the migration's branch point: each PR green alone, red merged, and every deploy chain skips production-apply until a fixture fix lands. Before merging such a migration, grep current main for writers of that table (`INSERT INTO <table>`, ORM inserts, test fixtures) that the PR's census did not list (2026-09-24 19:56: #19994's 0157 made `access_grant.kind` NOT NULL; #20058, merged four hours earlier, had added an `access_grant` insert without `kind` in a Playwright fixture; the `down_revision` check passed and this class went through).

**You are not a reviewer** (Sami, 2026-09-08, verbatim: "YOU are not supposed to be reviewing anything. That's not the correct process. You dispatch an oracle to red-team their end-to-end testing plan/evidence, but that's it. You are not a reviewer, and stop pretending to be one."). Code review is the owner's: their bot threads, their thermo pair, their simplify pass. You do not read diffs, run astra passes, skim hunks, or classify a reviewer's finding as correctness or cleanup — the owner dispositions threads; you check the GraphQL count. The **one** review-shaped thing you dispatch is an `oracle` (read-only) over the owner's e2e plan and evidence: does what they ran prove the changed behaviour on the surface that executes it, at the head being merged? Give it the READY packet, the PR body's verification section, and the PR's file list; take back named gaps, relay them as the oracle's, and merge when the owner closes them. Docs-only PRs have no e2e; no oracle.

E2E means the surface that *executes* the change. When a PR configures a third-party runtime (agent, collector, scheduler), demand proof from that runtime. And when reviewers agree a tightened assertion is safe **on theory**, run it once against real data before merging: a "safe" e2e tightening would have false-failed every run of its own lane, and only dev-slot data showed it.

A batch scope, blast radius, or "N instances" count handed to you is a claim about the tree and gets the same treatment as a proof: a string match shows a file *mentions* something; only the call site shows the code *does* it. Three censuses in one night were wrong from grep alone — docstring prose over-counted (10 reported against 18 real; a fixture reported "still broken" that was already fixed), and an anchored regex missed every absolute-URL call (four tasks reported clean that were not). Ask how the count was derived before registering N PRs against it; a zero-diff PR declined because the owner ran the fixture on a live sandbox against main is the right outcome, not a missed item.

An observation is not a mechanism. "Adding X made it work" is a correlation until the owner can say why, and relaying it as a property manufactures a constraint ten other agents then design around — one evening's "the resolver is viewport-scoped; scroll first" reached ten workers before a production reproduction showed the resolver was never viewport-scoped (the listing was, and a harness on a pre-fix image was the likelier variable). Relay a live-behaviour claim only with the image tag, sha, or config it was observed on attached; without that, the next person cannot tell whether the explanation or the conditions were the variable.

## 4. Loop

**Per-PR record.** Identify the existing queue record from the request or current authoritative role notes before adding anything. If none is supplied, keep the gate evidence on the existing PR/issue surface; never guess or create a queue issue or second tracker. Record the PR number, observed head, and owner; the check/thread/evidence facts for that head with checked-at timestamps and GitHub/run source links; the disposition; and the next responsible action. For runtime proof, name the consuming component, exact revision, and observation/run id. Update it at registration, each surfaced delta, and merge. GitHub is live truth: this record is evidence, not a derived queue database or helper.

1. **Register at open**, not at READY: PR#, head, purpose, files, the e2e surface the owner will prove it on. Send the gate contract then — not after they report ready.
2. **Sweep every 15 minutes**: every open PR you own, all authors. Heads, CI, threads, mergeability. Pull; do not wait for reports.
3. **Verify at surfacing time from GitHub**, never from the report.
4. **Verify the READY packet against GitHub**: head, the required aggregate check's run id, GraphQL unresolved count, mergeability, owner's thermo verdict at the code head.
5. **Dispatch the oracle** on the e2e plan/evidence for any PR that changes behaviour. Relay its gaps with the oracle's wording; do not add findings of your own.
6. **Merge** when CI, threads, thermo, and the oracle hold, under the current authority; record it on that existing evidence surface with the gate facts. Do not open the diff.
7. **Post-merge**: `post-merge` skill, name the owner's post-merge proof and its expected signature, and name who owns the rebases of PRs sequenced behind it. **Enumerate the merged PR's stacked CHILDREN in the same breath** — `gh pr list --base <merged branch>` — because a squash-merged parent leaves every child CONFLICTING, and tell each child's lane in ONE message rather than letting them discover it a round at a time. Measured 2026-09-26: nine repacket rounds on one stack (#1383, #1410, #1411, #1405, #1408, #1395, #1389, #1430, #1390/#1403), each lane finding the same conflict separately after its parent landed.
8. **Compound** (Sami, 2026-09-08): after the green light, the owner runs `ce-compound` on the PR — the learnings that would make the next iteration faster, especially anything that can be pushed without an extra review — and lands them as a **docs-only follow-up PR** (docs-only skips thermo; a repush to the merged PR would re-trigger CI). The follow-up ships in the owner's next working block; it is not optional and it is not a shelf.

## 5. Identity and approval mechanics

- **Agent PRs use the bot identity.** Check the author, required reviewers and approved credentials before promising a merge. A self-approval restriction or missing review is an unmet requirement, not permission for an admin bypass.
- Verify the identity and session-bound credential routing of any write path. Tool choice alone does not establish which identity will post.
- Paths in the repo's `CODEOWNERS` may require a non-author team approval. Establish the actual requirement at registration.
- An expired, unavailable or rejected credential is not a reason to reuse a historical personal token or invent another authorization path.

## 6. Relay Sami's answers

For a native Dispatch answer, read its ask and reply thread with
`dispatch_read({ref: "dispatch://<KEY>/ask/<id>"})`; GitHub issue comments are not
that record. Use the linked PR and current queue record to identify the originating
owner or role. Check whether the owner already acted, then relay any still-pending
ruling once through Envoy with its source link and exact scope. If the answer was
actually posted on GitHub, read that specific thread instead of substituting it
for a Dispatch answer.

## 7. Sequencing with owners

- **Packets, not sweeps** (Sami, 2026-09-23 17:12Z: "why do you need to sweep for anything? Shouldn't active agents be notifying you when they're ready?"). The queue acts on a lane's READY packet and on CI settling for a packeted PR; it does not census every open PR on a timer. The one standing poll is an **orphan check every 30 minutes**: PRs whose owner session is gone (a retired role, a closed lane) and that nobody will packet — those the queue adopts (§7 "Whose packet") or closes. Every packet is still verified at the head on arrival; that verification, not the sweep, is what caught the wrong-count packets of 2026-09-23 (#19868, #19888, #19936).
- Demand READY from **facts**: head, CI at that head, GraphQL thread count, the owner's thermo verdict at the code head, and the e2e evidence (surface, command or run id, what was observed). Owners who built a `pr-gate` command (head + check conclusions + unresolved count → READY/NOT) stopped producing false reports entirely — recommend it.
- **Never let an owner foreground-poll CI.** 77 of 137 minutes on one PR, 126 minutes on another, 136 on a third. A supervised background watcher is the fix.
- When two PRs collide, get the path list from both owners and serialize only the shared boundary. Whoever is mid-repair absorbs the rebase.
- **A held item's state is RE-DERIVED at every periodic, never carried forward.** Head sha, verdict list and mergeability come from a fresh read each time; "unchanged since T" may be written only after a read that returned the same head, and if your last read is older than the item's own likely settle time it is not a fact, it is a memory. One controller reported a pull request stuck for SIX HOURS - conflicting, no verdict - while its owner had rebased at 03:51 and a reviewer had approved at 04:13; re-reading the surface merged it in one step. It was the requester's own explicit ask (2026-09-26). And "escalate next periodic", written twice, is itself the signal to escalate NOW by another route, starting with re-reading the thing you are escalating about.
- **A packet whose only verdict is the owner's declares itself in its first line**, as `SELF-VERDICT - needs clearance or an independent reader`, and the controller holds until one exists. It never reasons its way to clearance from an earlier general ruling: one merge on that inference was judged correct afterwards by an independent reader, which is luck, not process. When the usual clearer is unreachable, the live independent-review path costs about ten minutes and is the answer (2026-09-26).
- **Never `| head -N` a verdict search: the verdict you want is the LAST one, not the first token.** A controller's `grep -oiE 'VERDICT...|BLOCK' | head -3` returned three hits of `BLOCK`, all references to a fixed round-one finding, and nearly read two positive reviews as rejections - the `VERDICT: MERGE at <head>` lines sat at body lines 85 and 102, past the cut (2026-09-26). Filter to the verdict terms and read every hit with its line number.
- **Whose packet.** The packet comes from the PR's *gate lane*, not from whoever is nearest. A PR that delivers an issue a coordinator session owns takes its packet from that coordinator, never from the PR's own lane — a lane may not gate its own PR (platform PO ruling, 2026-09-23 09:07Z, after #19903's lane-local reviewer said MERGE while the coordinator's gate was finding a blocking item in the same file). Test: the PR body or its tracker link names an issue that coordinator owns → hold for their packet. A lane with no coordinator (docs from the librarian, an SRE runbook, an orphaned PR the queue adopted) packets itself with an independent reviewer's verdict.
- **Gate the merge in the same read as the census.** Never run "census, then merge" as two hand-typed steps or as two commands on one line: #19903 merged with a blocking thread posted four minutes earlier because the census printed `unres=1` and the merge on the same line ran anyway. The merge script takes the head, re-reads `pr-checks-result` and `reviewThreads.isResolved`, and refuses unless both pass at that read.
- **Same-file siblings: the oldest approved PR merges first.** Three IPI-list PRs sharing `IpiTaskList.tsx` landed 90 s ahead of a fourth twice in one night, conflicting an approved PR each time (#19853, bumped by #19854 then #19862). When two ready PRs touch one file, the one that has waited longest goes first and the other rebases.
- Retro: after a slow PR, have the owner dispatch a strong subagent over their own transcript (where wall-clock went, which rounds were avoidable, what would halve it at the same bar). Do it for yourself too — it is how this section got written.
- **Stacked PRs.** Two facts decide the mechanics, both learned 2026-09-24/25 on one stacked series. (1) Merging *into* an intermediate branch forces a restack of every PR above it (the squash replaces the commits they sit on); merging *top-down* — the topmost PR first, so nothing is ever above the one being merged — forces none (Sami, via that lane, 23:48Z: "we are not blocked on anything; the fix is either `gh stack` or simply merging the stack top-down"; his first answer to a proposed repo-settings change for merge commits was "You're being an idiot. Use gh stack"). (2) Once PRs are grouped as a **GitHub Stack** (`gh api repos/O/R/pulls/N -q .stack` is non-null), `PUT /pulls/N/merge` is refused for every member — "Merging stacked PRs via this endpoint is not supported. Use the asynchronous merge endpoint instead" — and the only merge shape is `gh stack merge <stack#> --yes --squash`: atomic, bottom-to-top, into the stack's trunk, scoped "up to and including PR N", never "just the top layer". Read that refusal as what it says; it is not a permissions problem. The extension runs under the real `gh` binary with `GH_TOKEN=<PAT>` from a clone of the repo (the dotfiles shim cannot run extensions). **Pre-flight every stack merge with `git merge-tree --write-tree` replayed against the actual trunk, PR by PR in stack order** — GitHub's per-PR `mergeable` on a stacked member is measured against the *stack base*, not trunk (#1287 read `mergeable=true` while conflicting with main in `scripts/e2e/README.md`; the atomic merge refused and nothing landed). A refusal names nothing; the replay names the file. Every member still lands on its own verdict at its own head; the order and the tool remove the restacks, not the gate. (3) After a squash merge of a stack's ROOT, run `git merge-base --is-ancestor <root sha> origin/main`: it answers NO, because the squash replaced that commit. GitHub retargets the leaves' BASES to main, but their commits still sit on the old root, so the stack needs one rebase onto main before anything above it is readable — a leaf whose base looks right is not therefore rebased (2026-09-25, after #19933's seventh merge).
- **An amended head has no ancestry to carry across.** Before reading a post-verdict delta, check `git merge-base --is-ancestor <verdict-sha> <head>`; if the verdict sha is a *sibling* (the owner amended), GitHub's three-dot compare `A...B` shows the whole contribution over the common base, not the amend — on #20042 (2026-09-24) it showed 22 added lines and the queue called them "the nit"; the direct tree diff `git diff A B` showed the real 6+/4-. Siblings get `git diff A B`, never `compare`.

## 8. What you do NOT do

- Review. No astra passes, no delta reads, no diff-shape skims, no ruling on whether a bot Major is "correctness". The owner owns every thread; you own the count. The night this was written the controller ran 21 astra passes on CI/infra PRs, adjudicated bot findings by hand, and held a green 61-file PR four hours on a "merge vs split" question it had the authority to answer.
- Turn an engineering call into a "Sami decision". Merge-vs-split, whether a Minor-only round needs a fresh pair, which of two green PRs first — yours. If something is genuinely his (authority, taste, risk), ask it on **dispatch** as a follow-up on the issue that tracks the queue — never a new issue per question, and never by recording it on the record issue and calling it asked (nothing subscribes him there). Sami's rule for every agent (verbatim, 2026-09-08): "they should have an issue that's tracking the work that they're working on, and they should add the question to that existing issue and not file a new issue for every question." Owners ask him themselves; you do not relay for them and you do not tell them when they may ask.
- Rebase, push, or run an owner's e2e. Return the gap named.
- Change CI, validators, or models to let content through. A one-time correction uses the existing label bypass, never a code change.
- Investigate deeply on a PR you own. If you are reading an owner's run transcripts, you are the bottleneck.
- Give inspecting subagents write access to a shared jj workspace.
- Keep a state machine. GitHub is the truth; re-query it. Keep a ledger of rulings and merges only.

## 9. Red flags — stop and re-verify

- "Threads all dispositioned" → re-query GraphQL yourself.
- "Branch tip" / "current head" on a live proof → check the pinned SHA in the run config.
- "Behavior-preserving" / "tests only" → diff the hunk.
- "Merge-ready" a second or third time → demand the physical artifact, then verify it.
- "Expected red" → list the reds.
- An owner reports the same class of finding on pass 3+ → the review is doing design work. Stop and force a design decision.
- An advisory result is offered as E2E proof → read its actual lane/case artifact; do not equate its workflow badge with a pass or require promotion merely to recognize valid evidence.
- A packet says "the pair ran" → open the pair's comments and read the first paragraph for a substitution disclosure ("the named agents cannot be spawned from this session"). On 2026-09-23 a coordinator gate whose spawn policy allowed only `scout` loaded the two rubrics into scout lanes and its packets summarised that upward as the pair; the real pair, run afterwards on four merged commits, found a false prose claim in every one (#19934, #19960, #19941, #19935). The rubric is not the review: model, depth, tool surface and cross-model independence are what the pair buys. When a merged body relied on it, post a correction comment on the PR; fixes are follow-ups, not reverts.
- A merged PR did not deploy → read the merge commit's **commit status**, not just its check-runs. Terminal on Vercel blocks a deployment whose squash author is not connected to the Vercel team (an external contributor's PR keeps their authorship through squash); the merge succeeds and production stays where it was. Sami's ruling (OPS-116, 2026-09-23): keep the workaround, deploy by hand or by the next connected-author commit, never connect the account. After merging an external author's PR there, read the status and name who deploys it in the merge body.
- Your own verification and the merge command share one shell invocation → split them, and gate the merge on the check's exit code (`./carry-check.sh … && ./merge-one.sh …`). Twice on 2026-09-24 (#19992 01:39Z, #1270 02:06Z) a diff-of-diffs / file-list check printed DIFFERS and the merge on the next line ran anyway, because the check's output was read after the merge. The first was a wrong-subject instrument (a stacked PR compared against merge-base(main) instead of its parent PR's head — the check measured the parent's contribution too); the second was a real file-list growth the packet had denied. Both outcomes were benign; the sequencing was the defect, and a correction comment on each PR was the cost. A check whose result you have not read has not run.
- "The queue writes every merge body" → read one merged commit's message back (`gh api repos/O/R/commits/<sha> -q .commit.message`). For two nights the merge scripts sent only `merge_method`+`sha` to `PUT /merge`, so every squash carried GitHub's `COMMIT_MESSAGES` default (the first bullet being whichever first commit's subject, true or not) while the written record sat only in the APPROVE review's body; the librarian found it on #20020 (2026-09-24). Fixed by sending `commit_title` and `commit_message`; the rule is the claim-is-not-coverage one applied to the queue itself — a path you built to write X has written X only when you have read X back.
- A PR with check-suites `queued` and **zero check-runs** → read `mergeable_state` before anyone says "CI is broken" (`landing-a-pr`, "Zero check-runs is not a failed check"). Which App suites sit queued by design is the repo's own fact.
- "Artifacts verified at head, counts match" and the merge follows → ask whether §4 step 5 ran. Verifying reviews, threads, CI and carries is the controller's half; the **oracle red-team of the e2e evidence** is a separate, dispatched instrument for every behaviour-changing PR, and no amount of artifact-checking substitutes for it. On 2026-09-24/25 the queue ran ~15 hours and ~40 behaviour-changing merges (production-affecting infra and platform) on packets whose e2e claims nobody adversarial had read; Sami had to say it (05:03Z: "remember that you should be dispatching an oracle to red-teaming the e2e testing evidence presented by agents"). The tell is a packet whose e2e line you *checked for presence* rather than handed to the oracle. Retroactive oracle passes go to owners as follow-ups, never reverts.
- A packet's merge condition is "the watcher is live" and you read its first log line → that proves the process started, not that its detector works. Ask for the line that names the thing it watches (a run id it attached to, a snapshot of that run's jobs), and read a second line. On 2026-09-25 the queue merged a production node-runtime replacement (#20054) on a watcher whose run-selection query was silently empty (`gh --jq` is not jq; `--arg` rejected) — it would have waited forever without a false green or a true one; the owner found it 16 minutes later while watching it produce nothing. The general form of the identity assertion: does the thing that came back name the thing I asked for.
- You are about to send a verdict, bounce or ruling to a session id you *remember* → read the PR's `Omp-Session:` trailer first (`gh api repos/O/R/pulls/N/commits --jq '.[].commit.message'`) and send to that. On 2026-09-25 09:21Z the queue relayed #20097's oracle verdict to the hiring lane (`01a0a2bf…`) instead of its owner (`01a0a231…`) on a remembered prefix; the recipient refused it and nothing was acted on, but a lane that had acted would have worked another PR's findings. Session ids collide on their first bytes; the trailer is the identity, memory is not.
- The oracle for a `cybertasks` PR returns a policy refusal after a minute → that is the seat, not the evidence: the Anthropic oracle refuses the CVE-task material under its cyber usage policy even when the question is about supervisors and restart wrappers (2026-09-25, cybertasks#249; the lane's own code-quality agent had refused the same way). Re-dispatch read-only on a non-Anthropic seat (`gpt-api`; `astra` when its subscription has quota) with the same brief, and record the seat in the ledger. A refusal is not a verdict and does not hold or clear the PR.
- A lane reports an oracle's blocking close is on the PR, and you merge on the gate + its word before reading the close yourself → search **all** content (body AND every comment) for the close *before* the merge command, not after. The closes often live in a comment, not the body: on 2026-09-25 11:23Z the queue merged #20125 having grepped only the PR body, where the pre-dispatch gate that closed the oracle's blocking (`pulumi stack output ref_luthien_admin_alb_arn_suffix` as check 0, replacing a false 'the ordering enforces itself' claim) returned zero hits — it was in the production-check comment, and a full-content search *after* the merge is what found it. It came out right; the sequence was the defect. Two corollaries the same PR taught: a lane's 'I landed that body edit' is a claim to verify by read-back, not trust (ImageBump5 reported two body edits landed; one — the mutation paragraph — had not, caught only by the queue's own grep finding no `9 passed`); and a minor whose *substance* is in the code and green in CI does not block even when its body prose is missing (that mutation paragraph became a post-merge body edit, no merge impact).

## Why the bar is this high, and why it is not higher

The gates caught, before anyone saw them: a DM lane that silently no-oped on 100% of real invocations; a judge that would have counted host solution files as attack evidence; credentials passed in `git` argv; a protected-resource replacement; a synthetic receipt that would have been recorded as a real red-team submission; a refusal path that exited 0; an in-place overwrite of a customer-delivered eval with no backup. Every one was "merge-ready" per its owner.

And the cost of over-applying it, measured the same night: 21 astra runs on CI/infra PRs against 4 on feature PRs; 8 review rounds on one advisory test lane; 8 controller passes on one ordering contract; five wording-only Minors each treated as its own controller round. The bar is: every finding fixed, one push per round, the controller checks counts and evidence and ships.

### A verdict head is a fact about a sha, not a checkbox on a PR

`./prq clear` (this controller's own instrument, not a repo-standard tool) and the poll loop check CI and threads at the *current* head. Neither
knows what head the thermonuclear pair actually ran at. So a PR whose owner said
"pair done" and then pushed real code merges with a gate-3 verdict that describes a
different tree.

The failure: the pair ran at one sha, the head moved to a commit carrying real code, and
the queue merged it the moment CI went green.

**Record the verdict head in this controller's own tracking file (e.g. `owners.txt`, not a
repo-standard artifact) when a READY packet arrives, and refuse to merge when the current head is not that sha** unless the controller's own diff-shape check of the delta (per §9's red flag for "behavior-preserving" / "tests only" claims) shows it is docs/comments only — the controller's call, stated in the merge body, per §2; an owner's claim that the delta is docs/comments only is a claim to verify, not a basis to skip the diff. A Minor-only round updates the head but not the verdict; real code
needs a fresh verdict at the new head. When the breach has already happened, the repair
is a follow-up PR registered at open -- never a reopen, and never a retroactive claim
that the old verdict covered the new tree.

### sdd governs how work is produced; the gates govern what merges

Sami's instruction on 2026-09-14 ("make sure all envoy agents on this box are properly following
the sdd process") makes `~/.dotfiles/plugins/sjawhar/commands/sdd.md` binding on every coordinator
whose work reaches the queue. The following is the controller's own reading of Sami's one-line
09-14 instruction (inferred, not verbatim) into packet-format expectations at READY — they describe
what a READY packet should show, not additional gates layered onto §3:

- a READY packet names the `reviewer` FINAL review head (post-acceptance) in addition to the
  thermonuclear pair's verdict head; a PR whose author reviewed it themselves is not READY;
- every open work item carries RAN / WAIVED-BY-SAMI / BLOCKED; a BLOCKED scenario - including one
  that was simply never run - stops readiness;
- the pair stays gate 3 ON TOP of sdd's reviewer gates, not instead of them.

The audit that produced this rule (23 of 30 sessions) found substance mostly
present and structure mostly absent: coordinators implementing themselves, default-tier
implementers instead of `deep`, self-review instead of `reviewer`. The one coordinator who reviewed
its own PR that night missed a Critical the bot then caught. Three scope questions went to Sami
(task-maintenance lanes; oracle vs scout; a project's LIVE-DEFERRED acceptance) - read his
answers before ruling on any of them yourself.

The controller does not implement either. Authoring a revert PR by hand is a deviation to record, not a mechanic to repeat: dispatch `deep`.
