Pre-Merge
Create a GitHub PR linking back to the PRD and slice issues, then review the full diff against the project's architectural principles. Produces advisory findings — does not block merge, auto-fix code, or file issues.
Invocation Position
This is a primary pipeline skill used after implementation has been verified and before merging to main, or when picking up someone else's PR for review.
Use /pre-merge when the branch is ready for PR creation, architectural review, and final plan-to-code reconciliation. Use /pre-merge --pr <number> when you are reviewing a PR you did not author.
Do not use it as a substitute for implementation verification, QA intake, or refactor planning. It assumes the work is already built and ready to review.
Modes
/pre-merge runs in one of three modes. All three reuse the architectural review dimensions defined in review-checklist.md; they differ in what they consume and what they produce.
- Author-mode (default) — invoked on your own branch with no
--prargument. The skill creates the PR (Phase 2) and prints findings to the terminal as advisories (Phase 4), then hands back there — it makes no fix commits of its own and opens no second pass. This is the mode auto-invoked by/executeStep 6 on the HITL path. What it reads is decided by branch state, not by a flag: a first review reads the whole branch; a re-run against a PR that already carries a review-currency stamp, whose head has since moved, takes the post-stamp delta — the commits after the stamped SHA — as the review's subject, and does not re-read what the earlier review covered. Phase 1 step 4 makes that decision and prints it. The delta is the subject, not the limit of what a reviewer may read:review-checklist.mdsettles what a reviewer reads, and that includes the tree around the delta. - Reviewer-mode — invoked as
/pre-merge --pr <number>against a PR you did not author. The skill skips PR creation (the PR already exists) and produces draft comment text (Phase 4) for you to review and post, structured perreferences/comment-craft.md(5P gate, Triple-R, Comment Signals, MMG Exchange). - Loop-mode — invoked as
/pre-merge --loop, or entered automatically when/executehands off on an AFK run. Runs Phases 1–4 as author-mode does, except Phase 1 step 4's scope decision: loop-mode always reads the whole branch and never takes the post-stamp delta, then continues into Phase 5: it records every finding in a durable ledger on the PR, attaches the evidence that supports or refutes each one, and hands back to the operator. Findings stop being terminal output in this mode; they become durable rows with owners. Loop-mode does not fix anything and makes no commits — the operator decides what happens to each finding (see Phase 5 § Why the loop does not fix).
Loop-mode's exit condition is that every finding has an owner — never that the review came back clean. "Zero findings" is a forbidden termination signal, consistent with Phase 4's existing minimum-findings guard, which was written because a near-empty review on a non-trivial diff means the review stopped early rather than that the code is flawless. A loop that terminates on clean reviews will reliably produce clean reviews and nothing else (Meadows, Seeking the Wrong Goal; Leveson: never reward low incident counts — reward reporting itself).
If you are running on a branch other than the user's working branch and --pr was not provided, ask once whether the user means reviewer-mode against a specific PR number rather than guessing — auto-detection saves a keystroke but misclassifying mode produces draft comments that would have been local advisories or vice versa.
When to Use
- Author-mode: after QA passes and before merging a feature branch to main; after Ralph finishes AFK execution and you've verified behavior; or for any branch you want reviewed before merge, even without a full pipeline run.
- Reviewer-mode: when a teammate or external contributor opens a PR and you want to apply the full architectural review in
review-checklist.mdto their diff and produce constructive comment text. - Loop-mode: when findings must survive the session that produced them — the AFK handoff from
/execute, or any branch you will review over several sittings and do not want to re-derive each time. Use it when the cost you are paying is losing track of findings, not making the fixes.
Execution Flow
Phase 1: Gather Context
Author-mode:
Ask for the PRD issue number. Accept "none" if this change didn't go through the full pipeline. In loop-mode entered from an AFK
/executehandoff, do not ask — take the issue number from the handoff (/executeStep 6 passes it) and treat its absence as "none". There is nobody to answer, so an unconditional question here would hang the run at its first step.If a PRD was given:
gh issue view <number> gh issue list --search "in:body #<prd-number>" --state all --json number,title,state,body --limit 100Parse boundary maps (Produces/Consumes sections) from each slice issue body.
Detect the base branch and assess the diff:
BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD --short 2>/dev/null | sed 's@^origin/@@') if [ -z "$BASE_BRANCH" ]; then for candidate in main master prod develop trunk; do if git rev-parse --verify "$candidate" >/dev/null 2>&1; then BASE_BRANCH=$candidate; break; fi done fi # A name is not a ref. $BASE_BRANCH names the branch (for `--base`, `git switch`); # $BASE_REF points at it, and is the only thing safe as a range endpoint. if git rev-parse --verify "origin/$BASE_BRANCH" >/dev/null 2>&1; then BASE_REF="origin/$BASE_BRANCH" else BASE_REF="$BASE_BRANCH" echo "note: origin/$BASE_BRANCH does not resolve — measuring against the local branch, which may be stale" >&2 fi git diff "$BASE_REF...HEAD" --stat git log --oneline "$BASE_REF..HEAD"For a stacked-PR slice, override
$BASE_BRANCHwith the sibling slice's branch name (the upstream the PR will target) and re-derive$BASE_REFfrom it. If no diff from the base, tell the user there's nothing to review and stop. Do not hardcodemain— Skill Kit's own repo usesprod, and many others usedevelop,trunk, or a team-specific name.Residual:
$BASE_REFis only as fresh as the lastgit fetch, and on a triangular fork (or a remote not namedorigin)origin/$BASE_BRANCHmay be absent or track your fork rather than upstream — theelsebranch then falls back to the local branch, which is the stale-ref behavior this guard exists to avoid. It says so on stderr rather than falling back silently, because a plausible wrong answer with no signal is what let this defect live for five months. If the counts look wrong,git fetchand re-run, or setBASE_REFby hand.Decide the scope — the whole branch, or the post-stamp delta. This decision is author-mode only. Loop-mode skips it and sets
SCOPE_FROM="$BASE_REF"unconditionally, reading the whole branch on every invocation, per Phase 3's loop-mode bullet. A first review reads the whole branch. A re-run against a PR this skill already stamped, whose head has since moved — a/fix-findingsround, or a hand fix after a deliberate lock deletion — takes the post-stamp delta as its subject. Read the stamp with the same expression/closeoutStep 2 uses;scripts/test-review-currency-marker.shpins the two byte-identical, andscripts/test-delta-review-scope.shruns this block against a fixture for every branch state it names:REVIEWED_SHA=$(gh pr list --head "$(git branch --show-current)" --json body -q '.[0].body // ""' \ | sed -n 's/.*<!-- reviewed-at: \([0-9a-f]\{40\}\) -->.*/\1/p' | tail -1) SCOPE_FROM="$BASE_REF" if [ -n "$REVIEWED_SHA" ] \ && git merge-base --is-ancestor "$REVIEWED_SHA" HEAD 2>/dev/null \ && [ "$REVIEWED_SHA" != "$(git rev-parse HEAD)" ] \ && [ -z "$(git log --merges --format=%H "$REVIEWED_SHA..HEAD")" ]; then SCOPE_FROM="$REVIEWED_SHA" fi if [ "$SCOPE_FROM" = "$BASE_REF" ]; then echo "review scope: whole branch, from $BASE_REF" else echo "review scope: post-stamp delta, from $SCOPE_FROM" fi git diff "$SCOPE_FROM...HEAD" --stat git log --oneline "$SCOPE_FROM..HEAD"Four states fall back to the whole branch, each on purpose: no stamp (a first review, or a hand-authored PR); a stamp that is not an ancestor of
HEAD(the branch was force-pushed and the reviewed commit rewritten away —/closeoutcalls this the stronger divergence signal, and it is not a smaller review); a stamp equal toHEAD(nothing new to scope to); and a merge commit after the stamp (the post-stamp diff would carry the base branch's own changes, which nobody on this branch wrote). The decision is printed so the terminal readout and the PR say the same thing about what was read.On a delta re-run, the delta is the subject and the tree is still readable. Brief each Phase 3 reviewer with the findings the post-stamp commits claim to close — the earlier readout in this session, the PR's ledger if loop-mode wrote one, or the commit messages themselves — and with the
/fix-findingsbreaker verdicts when there are any. The first question per commit is whether the fix closes its finding at every site the finding named, which is the Fix Completeness dimension; the second is what the new text contradicts nearby, which is the census inreferences/restated-claims.md. Both need the surrounding tree, and the checklist's context contract already grants it; the scope narrows what the review is about, never what the reviewer may open.
Reviewer-mode (--pr <number>):
Fetch the PR and its diff:
gh pr view <pr-number> --json number,title,headRefName,baseRefName,body,author,url,state gh pr diff <pr-number>If the PR is already merged or closed, tell the user and stop — review comments on a closed PR are surfaced separately and rarely useful.
Identify the PRD issue from the PR body. Look for
Closes #<n>,Refs #<n>, or a## PRDsection pointing at an issue. If found, run the samegh issue view+ slice-issue search as author-mode step 2 to load PRD context and boundary maps. If the PR has no PRD lineage, treat it as the "no PRD" branch — the PRD-gated dimensions skip themselves, each in the phase its**Runs in:**marker assigns it to.Note the diff size and base branch from the PR JSON. No local branch math —
gh pr diffreturns the merged-base-to-head diff directly. Do not try to check the PR out locally; you are reviewing the diff, not running it.
Phase 2: Create the PR
Skip this phase entirely in reviewer-mode — the PR already exists, you did not author it, and rewriting someone else's PR body is out of scope. Proceed to Phase 3.
Check for an existing PR:
gh pr list --head $(git branch --show-current) --json number,urlCreate or update the PR. Use
gh pr create --base "$BASE_BRANCH"(override--basefor stacked-PR slices to the sibling slice's branch) orgh pr edit.
PR body template (when PRD exists):
## Summary
[For trivial PRs — typo fixes, dep bumps, formatting-only, single-line reverts — 1–2 sentences derived from the PRD's Problem and Solution sections.
For non-trivial PRs — behavior changes, new surface area, bug fixes with non-obvious root causes, refactors crossing module boundaries — write a plain-language walkthrough: one paragraph of domain setup, what changed and why each piece was the right move, and why it matters. Aim for a reader who doesn't have the codebase in their head. See `references/writing-for-humans.md` for the shape and revision bar.]
## PRD
Closes #<prd-issue-number>
## Slices
- [x] #N — Title (for closed slices)
- [ ] #N — Title (for still-open slices)
## Key Decisions
[Bullet list of notable implementation decisions that refined or diverged from the PRD. Derived from commit messages and slice issue comments. Omit this section if nothing diverged.]
PR body template (no PRD):
## Summary
[For trivial PRs — typo fixes, dep bumps, formatting-only, single-line reverts — 1–2 sentences derived from the diff and commit messages.
For non-trivial PRs, write a plain-language walkthrough: one paragraph of domain setup, what changed and why each piece was the right move, and why it matters. See `references/writing-for-humans.md`.]
Write the
## Review Notesblock, when/executehanded one over. Both the author-mode and loop-mode handoffs pass a block of re-runnable verification claims — which commands ran and their exit status, which tiers were skipped and why, scope absorbed under the Consumes gate, assumptions that shifted, known-weak spots. Emit it verbatim after## Summary; do not summarize or re-word it. Its whole value is that the reviewer can re-run the claims, and every summarization hop is a lossy transformation authored by the agent under review. See/executeStep 6 for the block's shape.Print the PR URL.
Note that the body gains one more section later. Phase 4 appends a
## Review Currencyblock recording the head SHA the review actually covered. It is written after Phase 3 runs, not here — a stamp written at PR-creation time would certify a review that had not happened yet.
Phase 3: Architectural Review
Consult review-checklist.md for the review dimensions and their violation patterns. That file is the roster — its ## N. headings are the only place the set of dimensions is defined, and nothing here restates it. The dimensions run identically in all three modes; only the diff they read differs:
- Author-mode — the local
git diff "$SCOPE_FROM...HEAD", where Phase 1 step 4 set$SCOPE_FROMto$BASE_REF(a first review: the whole branch) or to the stamped SHA (a re-run whose head moved: the post-stamp delta). On a delta re-run each reviewer is also briefed with the findings the post-stamp commits claim to close and any breaker verdicts, and reads the tree around the delta as the checklist's context contract allows — the delta is the subject, not the reading limit. - Reviewer-mode — the
gh pr diff <pr-number>output. - Loop-mode — the local
git diff "$BASE_REF...HEAD"— the whole branch on every invocation; loop-mode does not take the delta scope. Loop-mode makes no commits, so on a later invocation the diff has moved only if the operator pushed fixes; the ledger, not a narrowed diff, is what stops the pass re-reporting settled findings.
Delegation exists for reviewer independence; parallelism on large diffs is a sub-case of it. When /pre-merge is auto-invoked by /execute Step 6 it runs in the session that just wrote the code, holding every rationalization the implementing agent made while writing it. The dimensions are sound; the reviewer is not independent. Cohen's finding is that the author's job is to annotate for a reviewer, not to be one — so the sub-agent split below is first a way to put a clean context in front of the diff, and only second a way to halve wall-clock on a big one.
So delegation is unconditional in all three modes — the session that wrote the code never reviews its own diff inline. The one exception is drawn by content, not size: the four trivial classes Phase 2's two body templates already name — typo fixes, dep bumps, formatting-only changes, single-line reverts — review in-session, and that is the only trivial/non-trivial distinction Phase 3 draws. The exemption covers Phase 3 only; a trivial-class diff large enough to trip Phase 4's minimum-findings guard still delegates there.
Size then decides how many sub-agents, never whether the review leaves the authoring session:
- Small diff (< 200 changed lines, < 10 files): one sub-agent runs every dimension the checklist marks as sub-agent work and whose own gating condition is met — each dimension's section in the checklist states its own gate; the notes below elaborate on a few of them but are not the inventory.
- Larger diff: spawn two sub-agents in parallel, splitting that same set between them.
Either way the controller-owned dimensions are outside this choice entirely — diff size decides how many sub-agents run, never whether a dimension the checklist withholds from sub-agents gets delegated anyway.
Why the trigger is content and not size. Cohen's Cisco dataset retires the proxy on its own evidence: four reviews of 1–2 lines each ran past 15 minutes, because small physical changes carried architecture-sized ramifications. This repo has its own instance — a 34-line, 2-file diff, comfortably inside the old band, whose composition defect the authoring session's pass missed across eight findings and a clean context returned as its top Concern in one pass (docs/solutions/architecture-decisions/self-review-blind-to-composition-2026-08-13.md). Deleting the band retires the proxy; the four-class exemption keeps what the band was actually protecting, and is narrower.
When sub-agents are unavailable, run the dimensions in-session and name the run degraded mode in the findings output: the reviewer holds the authoring session's context, so its independence is gone and the findings should be read accordingly. This is the same declaration /improve-pipeline Phase 4 makes when its dialectic cannot be spawned. Degraded mode is a disclosure, not a second exemption — do not reach for it because delegation is inconvenient.
The context contract is about provenance, not permission. It has three parts, and the closed list is only the first of them.
Handed over — the same in all three modes. The diff, review-checklist.md, references/writing-for-humans.md, and — when one exists — the PR body's ## Review Notes block. Nothing else is given to a sub-agent, in particular not the implementing session's context. An externally-authored PR reviewed in reviewer-mode has no ## Review Notes block, because /execute never ran on it; that is an absent input, not a missing step.
Reached for itself — durable state, read at the source. A dimension's own procedure may send its sub-agent past that list: to the merged tree, the branch's commit history — git log, the commit messages, the per-commit diffs — git show on a deleted path, the slice or PRD issue body, the package registry, the research archive, an installed .d.ts, docs/solutions/, a scratch tsc --noEmit. The commit history is on that list because two dimensions cannot execute without it: Vertical Slice Integrity is defined entirely over commit structure, and Surgical Scope names the commit messages and branch name as its stated-task source of last resort. It is a separate artifact, not a summary of the diff, so reading it does not touch the rule below. In reviewer-mode, gh pr view <n> --json commits reaches the commit messages and SHAs without a local checkout; it returns no per-commit diffs, so a pattern that needs them cannot be checked there. That is not an exception to the contract; it is the contract working. Reading a durable artifact yourself is what preserves independence — what destroys it is receiving that artifact pre-digested by the session under review. One rule governs it: read it at its source and cite it, never accept the controller's account of it. The reviewer reading the diff rather than a summary of the diff is the same rule, applied to the one input that is always present.
Withheld absolutely — the change's context. That phrase means the authoring session's working state: its reasoning, the alternatives it discarded, the justifications it assembled while writing the diff, and any controller-authored narration, summary, or paraphrase standing in for something the sub-agent could have read directly. ## Review Notes is handed over despite being author-written because it is a checkable record — /execute Step 6 requires commands and exit statuses the reviewer can re-run — and not a construal to inherit.
What that makes decidable. A sub-agent can substantiate a finding when the evidence is reachable by a procedure the dimension itself names, from the diff plus durable state of the kind above. It cannot when the finding needs a view assembled across artifacts that no single named procedure reconstructs — which is the ground the controller bucket stands on, stated per-dimension in each controller-owned **Runs in:** marker rather than as a blanket rule here.
Loop-mode adds exactly one thing: from pass 2 on, the states and evidence recorded in the ledger, so the pass does not re-report findings the operator already settled. It never adds the previous pass's severity judgments; Phase 5's ledger section gives the full forward/withheld split and the reason for it.
Both reference files are rubrics — what to look for, and the bar the resulting prose must meet. The independence contract withholds the change's context; it was never about withholding the standards the review is held to.
The split is derived from the checklist, never restated here. Every dimension in review-checklist.md carries a **Runs in:** marker directly under its heading naming exactly one of three owners — sub-agent A, sub-agent B, or the controller, in Phase 4 (the checklist's legend defines each bucket's theme). Read the markers and hand each sub-agent the dimensions marked for it. Dimensions marked for the controller are not sub-agent work and are not delegated; Phase 4 runs them in-session, where the GitHub state they need is already loaded.
This is deliberately not a list. A hand-maintained copy of the roster sat here and shipped wrong from birth; scripts/test-review-dimension-partition.sh carries that incident in its header, and fails on any dimension the canon leaves unassigned.
Each sub-agent reads the full diff and its assigned dimensions from review-checklist.md, then returns findings in the three-tier severity format — each Suggestion and Concern written to the shape and revision bar in references/writing-for-humans.md, which is handed over as a rubric for the finding text even though the doc scopes itself to issue and PR bodies. Observations are exempt, per Phase 4's exemption — not the doc's own when-to-skip list, which exempts artifact classes and reaches no finding. Phase 4 states the bar and the reason for it.
The reviewer always reads the actual diff, never a summary of it. A summary is a lossy transformation authored by the controller under review; a fresh context buys independence from rationalization and buys nothing against misreporting (Leveson: no control system performs better than its measuring channel).
Gates, thresholds, and per-dimension procedures are stated in the checklist and nowhere else. Several dimensions fire only when the diff meets their own condition; several carry numeric bands, an exemption, or a named verification procedure. All of it lives under that dimension's heading — hand each sub-agent its assignment and let it read its own gate. A copy here would be a second operative site for the same claim, so changing a band in one file would ship a stale one in the other: the class references/restated-claims.md defines, and the one this skill's own Deep Modules bullet detects. scripts/test-restated-review-operatives.sh covers part of this; its header is the one place that states which part, and it is not restated here. Read it before treating a green run as the class being closed.
TypeScript projects: /ts-audit complements the architectural review with type-safety analysis on changed .ts/.tsx. Whether it runs depends on the mode:
- Author-mode and reviewer-mode: mention it, do not invoke it. For branches with significant
.tsor.tsxchanges, note it as an option — "For deeper TypeScript analysis, consider running/ts-auditon the changed files" — and leave the decision with the user. This is the deliberate HITL boundary; the scoping below does not move it. A soft "significant" is the right bar here, because the cost of misjudging it is one unnecessary sentence. - Loop-mode: auto-invoke it, and record its findings in the Phase 5 ledger alongside the dimension findings. It is already the recommended next action at exactly this point for exactly these files; the only reason it was ever manual is that nothing drove the cycle. One constraint, because an invoke rule needs a decidable trigger where a mention rule does not:
- Trigger — more than 50 changed
.ts/.tsxlines, or more than 2 changed.ts/.tsxfiles, measured over the diff this pass reads. Below that, skip the audit and record the skip on the ledger's "Checks not run this pass" line rather than passing over it silently — the same rule Review-friendly Size already follows for suppressed size findings. "Significant changes" is a usable instruction for a human deciding whether to mention a tool and an unevaluable one for a loop deciding whether to run it. - Findings it repeats from an earlier pass are matched against the ledger and left as the rows they already have, rather than added twice.
- Trigger — more than 50 changed
Verify, don't suspect — library callback semantics, subpath swaps, and provider schema constraints. When a finding turns on how a library treats a value the application hands it (return from a callback, object passed to a hook, systemMessages/tools/middleware collection semantics), the sub-agent must cite the installed type definition — node_modules/<library>/**/*.d.ts file path and line — in the finding. If a research archive entry exists for this feature, prefer its callback_contracts_snapshot (see research/SKILL.md Phase 1.25). For findings that turn on which subpath of a package an import resolves through — runtime-affecting swaps disguised as type-only diffs across sibling subpaths of multi-runtime packages — prefer the installed_versions_snapshot (see research/SKILL.md Phase 5b); Boundary Map Contracts' spec-reality check item 2 is the gate that consumes it. For findings that turn on provider schema constraints when an SDK wraps a provider — the SDK's type signature accepts a shape (JSON Schema, Zod, tool definitions) that the underlying provider's actual contract rejects (e.g. Gemini's response_schema rejecting numeric enums, Anthropic's tool.input_schema honoring only a subset of JSON Schema, OpenAI Structured Outputs' schema-subset divergence from JSON Schema 2020-12) — the citation must include the provider's contract docs at the installed SDK version, not only the SDK's permissive .d.ts. Hedged language ("if the library replaces X rather than merges", "if this field is accepted", "the SDK lets you pass any schema") without a source citation is not acceptable for this class of finding — the proof is one grep or one provider-docs page away and the failure mode is runtime-invisible. Either cite the source and classify as Observation/Suggestion/Concern per the severity rules, or downgrade to a named follow-up with an explicit "verify before merge" action.
Phase 4: Present Findings
Run the controller-owned dimensions first, then combine findings from all dimensions (or sub-agents).
Controller-owned dimensions run here, in this session. Every dimension in review-checklist.md whose **Runs in:** marker reads the controller, in Phase 4 is yours to execute — Phase 3 did not delegate it, and no sub-agent could have. The marker is on those dimensions because their procedures need a cross-slice view — the PRD, every slice issue, and the set of merged slices held together at once. Phase 1 assembles exactly that, in this context, which is the whole reason the work lands here.
Read each such dimension's procedure from review-checklist.md and run it now. Its findings are ordinary findings: they carry the severity the checklist assigns them, they join the three tiers below, and in loop-mode they get ledger rows like any other. In particular, a Concern from a controller-owned dimension is still a Concern, named escalation and all — the relocation moved where the check runs, not what its verdict is worth. There is no tier above Concern; a dimension whose verdict should stop a merge says so by naming that action inside its Concern, which is what Coverage Matrix Reconciliation does for an unmapped Must.
Then run them through the same evidence discipline as everything else: a controller-owned dimension is not exempt from citing what supports it. What it is exempt from is the delegated-finding check immediately below, which exists to catch a sub-agent misreporting; there is no sub-agent here.
If a controller-owned dimension gates itself off — Coverage Matrix Reconciliation only fires when this PR closes the last slice of a multi-slice PRD — say so in the findings output rather than skipping silently, the same way Review-friendly Size declares a suppressed size finding. A dimension that reports nothing and a dimension that never ran read identically otherwise, and that ambiguity is exactly what let this dimension go missing for months.
Check delegated findings against the tree before presenting them. Delegation removes one failure mode and exposes another: a fresh context buys independence from rationalization and buys nothing against misreporting (Leveson — Phase 3 says this of summaries, and it holds equally for sub-agent output). Loop-mode already handles it, at Phase 5 Step 2, which records refuted — <evidence> when the tree contradicts a claim. Author-mode and reviewer-mode had no equivalent, so a sub-agent's misreport printed as an advisory with nothing between it and the reader. Now that every non-trivial review is delegated, that gap sits on the default path.
So for each delegated finding, run Phase 3's "Verify, don't suspect" rule from this context — the grep, file path, and line that support or refute it; the installed type definition when the finding turns on library semantics — and then:
- Supported by the tree — present it, with the evidence cited in the finding.
- Refuted by the tree — do not present it as a finding. Record it once as a factual note (
sub-agent B reported X; path:line contradicts it), printed after the three tiers alongside the other reporting-only notes below, so the check is visible rather than a silent deletion. It is not gated on a PRD the way Scope Notes is; a refuted finding on a no-PRD review still gets its line. - Neither confirmable nor refutable from the tree — the disposal depends on whether the finding is of the class "Verify, don't suspect" governs. If it turns on library callback semantics, subpath resolution, or provider schema constraints, apply that rule's downgrade clause: it does not print at Observation, Suggestion, or Concern, but as a named follow-up with an explicit "verify before merge" action. That rule already denies an uncited finding of this class a tier, and a controller that could not cite it either has not changed the citation state. Every other finding is presented at the tier the sub-agent assigned, with the unverified basis named — the downgrade clause does not reach it, and does not license the tier either.
Checking is not re-judging. The parent verifies claims; it does not re-rank a sub-agent's severity, and it does not reconcile one sub-agent's findings against the other's.
This rule governs terminal presentation only, and loop-mode runs Phase 4. A refuted finding still gets its ledger row, open, with the refutation attached — Phase 5 Step 1 takes every finding from Phase 3 with no filtering, and Step 2 keeps refuted ones on the explicit ground that dropping one is a decision the operator makes. Suppressing a refuted finding from the terminal is presentation; suppressing it from the ledger would be the unacknowledged report the ledger exists to prevent. Where the two rules would disagree, the ledger wins.
Minimum-findings guard. Before presenting, count the total findings — all three tiers, plus any downgraded verify-before-merge follow-ups, which are findings whose print location moved, not findings that stopped existing. If the total is fewer than 4 on the diff Phase 3 read — the whole branch on a first review, the post-stamp delta on a re-run, so a two-commit fix does not trip this — and that diff is of any meaningful size (more than ~50 changed lines or more than 2 files), do one more focused pass explicitly looking for what you might be missing — scope drift, silent assumption changes, shallow modules, tests that only cover the happy path, or new state files that slipped past State Discipline. That second pass runs in a fresh sub-agent, on the same context Phase 3 specifies — not as a re-read in this context. It is spawned from Phase 4, so say so explicitly, and read that context off Phase 3 rather than off a list here — including the one thing loop-mode adds to it, the ledger's recorded states and evidence. An enumeration at this distance from the contract is how this sentence previously dropped the ledger and sent the second pass to re-report findings the operator had already settled. Its findings are held to the same reader bar as any other. Brief it to skip the controller-owned dimensions. It is handed the whole checklist, and those dimensions were already disposed of above — run, or declared self-gated-off. Phase 3's sub-agents get the checklist with an assignment — the dimensions marked for them — so nothing controller-owned is ever offered; Phase 4's second pass gets the file with no assignment, so it must be told what to skip. Without it the pass either silently drops them or re-runs them from a context that cannot support the verdict. The guard fires precisely when the first pass came back thin, and the bias blind spot means hygiene cannot be self-administered (Kahneman, Sibony & Sunstein, Noise) — a re-read holding the first pass's context reproduces the review that was thin, and launders it as an independent second look. Its findings go through the evidence check above like any other delegated finding. A count of zero or one on a non-trivial diff is a signal that the review stopped too early, not that the code is flawless. If after the second pass the count is still low, present what you have — do not fabricate findings to hit a quota.
Hold each finding to the same reader bar as the PR body. Phase 2 already requires a plain-language walkthrough for the bodies it writes on non-trivial PRs. The findings had no equivalent bar, and they are this skill's primary product — the body is scaffolding around them. A finding a reader cannot parse fails the same way a finding that was never raised fails, and it fails silently: the tier prints, the ledger row shows an owner, and nothing registers that the signal did not transmit. So write each Suggestion and Concern to the shape and revision bar in references/writing-for-humans.md — name the part of the system in domain terms, front-load the claim before qualifying it, close with what it prevents or unlocks, then strip the clutter.
Two limits. Observations are exempt, as is any finding whose domain meaning is self-evident — a one-line note about a naming pattern carries no domain setup. That exemption is stated here as this skill's own rule rather than borrowed from the doc's when-to-skip list, which exempts artifact classes (typo fixes, dep bumps, formatting-only PRs, single-line reverts, trivially-reproducible bugs) and reaches no finding. Four of those five are diffs Phase 3 never delegates, so the list a review sub-agent holds is inapplicable to it by construction; what does transfer is the closing rule beneath it — when in doubt, one sentence beats a padded walkthrough.
Second, the bar is on clarity, not length — a finding that got longer without getting clearer failed it. Read this alongside the minimum-findings guard above: that guard forbids inventing findings to hit a count, this one forbids padding the findings you have.
The bar governs the finding text itself, so it carries into all three modes — author-mode's terminal advisories, the reviewer-mode drafts built from the same findings, and the loop-mode ledger rows that outlive the session that produced them, where the reader is coldest.
Findings arrive written to the bar; this phase does not reword them. Phase 3 puts the obligation in the writer's brief — delegated or in-session — so the bar is met at authorship rather than retrofitted here. The prohibition is narrow and covers one act: rewriting a returned finding to fix its prose. In author-mode the parent is the session that wrote the code, so passing an independent reviewer's findings through it to be reworded would spend the independence delegation just bought. When findings arrive below the bar, the fix belongs in Phase 3's brief, not in a cleanup pass here.
Parent-authored text built from a finding is not covered by that prohibition and is governed by the bar directly — reviewer-mode's Triple-R Rationale and loop-mode's ledger Finding cell are both written by the parent, and both are held to it.
Author-mode prints terminal advisories (below). Reviewer-mode transforms those same findings into draft PR comment text (see "Reviewer-mode comment drafts" below) — same dimensions, same severity classification, different output shape.
Present in the terminal using three tiers (author-mode):
## Architectural Review
### Observations (for awareness — no action needed)
[Patterns noticed that aren't violations. Example: "The presence module
exports 6 functions — reasonable, but worth watching if it grows."]
### Suggestions (action optional — would improve quality)
[Grouped by dimension. Things that aren't violations but would make
the code better. Written to the reader bar above.]
### Concerns (action recommended — potential principle violation)
[Grouped by dimension. Each concern cites the principle, shows the
specific code, and explains why it matters — and reads cold to someone
who did not write the diff, per the reader bar above
(`references/writing-for-humans.md`).]
### Verify before merge (findings that hold no tier)
[Findings the "Verify, don't suspect" downgrade clause removed from the
tiers — library callback semantics, subpath resolution, or provider schema
constraints that nothing could cite. Each names the check that would settle
it. Omit the section when there are none.]
---
No action is required. These are advisory.
When ready, merge the PR at <PR-URL>.
This block is the last review action author-mode takes. Finish the rest of Phase 4 below, then hand back at the ## Handoff next-step menu (references/next-step-menu.md) — that menu is where what-happens-to-a-finding gets decided, and the user picks, not this session.
Scope Notes (only when a PRD with slice issues was provided):
After the three-tier findings, note any significant scope drift between the planned decomposition and the actual diff:
- Work that appears in the diff but wasn't in any slice's Boundary Map (omitted scope discovered during implementation)
- Declared Produces that don't appear in the diff (planned work that was cut or deferred)
- Slices where the actual diff footprint was dramatically different from the boundary map's declared scope
These are factual notes, not review findings. They don't produce Observations, Suggestions, or Concerns — they record plan-vs-actual divergence so the user and /compound can decide whether a pattern is worth capturing. Omit this section entirely if the diff aligns closely with the planned boundary maps.
**Acceptance-criteria checkbox reconcilia
…(truncated)