Boatstack reviews its own pull requests with a control program built on the
domain-neutral kernel: boatstack-reviewer
(boatstack/cmd/boatstack-reviewer). The loop runs locally — normally driven
by a coding agent — and CI verifies the result deterministically. No reviewer,
model, or API key runs in CI.
Boundary: a pull request head enters review-verified state.
Control law: a head is review-verified only when a sealed receipt binds its exact receipt-excluded tree, produced by the review program whose policy assets are admitted at the pull request base revision, through a kernel receipt chain that ends in convergence.
The proposer (agent or human) is untrusted. It produces candidate findings under the admitted review policy; the reviewer owns admissibility, freshness, the convergence measure, receipts, and recovery through the kernel's resolve/apply relation.
- Modes:
unreviewed→findings-open→converged(the only marked mode), withescalatedfor bounded non-convergence. - Admitted policy:
.github/codex/review-prompt.md(review instructions) and.github/codex/review-output-schema.json(output contract). Their exact bytes, the round bound, the stall window, and the priority weights are hashed into the program fingerprint; any change stales every prior prescription and receipt. - Convergence measure: each finding weighs by priority (P0 1000, P1 100,
P2 10, P3 1). A submission that fails to decrease the measure extends a
stall run; the loop escalates on the third consecutive non-improving
submission or after sixteen rounds in one generation. The bounds are
calibrated against mined review history
(
boatstack/cmd/boatstack-reviewer/testdata/review_rounds.json). - Freshness: every submission binds the exact committed tree it reviewed. A dirty worktree, a new commit, or an edited candidate refuses admission instead of recording a stale round.
Work on a branch, commit your change, then:
boatstack-reviewer resolve --actor <name>— prints the control state and the instructions: the admitted prompt path, the exact review range (merge-base..HEAD), and the output contract. Perform the review the prompt describes over exactly that range and write the findings JSON to a file, conforming to the output schema.boatstack-reviewer submit --findings <path> --actor <name>— the reviewer validates the candidate (schema, diff anchors, tree binding) and the kernel commits one transition: findings recorded, converged, or escalated. Refusals name their reason and record nothing.- Fix the recorded findings, commit, and repeat. The measure must trend
down; convergence requires a fresh review of the fixed tree whose verdict
is
patch is correct. boatstack-reviewer seal— verifies the full receipt (round trajectory, kernel receipt chain, final review bytes) locally, archives it in the local store, and writes only a minimal attestation to.github/reviews/<instance>.receipt.json: the reviewed tree and the program fingerprint — the two facts CI cannot re-derive. Commit that file with the pull request; pushing can wait until you are ready. The receipt directory is excluded from the tree binding, so committing the attestation does not invalidate it.boatstack-reviewer showprints a recorded review itself — the exact archived findings of the latest round (--round <n>for earlier ones) and any staged, not-yet-submitted candidate — without resolving or changing anything.status,reopen --actor <name>(human capability, after escalation or to re-review a settled generation), andrecover --actor <name>(after an interrupted effect) complete the surface.
Two Yield workflows wrap this surface so any registered coding agent drives the loop through recorded, resumable operations instead of remembering the command order (adapters are registered for Cursor, Codex, and Claude Code under their skill directories):
skills/self-review— report-only: builds the reviewer from the current tree, resolves the control state, has the agent review exactly the admitted range under the admitted schema, submits, and reports the recorded verdict in the conversation. It changes no code, verifies afterwards that no tracked file changed, and never seals, commits, or pushes.skills/self-review-solve— drives to convergence: fixes open findings in code (committed by the agent), re-reviews the fixed tree, repeats within a bounded attempt budget, then seals and commits the minimal attestation locally. It never pushes; pushing is the user's decision. An escalated loop asks the human before reopening.
Run either with .yield/bin/yskill run 'skills/<name>' from the repository
root. yskill doctor 'skills/<name>' --test exercises each workflow against
a scratch repository (fixture-created, sentinel-switched), so testing never
touches real review state.
CI (.github/workflows/review-verified.yml) rebuilds the verifier and runs
boatstack-reviewer verify --dir .github/reviews --base <base> --head <head>,
which re-admits the policy from the base revision, recompiles the program
fingerprint, recomputes the receipt-excluded head tree, and checks that the
committed attestation names exactly those two facts. Nothing else travels
with the pull request: the attestation is deliberately minimal because the
program fingerprint already hashes the prompt bytes, the schema bytes, the
round bound, the stall window, and the priority weights.
Like work-package verification, the committed attestation is honest about
its boundary: it proves a review program with the base-admitted identity
sealed a convergence over the exact bound tree. The full evidence — round
trajectory, kernel receipt chain, final review bytes, and the honesty
markers semantic_correctness: not-evaluated and origin_authenticity: not-proven — is verified in full at seal time and archived in the local
store, not in the commit. The attestation does not prove the review was
semantically right, and it does not prove who performed it. Branch
protection and human judgment remain the authority for merging.
Local review state, including the archived full receipt, lives under
.git/boatstack-review/<instance>/ and never enters a commit.