# Check Delivery

> Review a finished implementation against the plan or spec it was built from. Runs the project's own verification gates first, then a panel of parallel reviewers over the diff. Use when an implementation is complete, before merging or releasing, when a change needs a second opinion that is not just a reading, or when the user invokes /check-delivery. Every behavioural finding must cite a command, a test, or a call site.

- Skill: `marekpolcar/check-delivery` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add marekpolcar/check-delivery`
- Raw SKILL.md: https://api.skillmd.com/api/skills/marekpolcar/check-delivery/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: marekpolcar (https://skillmd.com/u/marekpolcar)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/marekpolcar/check-delivery

---


# Delivery review (/check-delivery)

The code exists. That changes what a review is: the strongest available evidence
is cheap to collect, so collecting it is mandatory rather than optional.

Sibling of `/check-plan`, which reviews the document before it is built. This
one reviews the delivery after. Where that skill's failure mode is a reviewer
inventing a file path, this one's is a reviewer inventing a behaviour.

**Announce:** "Reviewing the delivery: gates first, then the panel."

**The one rule everything else serves:** a claim about what the code does at
runtime is not a finding until a command, a test, a compiler, or a named call
site says so. Reading the changed lines is a lead. The gates have already run by
the time any reviewer thinks; their output is in context and outranks any
reading.

## Hard rules

- **Gates before agents.** No reviewer is dispatched until the project's
  verification gates have been discovered, run, and recorded. A required gate
  that fails because of this change is a BLOCKER reported before dispatch, with
  the real output quoted. See `references/gates.md`.
- **Attribute before reporting.** A gate that was already red on the base commit
  is a verification limitation, not a finding against this change. Prove it with
  a detached worktree at the base commit, never by stashing.
- **Read-only against git, except the review log.** Never stash, never commit,
  never push, never switch branch, never `git add`. The working tree may hold
  another session's uncommitted work, and a bare stash captures all of it.
- **Only you write, apart from confirmed fix agents.** Reviewers return text.
  Background subagents do keep `Edit` and `Write`, so this is a deliberate rule
  and not a tool limitation: several agents editing one file concurrently corrupt
  it, and every finding must survive the Step 5 rejection pass before anything
  lands. Fix agents run only after the user has confirmed a numbered list.
- **Plan compliance is not correctness.** A faithful implementation of a wrong
  plan scores full compliance. Step 2 caps the verdict when the plan was never
  independently reviewed.
- **Missing evidence is a coverage limitation, not a defect.** A reviewer that
  crashed, a gate that cannot run, a command that failed: report reduced
  confidence. Never convert a tool failure into a finding against the change.
- **Returning PASS is a real result.** Do not manufacture findings to justify
  having run. A clean change with green gates returns PASS, lists the commands
  and their output, and stops.

## Step 0. Scope: the change, the plan, the scratch directory

Create a scratch directory for this run inside your session scratchpad. Every
gate transcript and prompt file written by this skill goes there, never into the
repository.

### Find the plan

The document this delivery is measured against may be a **plan** (ordered tasks,
a sequence someone executed) or a **spec** (goal, decisions, artifacts, surfaces,
verification, no ordering). Either works: both state what was supposed to be
true when this was done, which is the only property this review needs. Record
which you got. Throughout the rest of this skill, **the plan** means whichever it
was.

- If the user gives a file path, read the document from that file. Record the
  path; Step 2 needs it.
- Otherwise look in the conversation for an explicit plan or spec: structured,
  with numbered steps, task lists, stated decisions, or a heading that labels it
  as one. Do not treat casual conversation, commit messages, or ad-hoc
  instructions as the plan.
- If none is found, ask: "Which plan or spec should I check this implementation
  against? Paste it or give me a file path." Do not guess and do not infer one
  from context. A review against an imagined plan reports compliance with
  nothing.
- If the user declines to supply one, you may proceed **without** the plan
  compliance perspective, and the verdict is capped at `CONCERNS`. Say so in the
  report. Never silently substitute the diff's own intent for a plan.

### Find the change

In order:

1. **User-specified files, commit, or range**: use exactly that.
2. **Git repository**: run `git log --oneline -10` for recent history, then pick
   one scope and record which:

   | Scope | How you get it |
   |---|---|
   | Uncommitted work | `git diff`, `git diff --cached`, **and** every path from `git ls-files --others --exclude-standard` read in full |
   | Branch versus base | `git diff <base>...HEAD` |
   | One commit | `git show <sha>` |

   A newly created file that was never `git add`ed has no diff: `git diff` and
   `git diff --cached` both return nothing for it. Miss the untracked union and
   the panel reviews the change with a whole new file invisible, while every
   reviewer reports confidently on what it could see. Union it in every time the
   scope is uncommitted.

   Detect the base branch with `git rev-parse --abbrev-ref --symbolic-full-name @{u}`.
   If that fails, try `git remote show origin | grep 'HEAD branch'`, then check
   whether `origin/main` or `origin/master` exists. If none work, ask.
3. **No git repository**: ask the user for the list of files to review.

### Edge cases, handled before anything else runs

- **Empty diff**: "No changes detected, nothing to review." Stop.
- **More than 30 files changed**: "This touches [N] files. To give a thorough
  review, can you narrow the scope? For example: specific directories, a commit
  range, or the most critical files." If the user declines, proceed with the
  first 30 files **of the change**, and record the truncation in the **Scope**
  section of the report. Never truncate silently.

  Derive the list from the scope you recorded, the same way the attribution
  pre-check in `references/gates.md` does:

  ```bash
  # uncommitted
  { git diff --name-only; git diff --cached --name-only; \
    git ls-files --others --exclude-standard; } | sort -u | head -30

  # branch versus base
  git diff --name-only <base>...HEAD | head -30

  # one commit
  git diff --name-only <sha>^..<sha> | head -30
  ```

  Do **not** reach for `git log --name-only` here. That is repo-wide commit
  history, not this change: it can list files the change never touched, and it
  can never list an untracked file, so on an uncommitted scope it may share
  nothing at all with the set under review. The report would then say "30 of N
  files reviewed" while naming 30 unrelated files, which is worse than
  truncating, because it reads as coverage.

- **Fewer than 5 lines changed in a single file**: skip the panel. Run the gates
  anyway, because they are the point, then run one comprehensive reviewer using
  the single-agent template in `references/agent-prompts.md`, then report.

### Gather context once, for everyone

- The full diff.
- Full contents of changed files, not just diffs, for files with more than 20
  changed lines or files directly implementing a plan item. Diff only for the
  rest. If the total would exceed roughly 50KB, prioritise plan-critical files
  and record which were truncated.
- The applicable `CLAUDE.md`, root and nested, for every directory the change
  touches. Reviewers judge against these, not generic best practice.

## Step 1. Run the gates

Do this before any reviewer is dispatched, and give the result to all of them.

Read `references/gates.md` and follow it: discover the gates in the documented
order, classify each required or advisory, run them, build the ledger, and
attribute every failure against the base commit before calling it a finding.

Two outcomes short-circuit the rest of the run:

- **A required gate is red and was green at base.** Report it as a BLOCKER now,
  quoting the real output, before dispatching anything. Reviewing code that does
  not compile wastes the panel and produces findings about a state nobody will
  ship. Ask whether to continue the review anyway; default to stopping.
- **A required gate cannot run.** Verdict `BLOCKED`, reported as a coverage gap.
  Name what would unblock it.

Otherwise carry the ledger forward. It is the first thing pasted into every
prompt in Steps 4 and 5.

## Step 2. Plan compliance is not correctness

The plan compliance check silently inherits the plan's own correctness. If the
plan was wrong, a faithful implementation of it scores full compliance and the
output reads as assurance. The better the implementation, the more confident the
wrong answer.

So before trusting compliance as a signal, find out whether the plan itself was
ever reviewed.

**If Step 0 found no plan at all, skip this step.** There is no log to look for,
and the cap Step 0 already applied stands unchanged. The rest of this step
presumes a plan path exists.

**Look for the review log** written by `/check-plan`:

```bash
PLAN=<the plan path from Step 0>
LOG="$(dirname "$PLAN")/reviews/$(basename "$PLAN" .md)-review.md"
ls -la "$LOG" 2>/dev/null || echo "no review log: plan was never independently reviewed"
```

**If the log exists**, read it and carry it forward:

- Record the latest round's verdict. A plan that ended `BLOCKED` or `REVISE`
  without a later clean round is itself a finding here, at **MAJOR or worse**:
  the implementation was built from a document known to be defective. Naming the
  severity matters, because Step 6's `CONCERNS` row fires on any surviving MAJOR.
  Without it, a plan reviewed and found defective would carry no cap at all while
  a plan never reviewed carries one, and the worse state would return the more
  reassuring verdict.
- Extract the log's **Out of scope** and any residual risk the review explicitly
  accepted. Those must not be re-reported as new defects by this run. Paste that
  list into every panel prompt under "already accepted, do not re-report".
- Extract the log's **Coverage limitations**. Anything the plan review could not
  verify is a place to look harder now that the code exists.

**If the log does not exist**, say so in the report, in these terms: "The plan
was never independently reviewed, so compliance with it is not evidence of
correctness." Then cap the verdict: an unreviewed plan can never yield `PASS`,
only `CONCERNS` at best, with the missing plan review named as the reason.

The cap is not a criticism of the implementation. It is an honest statement of
what this run can and cannot establish, and the remedy is one command:
`/check-plan` on the plan.

## Step 3. Classify

- **Risk class.** High if the change touches money, auth, authorization,
  destructive operations, data migration, public APIs, concurrency, or an
  irreversible rollout. Otherwise medium, or low when local and reversible.
- **High-risk surfaces touched.** List them explicitly by file, from the risk
  classes above as they appear in *this* repository. A change to any of them
  makes the risk class high and puts the matching perspective in the panel,
  adversarial.
- **Change kind.** Code, configuration, infrastructure, documentation, copy. A
  documentation-only change drops the test coverage and performance perspectives
  rather than running them to produce a wall of "not applicable".

Risk class sets panel size and how many perspectives run adversarially. Both are
in `references/agent-prompts.md`.

## Step 4. Dispatch the panel

Read `references/agent-prompts.md`. Pick perspectives from the menu for coverage
of what the change actually touches, assign each collaborative or adversarial
mode, and launch them **in parallel in a single message**.

Every agent gets, pasted in full and never referenced:

1. The plan text, or an explicit statement that there is no plan.
2. The full diff.
3. Full contents of the key changed files.
4. **The gate ledger and the quoted output of every non-zero gate.** This is what
   makes the evidence rule cheap to obey rather than aspirational.
5. The applicable `CLAUDE.md` excerpts.
6. The accepted residual risks from Step 2, or the note that there was no review
   log.
7. Its mandate, its evidence rules, the scope rule, and the severity scale.

A subagent has none of your context. A reference to "the change" is a reference
to nothing.

## Step 5. Synthesize

Collect the panel, then work in this order. The order matters: rejection happens
before deduplication so noise cannot survive by being reported twice.

**1. Reject on scope.** Accept a finding only when the evidence shows one of:

- the diff introduced it;
- the diff made it reachable or materially worse;
- it violates an acceptance criterion of the plan on a path this change touches;
- it is a required-gate failure caused by this change, per the attribution in the
  ledger.

Everything else is a limitation or an out-of-scope observation. It goes in the
report under **Out of scope** and is **never** turned into recommended work and
never handed to a fix agent. Reading unchanged code to prove an affected path was
permitted; the unrelated defects noticed on the way did not thereby come into
scope.

The per-agent guards are instincts. This is the enforcement, and it is the only
place in the run that can tell whether "only flag issues in the changed code" was
actually obeyed. Check it, do not assume it.

**2. Reject on quality.** Drop findings that are unsupported, that state taste as
fact or style as requirement, that recite generic best practice with no
demonstrated connection to this change, or that justify architecture by
hypothetical future scale.

**3. Check the evidence.** Every surviving finding must name one of the five
evidence kinds and carry the thing itself: a command with its real output, a
named test and its assertion, compiler output, a `file:line` call site, or for
`plan_text` the quoted plan sentence plus the `file:line` that contradicts it.
The evidence must actually support the claim, not merely sit next to it. A
confident sentence is not evidence.

A **behavioural** claim resting only on a reading of the changed lines is
**capped at MAJOR**. Do not promote it because it sounds serious; if it is
serious it is worth one command to prove, and you can run that command now.

The cap is on behavioural claims only. A `plan_text` finding asserts nothing
about runtime, so it is not capped: a missing or half-done plan item can be a
BLOCKER on its own. Check the reverse abuse too, which is the likelier one: a
finding tagged `plan_text` whose text actually claims what the code will do when
it runs is a behavioural claim wearing the wrong label. Retag it, and if it then
has no command, test, compiler line or call site behind it, cap it at MAJOR.

**4. Deduplicate.** Same location and same nature of problem merge into one
finding, keeping the strongest evidence and the highest severity. Do **not** merge
two different problems that share a line: a naming issue and an authorization
hole at the same line are two findings. Preserve genuine disagreements between
reviewers rather than averaging them, and say so explicitly.

**5. Preserve disagreement.** Where two reviewers reached opposite conclusions on
the same line, that disagreement is the most valuable signal in the run. Resolve
it with evidence: run the thing that decides it. Say which way you resolved it
and why. Never average two positions into a hedge, and never report the
disagreement as if it had not happened.

**6. Classify.** BLOCKER, MAJOR or MINOR, per `references/agent-prompts.md`. The
same scale `/check-plan` uses, so a plan and its delivery speak one language.

## Step 6. Verdict

| Verdict | When |
|---|---|
| `PASS` | Nothing survived above MINOR, every required gate is green and attributed, and the plan carried a clean `/check-plan` review. Report the commands and their output, list what was verified, and stop. |
| `CONCERNS` | At least one MAJOR survived, or a required gate could not be fully attributed, or the plan was never independently reviewed. Safe to release with named residual risk. Name the reason. |
| `FAIL` | Any surviving BLOCKER, including a required gate that this change turned red. |
| `BLOCKED` | A prerequisite is missing: a required gate cannot run, the environment is unavailable, or the change could not be reviewed at all. Reported as a coverage gap, never as a product defect. |

**Precedence, because more than one row can be true at once.** Take the most
severe that applies, in this order: `BLOCKED`, then `FAIL`, then `CONCERNS`,
then `PASS`. Without this the common case is ambiguous: a run with one surviving
MAJOR, green gates and a clean plan review satisfies the wording of both `PASS`
and `CONCERNS`, and two coordinators would report different verdicts for the
same evidence. A MINOR alone does not cost a `PASS`; a MAJOR does, because MAJOR
means someone must fix it before the next change touches that area.

`BLOCKED` and `FAIL` can also both apply, when one required gate turned red and
a different one could not run. `BLOCKED` wins: it says the review could not
establish what it set out to establish, which is a different message to the
reader than a defect that was found.

The no-plan case belongs to Step 0 and is not a `BLOCKED` trigger. If the user
was asked for a plan and declined, Step 0 already proceeds without the plan
compliance perspective and caps the verdict at `CONCERNS`. Only a change that
could not be reviewed at all reaches `BLOCKED` on that axis.

Two caps apply after the table, and both are honesty about what this run can
establish rather than criticism of the code:

- **No plan review log**: the verdict cannot be `PASS`. `CONCERNS` at best, with
  "the plan was never independently reviewed" named as the reason and
  `/check-plan` named as the remedy.
- **No plan at all**: the verdict cannot be `PASS`, and the plan compliance
  perspective was not dispatched. Say both.

`BLOCKED` outranks the caps, consistent with the precedence order above: a gate
that cannot run is reported as `BLOCKED` rather than as `CONCERNS`, because the
two call for different actions.

## Step 7. Fix, only after confirmation

Ask: "Want me to fix the BLOCKER findings?"

If yes:

1. **Present a numbered list** of proposed fixes, each naming the file, the
   change, and the finding it closes. Nothing from **Out of scope** appears in
   this list, ever. A finding rejected at Step 5 does not come back as a fix
   because it was easy.
2. **Ask which to apply**: all, specific numbers, or none. Wait for the answer.
3. **Only then** dispatch one fix agent per approved fix, or per group of
   genuinely related fixes. Each gets the specific finding, the file contents,
   the exact change, and an instruction to make only that change and nothing
   else.
4. **Re-run the affected gates** after the fixes land and report the new exit
   status. A fix that turns a gate red is worse than the finding it closed.

Do not dispatch fix agents without explicit approval. Code changes are harder to
reverse than document changes, and the confirmation gate is the safety mechanism
here, not tool restriction: background subagents do keep `Edit` and `Write`.

Never `git add`, never commit, never push. Leave the fixes in the working tree
for the user to stage, because the tree may hold another session's work and
staging by path can sweep it in.

## Step 8. Log and report

**Log.** Append this round to
`<plan-dir>/reviews/<plan-basename>-delivery-review.md`, creating it if absent.
That is a sibling of `/check-plan`'s `<plan-basename>-review.md` in the same
directory, so a plan accumulates its pre-build and post-build reviews side by
side. Rounds are separated by `---` and appended at the end, never rewritten. If
there was no plan file, skip the log and say so.

```markdown
---

