references/01_MERGE_GATES.md
## Merge-readiness contract
Check each gate; cite evidence (file:line, criterion, check name, issue number).
A gate that can't be confirmed is a **blocker**, not a pass — never assume green.
| Gate | What it means | Blocker when |
|---|---|---|
| **Acceptance coverage** | The receipt's acceptance-coverage field accounts for every SPEC acceptance criterion (review-change verified the mapping). This gate confirms the receipt *names* the criteria — it never remaps diff hunks to criteria itself. | The receipt omits a criterion the SPEC lists, or its coverage field is absent/generic. |
| **All phases complete** | Feature: every phase in `PLAN.md`/`TASKS.md` is done and logged in `progress.md`. Fix: the SPEC is fully implemented. | Any unchecked task or unimplemented phase without an explicit, tracked deferral. |
| **Scope integrity (creep)** | The PR implements the SPEC and no more; out-of-scope work was split out. | Undocumented scope creep, or in-scope work missing. |
| **Docs updated** | Every "Affected docs" criterion is satisfied; per-phase docs (`progress`/`testing`/`known-issues`/`decisions`) reflect reality; the doc map still resolves. **Never merge with documentation still pending.** | A doc the map or SPEC requires is stale, missing, pending, or contradicts the code. |
| **Traceability** | `Closes #N` is in the PR body when the work is issue-born (from `plan-feature-from-issue` or `plan-fix`); the roadmap/fix-index entry matches, is **still present** (removed only *after* merge, never before), and carries the linked PR reference (`done · [#<pr>](<pr-url>)`). | Issue-born work without `Closes #N`; a roadmap/index entry out of sync; the entry dropped before merge; or a `done` row without its PR link. |
| **Verification gate / CI** | The project's gate passes — type-check, tests, build — and `statusCheckRollup` is green at the current head. | Any required check failing, pending, or absent where the project requires one. |
| **Mergeability** | Branch is off the default base, independently mergeable (no conflicts), not stacked on another PR, not draft. | Wrong base, conflicts, stacked dependency, or still draft. |
| **Review receipt** | A current `REVIEW-PASS` receipt is posted on the PR: the newest comment carrying `<!-- review-change:pass sha=<40-hex> contract=v1 -->` whose `sha` equals the PR's current head SHA. Its scope/axes, acceptance coverage, invariant result, and manual checks are the review evidence this audit consumes. | Receipt absent, or its marker `sha` predates the current head (any later commit voids it). The blocker routes to `/review-change`; never re-review the diff from here (AC 13). |
| **Closure integrity** | The governing **feature** SPEC's capability closure was taken and recorded — `design-feature` was actually run, not bypassed. Fix-governed PRs: `n/a` (no closure block by design). | A present `Capability closure` block has a blank row, or a resolved non-`n/a` row with no matching acceptance criterion. |
| **Scope integrity (descope)** | An issue born during this unit that maps to an unmet SPEC acceptance criterion or phase task has a matching, user-approved, dated `## Amendments` entry — descoped scope was recorded, not silently exported. Detection is two-path: a slug/issue-number text match, **or** an issue linked from an `## Amendments` row (`#89`) — either is sufficient to enumerate the issue, so a descoped issue with a generic title/body is not invisible to the gate. | An issue born since branch divergence that references this unit (by either detection path) maps to an unmet criterion/task with no matching `## Amendments` entry, or an `## Amendments` row that is undated, unapproved, or unlinked to an issue. |
| **Architectural invariants** | The **receipt** records the invariant result review-change took against the optional project invariant document; this gate confirms that result is explicit (`pass | blocker | n-a`) and does not reclassify it (AC 13). No document → `n/a: no project invariants declared`, not a blocker. | The receipt's invariant result is absent/ambiguous, or a recorded `blocker`/`violates`/`introduces`/`changes` lacks the cited decision the review surfaced. |
> The review evidence is the receipt, never a re-review: verify the newest
> `review-change:pass` marker's `sha` against the PR's head (Step 1). A current
> receipt passes this gate regardless of its axes' content — the audit consumes,
> it does not re-litigate. A missing or stale receipt is a blocker routed to
> `/review-change`.
references/02_CLOSURE_AND_SCOPE_GATES.md
## Closure and scope gates
> **Closure integrity — fixed output.** Detection is purely mechanical: grep the
> governing SPEC for a `Capability closure` heading — match the heading text, not
> a fixed level (SPECs nest it as `### Capability closure` under `## Product half`;
> older ones use `## Capability closure`) — never dates, never versions, never
> judgment.
> - **Fix-governed PR** (`docs/fix/<n>-<topic>/SPEC.md`) → **n/a**, always. Fix
> SPECs carry no closure block by design; never emit a warning for one.
> - **Feature SPEC, block present** → evaluate the three boxes, each a blocker
> on failure:
> 1. the block exists in the SPEC (true whenever this path is reached)
> 2. zero blank rows — every entity/capability/role row is either filled
> (UI + API + test) or carries an explicit `n/a: <reason>`
> 3. every resolved non-`n/a` row maps to a listed acceptance criterion
> `n/a: <reason>` is a **fully valid, passing** row — the gate verifies the
> decision was *taken and recorded*, never that UI/API surface exists. Never
> push a blank row into inventing surface to pass this gate.
> - **Feature SPEC, block absent** → the SPEC predates or bypassed
> `design-feature`. Never a blocker — emit a dated **warning**, PR still
> merges:
> ```
> design-debt: closure absent, SPEC predates the rule (dated <YYYY-MM-DD>)
> ```
> This warning is itself the **retrofit trigger**: the next unit of work that
> touches this feature must fill the closure via `/design-feature <slug>`
> (upsert — fills only the missing rows, destroys nothing recorded) *before*
> that new work is planned. See `design-feature`'s upsert semantics for the
> other half of this contract.
> **`done` ≠ merge-ready.** A unit flips to `done` when its PR opens (built, not
> merged — merge state lives in the forge). So a `done` roadmap row is *not* evidence
> of merge-readiness: this gate still has to pass on its own. The two things this gate
> most often catches on a `done`-but-unmerged unit are **pending docs** and a
> **prematurely-removed issue/fix-index entry** — both are blockers.
> **Scope integrity (descope) — fixed output.** A cheap way to look finished is
> to quietly convert unfinished SPEC scope into a follow-up issue — the unit
> reads as done, the scope silently moved to the backlog. This gate catches it
> mechanically, keyed off the same `## Amendments` log `execute-phase`'s
> descope guard writes to (single source — see that skill's *Descope guard*
> section):
> 1. List issues **born since the branch diverged**
> (`git log <base>..HEAD --format=%ad --date=short | tail -1` for the
> earliest commit date, then `gh issue list --state all --search
> "created:>=<date>"`) that **reference this unit**, via **either** of two
> detection paths — a hit on either is sufficient, run both, never only the
> first:
> - **text match** — title/body mentions the feature/fix slug or issue
> number, or
> - **`## Amendments` link** (`#89`) — the issue is linked from a row in
> the governing SPEC's `## Amendments` section (the same log
> `execute-phase`'s descope guard writes to — single source, see that
> skill's *Descope guard*), **regardless of the issue's own title/body
> text**. This closes the coverage gap a generic-titled or slug-unaware
> descoped issue leaves in the text-match path alone: an issue linked
> from an amendment row is unambiguously about this unit no matter what
> it's titled.
> 2. For each such issue (from either path), run the per-issue checklist:
> - ✓ the SPEC criterion/task it touches is still **met in the PR** — pass,
> it's discovered work or already covered, or
> - ✓ a matching `## Amendments` entry exists in the governing SPEC
> (dated, **user-approved**, and **linked** to this issue's number) — pass,
> the descope was properly recorded
> - neither holds → **BLOCKER**.
> 3. Symmetrically, every `## Amendments` row in the governing SPEC must itself
> be dated, user-approved, and link a real, existing issue — an `## Amendments`
> row missing any of those is also a **BLOCKER** (a hollow amendment is the
> same failure as no amendment at all).
> - **Scope:** any SPEC-governed PR — **feature and fix** alike, both carry
> acceptance criteria a lazy run could export. No issues born during the unit,
> or none referencing it → the gate **passes** (nothing was exported).
> - This gate never re-litigates whether the *original* criterion was reasonable
> — only whether its descope, if any, was recorded and approved before the
> issue was filed.
> - **Backstop, not primary.** `execute-phase`'s creation-time descope guard
> (`skills/execute-phase/SKILL.md` *Descope guard*) is the **primary**
> control — it stops a descope from ever reaching an issue without an
> approved `## Amendments` entry first. This gate is the **backstop** that
> catches what the primary control missed (a descope-filed issue from a
> session that bypassed the guard, or a hand-filed issue). The `## Amendments`
> -link detection path (`#89`) widens this backstop's *coverage* only — it
> changes nothing about `execute-phase`'s own contract or precedence.
## Pre-execution lineage and obligation closure (feature and fix PRs)
This gate sits downstream of both pre-execution reviews, so it verifies their
authority **survived the build** — it never re-reviews a plan and never re-judges a
verdict:
1. **Upstream lineage is current.** The unit's `progress.md` carries
`## Pre-execution review receipt v1 — plan` whose digest re-derives identically
(`scripts/pre-execution-snapshot.mjs verify --stage plan --parent <the receipt's
Product digest>`; a fix unit binds no parent —
`structural.reasonCode`/`changedPaths` name the drifted dimension), and — for a
feature unit — its named `— spec` parent re-derives the same way. Bound artifacts
are frozen: new implementation-phase files are allowed, edits to a bound artifact
are not. Stale, missing, wrong-stage **or impossible-timeline** lineage → **BLOCKED**,
`→ Next: /review-plan <unit>` (or `/review-spec <unit>` when the parent is the
broken link). A `SPEC-REVIEW-PASS` never satisfies the plan hop, and vice versa.
2. **Obligations are closed.** Every row of the unit's obligation ledger is
`verified` — with the validator that ran on this candidate — or an explicit
`n/a: <reason>`. Any `planned`, `in-progress`, blank, or `deferred` row is
**BLOCKED**, naming the ids. `deferred` is legal only when the user amended the
governing SPEC first (cite the amendment); without one it is an open obligation
wearing a new name, and it may not be exported to a follow-up issue to clear the
gate.
3. **Planning findings are resolved.** `planning-findings.md` holds no open row for
the bound snapshot: a PASS may not coexist with an unresolved material finding.
4. **Authority is unchanged.** `audit-pr` remains the only emitter of `MERGE-READY`;
a pre-execution PASS is upstream evidence, never a merge verdict, and nothing here
merges, closes, comments down, or files an issue.
A legacy unit with no ledgers is not exempt: the missing ledgers must be constructed
and reviewed through the adoption route (the pre-execution gate in `execute-phase`'s
preflight) before MERGE-READY. The audit never coerces old evidence into the new
format, never edits `ACCEPTANCE.md`, and never accepts a hand-written table that the
plan snapshot does not bind.
references/03_AUDIT_PROCESS.md
## Process
1. **Gather** — Step 0: project contract, PR, SPEC + artifacts, CI status.
2. **Consume the review receipt** — Step 1: fetch the PR's `headRefOid` and
comments in one query (`gh pr view <N> --json headRefOid,comments`) and take
the **newest** marker
`<!-- review-change:pass sha=<40-hex> contract=v1 -->`. Its `sha` must equal
that query's `headRefOid` current head SHA. Any mismatch is stale; do not
use a local diff to preserve a receipt for a different PR head.
- **current** → acknowledge scope/axes, acceptance coverage, invariant result,
manual checks; continue to the gates.
- **absent / stale** → **BLOCKER** (no review evidence at the head), routed to
`/review-change`; never re-review from here.
3. **Walk the contract** — evaluate every gate above against evidence. For each,
record pass / blocker / n-a with the specific artifact or check that proves it.
4. **Confirm deferrals are real** — for anything postponed (an unchecked task, a
review finding, a known issue), verify a tracked issue + trigger exists. A
deferral with no destination is a blocker, not a pass.
5. **Decide** — one verdict:
- **MERGE-READY** — every applicable gate passes (including a current receipt);
list the few things the human should still eyeball (the manual-verification
items the receipt surfaced).
- **BLOCKED** — one or more gates fail; output the ranked blocker list.
6. **Persist blockers to the fold ledger (BLOCKED verdict only).** Every blocker
on a **BLOCKED** verdict is, by definition, fix-now — merge is gated on it.
Append each to the unit's fix-now fold ledger `review-findings.md` (same
location and fixed schema
`| id | file:line | axis | severity | class | route | folded |` as
`review-change`'s persist step) — the **same ledger**, not a separate one
(D4: the fold cycle consumes one list). **Merged unit → no write** — check
`gh pr view --json state`; `MERGED` skips the persist step entirely. For
each blocker: `file:line` = the cited evidence location (the gate name
when no single line applies); `axis` = the gate name (e.g. `Review
receipt`, `Docs`, `Traceability`); `severity` = `high` (a blocker gates
the merge by definition); `class` = `fix-now`; `route` = the routing this
skill's own Routing section assigns to that kind of blocker; `folded`
starts `no`.
Re-runs **dedupe by `file:line` + axis**, identical to `review-change`'s
rule — a blocker already on the ledger at that `file:line`+axis is not
re-appended; a genuinely new blocker gets the next `Fn` id.
7. **Post the MERGE-READY comment on the PR (MERGE-READY only).** The verdict
must be visible on the PR itself — as a **comment**, never in a commit
message (a commit trailing "MERGE-READY" pollutes history and goes stale
the moment the branch moves). Write the body to a file (Markdown rule —
see Guardrails) and run
`gh pr comment <N> --body-file <path>` with exactly this body:
```markdown
<!-- audit-pr:merge-ready sha=<head SHA> -->
## ✅ audit-pr: MERGE-READY
- **Audited head:** `<head SHA>` · CI: <green|local-gate-green>
- **Review receipt:** `REVIEW-PASS` at `<head SHA>` (consumed, not re-reviewed)
- **Date:** <YYYY-MM-DD>
- **Before merge, a human should still verify:**
- <manual-verification item — or "nothing">
Any commit after `<head SHA>` voids this verdict — re-run `audit-pr`.
```
**Idempotent:** first check the existing comments
(`gh pr view <N> --json comments`) for the `<!-- audit-pr:merge-ready -->`
marker — same SHA already commented → skip (say so); older SHA → post the
new comment (the newest marker wins). Never post a comment for a BLOCKED
verdict — blockers go in the chat report only, so the PR page never shows
a stale green flag.
8. **Report** — the verdict block below, always headed by the PR's full URL.
In an active `ship-roadmap --fullauto` AUDIT stage, return the verdict to the
conductor; never run its merge wrapper from this skill.
references/04_VERDICT.md
## Verdict format
```
PR #<N> — <title>
URL: <full PR URL — always printed; the user works across several projects
and not every agent shows a CI monitor or PR list>
Base: <default> ← Head: <branch> @ <head SHA> CI: <green|failing|pending>
VERDICT: MERGE-READY | BLOCKED (<count> blockers)
Blockers (ranked):
1. [<gate>] <what's wrong> — evidence: <file:line | check | criterion>
→ fix: <smallest action to clear it> (<route>)
...
Warnings (non-blocking — never change the verdict):
- design-debt: closure absent, SPEC predates the rule (dated <YYYY-MM-DD>)
Non-blocking nits:
- <minor item> — <pointer>
Before merge, a human should still verify:
- <manual-verification item from the review-change receipt>
→ Next:
Print the ONE verdict bullet that matches, THEN — if a closure warning fired —
also print the closure bullet (a warning never blocks, so it co-occurs with a
MERGE-READY verdict; the two lines print together, never one instead of the other):
· MERGE-READY, standalone/manual audit → you merge: <full PR URL>, then
/plan-feature --next (the next roadmap unit) or pick an issue with /triage-issue
· MERGE-READY inside active ship-roadmap --fullauto → return this SHA-bound
verdict to the conductor; it runs the transient merge wrapper
· BLOCKED → clear the top blocker (routed above), then re-run /audit-pr
· Receipt absent/stale blocker → /review-change (re-review at the head), then
re-run /audit-pr — never re-review from this audit
· Closure warning (in addition to the verdict above) or a closure blocker →
/design-feature <slug> — fills the missing closure rows (upsert, destroys
nothing) before further work on this feature is planned; re-run /audit-pr after
· Scope-bleed blocker → record the missing `## Amendments` entry (user-approved,
dated, linking the issue) in the governing SPEC, or re-classify the issue as
genuinely discovered work via /triage-issue; re-run /audit-pr after
```
If MERGE-READY, omit the blocker list and state it plainly: nothing blocks merge.
The `→ Next:` block is always printed — on MERGE-READY it repeats the **full PR
URL** (merge it yourself, or the merged link) and points the user at the next
concrete unit so a finished feature never dead-ends at the merge.
Example (generic — substitute your project's numbers and gates):
```
PR #142 — Add CSV export to the reports view
Base: main ← Head: feat/14-csv-export CI: green
VERDICT: BLOCKED (2 blockers)
Blockers (ranked):
1. [Tests] Export handler has no test — acceptance criterion "export
round-trips the rows" is unverified
→ fix: add an integration test for the handler (fold into the current phase)
2. [Traceability] PR body is missing `Closes #131` for issue-born work
→ fix: add `Closes #131` to the PR body (execute-phase)
Non-blocking nits:
- Help text wording diverges from the other commands — docs/USAGE.md
Before merge, a human should still verify:
- The exported file opens cleanly in a spreadsheet app (visual)
```
references/05_ROUTING_AND_GUARDRAILS.md
## Routing (blockers, by kind)
- **Missing/stale review receipt** → `/review-change` (re-review at the head, then
re-run `audit-pr`) — never re-review from here.
- **Incomplete in-scope work** → fold into this branch via `execute-phase`
(the relevant phase or `--fix`); re-run `audit-pr` after.
- **Out-of-scope defect surfaced** → `plan-fix` (new fix entry), not this PR.
- **Deferred finding lacking a home** → `triage-issue` to file + classify it.
- **Stale/missing docs** → update per the doc map (often a quick `execute-phase`
doc commit), then re-audit.
- **Red CI / failing gate** → report the failing check; the dev fixes on-branch.
## Guardrails
- **Read-first verdict. Never push, edit, refactor, or merge.** Its only forge
write is the **MERGE-READY comment** (Process step 7 — idempotent,
comment-only, never a commit tag). Fullauto merge execution belongs only to
the active `ship-roadmap --fullauto` conductor.
- **Never re-review the diff.** The `REVIEW-PASS` receipt is the review evidence;
a missing/stale receipt is a blocker routed to `/review-change`. The audit does
not compose `review-change`, rescan axes, judge test quality, remap diff hunks
to acceptance criteria, or reclassify architectural invariants (AC 13).
- **Forge bodies are Markdown, not shell — never hand-escape.** The comment's
backticks are formatting; a `\` before them renders literally. Write the
body to a file and pass `--body-file <path>` — never inline `--body "…"` or
a quoted heredoc. Verify with `gh pr view <N> --json comments` that no
literal `` \` `` survived.
- **Never imply that MERGE-READY is permission.** It is evidence bound to one
SHA; pending work makes it stale, and merge ownership remains external.
- Never report MERGE-READY on an unconfirmed gate — absence of evidence is a blocker.
- Honor the project's **Workflow conventions** (gate, docs-language, evidence —
every blocker cites file:line/check/criterion/issue — track-don't-inline:
out-of-scope problems become issues/fix entries, never silent additions here).
## Normalized Repository State
Audit against frozen NRS facts in `docs/workflow/REPOSITORY_STATE.md` and report conflicts as contradictions. This audit
is read-only: only `resolve-repository-state` may update a frozen fact or decision.
## Architectural invariants
The invariant result is part of the review evidence the receipt carries
(`- Architectural invariants: pass | blocker | n/a`). This audit **does not
reclassify** invariants (AC 13) — it confirms the receipt records an explicit
result and mirrors it into the verdict:
- `n/a: no project invariants declared` (the review recorded no applicable
document) → pass, not a blocker.
- `pass` (the review evidenced every applicable rule as preserved, or an
explicit architectural decision is recorded) → pass.
- `blocker` / `violates` / `introduces` / `changes` in the receipt → **merge
blocker** routed to the decision the review surfaced; the PR's head cannot be
merged until the project's declared authority applies the decision and the
review re-runs.
State `Architectural invariants: pass | blocker | n/a` in the verdict. A decision
record alone does not pass; never accept a SPEC, implementation, or passing test
as the missing decision.
references/PORTABILITY.md
## Portability (agents other than Claude Code)
The workflow is the contract; Claude Code features are conveniences. On an
agent that lacks one, apply the fallback — never skip the step the feature
enables:
- **No slash-command menu** — where this skill says `/<skill>`, open that
skill's `SKILL.md` (wherever your agent installed the skills) and follow it
literally, in a fresh conversation: hand-offs assume a clean context.
- **No per-skill `model:`/`effort:`** — on the `#claude` branch the frontmatter pins these tiers; here, pick tiers yourself:
the merge gate is the highest-stakes automated verdict — run it on your
**strongest** model, never on the cheap tier that wrote the code.
- **Receipt consumption is comment-based, not forge-branded.** The
`review-change:pass` marker lives in PR comments (`gh pr view <N> --json
comments` on GitHub). On a forge without a native comments list, use its
closest equivalent (MR notes, review threads); the newest-marker-wins and
head-SHA comparison semantics are forge-independent.
SKILL.md
---
name: audit-pr
user-invocable: true
version: 5.1.0
argument-hint: <pr-number> (optional — defaults to the current branch's PR)
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
license: MIT
description: >
Audit a whole PR against the delivery contract and return MERGE-READY or
evidenced blockers with the full URL. Consumes the current review-change
REVIEW-PASS receipt instead of re-running review axes; posts a SHA-bound
ready comment; never edits or merges. Triggers: "audit-pr", "is this PR
ready", "merge gate".
---
# Audit PR
The manager's **"can this ship?"** gate. A read-first audit over the *entire* PR —
its SPEC, all phases, docs, CI status, and review receipt — that returns a single
verdict: **merge-ready** or a ranked list of **blockers**. **Never edits,
refactors, or merges.** The human merges, or an active
`ship-roadmap --fullauto` invocation consumes the SHA-bound verdict and performs
its separate fail-closed merge step.
`audit-pr` does **not** re-review the diff. It consumes the current SHA-bound
`review-change` receipt (the `REVIEW-PASS` comment marker) as the review
evidence, blocks on a missing or stale receipt routed to `/review-change`, and
independently evaluates only the delivery gates below.
## Turn contract — verify before ending the turn
```
✓ The review receipt was consumed from one PR snapshot: `headRefOid` + newest
matching `review-change:pass` marker fetched together; absent or any SHA
mismatch → blocker routed to `/review-change`, current → its scope/axes/
acceptance coverage/manual checks acknowledged without re-review
✓ Upstream lineage was re-verified (current plan receipt + parent spec receipt,
digests recomputed), every obligation row is `verified`/`n/a`, and no planning
finding is open — stale or missing lineage is a blocker, never a formality
✓ The verdict block was printed in the fixed format: `VERDICT: MERGE-READY | BLOCKED` with ranked, evidenced blockers
✓ The PR's FULL URL is printed in the verdict header (the user may be juggling
several projects and agents without a CI monitor — the link in the chat is
the contract, never "PR #N" alone)
✓ MERGE-READY verdict? Then the MERGE-READY comment was POSTED on the PR
(`gh pr comment --body-file` RUN, idempotent by SHA marker) — a comment,
never a commit-message tag. BLOCKED → no comment posted
✓ Nothing was edited, refactored, or merged; merge authorization is outside
this skill and cannot be inherited from docs or an earlier session
✓ No review pass was composed or reconstructed: a missing/stale receipt is a
blocker, never a prompt to re-run review axes from this skill
✓ Closure integrity was evaluated and its result stated explicitly: pass /
blocker / warning / n-a (fix-governed PRs are always n-a; never skipped
silently)
✓ Scope integrity (descope) was evaluated and its result stated explicitly:
pass / blocker / n-a (no unit-referencing issues born on the branch → n-a;
never skipped silently)
✓ Architectural-invariant preservation was evaluated and its result stated
explicitly: pass / blocker / n-a (no project document → n-a; never skipped)
✓ The closing `→ Next:` block is printed as the ABSOLUTE last output
```
About to end the turn with any box unchecked? The turn is NOT done — complete
the missing box first (weak models drop end-of-document duties; this list is
first on purpose).
## When to use
- After the work is "done" and before merging — the final gate once `review-change`
is clean (its `REVIEW-PASS` receipt is posted) and all phases are committed.
- When you want one defensible answer to "is this PR actually ready?" rather than
trusting that every loose end was tied off.
`review-change` reviews the *diff* for quality and posts its SHA-bound receipt;
`audit-pr` consumes that receipt and audits the *PR as a unit of delivery* — that
everything the SPEC promised is present, traceable, and green. A missing or stale
receipt is a blocker routed back to `/review-change`, never re-litigated here.
## Scope
The whole pull request: the branch vs. the default base, **plus** its SPEC and
planning artifacts, the roadmap entry, the doc map, the PR body, issue links, and
CI. Default target is the current branch's PR; accept a PR number to target another.
## Step 0 — Discover the project & the PR (always first)
1. **Project contract.** Per the agent guide's **Workflow conventions** +
**documentation map**, then read what THIS skill needs: the roadmap and the
project's verification gate (type-check / tests / build / CI). Do **not** load
full feature/fix templates — the SPEC below is the only planning artifact this
audit reads (AC 14).
2. **The PR.** Identify it and read it in full (forge CLI per the project's
Workflow conventions — examples use `gh`):
```sh
gh pr view <N> --json number,url,title,body,baseRefName,headRefName,headRefOid,isDraft,mergeable,mergeStateStatus,files,commits,statusCheckRollup,closingIssuesReferences
```
If no PR number is given, resolve the current branch's PR
(`gh pr view --json ...`). If none exists yet, audit the branch vs. the default
base and say "no PR open yet" — the contract still applies.
3. **The SPEC.** Locate the governing SPEC — `docs/features/<NN>-<slug>/` (feature)
or `docs/fix/<n>-<topic>/` (fix) — and its planning artifacts (`PLAN.md`,
`TASKS.md`, `progress.md`, `testing.md`, `known-issues.md`, `decisions.md`) when
present. The SPEC is the source of truth for what "done" means.
## Step 1 — Consume the review receipt (always, before any gate)
The review evidence is the SHA-bound `REVIEW-PASS` receipt `review-change` posts
on the PR — **never** a re-review composed here. Fetch `headRefOid` and the PR's
comments together, then find the **newest** comment carrying the marker
`<!-- review-change:pass sha=<40-hex> contract=v1 -->`:
```sh
gh pr view <N> --json headRefOid,comments
```
- **current** — marker `sha` equals that snapshot's `headRefOid` (the current
head SHA). Acknowledge
its scope/axes, acceptance coverage, invariant result, and manual checks as the
review evidence, then evaluate the delivery gates below.
- **absent** — no matching marker on the PR → **BLOCKER**: no review evidence at
the head; route to `/review-change`.
- **stale** — a marker exists but its `sha` does not equal `headRefOid`. Any SHA
mismatch voids the receipt → **BLOCKER**: route to `/review-change` for a
re-review. Do not use a local `git diff` to override the PR-head comparison.
Never compose, reconstruct, or "spot-check" the review from the diff to clear a
missing/stale receipt — that is `review-change`'s turn, and re-litigating axes
here is exactly what the receipt gate removes (AC 13).
## Progressive loading — mandatory audit route
The reference allowlist is exactly the six linked paths below. Never invent or
read another `references/` path. After discovery and the Step 1 receipt check,
every audit loads and applies exactly these five mandatory resources in order:
1. [01 merge gates](references/01_MERGE_GATES.md) for delivery, CI, traceability,
review-receipt, and mergeability evidence.
2. [02 closure and scope gates](references/02_CLOSURE_AND_SCOPE_GATES.md) for
capability closure and descope provenance.
3. [03 audit process](references/03_AUDIT_PROCESS.md) to gather, decide, persist
blockers, and post the SHA-bound MERGE-READY comment.
4. [04 verdict](references/04_VERDICT.md) before output, then
[05 routing and guardrails](references/05_ROUTING_AND_GUARDRAILS.md). These
mandatory resources own the `docs/workflow/REPOSITORY_STATE.md` evidence
rules and Architectural invariants gate.
Read [portability](references/PORTABILITY.md) only when the declared forge or
agent actually lacks a named primitive; otherwise skip it. The project artifact
`docs/workflow/REPOSITORY_STATE.md` is evidence, not a skill reference. All
resources are one hop from this file. Missing evidence or a missing required
resource is a blocker; never infer a pass.
## Merge ownership
This skill **never merges**, including when project docs contain `merge: auto`,
the user previously approved a merge, or a tool retained an earlier permission.
Those signals cannot change this skill's read-first boundary.
The **sole automated merge authority** is the AUDIT stage of an actively invoked
`ship-roadmap --continue --fullauto` run. Its MERGE-READY comment is evidence,
not permission; the repository wrapper independently verifies that comment,
the forge's current head/default base, green checks, and the `merge: fullauto`
decision fetched at that head. The wrapper owns fresh sync checks, transient
state, merge execution, cleanup, and the automerge PR comment. A standalone/
manual call to this skill always hands the MERGE-READY URL to the human.
## Portability
Translate forge commands, never the gate semantics. Use the explicit fallbacks
in [portability](references/PORTABILITY.md).
## Relationship to other skills
```
execute-phase (all phases done) ─▶ review-change (REVIEW-PASS receipt posted) ─▶ audit-pr ─▶ merge
│
blockers ─┬─ receipt absent/stale ──▶ /review-change ──────┘ (re-review, re-audit)
├─ in-scope ──▶ execute-phase ────────┘ (fold, re-audit)
├─ out-of-scope ──▶ plan-fix
└─ deferral ──▶ triage-issue
```
- Consumes the `review-change` `REVIEW-PASS` receipt (its scope/axes, acceptance
coverage, invariant result, manual checks) plus the artifacts of `plan-feature` /
`plan-fix` / `execute-phase` (SPEC, phases, docs, `Closes #N`).
- `audit-docs` is the cross-document coherence check; `audit-pr` is per-PR merge
readiness; `product-audit` is the periodic, product-wide full sweep.
## Done when
- The review receipt was consumed: a current marker was acknowledged, or a
missing/stale one became a blocker routed to `/review-change` (never re-reviewed
here).
- Every applicable gate has a pass / blocker / n-a verdict backed by cited evidence.
- A single top-line verdict (**MERGE-READY** or **BLOCKED** with ranked blockers) is
reported **with the PR's full URL in the header**, each blocker routed, with the
human's manual-verification list explicit.
- On MERGE-READY the merge owner is explicit: a standalone audit hands the URL
to the human; an active `ship-roadmap --fullauto` AUDIT stage receives the
SHA-bound verdict and owns every later merge check.
- The **closing `→ Next:` block is printed** (merge link → then the next unit via
`/plan-feature --next` or `/triage-issue`; BLOCKED → the routed fix, then re-audit).
- Nothing was edited, refactored, or merged.