Code Review Protocol
Code review is risk mitigation, not gatekeeping — catching what the author couldn't see, and occasionally sharing a better pattern when it genuinely helps.
Two-sided protocol. Reviewers load it to raise findings; authors load it to answer
them. Both sides read the whole file — a contested finding converges only when both
agree what [blocker] means and what closes one. Everything through Review Summary
Format is shared; Answering Findings is author-side.
Before reviewing, establish context:
git diff --cached --name-only, then git diff --cached --stat, then targeted path diffs). For PRs or commits, inspect changed files and stats before reading targeted hunks. Only broaden if explicitly asked.[overreach].[question].have-you-considered); "I'd have done it differently" is not a finding. [question] when exploratory, [concern] when materially cheaper and still cheap to switch. After round 1 the approach is settled — reopening it is relitigation.[blocker] or [concern].Sanity skims the diff for obvious issues — trivial changes, config, docs. Standard is the default: full change set via targeted diffs, P0-P3, spot-checked tests. Deep adds source context, all priorities, and data-flow tracing — security-sensitive work, core architecture, unfamiliar domains. Escalate to Deep if the review surfaces unexpected complexity.
Announce mode and scope: "Reviewing [scope] in [mode] because [reason]. Adjust?"
Review in this order. Stop and flag blockers immediately.
| Priority | Category | Focus | |----------|----------|-------| | P0 | Security | Injection, auth bypass, secrets exposure, unsafe deserialization | | P1 | Correctness | Does it do what it claims? Edge cases? Error paths? | | P2 | Data integrity | Validation, transactions, idempotency, race conditions | | P3 | Architecture & Operability | Coupling, contracts, backward compat, observability, rollback | | P4 | Performance | Only if measurable impact — N+1, unbounded growth, hot paths | | P5 | Maintainability | Readability, naming, complexity, test quality | | P6 | Style | Only if egregious or violates established conventions |
Attention budget: P0-P2 (70%) catch most production incidents. P3-P4 (20%). P5-P6 (10%) only when egregious.
Not a sweep of what review normally covers — you already do that. These are the checks that get skipped:
Severity tags:
| Tag | Meaning | Blocking? |
|-----|---------|-----------|
| [blocker] | Must fix before merge — security, correctness, data integrity | Yes |
| [concern] | Should address — architecture, significant maintainability | Discuss |
| [suggestion] | Consider — minor improvements, alternatives | No |
| [question] | Clarify — reviewer may be missing context | No |
| [nit] | Take or leave — style, naming preference | No |
| [appraisal] | Acknowledge — good pattern, notable improvement | No |
| [overreach] | Beyond initial scope, or a larger solution than the finding required — shrink or split | Yes, in corrective rounds |
| [vestigial] | Leftover from a superseded design — delete | Only when it worsens net value or risk |
Structure:
[tag] file:line — Brief issue
Why it matters: [impact if not addressed]
Likelihood: [how it is reached — entry point, input, condition]
Suggestion: [concrete alternative, if any]
For [nit] and trivial [suggestion]: one-liner is fine.
On [blocker] and [concern], add Closure condition: — the observable state required for approval. Any Suggestion: is advisory; the author chooses the implementation. For findings about a mismatch between code and docs/spec/description, name which side is authoritative — otherwise the response defaults to changing code. A stated impact assessment bounds the response: escalating above it needs the reviewer's explicit agreement.
Severity requires evidence. [blocker] requires a concrete failure path, a violated
invariant, or a deterministic build or validation failure; a hypothetical naming none of
these is [concern] at most. Severity is likelihood × impact, assessed before the tag is
chosen, not defended after — and a low-likelihood failure that is catastrophic or
irreversible can still block.
Repeated patterns: Flag 2-3 occurrences, then ask the author to fix the pattern throughout.
Don't:
[concern] or [blocker] costs a round it has not earned[overreach]; independent controls at separate boundaries are defence in depthDo:
[suggestion] with risk assessment (likelihood, impact, failure mode) — unless the failure is catastrophic or irreversible, which can still block. Don't suppress legitimate findings; document the tradeoffNet value gate — mandatory at the approval boundary. A clean ledger is not approval. Every verdict states two values, one concrete sentence each: as submitted and with the findings resolved — benefit obtained, complexity or risk retained, versus not merging. No verdict is exempt; the assessment is the forcing function.
The resolved value decides. Negative as submitted but positive resolved is ordinary Request Changes. Still marginal or negative once resolved means the change should not exist in this shape — name what changed since it opened and produce a Decision Request, never a unilateral close. Run the vestigial sweep first; it feeds this gate.
Approve when:
TECH_DEBT.md)[suggestion]/[nit] don't block — unblock progress while noting improvementsRequest changes when:
[overreach], or blocking [vestigial], findings remain in a corrective roundComment without blocking when:
Author-side. Load on receiving review feedback — a REJECTED verdict in multi-agent mode, review comments in Pairing.
A corrective commit answers findings. It is not an opportunity to improve the change. Run the reviewer's tests against it before submitting:
[overreach], and the
reviewer will say so. Say it first. A new interface, dependency, migration, or
abstraction introduced to answer a [concern] or [suggestion] is [overreach]
by default.Contesting. Complying with a finding that causes greater harm is not
compliance — it is the next defect. A finding may be returned unfixed as
[contested], which requires a named concrete harm: the behavior that breaks,
the invariant violated, the cost incurred. "This would be complex" is not a
named harm and does not open a contest.
When the reviewer escalates. A Decision Request or Recommend Reframe is not a
finding to fix, and a corrective pass is not an answer to one. Address the decision on
its merits — agree, or refute its premise with evidence — and leave the call with the
human. Do not put your own approval request in front of the human while theirs is
unanswered: that is two asks, and one of them quietly disappears.
Comply and record. Below contesting: implement the fix and record the objection —
trade_off in multi-agent mode, the Change Summary trade-offs row in Pairing. It costs
no round and blocks nothing, and it is the right move for a harm too diffuse to name:
coupling introduced, future changes made harder, a shape that will be regretted. Silent
compliance on a real objection is the failure mode, not contesting.
A refuted contest is a successful contest. It surfaced evidence the reviewer had and the author didn't, which is the point — being answered is not being wrong (CORE Rule 14).
The four permitted reviewer responses are defined in CORE Rule 12. Escalate's carrier
here: Pairing a Decision Request; multi-agent, declared in the rejection verdict and
carried to the human by the doer via mark-blocked.
If fixing A breaks B and fixing B breaks A the spec is broken, not the code (CORE Rule 11): that is Escalate, not another round.
One definition for the review exchange. Contracts own state transitions and permissions; this table owns the response vocabulary and its carriers. Where they diverge, that is a defect in whichever change introduced it — fix both, do not pick.
| Event | Actor | Permitted response | Pairing carrier | Multi-agent carrier | Closure |
|-------|-------|--------------------|-----------------|---------------------|---------|
| Finding raised | Reviewer | A tag per Feedback Format | Review output | Rejection reason on submit-verdict REJECTED | Author answers it |
| Finding answered | Author | Fix; fix and record the objection; or contest naming a concrete harm | Reply to the review | Resubmission commit message; an empty commit when no code changes | Reviewer responds |
| Contest received | Reviewer | Accept, Counter, Refute, Escalate — never bare restatement | Review output | Verdict text | One of the four is stated |
| Contest accepted | Author | Record the trade-off | Change Summary, trade-offs row | Coder logs trade_off | Finding closed |
| No consensus | Author | Escalate | Decision Request as the approval request's Ask | mark-blocked — harm in blocked_reason, disagreement in blocked_questions | Human or Orchestrator rescopes |
| Reframe, or resolved net value not positive | Reviewer | Recommend Reframe | Decision Request; its own comment on a PR | submit-verdict REJECTED whose reason declares the reframe | Author marks BLOCKED rather than resubmitting |
Reviews converge by bounding the change set, not by narrowing inspection. Every round reviews the current change set in full — the change set is what cannot grow.
Continuation or independent. A continuation is this reviewer's next round: reconcile prior findings, do not re-derive them. An independent review is round 1 of its own whatever verdicts already exist — full change set, all findings published including P3-P6 even when the verdict is Approve, no downgrading to match an existing approval. Do not restate a finding another reviewer already raised — a second review earns its cost by complementing, not echoing. Speak to a prior finding only to disagree with its severity or its resolution.
Prior rounds are the ones this reviewer ran in this session. In Pairing the session boundary is the reviewer boundary — a fresh session is an independent reviewer, and review notes found on disk are evidence, not its own rounds.
Every round:
Round N — remaining X→Y, files A→B.Do not escalate methodology to match a prior reviewer. Review mode cannot exceed the original mode unless the change itself introduced new complexity or risk.
Corrective commit review:
The author's obligations are in Answering Findings; judge against those.
[overreach] on the fix rather than opening a round on the states it invented. Reviewing a surface the fix created is how loops fail to converge.[vestigial] on evidence that it exists only to serve a design since replaced
and no longer earns its complexity — not on a count of callers. Block only when
it worsens net value or creates correctness or security risk; otherwise raise a
[concern]. Rounds see deltas; nobody sees the sum unless this runs deliberately.[suggestion] is addressed when it is inside the initial scope, or is a no-behavior-change edit to a file already in the change set. Everything else routes to follow-up. Deferring a suggestion is safe; losing it is not.Stop when no [blocker], [overreach], or blocking [vestigial] remains, [concern] items are fixed or deferred with rationale, validation exercises the changed behavior, and no new P0-P2 issue was introduced. Remaining [suggestion], [nit], and low-risk [question] items do not justify another round.
Divergence: files growing while remaining findings do not fall is non-convergence. Stop, restate the original finding set, escalate to the author or human.
Blast-radius proportionality: depth scales with blast radius, not with prior review depth. Dev tooling, scripts, config and docs get at most one Standard review plus a focused verification pass. Production behavior without schema, auth or public API impact gets Standard plus focused re-reviews until blockers close. Auth, security, data integrity, migrations, public API and production runtime may have a Deep review, and later rounds still reconcile rather than re-derive.
Matching or exceeding a prior review's rigor to appear credible — rather than because the change warrants it — is a methodological arms race, and it is how loops stop converging. Prefer a smaller, evidence-focused re-review over a broader, more impressive one.
When the loop is the problem rather than either side of it, the call belongs to the human. Both roles use this form.
Signature: findings not falling while the change set grows; each round's blockers landing in what the previous round's fix introduced; settled work held across rounds by an unsettled subsystem; resolved net value marginal or negative.
The format is the content:
Ask,
and the Ask is the decision it requests. On a PR it is its own top-level comment.
What buries it is a soft heading and a list of fixes above it, not its position.Compact (Approve/Comment, zero blockers/concerns, ≤3 suggestions, approach sound, high confidence — size is not a criterion):
Review: [mode] — Approve
Net value: [one sentence: benefit obtained, complexity retained, versus not merging]
Full (everything else):
Review: [mode] — [verdict: Approve / Request Changes / Comment / Recommend Reframe]
Blockers: [count or "None"]
Concerns: [count or "None"]
Suggestions: [count or "None"] ← None/None/None is a complete review
Overall: [1-2 sentence assessment]
Approach: [round 1 — sound, or the named alternative and its benefit]
Absence: [baseline used — nothing missing, or what is]
Sweep: [from round 3 or a mid-review design change — vestigial or disproportionate, or neither]
Net value: [as submitted — one line] / [with findings resolved — one line]
Blast Radius: [Low: internal refactor | Medium: logic change | High: migration/public API]
Confidence: [high: thorough | medium: focused on key areas | low: quick pass]
Sources: [what was read — diff, source files, specs, ADRs and decision records, validation output]
Next step: [e.g., "Merge after minor suggestions" | "Ready for another look"]
Pairing (default): All prompts apply. "Adjust?" allows human to override review mode.
§BRAND_NAME_TITLE§ (multi-agent): No interactive prompts.
| Pairing Prompt | §BRAND_NAME_TITLE§ Behavior |
|----------------|---------------|
| Mode announcement ("Adjust?") | Announce mode, no prompt |
| "Ask the author" / "Clarify" | Check task spec and blackboard; if still unclear, note as [question] |
| "Consider suggesting a split" | Note as [concern] — do not block review |
| [overreach] finding | Also log a scope_deviation anomaly |
| "Routes to follow-up" | Record in the verdict text — no anomaly. Reserve debt_created for a known deficiency retained in the implementation |
| Non-convergence (see Divergence) | Log scope_deviation, or retry_loop when the coder is cycling; review_budget_exhausted is planner-owned at 5 cycles — do not preempt it |
| [vestigial] finding | Same as [overreach] — also log a scope_deviation anomaly |
| [contested] response | Reviewer answers in the verdict text and logs nothing. If the reviewer accepts, the
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer