Build Polish
Get to done. While a build is being built, each version or increment gets its own
build-evaluate verdict — and none of those verdicts is the deliverable being done. The Yellow
Sheet went through 1.0 to 1.4 that way, evaluated many times and never done. Polish is the end of
the build: the owner defines done once, the real thing runs until it matches, and polish marks the
deliverable complete.
Three measured facts shape it.
- 45% of all must-fix findings across 21 review rounds sat in text the previous round's repair
wrote (
mem:gate_philosophy). Polish reviews by rule and by harness, not by panel.
- Exit codes and counts have called builds done that were not — a green renderer over an empty
tab, "workbook written" over 0 of 70 money cells, a floor 40 below its count. The done check
reads the artifact, never the exit code.
- Two drivers on one shared tree cost a whole measurement round on 2026-09-10 — the reason for
the one-run cap below.
Where it sits
while the build is being built, per version or increment:
prd → probe → validate → plan → estimate → execute → evaluate
at the end of the build, once:
POLISH → the deliverable is done
Polish replaces any further evaluate. It never runs the full suite or the full mutation table:
those did their job while the versions were built. It checks the finished thing against real
examples, and uses single mutation rows, or small sets of them, where their output drives a fix.
Preconditions — REFUSE if unmet
- The owner has called the build at its end: no planned version or increment is left to execute.
- Polish runs on the last version's slug:
.claude/PRPs/{slug}/prd.md and state.json exist, and
the last increment's build-execute reported success.
- If
probes/run.sh exists, it was re-run this session with 0 MISMATCH.
- The build names a core-function command and at least one golden with an oracle. With no golden
there is nothing to polish against; that is build work — stop and say so.
Fixed caps
Three rounds. Stagnation — two rounds in which no ledger row left OPEN — runs five-whys, then
stops. Three FAILs on one target stop the loop as a process defect (Hard Rule 9). No clock, ever
(Hard Rule 8). One run of the core function at a time.
What the owner sees
| When |
The owner sees |
The owner is asked |
| Start |
The done definition, pre-filled from the release standard, the last PRD, state and every version's evaluate |
Once: Confirm / Adjust / Stop |
| Rounds |
Nothing. No status reports at round boundaries |
Only for a target change, a scope call, or a fact only a human holds — after the repo was searched for it (Hard Rules 4 and 11) |
| End |
The deliverable marked complete, or stopped, and the report (§ Close) |
Only the questions the ledger could not settle |
Phase 0 — define DONE (the preflight gate)
Read the deliverable's release standard (the owner's words for what shipping means), the last
version's prd.md and state.json, every version's evaluate.md, and the build's corpus skill if
it has one. Pre-fill the definition — the owner confirms, never authors. Write it as the
## Phase 0 section of the ledger (§ Ledger):
| # |
Field |
Must contain |
| 1 |
DONE |
The release standard in one sentence, quoted, with its source line |
| 2 |
GOLDEN SET |
Every item by name, never a glob, and the count N. Per item: the oracle command, its expected result, and a numeric floor equal to the item's latest recorded count, cited file:line |
| 3 |
WITNESSES |
W1, the driver's own tally. W2, a program that reads the surface the persona reads — never the file W1 reads. Each with its literal expected output |
| 4 |
RUN |
The core-function command, the live-driver patterns, and the output paths to snapshot |
| 5 |
GUARDS |
How to run one mutation row, or a set, alone (--only), from the directory it needs. Never the full table |
| 6 |
JOURNEY |
The persona and the surface they read, from the build's own memory; the decision the output supports; the acceptance bar in the user's words; the steps — what they see, what must be true, which golden evidences it |
| 7 |
NOT THIS SESSION |
The named out-of-scope items, including every corpus item left out of the golden set and every journey step no source documents |
Below the table, the output of shasum -a 256 <absolute path>... for every golden file and every
oracle and witness program — one hash path line each. polish.sh pin refuses a Phase 0 without
these lines or whose lines do not match the files, and re-checks them on every later call.
The target rule — stated here, cited by name everywhere else: only the owner moves DONE, a
golden, a floor, a witness, a PRD number, a pin, a contract, a pinned constant or a refusal limb.
The session never does, whatever a round measured. On PIN MOVED or GOLDEN MOVED, stop: show
the owner what changed, ask the Phase 0 question again, record their answer in
state.json → decisions, and only then run polish.sh pin {slug} --repin — the script refuses a
re-pin until decisions has grown.
Reject the definition if it has: (a) pass, green or exit 0 with no count; (b) an
existence-only check such as "workbook written"; (c) a criterion only an opinion can judge; (d) a
witness, floor or golden the session can edit; (e) an answer key a human keyed by hand used as a
gating golden — it carries figures no document states, and fixing toward it writes them into the
output; (f) a golden set smaller than the corpus, unless each omitted item is named in NOT THIS
SESSION; (g) a witness that reads a log, or the file the other witness reads, instead of the
surface the persona reads; (h) a journey step marked UNDOCUMENTED — it moves to NOT THIS SESSION
before the pin.
Then bash .claude/skills/build-polish/polish.sh pin {slug} and ONE AskUserQuestion — the DONE
sentence, N, the floors and the journey steps, with options Confirm / Adjust / Stop. That answer
is the owner's approval of done: when the done checklist later passes, nothing is asked again.
polish.sh run refuses without the pin, so nothing runs before that answer.
Phase 1 — load what is already known
Read, never re-derive: mem:index and the memory it routes this build to (current state, what is
settled, parked, still the owner's); the slug's state.json → decisions, awaiting_human,
what_is_NOT_claimed — a missing key is unknown, not empty, and shapes vary by slug; every
version's evaluate.md must-fix and notes; the ledger. Search the parking lot and large memories
with grep.
Carried items. A parking-lot entry whose last line ends → build-polish is on this run's list —
grep -n '→ build-polish$' .claude/parking-lot.md finds them. Each joins round 1's candidates as
lot-<n> and goes through triage like any other; an entry polish takes moves into the ledger and
leaves the lot.
The round — at most three
RUN. polish.sh run {slug} {round} --driver <pattern>... --keep <path>... -- <command>.
It refuses while a driver is live, tees the FULL log, checks that nothing outlived the command,
and copies the kept paths into a read-only snapshot with a sha256 manifest and a fingerprint of
the code. Run a long command as a background Bash call. The command's exit code is data,
printed, never polish's verdict. A kept path the command did not produce is listed in
missing.txt and on the summary line; that item is NOT MEASURED this round, never a clean
compare.
COMPARE. Run each item's oracle against the snapshot. Every difference is a candidate.
A mutation row, or a set of them, may run here too when its output would point at a fix.
READ. In ONE message, one subagent per golden item — every item in round 1, then only items
whose manifest lines changed. Two readers, kept apart:
- Golden reader, only for an item no oracle script covers: compares the snapshot with the
golden and cites the position on both sides.
- Journey walker: gets the snapshot and NO golden, because a reader who knows the answer
cannot test whether the output explains itself. Walks each JOURNEY step as the persona.
Both prompts carry the snapshot path and say findings only AND run nothing (§ Prompts).
Every finding is a triage candidate — a lead, never a verdict.
TRIAGE. Per new candidate: polish.sh seen {slug} <key>, then the triage checklist, then
one ledger row.
FIX. PROBLEM rows that question 7 cleared: the smallest change that closes the anomaly,
past the veto (§ Reviewers). Then run the mutation rows that pin the lines the fix changed,
alone (--only); every one must be caught. No full suite, no full table.
REVIEW when § Reviewers says so. The next round re-runs everything, which is what catches a
fix that broke a different item.
A round with no new PROBLEM and no fix goes straight to the done checklist.
The gated checklist — one mechanism, two lists
Run it with mcp__sequential-thinking__sequentialthinking:
totalThoughts is the list's length. One thought per question, in order. Never skip, reorder or
add a question.
- Each thought starts
Q<n>:, quotes the command it ran and its verbatim output (or a
file:line and the quoted line), and ends → YES or → NO.
- A thought without quoted evidence takes the fail-closed branch: in triage the row stays OPEN
and blocks DONE; in the done check it is NO.
- An opinion never answers a question, the model's or a subagent's. A reader's report is a
lead for a question, never its evidence.
- The first terminal answer ends it (
nextThoughtNeeded: false) and emits one ledger row or one
verdict line.
Triage — is this problem really a problem?
Questions 1 to 4 are exits: a YES ends the checklist with that class. Questions 5 and 6 classify:
YES at either is a PROBLEM, and NO at both is a NOTE that ends the checklist. Question 7 routes a
PROBLEM.
- SETTLED?
polish.sh seen prints a VERDICT line — a ledger row, an evaluate.md verdict or
a state.json decision — for this key and value → SETTLED, cite it. A LEAD line (parking lot,
memory) is a lead, never a verdict. Two keys reopen instead: a FIXED row's key seen again means
the fix did not hold — go to question 7 as a PROBLEM; a NOISE row's key seen again on a fresh
snapshot goes on to question 2.
- NOISE? The snapshot artifact itself — never the log, never a summary — does not show it →
NOISE, and the row names the cause: a trimmed log, a live driver, a moved HEAD, a stale
snapshot. "Did not reproduce" is not a cause; with none named, answer NO.
- GOLDEN WRONG? The source line our value cites, opened in the snapshot and quoted, states
that value, and the golden's figure has no such line — or the golden predates the source →
NOTE, ASKED. A citation alone is our reading of the source, not the source. Before saying an
input was not supplied, open the input packet.
- SELF-INFLICTED? A fix from this session touched its path → revert that fix; the row stays
OPEN until the next round's snapshot. Gone there → the revert stands, row CLOSED. The original
anomaly back instead → PROBLEM, ASKED: the fixes oscillate, and the owner picks.
- LIMB 1. Does any value a persona reads change, whether or not a JOURNEY step names it?
- LIMB 2. Does any output state a check, PASS, agreement or coverage that no source line
supports? On a path no golden exercises, a one-variable synthetic reproducer answers this.
- TARGET? The fix falls under the target rule → the row stays PROBLEM with status ASKED, and
the owner is asked this round. NO → fix it this round.
Two standing rules. A stochastic reading path — OCR, a model reading a page — is not tested by
repetition: a figure carrying a check the paper does not support is a PROBLEM the first time. The
journey can promote a finding and never demote one; an intact step still goes through question 6.
Done — is done really done?
The first NO ends it: NOT DONE.
polish.sh pin {slug} exits 0 and prints pin OK, goldens unchanged and snapshot fresh: —
the definition, the goldens and the witness programs are as the owner confirmed them, and the
latest snapshot measured the code as it stands. A first pin or a re-pin prints none of these.
- The latest snapshot holds all N items, counted from W1's output inside it.
- Every item meets its floor, read by W2 from the surface the persona reads.
- Nothing NOT MEASURED or SKIPPED is counted as PASS; each has its own NOTE row, or is named in
NOT THIS SESSION.
- W2 agrees with W1 on every item.
- Every mutation row polish ran was caught, and every line polish changed is pinned by a row that
ran or was reviewed under § Reviewers.
grep -cE '\| PROBLEM \| (OPEN|ASKED) \|' on the ledger prints 0.
- Every JOURNEY step has a walker's
found: YES whose position the session opened in the latest
snapshot and quoted.
- The release scorecard: every clause of DONE and every criterion of the last version's PRD scores
PASS from the latest snapshot — one thought each, quoted evidence. SKIPPED and NOT MEASURED are
listed on their own line, never counted as PASS.
Reviewers
KISS/YAGNI is the dominant reviewer, applied as a rule to every fix before it lands. Veto the
fix if its diff adds a file, flag, config key, class, abstraction or schema — unless removing that
addition brings the anomaly back. If the lines that do not close the anomaly outnumber the lines
that do, veto. A vetoed fix goes back to step 5, smaller.
Correctness comes before size. The real results, the pinned rows and the code reviewer decide
whether a fix is right; the veto then picks the smallest right fix.
Spawn simplifier and code-reviewer together — findings only, run nothing — in two cases:
- a round whose fix changes a line no mutation row pins and no golden item exercises;
- once before the done checklist, over polish's own combined diff, if polish changed any code.
The code reviewer blocks only on the must-fix bar: a wrong result a human relies on, or the tool
claiming something it has not verified (Hard Rule 9). The simplifier blocks only through the veto.
Everything else they say is a note for the close report and never re-enters the loop. After each
review, record it and check for drift; drift means stop reviewing that file.
python3 .claude/hooks/review-drift.py record <file> --must N --should N --note N --self-inflicted N
python3 .claude/hooks/review-drift.py check <file>
Ledger — the knowledge harness
One file: .claude/PRPs/{slug}/review/review-polish-audit.md. review is an existing kind, and
audit in the name exempts it from the no-postmortem gate, so verdicts may carry dates.
---
type: note
title: "Polish audit — {slug}"
related: [".claude/PRPs/{slug}/prd.md"]
updated: YYYY-MM-DD
status: current
schema: okf-adapted-v0.1
---
# Polish audit — {slug}
## Phase 0
(the seven fields, then the sha256 lines)
## Anomalies
| key | class | status | cite | round |
|---|---|---|---|---|
| matter-d/total_charges=0.00 | PROBLEM | FIXED | record.json:41 | 1 |
- key is item/field=observed value. A CLOSED row is never re-triaged unless its class is NOISE;
a FIXED row whose key comes back reopens as a PROBLEM. A new value opens a new row.
- class SETTLED, NOISE, NOTE, PROBLEM. status OPEN, FIXED, CLOSED, PARKED, ASKED.
- One anomaly per physical line; a bare
file:N cite, never in backticks, never a .log. Never
the claims-ok marker — one occurrence disables the document-claims gate for the whole file.
- A verdict with no cite or decision number stays OPEN: the loop cannot settle its own findings
without evidence.
- Matters and people are letters or roles. No quoted document text.
Close
- DONE — the done checklist passed, so the deliverable is complete. On the last version's slug,
set
state.json → state to complete and polish.state to done, and the PRD's
status: complete; record the deliverable as done, with the date, in the build's state memory.
No second question: the owner approved this definition of done in Phase 0.
- STOPPED — cap, stagnation, three FAILs, or any PROBLEM row OPEN or ASKED. A wrong result
waiting on the owner is still a wrong result: the verdict is STOPPED, never "done with notes".
Route every open row before reporting. NOTE → .claude/parking-lot.md at its next free number,
PARKED. Every ASKED row → state.json → awaiting_human, list or object as the slug already has
it. A trap seen in two sessions → a Serena memory plus its mem:index row.
Report in build-execute's four-part session-report shape, no jargon, plus the ledger counts by
class and, for each JOURNEY step, the snapshot position beside its golden.
Prompts
Journey walker
You are {persona} ({memory and section it comes from}). This matter is live. Using ONLY the
snapshot at {path} — no golden, no code — try each journey step: {steps}. For each step: would you
know what to do, could you find it, would you recognise it, would you know you are done? Apply
U1-U6. Findings only. RUN NOTHING: no driver, generator or test. You may Read files, or print one
with a single python3 line that only opens it. Refer to matters by letter.
Per step:
step: <n> | task: <what you tried>
found: YES|NO — <tab!cell, or the words you used>
stuck: <the verbatim words that stopped you> | none
trust: act | check | reject — <one clause>
tag: PROBLEM(U#) | NOTE(U#) | CLEAN
| U |
Check — a NO is a finding, pre-tagged so a reader cannot inflate it |
NO is |
| U1 |
Every figure names its source: a document and line, or a call with who and when |
PROBLEM |
| U2 |
Every blank and every total says what it does not cover |
PROBLEM |
| U3 |
No status claims more than was checked |
PROBLEM |
| U4 |
Every difference from the golden carries a reason or says UNKNOWN |
PROBLEM |
| U5 |
Every flag names one next action |
NOTE; PROBLEM if the action is wrong |
| U6 |
The output uses the reader's order and words, once |
NOTE |
Golden reader
"Compare {item} in the snapshot at {path} with its golden at {golden}. For each difference, cite
the position on both sides. List differences only; no verdicts. Findings only. RUN NOTHING."
Worked example — the Yellow Sheet
- DONE: the release standard in the parking lot's header — every figure from every document
reaches the workbook, and every penny of difference against the firm's finished sheet is
accounted for or named UNKNOWN with a plainly stated reason.
- RUN:
bash -c 'cd <case-folder> && python3 tests/run_corpus.py'; drivers run_corpus.py,
run_1_, run-mutations.sh, yellow-sheet.sh; keep each case folder under the cases root
(_corpus-matter-<x>) by name, plus _corpus-logs. That tree also holds case folders named before the letter scheme,
which is why items are named and never globbed.
- GOLDEN SET: all six matters. Oracle
tests/check_real_matter.py <case-dir>, the
printed-total identity — grep its output for SKIP, which also exits 0. Floor: each matter's money
cells at their latest recorded count, cited; an intended decrease is a target change for the
owner.
- W1 the table in
summary.json, which run_corpus.py computes from record.json. W2 the
money cells counted in each matter's output/yellow-sheet.xlsx with openpyxl — the workbook the
persona opens, not the record W1 already read. run_corpus.py exits 1 while an UNREAD refusal
is outstanding — data, not failure.
- GUARDS:
(cd <case-folder> && bash tests/run-mutations.sh --only=<rows>) — one row, or a
comma-separated set.
- The firm's finished sheets go through
answer_key_diff.py. The release standard asks that every
difference carry a reason or say UNKNOWN (U4) — never that the sheet match them (reject rule e).
- JOURNEY: personas and surfaces from
mem:yellow_sheet/output_format.
Guidelines
- One change per anomaly; a round may carry several.
- Never edit the golden, the witness or the definition to make a round pass — the target rule.
- Polish owns done for the deliverable: the only stage that marks it complete, and only when its
done checklist passes. A version's evaluate verdict is an input to Phase 0, never the
deliverable's done.
1---2name: build-polish3description: The final stage of a whole build, and the stage that owns done. Once the build's planned versions and increments are finished, build-polish runs the real thing rapidly until it matches its goldens, then marks the deliverable complete; build-evaluate is not run again. Phase 0 is a preflight gate: it writes the definition of done (the release standard, a named golden set with numeric floors, two independent witnesses, the end-user journey) and nothing runs until the owner confirms it. Then up to three rounds: one serialized run of the core function into a frozen snapshot; comparison against the goldens; parallel read-only subagents that check it and walk the user journey; an evidence-gated sequential-thinking checklist deciding whether each anomaly is really a problem; the smallest fix, under a KISS/YAGNI veto and code review. The end check stays small: real results, plus single mutation rows or sets whose output drives a fix. Triggers - polish the build, final polish, get it to done, is it done, /build polish.4---56# Build Polish78**Get to done.** While a build is being built, each version or increment gets its own9build-evaluate verdict — and none of those verdicts is the deliverable being done. The Yellow10Sheet went through 1.0 to 1.4 that way, evaluated many times and never done. Polish is the end of11the build: the owner defines done once, the real thing runs until it matches, and polish marks the12deliverable complete.1314Three measured facts shape it.1516- **45% of all must-fix findings** across 21 review rounds sat in text the previous round's repair17 wrote (`mem:gate_philosophy`). Polish reviews by rule and by harness, not by panel.18- **Exit codes and counts have called builds done that were not** — a green renderer over an empty19 tab, "workbook written" over 0 of 70 money cells, a floor 40 below its count. The done check20 reads the artifact, never the exit code.21- **Two drivers on one shared tree cost a whole measurement round** on 2026-09-10 — the reason for22 the one-run cap below.2324## Where it sits2526```text27while the build is being built, per version or increment:28 prd → probe → validate → plan → estimate → execute → evaluate29at the end of the build, once:30 POLISH → the deliverable is done31```3233Polish replaces any further evaluate. It never runs the full suite or the full mutation table:34those did their job while the versions were built. It checks the finished thing against real35examples, and uses single mutation rows, or small sets of them, where their output drives a fix.3637## Preconditions — REFUSE if unmet3839- The owner has called the build at its end: no planned version or increment is left to execute.40- Polish runs on the last version's slug: `.claude/PRPs/{slug}/prd.md` and `state.json` exist, and41 the last increment's build-execute reported `success`.42- If `probes/run.sh` exists, it was re-run this session with 0 MISMATCH.43- The build names a core-function command and at least one golden with an oracle. With no golden44 there is nothing to polish against; that is build work — stop and say so.4546## Fixed caps4748Three rounds. Stagnation — two rounds in which no ledger row left OPEN — runs `five-whys`, then49stops. Three FAILs on one target stop the loop as a process defect (Hard Rule 9). No clock, ever50(Hard Rule 8). One run of the core function at a time.5152## What the owner sees5354| When | The owner sees | The owner is asked |55|---|---|---|56| Start | The done definition, pre-filled from the release standard, the last PRD, state and every version's evaluate | Once: Confirm / Adjust / Stop |57| Rounds | Nothing. No status reports at round boundaries | Only for a target change, a scope call, or a fact only a human holds — after the repo was searched for it (Hard Rules 4 and 11) |58| End | The deliverable marked complete, or stopped, and the report (§ Close) | Only the questions the ledger could not settle |5960## Phase 0 — define DONE (the preflight gate)6162Read the deliverable's release standard (the owner's words for what shipping means), the last63version's `prd.md` and `state.json`, every version's `evaluate.md`, and the build's corpus skill if64it has one. Pre-fill the definition — the owner confirms, never authors. Write it as the65`## Phase 0` section of the ledger (§ Ledger):6667| # | Field | Must contain |68|---|---|---|69| 1 | DONE | The release standard in one sentence, quoted, with its source line |70| 2 | GOLDEN SET | Every item by name, never a glob, and the count N. Per item: the oracle command, its expected result, and a numeric floor equal to the item's latest recorded count, cited file:line |71| 3 | WITNESSES | W1, the driver's own tally. W2, a program that reads the surface the persona reads — never the file W1 reads. Each with its literal expected output |72| 4 | RUN | The core-function command, the live-driver patterns, and the output paths to snapshot |73| 5 | GUARDS | How to run one mutation row, or a set, alone (`--only`), from the directory it needs. Never the full table |74| 6 | JOURNEY | The persona and the surface they read, from the build's own memory; the decision the output supports; the acceptance bar in the user's words; the steps — what they see, what must be true, which golden evidences it |75| 7 | NOT THIS SESSION | The named out-of-scope items, including every corpus item left out of the golden set and every journey step no source documents |7677Below the table, the output of `shasum -a 256 <absolute path>...` for every golden file and every78oracle and witness program — one `hash path` line each. `polish.sh pin` refuses a Phase 0 without79these lines or whose lines do not match the files, and re-checks them on every later call.8081**The target rule** — stated here, cited by name everywhere else: only the owner moves DONE, a82golden, a floor, a witness, a PRD number, a pin, a contract, a pinned constant or a refusal limb.83The session never does, whatever a round measured. On `PIN MOVED` or `GOLDEN MOVED`, stop: show84the owner what changed, ask the Phase 0 question again, record their answer in85`state.json → decisions`, and only then run `polish.sh pin {slug} --repin` — the script refuses a86re-pin until `decisions` has grown.8788**Reject the definition** if it has: (a) pass, green or exit 0 with no count; (b) an89existence-only check such as "workbook written"; (c) a criterion only an opinion can judge; (d) a90witness, floor or golden the session can edit; (e) an answer key a human keyed by hand used as a91gating golden — it carries figures no document states, and fixing toward it writes them into the92output; (f) a golden set smaller than the corpus, unless each omitted item is named in NOT THIS93SESSION; (g) a witness that reads a log, or the file the other witness reads, instead of the94surface the persona reads; (h) a journey step marked UNDOCUMENTED — it moves to NOT THIS SESSION95before the pin.9697Then `bash .claude/skills/build-polish/polish.sh pin {slug}` and ONE AskUserQuestion — the DONE98sentence, N, the floors and the journey steps, with options Confirm / Adjust / Stop. That answer99is the owner's approval of done: when the done checklist later passes, nothing is asked again.100`polish.sh run` refuses without the pin, so nothing runs before that answer.101102## Phase 1 — load what is already known103104Read, never re-derive: `mem:index` and the memory it routes this build to (current state, what is105settled, parked, still the owner's); the slug's `state.json → decisions`, `awaiting_human`,106`what_is_NOT_claimed` — a missing key is unknown, not empty, and shapes vary by slug; every107version's `evaluate.md` must-fix and notes; the ledger. Search the parking lot and large memories108with grep.109110**Carried items.** A parking-lot entry whose last line ends `→ build-polish` is on this run's list —111`grep -n '→ build-polish$' .claude/parking-lot.md` finds them. Each joins round 1's candidates as112`lot-<n>` and goes through triage like any other; an entry polish takes moves into the ledger and113leaves the lot.114115## The round — at most three1161171. **RUN.** `polish.sh run {slug} {round} --driver <pattern>... --keep <path>... -- <command>`.118 It refuses while a driver is live, tees the FULL log, checks that nothing outlived the command,119 and copies the kept paths into a read-only snapshot with a sha256 manifest and a fingerprint of120 the code. Run a long command as a background Bash call. The command's exit code is data,121 printed, never polish's verdict. A kept path the command did not produce is listed in122 `missing.txt` and on the summary line; that item is NOT MEASURED this round, never a clean123 compare.1242. **COMPARE.** Run each item's oracle against the snapshot. Every difference is a candidate.125 A mutation row, or a set of them, may run here too when its output would point at a fix.1263. **READ.** In ONE message, one subagent per golden item — every item in round 1, then only items127 whose manifest lines changed. Two readers, kept apart:128 - *Golden reader*, only for an item no oracle script covers: compares the snapshot with the129 golden and cites the position on both sides.130 - *Journey walker*: gets the snapshot and NO golden, because a reader who knows the answer131 cannot test whether the output explains itself. Walks each JOURNEY step as the persona.132133 Both prompts carry the snapshot path and say **findings only** AND **run nothing** (§ Prompts).134 Every finding is a triage candidate — a lead, never a verdict.1354. **TRIAGE.** Per new candidate: `polish.sh seen {slug} <key>`, then the triage checklist, then136 one ledger row.1375. **FIX.** PROBLEM rows that question 7 cleared: the smallest change that closes the anomaly,138 past the veto (§ Reviewers). Then run the mutation rows that pin the lines the fix changed,139 alone (`--only`); every one must be caught. No full suite, no full table.1406. **REVIEW** when § Reviewers says so. The next round re-runs everything, which is what catches a141 fix that broke a different item.142143A round with no new PROBLEM and no fix goes straight to the done checklist.144145## The gated checklist — one mechanism, two lists146147Run it with `mcp__sequential-thinking__sequentialthinking`:148149- `totalThoughts` is the list's length. One thought per question, in order. Never skip, reorder or150 add a question.151- Each thought starts `Q<n>:`, quotes the command it ran and its verbatim output (or a152 `file:line` and the quoted line), and ends `→ YES` or `→ NO`.153- **A thought without quoted evidence takes the fail-closed branch**: in triage the row stays OPEN154 and blocks DONE; in the done check it is NO.155- **An opinion never answers a question**, the model's or a subagent's. A reader's report is a156 lead for a question, never its evidence.157- The first terminal answer ends it (`nextThoughtNeeded: false`) and emits one ledger row or one158 verdict line.159160### Triage — is this problem really a problem?161162Questions 1 to 4 are exits: a YES ends the checklist with that class. Questions 5 and 6 classify:163YES at either is a PROBLEM, and NO at both is a NOTE that ends the checklist. Question 7 routes a164PROBLEM.1651661. **SETTLED?** `polish.sh seen` prints a VERDICT line — a ledger row, an `evaluate.md` verdict or167 a `state.json` decision — for this key and value → SETTLED, cite it. A LEAD line (parking lot,168 memory) is a lead, never a verdict. Two keys reopen instead: a FIXED row's key seen again means169 the fix did not hold — go to question 7 as a PROBLEM; a NOISE row's key seen again on a fresh170 snapshot goes on to question 2.1712. **NOISE?** The snapshot artifact itself — never the log, never a summary — does not show it →172 NOISE, and the row names the cause: a trimmed log, a live driver, a moved HEAD, a stale173 snapshot. "Did not reproduce" is not a cause; with none named, answer NO.1743. **GOLDEN WRONG?** The source line our value cites, opened in the snapshot and quoted, states175 that value, and the golden's figure has no such line — or the golden predates the source →176 NOTE, ASKED. A citation alone is our reading of the source, not the source. Before saying an177 input was not supplied, open the input packet.1784. **SELF-INFLICTED?** A fix from this session touched its path → revert that fix; the row stays179 OPEN until the next round's snapshot. Gone there → the revert stands, row CLOSED. The original180 anomaly back instead → PROBLEM, ASKED: the fixes oscillate, and the owner picks.1815. **LIMB 1.** Does any value a persona reads change, whether or not a JOURNEY step names it?1826. **LIMB 2.** Does any output state a check, PASS, agreement or coverage that no source line183 supports? On a path no golden exercises, a one-variable synthetic reproducer answers this.1847. **TARGET?** The fix falls under the target rule → the row stays PROBLEM with status ASKED, and185 the owner is asked this round. NO → fix it this round.186187Two standing rules. A stochastic reading path — OCR, a model reading a page — is not tested by188repetition: a figure carrying a check the paper does not support is a PROBLEM the first time. The189journey can promote a finding and never demote one; an intact step still goes through question 6.190191### Done — is done really done?192193The first NO ends it: NOT DONE.1941951. `polish.sh pin {slug}` exits 0 and prints `pin OK`, `goldens unchanged` and `snapshot fresh:` —196 the definition, the goldens and the witness programs are as the owner confirmed them, and the197 latest snapshot measured the code as it stands. A first pin or a re-pin prints none of these.1982. The latest snapshot holds all N items, counted from W1's output inside it.1993. Every item meets its floor, read by W2 from the surface the persona reads.2004. Nothing NOT MEASURED or SKIPPED is counted as PASS; each has its own NOTE row, or is named in201 NOT THIS SESSION.2025. W2 agrees with W1 on every item.2036. Every mutation row polish ran was caught, and every line polish changed is pinned by a row that204 ran or was reviewed under § Reviewers.2057. `grep -cE '\| PROBLEM \| (OPEN|ASKED) \|'` on the ledger prints 0.2068. Every JOURNEY step has a walker's `found: YES` whose position the session opened in the latest207 snapshot and quoted.2089. The release scorecard: every clause of DONE and every criterion of the last version's PRD scores209 PASS from the latest snapshot — one thought each, quoted evidence. SKIPPED and NOT MEASURED are210 listed on their own line, never counted as PASS.211212## Reviewers213214**KISS/YAGNI is the dominant reviewer, applied as a rule to every fix before it lands.** Veto the215fix if its diff adds a file, flag, config key, class, abstraction or schema — unless removing that216addition brings the anomaly back. If the lines that do not close the anomaly outnumber the lines217that do, veto. A vetoed fix goes back to step 5, smaller.218219**Correctness comes before size.** The real results, the pinned rows and the code reviewer decide220whether a fix is right; the veto then picks the smallest right fix.221222Spawn `simplifier` and `code-reviewer` together — findings only, run nothing — in two cases:223224- a round whose fix changes a line no mutation row pins and no golden item exercises;225- once before the done checklist, over polish's own combined diff, if polish changed any code.226227The code reviewer blocks only on the must-fix bar: a wrong result a human relies on, or the tool228claiming something it has not verified (Hard Rule 9). The simplifier blocks only through the veto.229Everything else they say is a note for the close report and never re-enters the loop. After each230review, record it and check for drift; drift means stop reviewing that file.231232```bash233python3 .claude/hooks/review-drift.py record <file> --must N --should N --note N --self-inflicted N234python3 .claude/hooks/review-drift.py check <file>235```236237## Ledger — the knowledge harness238239One file: `.claude/PRPs/{slug}/review/review-polish-audit.md`. `review` is an existing kind, and240`audit` in the name exempts it from the no-postmortem gate, so verdicts may carry dates.241242```markdown243---244type: note245title: "Polish audit — {slug}"246related: [".claude/PRPs/{slug}/prd.md"]247updated: YYYY-MM-DD248status: current249schema: okf-adapted-v0.1250---251# Polish audit — {slug}252253## Phase 0254(the seven fields, then the sha256 lines)255256## Anomalies257| key | class | status | cite | round |258|---|---|---|---|---|259| matter-d/total_charges=0.00 | PROBLEM | FIXED | record.json:41 | 1 |260```261262- **key** is item/field=observed value. A CLOSED row is never re-triaged unless its class is NOISE;263 a FIXED row whose key comes back reopens as a PROBLEM. A new value opens a new row.264- **class** SETTLED, NOISE, NOTE, PROBLEM. **status** OPEN, FIXED, CLOSED, PARKED, ASKED.265- One anomaly per physical line; a bare `file:N` cite, never in backticks, never a `.log`. Never266 the claims-ok marker — one occurrence disables the document-claims gate for the whole file.267- A verdict with no cite or decision number stays OPEN: the loop cannot settle its own findings268 without evidence.269- Matters and people are letters or roles. No quoted document text.270271## Close272273- **DONE** — the done checklist passed, so the deliverable is complete. On the last version's slug,274 set `state.json → state` to `complete` and `polish.state` to `done`, and the PRD's275 `status: complete`; record the deliverable as done, with the date, in the build's state memory.276 No second question: the owner approved this definition of done in Phase 0.277- **STOPPED** — cap, stagnation, three FAILs, or any PROBLEM row OPEN or ASKED. A wrong result278 waiting on the owner is still a wrong result: the verdict is STOPPED, never "done with notes".279280Route every open row before reporting. NOTE → `.claude/parking-lot.md` at its next free number,281PARKED. Every ASKED row → `state.json → awaiting_human`, list or object as the slug already has282it. A trap seen in two sessions → a Serena memory plus its `mem:index` row.283284Report in build-execute's four-part session-report shape, no jargon, plus the ledger counts by285class and, for each JOURNEY step, the snapshot position beside its golden.286287## Prompts288289### Journey walker290291```text292You are {persona} ({memory and section it comes from}). This matter is live. Using ONLY the293snapshot at {path} — no golden, no code — try each journey step: {steps}. For each step: would you294know what to do, could you find it, would you recognise it, would you know you are done? Apply295U1-U6. Findings only. RUN NOTHING: no driver, generator or test. You may Read files, or print one296with a single python3 line that only opens it. Refer to matters by letter.297Per step:298step: <n> | task: <what you tried>299found: YES|NO — <tab!cell, or the words you used>300stuck: <the verbatim words that stopped you> | none301trust: act | check | reject — <one clause>302tag: PROBLEM(U#) | NOTE(U#) | CLEAN303```304305| U | Check — a NO is a finding, pre-tagged so a reader cannot inflate it | NO is |306|---|---|---|307| U1 | Every figure names its source: a document and line, or a call with who and when | PROBLEM |308| U2 | Every blank and every total says what it does not cover | PROBLEM |309| U3 | No status claims more than was checked | PROBLEM |310| U4 | Every difference from the golden carries a reason or says UNKNOWN | PROBLEM |311| U5 | Every flag names one next action | NOTE; PROBLEM if the action is wrong |312| U6 | The output uses the reader's order and words, once | NOTE |313314### Golden reader315316"Compare {item} in the snapshot at {path} with its golden at {golden}. For each difference, cite317the position on both sides. List differences only; no verdicts. Findings only. RUN NOTHING."318319## Worked example — the Yellow Sheet320321- **DONE**: the release standard in the parking lot's header — every figure from every document322 reaches the workbook, and every penny of difference against the firm's finished sheet is323 accounted for or named UNKNOWN with a plainly stated reason.324- **RUN**: `bash -c 'cd <case-folder> && python3 tests/run_corpus.py'`; drivers `run_corpus.py`,325 `run_1_`, `run-mutations.sh`, `yellow-sheet.sh`; keep each case folder under the cases root326 (`_corpus-matter-<x>`) by name, plus `_corpus-logs`. That tree also holds case folders named before the letter scheme,327 which is why items are named and never globbed.328- **GOLDEN SET**: all six matters. Oracle `tests/check_real_matter.py <case-dir>`, the329 printed-total identity — grep its output for SKIP, which also exits 0. Floor: each matter's money330 cells at their latest recorded count, cited; an intended decrease is a target change for the331 owner.332- **W1** the table in `summary.json`, which `run_corpus.py` computes from `record.json`. **W2** the333 money cells counted in each matter's `output/yellow-sheet.xlsx` with openpyxl — the workbook the334 persona opens, not the record W1 already read. `run_corpus.py` exits 1 while an UNREAD refusal335 is outstanding — data, not failure.336- **GUARDS**: `(cd <case-folder> && bash tests/run-mutations.sh --only=<rows>)` — one row, or a337 comma-separated set.338- The firm's finished sheets go through `answer_key_diff.py`. The release standard asks that every339 difference carry a reason or say UNKNOWN (U4) — never that the sheet match them (reject rule e).340- **JOURNEY**: personas and surfaces from `mem:yellow_sheet/output_format`.341342## Guidelines343344- One change per anomaly; a round may carry several.345- Never edit the golden, the witness or the definition to make a round pass — the target rule.346- Polish owns done for the deliverable: the only stage that marks it complete, and only when its347 done checklist passes. A version's evaluate verdict is an input to Phase 0, never the348 deliverable's done.