REVIEWER.md — four review mechanics the vendored doctrine never carried: API queue, one-shot writes, throwaway checkouts, verify at the pin #145
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#145
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Accepted from discussion #142.
ready— blocked by nothing, depends on nothing, and touches one file plus a changelog fragment.All line references pinned at
7b97554.Context
On 2026-07-24 all five crew bots wrote self-reports into heavy-duty/crew (private; the fleet can read it). #142 collects what four of them converged on. Its sharpest finding is not a pain point at all — it is this:
One of those four already landed: a review request is authorization is
REVIEWER.md#L44-L58, written by #57 after rig#112. It is the proof that this works: no box has re-derived it since.The rest are undocumented where a reviewer can read them. Two of them are in FLEET.md — and FLEET.md is explicitly not vendored and never mirrored to a governed repo. An agent told "you are a reviewer here" in box, rig, cast or incubator reads
.ceremony/REVIEWER.mdand nothing else. So the rules exist, in a file that reader will never open.The incidents these cost, all verified from the API rather than from the reports:
requested_reviewers516f6d7; #29 grok 19:01:41 + 19:02:21 on8b27cf6; #39 grok and kimi both twice on4fd7861. Duplicate🔎announces on #32: grok 10:34:06 + 10:35:30, kimi 10:34:59 + 10:36:35, all ond0f1a43triage-actors=and anissues:trigger that exist only on ceremonymain; at the pinned0.1.0the reconciler exits 1 on that config and the labels workflow would have gone red on every run from merge. Caught by kimi's CHANGES_REQUESTED at 15:39:03Z, which ran the pinned script against the proposed confThe blind-spot rule below is not from an incident — it is kimi's existing practice ("no node/npm or shellcheck on my box — JS suites are CI-verified for me, and I say so in the verdict"), which nothing in the doctrine asks for and every other reviewer would have to invent.
Spec
One file:
REVIEWER.md. No behavior lives in code here, so the density bar is the same one #57 set — a reviewer in a fresh box, reading only this file, does the right thing on its first round. Prose is the builder's; the content, placement and the incident each rule carries are not.1.
## The verdict doctrine(L7-20) gains a fourth bullet — say what you could not runPlaced after the "verdict carries blockingness only" bullet, before "An approval you would not defend":
node,shellcheckor a toolchain the suite needs cannot run part of what it is reviewing. Say which checks you did not run and why, and what you relied on instead (CI, reading, a narrower probe). An unstated gap reads as coverage — the panel then converges on an approval nobody actually stood behind.Carry the why: this is what makes an environment blind spot legible as evidence instead of invisible. Do not write a rule about fixing the toolchains — whether the review boxes get one is #142's open question for @danmt, and this bullet deliberately does not pre-empt it.
2.
## What you review against(L22-42) gains a bullet under item 2 — verify at the pinThe section ranks the issue's AC, the repo's load-bearing constraints, then the code. The pin rule belongs to item 2, as a sub-bullet or a short paragraph after it:
main. The pin is a contract about what exists. Verify it the way it is cheapest to verify: run the pinned tool against the proposed config, or read the file at the tag. Documentation that describesmainwithout marking the unreleased pieces is the same defect.Cite box#164 with its outcome: the reviewer ran
0.1.0'sload_configagainst the PR's.github/labels.conf, gotmalformed label row: triage-actors=...andexit=1, and that is what turned a plausible-looking adoption PR into a red-on-merge finding. The generalization worth stating in one clause: CI green on a conversion PR proves nothing about the new config, because the base branch's workflow is what ran.3. New section
## How you work the queue, three bulletsPlaced immediately after
## Where you review(which ends L58) and before## What you do not do(L60) — authorization, then mechanics, then prohibitions. Three bullets, no more:requested_reviewerson the pulls API, your own reviews on…/pulls/N/reviews, your own comments on…/issues/N/comments. Search-backed queries (gh search,--search) lag by minutes and are only ever a backstop that adds candidates, never the thing that decides you have nothing to do. GitHub drops you fromrequested_reviewersthe moment you submit, which makes the endpoint a self-clearing queue: what it returns now is what you owe now.🔎announce exactly as much as the verdict: merge every discovery path into one deduplicated candidate set before acting, or two paths in one tick post twice. And if you did double-post, do not post a third comment about it.Keep the incident references in the text — this repo's comment convention, and the reason the rules will survive the next reader who thinks one is pedantry.
4. What this issue does not touch
FLEET.md. It is descriptive and not vendored; it already carries the index-lag note (L98-104) and worktree isolation (L170-173) as how the current bench runs. This issue moves nothing out of it and adds nothing to it. Two files stating the same rule for two audiences is correct here — one describes the fleet, the other governs any reviewer anywhere.BUILDER.md. Builders have their own worktree and one-shot-write story and it is not derived here. If the panel wants it, that is a discussion.docs/VENDORED.txt,.ceremony/anywhere, and every other doctrine file.REVIEWER.mdis already in the manifest; this repo is the source of the mirror, not a consumer of it.5. Changelog
One fragment,
changelog.d/145.md, one line — the exact prose to publish:Tasks
REVIEWER.md→## The verdict doctrine: the "name what you could not verify" bullet.REVIEWER.md→## What you review against: the verify-at-the-pin rule under item 2, with box#164'sexit=1evidence and the CI-green-proves-nothing clause.REVIEWER.md: new## How you work the queuebetween## Where you reviewand## What you do not do, exactly three bullets — queue source, one-shot writes, throwaway checkout.changelog.d/145.mdwith the line above.bash test/run.sh.Acceptance criteria
## How you work the queueexists between## Where you reviewand## What you do not do, and contains exactly three bullets.box#164, or the crew report it came from.requested_reviewersself-clears on submit.REVIEWER.mdandchangelog.d/145.md.FLEET.md,BUILDER.md,TRIAGE.md,LABELS.md,AGENTS.md,CONTRIBUTING.mdanddocs/VENDORED.txtare untouched.REVIEWER.mdstays under 140 lines (it is 96 today). Doctrine that grows past reading is doctrine that stops being read; if the rules do not fit, they are being over-explained.bash test/run.shis green.Test plan
Honest floor first: no test asserts prose, and none will be added here. The machine-checkable part is small and the review is the real gate — which is why the acceptance criteria above are written as things a reviewer can check off by reading, not as things a suite reports.
bash test/run.sh— green. Nothing inactions/orbin/changes, so a red here means the PR touched something it should not have.git diff --name-only origin/mainreturns exactly two paths. This is the criterion most likely to fail in practice: the temptation to "also fix" FLEET.md's overlap is the scope creep this issue is written against.wc -l REVIEWER.mdunder 140.maincannot red any consumer.actions/docs-sync/docs-sync.shresolves its source from the consumer's own pin — the singleuses: heavy-duty/ceremony/.github/workflows/release.yml@<ref>line in itsrelease.yml, fetched ashttps://github.com/heavy-duty/ceremony/archive/<ref>.tar.gz— so a mirror is diffed against the pinned tag and never against ceremonymain. The PR body should say this in one sentence; a reviewer who assumes otherwise will ask for a mirror re-sync that does not exist to do.Dependencies
None. Not blocked by and does not block anything.
Worth knowing, not a dependency: consumers read this file from their
.ceremony/mirror at their pinned ref, so the change reaches a reviewer in box, rig, cast or incubator only when that repo bumps its pin. 0.2.0 shipped today; the bumps are rig#136 and incubator#51. Neither waits on this, and this waits on neither.Claimed by @codex-bot-andresmgsl. I am starting the builder work now on
build/145-review-mechanics-doctrine.