Skip to content

Proof-carrying review

Ordinary review asks you to reconstruct intent from a diff: you read the change and guess what it was meant to do, then guess whether it does it. For agent-authored PRs that is backwards. The agent that wrote the change has the session, the repo, and the implementation context you don’t. It is the best source for why this is correct — and the worst use of it is making you re-derive that from the lines it produced.

garden pr explain flips the direction. The author writes a walkthrough: the change ordered into blocks, each stating what it does and pointing at proof that it does it. Review becomes adjudicating evidence.

This is deliberately not a session dump. Raw sessions are enormous, ephemeral, and often personal. A walkthrough is the small, curated artifact the author chooses to stand behind.

The Walkthrough tab of a pull request. A sidebar outlines the block tree; the first block, “An ack now means the event is on disk”, carries critical path, scrutinize and risk: high tags beside a panel listing its test proofs.The Walkthrough tab of a pull request. A sidebar outlines the block tree; the first block, “An ack now means the event is on disk”, carries critical path, scrutinize and risk: high tags beside a panel listing its test proofs.
A PR’s Walkthrough tab: the summary, the author’s confidence, and the block tree in the reading order they chose.

A block’s claim is established by its own proof plus the claims of its children. The top-level blocks are the roots; together they prove the PR as a whole. So a high-level claim sits at the top and the pieces that establish it nest underneath, each with proof of its own:

  • An ack now means the event is on disk
    • Append fsyncs before it returns
    • A journal failure declines the ack instead of hiding it

The scaffold that garden pr explain <pr> prints starts at one block per changed file, but that is only a starting point. Blocks get split when a file’s hunks do different things, merged when they’re trivial, and nested to build the tree. Sibling order is the reading order — it is never re-sorted.

Attention and risk are different questions

Section titled “Attention and risk are different questions”

Every block carries both, because “important to understand” and “dangerous if wrong” are not the same property:

  • attentionskim, review, or scrutinize. How hard to look.
  • risklow, medium, or high. Blast radius if it’s wrong.

A subtle-but-reversible block and an obvious-but-irreversible one need different handling from a reviewer, and collapsing them into one “importance” score loses exactly the distinction that routes attention well.

The PR-level confidence and critical_path do the same job at the top: the author’s own certainty, and the two or three blocks to read if you only have five minutes.

Each block lists what the author did not verify. An honest gap list beats any amount of prose — it is the difference between a claim and a claim you can calibrate:

The 503 path never runs in any test. A full disk is the realistic trigger and nothing simulates one.

That is a reviewer’s next question, answered before they asked it.

Each proof entry is exactly one kind: a test CI already runs, a command you can run yourself, an attachment (a screenshot or recording), a pointer at any code in the repo — in the diff or not — an external link to a CI run or preview, or a bare note, which is the weakest and pairs with unproven.

garden does not verify proof. CI runs the tests, the CLI handles the attachments, and you follow the pointer. The discipline is in having to name something concrete.

To say a block is proven by another block, make it a child — that’s the tree.

A single block, “Append fsyncs before it returns”, with its claim on the left and a proof panel on the right showing the body of TestAppendIsDurableBeforeReturn.A single block, “Append fsyncs before it returns”, with its claim on the left and a proof panel on the right showing the body of TestAppendIsDurableBeforeReturn.
Each block’s proof is a tab away: selecting a test proof shows the test itself, next to the claim it establishes.

The tree is fixed by the nesting; layout chooses how it flattens into the reading pane. The sidebar outline stays top-down regardless.

layout reading order
top-down (default) each claim before its sub-proofs — conclusion first
bottom-up the building blocks before the claim they support
sandwich summary, then bottom-up construction, then a closing synthesis

You do not have to cover every hunk. Cover what a reviewer needs to understand and trust, and leave out imports, renames, formatting, and generated code.

Nothing is hidden by that: garden computes the hunks no block covers and shows them as an “unaccounted for” list. An uncovered hunk is a signal that the author judged it didn’t need explaining — and a reviewer who disagrees can comment and ask why.

Reviewed state follows the code, not the block

Section titled “Reviewed state follows the code, not the block”

Blocks have no stable identity across revisions — they split, merge, move, and vanish. So marking a block reviewed does not record “I read block b3”. It records “I have seen these hunks”, keyed by a content hash of the covered lines, using the same checkpoint machinery as per-file mark-reviewed.

At the next revision each block resolves against what you’ve already seen:

  • every hunk seen → reviewed, and the block collapses;
  • some changed or new → partial, surfacing only what changed;
  • none seen → unreviewed.

Because the state belongs to the content, a re-blocked walkthrough doesn’t cost you a re-review. The author can restructure the whole document and the code you already read stays read.

Threads attach to a block — and to the unaccounted-for section, so “why didn’t you explain this?” has somewhere to go. They behave like every other garden comment: drafts until submitted, and they gate the merge while unresolved.

A reviewed block collapsed to a single green row, above an expanded block whose panel shows a “not verified” gap and carries a reviewer’s comment thread.A reviewed block collapsed to a single green row, above an expanded block whose panel shows a “not verified” gap and carries a reviewer’s comment thread.
A reviewed block collapses to one line. Below it, a block’s unproven gap — and the thread it prompted.

A walkthrough belongs to one revision. A new push means a new revision and a fresh walkthrough — garden doesn’t track blocks across revisions, because the churn when blocks split and merge is not worth automating. garden pr explain on a later revision starts from the previous one, to edit and re-apply.

It lives in garden’s backend, with no source-control footprint, and is frozen when the PR merges: a permanent record of why this was done and what was verified, readable long after everyone involved has forgotten.

Terminal window
garden pr explain 42 # prints a scaffold from the diff
# …edit it…
garden pr explain apply 42 -f walkthrough.yaml
garden pr explain show 42 # read it back

There is no editor. Fill the printed template and pipe it back — agents can’t drive editors, so the flow is print-template → fill → apply. garden push prints the same reminder when an agent is the author.

Full schema: garden pr explain, or garden docs walkthrough.