## Persist and decide

When the unit's review receipt is missing or stale, the re-entry command is the
**emitted** `next.continuation` (`rendering` for display) — quote it, never author
exact command tokens.

11. **Persist fix-now findings to the fold ledger.** A migrated unit (issue #308)
   carries the ledger in its own `SPEC.md`: OPEN rows in `## Findings`, and the
   review, gate and finding-verification marks as `## Log` lines (the `R`, `G` and
   `V` kinds of the published `log-kind@1` vocabulary) carrying their exit codes and
   head SHA. A legacy unit keeps the side file beside its other docs
   (`docs/features/<NN>-<slug>/review-findings.md` for a feature,
   `docs/fix/<n>-<topic>/review-findings.md` for a fix). Probe the doc first and
   write to exactly one carrier — a unit with the `## Findings` section never
   gains a side file. Each carrier has **its own** fixed schema; a row is never
   written in the other's grammar:

   ```
   | id | file:line | axis | severity | class | route | folded |
   ```

   is the legacy schema, and only a legacy unit is written with it. A migrated unit
   writes `findings-table@1` — six columns, no `folded` cell, and `class` holding
   the owner that repairs the row (`product`/`plan`/`source`/`environment`/`runtime`)
   while `route` holds the disposition (`fold`/`replan-in-unit`/`decision-required`/
   `product owner — …`) — the grammar the unit doc itself publishes:

   ```
   | id | S# / file:line | axis | severity | class | route |
   ```

   `folded: no → yes` is therefore a **legacy-only** flip: in a migrated carrier a
   closing fold deletes the row and appends its `## Log` `F` line, and `ledger-ownership@1`
   / `fold-findings:folded-flag` stays the sole writer of whichever close it is.

   **Merged unit → no write** (a PR exists and its state is `MERGED` — check
   `gh pr view --json state` when a PR is open; otherwise the unit is unmerged
   by definition). Otherwise, for each **fix-now** finding of severity `high`
   or `med` (only ledger severities; finder scale
   converts through the canonical table in
   `CLASSIFY.md`):
   append a row
   (create the file with the header row when missing), carrying the
   verbatim `Sev` value into `severity`; a legacy row's `folded` always starts `no`
   (a migrated row has no such cell — every row in `## Findings` is open) — that
   row comes from a **confirmed** candidate only and carries its
   `finding-mark@1` signature as a **separate `VF-` row** in a legacy carrier, or as
   a `## Log` `V` line in a migrated one (reviewer, head SHA, recheck + reproducer),
   as modeled in `LEDGERS.md` (§finding-mark@1) and the fixture.
   `ledger-ownership@1` / `fold-findings:folded-flag` is the sole writer of
   the `folded: no → yes` flip.
   A `low` finding is **never persisted to the fold ledger** — report-only
   note (step 13), never blocking (finders' materiality floor). Re-runs
   **dedupe by `file:line` + axis**:
   a row already on the ledger at that `file:line`+axis is not re-appended;
   a re-report at a folded row's location is legitimate only as `regression of <id>`
   (fix provably failed) or `DISPUTED`; else `Fn+1`.
   **Non-fix-now findings are never written here** — they keep
   their destinations from step 11 (outcome routing): independent future
   capabilities batch as proposals; only the user routes them to `triage-issue`
   (independent proposals, audit findings, or `--prioritize-now` runs) (D3).
   **Commit the ledger append** — rows + `REVIEW-RAN` + `GATE-RAN` marks,
   one commit (a reviewer records a `GATE-RAN` mark for the gate run the review
   performed and consumes an identical-head green mark instead of re-running,
   see `LEDGERS.md` §gate-ran@1; `docs(<unit>): persist review findings`);
   pushed when a PR is open;
   an uncommitted append hands the next review a dirty-tree stop. On
   `REVIEW-PASS` with an open PR the SHA-bound receipt is the durable record:
   head and posted receipt stay identical.
   This skill's only mutations are the rows + `REVIEW-RAN` + `GATE-RAN` marks
   (all in the step 11 commit), and, on `REVIEW-PASS` with a PR, the receipt
   comment (step 12) — it never runs a fold, executes a phase, or edits source
   (see the review-end turn boundary in the SKILL.md Turn contract).
12. **Close out the final-review receipt before reporting.** Derive the
   `Decision` from step 7 and persist step 11 first. Then — **only on
   `Decision: REVIEW-PASS` and when the PR exists** — run the receipt emitter,
   which is a precondition of the report, not a follow-up:

   ```
   bun scripts/review-receipt.mjs emit --pr <N> \
     --head "$(git rev-parse HEAD)" --scope "<reviewed surface>" \
     --axes "<axes run and skipped>" --coverage "<criterion-to-evidence>" \
     --invariants pass|n/a --proposals <n> --manual "<items or none>" \
     --scope-base main
   ```

   `--scope-base <ref>` (fix/286) records the affecting-path scope manifest
   beside the reviewed head: the emitter derives it from the branch delta vs
   that ref, so a later foreign-only commit (session log, agent toolstate) no
   longer voids the receipt at the merge gate — any affecting-path delta still
   voids it. Never hand-assemble the manifest or its digest.

   The script is the contract: it refuses a PR whose `headRefOid` differs from
   the reviewed head, posts the one idempotent SHA-bound comment (skipping an
   identical one), re-reads the comments, and **exits non-zero unless the newest
   `<!-- review-change:pass sha=… contract=v1 -->` marker names the reviewed
   head**. Never hand-assemble the body and never post it inline; the fixed body
   lives in the script and its suite. A non-zero exit means no receipt landed —
   fix that before printing anything in step 13, and never recommend
   `/audit-pr` while the receipt is not current.

   `REVIEW-FAIL` and `NEEDS-DECISION` post **no** passing receipt: record the
   status and continue to step 13. No PR → the documented pre-PR path, and the
   receipt box reads `n/a: no PR`.

   Read-only check, any time: `bun scripts/review-receipt.mjs verify --pr <N>`
   prints `current | absent | stale` and exits `0 | 3 | 4`.

13. **Report block — Return exactly this structure** after step 12 succeeds
   (fixed chat-report block; this is not the end of the turn):

   ```
   REVIEW CHANGE — scope: <scope>
   Axes run: <list>   Skipped: <list + why>
   Architectural invariants: pass | finding (<ID>) | n/a: no project invariants declared
   Receipt: current at <head SHA> | n/a: no PR | none: REVIEW-FAIL/NEEDS-DECISION

   <the synthesized decision table (step 7)>

   Manual verification (a human must check):
   - <item> …

   Notes (low · report-only, never persisted):
   - <finding + evidence, or none>

   Refuted (verified false — reported with counter-evidence, never persisted):
   - <candidate + counter-evidence, or none>

   Proposals (step 11): <n> — batched for the user, no issues created (D3)

   Summary: <1-2 sentences>
   Decision: REVIEW-PASS | REVIEW-FAIL | NEEDS-DECISION   (D10: review says these three; only audit-pr says MERGE-READY)
   ```

14. **Next step.** The `→ Next:` block is **never one static template** — branch
   on the `Decision` value from step 7 and emit the matching block **verbatim,
   as multiple literal lines**. Never join the `·` sub-bullets into one prose
   line — each sub-bullet is its own line, exactly as quoted below.
   For `REVIEW-FAIL` or `NEEDS-DECISION`, list every open finding ID in the
   closing recommendation, joined with ` + `; never hand off only the first.
   The `→ Next:` block is a **recommendation, not a to-do list**: it names what
   the *next* user-initiated invocation should be, and this turn ends when the
   report block (step 13) is printed — emit the block and end the run; do not
   begin the recommended command.

   **`Decision: REVIEW-FAIL`** (any fix-now finding open) — the recommended line
   is the fold, never the merge gate. Findings were persisted in step 11; **no
   passing receipt was posted** (step 12):

   ```
   → Next: /fold-findings — repair all open fix-now findings: <F1> + <F2> + <F3>,
     then re-run /review-change on the changed HEAD (bounded at two cycles; a
     third cycle never starts without an explicit user instruction)
     · /audit-pr → only after the table is clean (not yet — findings open)
      · any finding routed replan-in-unit or owned by plan? → `node
        scripts/unit-route.mjs <unit>` prints `route: replan` and the planner
        command (`/unit-lane <unit>` for a feature, `/unit-lane --fix <n>` for a
        fix); the lane re-runs its plan step on this branch, its review step
        gates, then `/execute-phase <unit>` (yes: list the finding ids; no: omit
        this line)
      · any finding owned by product? → `bun scripts/unit-route.mjs <unit>` (node fallback
        if bun is not installed) prints
        `route: product` + the lane hand-off — `/unit-lane <unit>` for a feature,
        `/unit-lane --fix <n>` for a fix: the lane repairs the half, its review
        step re-judges it (yes: list the ids; no: omit this line)
      · independent proposals → present to the user; only the user routes them
        to /triage-issue
     · adversarial recommendation checklist fired AND this run was
       single-reviewer? → re-run the fold review as /review-change
       --adversarial N (N per the ladder below) instead of single-reviewer

   The two-cycle cap scopes the **review→fold loop on source findings** only (a
   finding already on the branch, repaired here). A planning repair routed by a
   `class: plan`/`product` finding is a **verdict response** under
   `pre-execution-review` POLICY §4 — it re-derives plan/Product authority, not
   source — so it is never a loop-defect stop and never counts against this cap.
       (yes: <which box fired>; no: omit this line)
     · SPEC drift flagged here AND on a prior unit? → /product-audit (yes: the
       founding assumptions are probably stale — don't keep patching a
       compounding error; no: omit this line)
   ```

   **`Decision: REVIEW-PASS`** (table clean) — the recommended line is the merge
   gate. Receipt: PR exists → current after step 12 (exact-SHA `REVIEW-PASS` at
   `<head SHA>`); pre-PR checkpoint → no receipt, the `progress.md` compact
   marker covers it (D7):

   ```
    → Next: /audit-pr — merge gate
      · independent proposals → present to the user; only the user routes them
        to /triage-issue
     · adversarial recommendation checklist fired AND this run was
       single-reviewer? → re-run as /review-change --adversarial N (N per the
       ladder below) before /audit-pr (yes: <which box fired>; no: omit this
       line)
     · SPEC drift flagged here AND on a prior unit? → /product-audit (yes: the
        founding assumptions are probably stale — don't keep patching a
        compounding error; no: omit this line)
   ```

   **`Decision: NEEDS-DECISION`** (a decision-required finding is open — step
   10) — block without creating an issue; surface the decision to the user, who
   alone resolves it:

   ```
   → Next: decision required — resolve all open findings: <F1> + <F2> + <F3>
     before the unit continues
     · present the decision-required finding(s) with evidence; no issue is
       created (D3) and no passing receipt was posted (step 12)
     · once the user decides, re-run /review-change on this same branch
   ```

   The `/product-audit` line fires **only on recurring drift** — the same kind
   of inconsistency surfacing a second time, not a single isolated finding;
   the yes/no checkbox above is how to decide, in both branches.