## Delivery round {N} - {YYYY-MM-DD}

**Verdict:** {PASS | CONCERNS | FAIL | BLOCKED}
**Scope:** {uncommitted | base <branch> | commit <sha>}, {N} files
**Plan review:** {verdict from the /check-plan log, or "none, verdict capped"}
**Panel:** {perspectives, mode each}

### Gates
| Gate | Command | Source | Exit | Attribution | Limitation |
|---|---|---|---|---|---|

### Previous round tracking (round 2+)
| # | Finding | Status | Notes |
|---|---|---|---|

### Findings
#### [BLOCKER|MAJOR|MINOR] {title}
- Location, Evidence kind, Evidence, Introduced by, Impact, Required change

### Verified
{claims checked and found correct, naming what was run}

### Out of scope
{adjacent problems deliberately not made findings}

### Coverage limitations
{what could not be verified, and why}
```

On round two or later, read the existing log first and track what the previous
round found: fixed, still open, or rejected with a reason. Paste that tracking
table into every panel prompt, so reviewers spend the round on what actually
moved instead of re-deriving the last round's findings and reporting them again
as new.

**Report.** Briefly, in this order: the verdict; the gates and their exit status;
the findings, most severe first, each with its evidence; where reviewers
disagreed and how you resolved it; what was verified; what remains unverified;
what was out of scope. Then the log path.

A `PASS` report is short and lists the commands that were run. That is the point
of running them.

## What this is not

- **Not `/code-review`.** That answers "is this code good"; this answers "does
  this delivery match its plan and is it safe to release". They overlap and do
  not replace each other.
- **Not `/security-review`.** A security perspective is in the menu, but a
  dedicated security review goes deeper than one panel seat.
- **Not a linter.** The project's linter is one of the gates, and its real output
  is evidence here. Do not reimplement its judgments.
- **Not browser QA.** When a finding turns on what a page actually does in a
  browser, drive the browser or delegate to whatever skill this project uses for
  that, and cite what it returned. Do not reason about the DOM from the diff.
- **Not a replacement for the plan review.** `/check-plan` checks whether the
  plan was right. This checks whether the code matches it. Compliance with an
  unreviewed plan is not correctness, which is why Step 6 caps the verdict.

## Credits

The delivery half of a pair with `/check-plan`, written by the same method: keep
a working tool's architecture, graft another skill's evidence discipline onto it.

Adapted from **`recheck`** in the [`claude-replan`](https://github.com/kojott/claude-replan)
plugin (v1.1.0) by **Jiri George Dolejs**, MIT + Commons Clause. It was already
stronger than its sibling `replan` in several places, and those were kept
deliberately rather than rewritten: `file:line` demanded in every output format,
the per-agent anti-inflation guards, the three edge cases (empty diff stops, over
30 files asks the user to narrow and documents any truncation, under 5 lines
collapses to one reviewer), the deduplication rules including not merging two
different problems that share a line, fix application gated behind a numbered
list the user confirms, and the refusal to infer a plan from casual conversation
or commit messages. The text here has since been rewritten end to end; nothing
upstream loads at runtime.

Evidence discipline came from reading `ln-12-delivery-reviewer` in
[`levnikolaevich/claude-code-skills`](https://github.com/levnikolaevich/claude-code-skills)
(`plugins/review-suite`), never installed: gates before agents with its discovery
order, and the evidence hierarchy that ranks a reproduced run above any reading.

From neither source: Step 2, plan compliance is not correctness plus the
review-log handshake with `/check-plan`, which is what makes the two a pair
rather than two skills that ship together; the pre-deduplication rejection pass;
and the four verdicts. Attributing a failing gate against a detached worktree at
the base commit, never a stash, is there because the working tree may hold
another session's uncommitted work. The fifth evidence kind, `plan_text`, was
added after a smoke test showed the original four capped every plan-compliance
finding below blocking level, which left the primary perspective unable to block
anything.

**2026-07-31:** two things came out. An independent cross-model reviewer tier ran
Codex against the repository on an OpenRouter pin, with a same-model subagent as
fallback; it made the `codex` CLI, an OpenRouter account and a funded key
prerequisites for a clean run, and degraded quietly when any was missing. And a
four-level `P0`-`P3` severity scale, whose top rung was defined against payment
surfaces enumerated in a project-scoped skill - meaningless in any other
repository. Severity is now BLOCKER / MAJOR / MINOR, the same scale `/check-plan`
uses.

