task-pipeline-skill 1.42.0 → 1.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,160 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.44.0 — six lessons other projects paid for, carried home by the mechanism that exists for it
4
+
5
+ `retro.publish` sends a skill-level lesson upstream as an issue. Six arrived in one day
6
+ from projects that are not this one, and every one is a diagnosis: the class, why the
7
+ existing doctrine did not catch it, and the fix by grade. This release is those six.
8
+
9
+ | Issue | What it bought |
10
+ |---|---|
11
+ | #30 | a name in `verified by` **resolves**, or the row is `unknown` — never `verified` |
12
+ | #31 | a probe that mutates a file asserts its plant landed **— now a guard** |
13
+ | #32 | a seam is not a deliverable: an explicit REQ for the boundary, phrased as a journey |
14
+ | #33 | the tests gate names **what each case consumes**; a timeout is unclassified, not slow |
15
+ | #34 | stage 10 carries a `publish:` line — an unarmed path stops looking like silence |
16
+ | #35 | a ratchet's matcher is itself a check: feed it a **near-miss it must reject** |
17
+
18
+ ### Two of them had already been found here, independently
19
+
20
+ **#35 is the neighbour probe**, shipped in v1.42.0 after a reader defeated six guards whose
21
+ evidence sat next to their subject. The reporting project reached it from a ratchet whose
22
+ matcher credited every parent with its child's coverage. Same class, two routes, no
23
+ contact — which is the strongest evidence either had.
24
+
25
+ **#31 is R-001**, born here on 2026-08-03 and **retired in v1.38.0** on its own trigger:
26
+ *"a probe harness exists that asserts the plant changed the parsed text"*. The harness does
27
+ exist. The retirement was still premature, because the condition was *"a harness exists"*
28
+ and the thing that mattered was *"the harness is used everywhere"*. It cost the reporting
29
+ project three incidents in one day and this repository six in this session's own releases.
30
+ **A retirement trigger phrased as the existence of a mechanism, rather than its reach, is
31
+ a trigger that fires early.**
32
+
33
+ ### The number that took four attempts
34
+
35
+ Enforcing #31 meant counting probes that mutate a file without asserting the plant landed:
36
+
37
+ ```
38
+ hand-written classifier 206 of 206 already carry it (wrong)
39
+ the guard, first version 22 do not (wrong — one spelling)
40
+ the sweep that followed "fixed" 6 sound probes, corrupted 5
41
+ the truth 16
42
+ ```
43
+
44
+ The guard corrected the hand count that motivated it. Then the guard was itself the class
45
+ two sections above — keyed to one spelling, it reported as defective six probes that
46
+ obeyed the rule in different words, and a sweep written from that verdict split five live
47
+ statements. Found by `compile()` and a restore from git.
48
+
49
+ **Every** mutating probe carries the assertion, and **no figure is written here** — the
50
+ third attempt to put one beside it was wrong too. The count is a `grep` away and the
51
+ guard computes it on every run; a number in prose next to a check that can count is
52
+ restating instead of computing, which is the rule this very release imports and which
53
+ this paragraph broke three times before it stopped trying.
54
+
55
+ - Guards: 261 → **275**.
56
+
57
+ ## v1.43.0 — the rail said where, and nothing said what happened
58
+
59
+ A fourteen-iteration session on this repository ended each return with the same question
60
+ from the operator: *what did you actually do?* The rail answered **where** the run was —
61
+ one line, computed, correct — and nothing answered the rest. Everything else was
62
+ recoverable from artefacts; what a run learned by accident was recoverable from nothing.
63
+
64
+ ### The hand-back
65
+
66
+ At both boundaries — an iteration's close and stage 10's — the run now writes four
67
+ sections and two lists:
68
+
69
+ ```
70
+ TASK the request as it was GIVEN, quoted from the brief
71
+ PROGRESS where the run stands against that request
72
+ DONE what was solved, each with its evidence
73
+ SURFACED what came up that nobody asked for
74
+
75
+ DECISIONS WAITING <n> each as a question with options, asked HERE
76
+ AMBIGUITIES <n> computed from four registers, with ids
77
+ ```
78
+
79
+ **TASK is quoted, never paraphrased** — a run that restates the request in its own words
80
+ after eight iterations has rewritten it, and the operator cannot see that happen.
81
+ **DECISIONS WAITING are asked, not parked**: a question in a report is answered days
82
+ later, if at all. And **AMBIGUITIES are computed**, from four registers an earlier stage
83
+ already wrote — open `OQ-####` rows, carry-over rows with no home, REQ rows whose check is
84
+ `review` rather than a command, and source-ledger rows reading *none found*. An unbounded
85
+ *"is anything unclear?"* becomes a ritual sentence within three runs.
86
+
87
+ **It is a gate criterion, not a good intention.** `progress.md` already carried one
88
+ instruction with no gate behind it — *"copy it, tick it"* — and the v1.37.0 audit found
89
+ that no run had ever obeyed it.
90
+
91
+ ### The reader found that this release built what it had just condemned
92
+
93
+ A gate criterion with **no artefact**. Every guard read the doctrine files, so all any of
94
+ them could establish was that the instruction was still written down — none could
95
+ establish that a run obeyed it. The reader then constructed a conforming hand-back
96
+ concealing a weakened test and showed that **nothing in the repository would notice**,
97
+ and that an audit a year later could reach no verdict either way, because there would be
98
+ no run records to check. This file's own diagnosis of *"copy it, tick it"* — a rung-1
99
+ rule read as rung 3 — reproduced one level up.
100
+
101
+ **The hand-back now has an address:** a `hand:` line in the run ledger, declared as its
102
+ fourth shape. `grep -c '^hand:'` against `grep -c '^iter:'` is what makes a missing one
103
+ readable.
104
+
105
+ Six more, all verified by planting and watching `PASS`:
106
+
107
+ - **`"hand-back"` as a bare substring could not tell a requirement from a mention** — a
108
+ gate reading *"the hand-back is OPTIONAL and may be skipped"* passed, in the release
109
+ whose entire argument is that it must be a criterion. Both gate guards now require the
110
+ normative phrase;
111
+ - **the gate span was unbounded below** — the GATE is the last bullet, so a paragraph
112
+ after it answered for it;
113
+ - **the template was every fence joined**, so a worked example — the likeliest next edit
114
+ to that section — would have answered for the template;
115
+ - **the two lists were left to prose** while the four sections were read from the fence,
116
+ which is the split this release wrote a guard to forbid;
117
+ - **the AMBIGUITIES subsection could be replaced by explicit judgement** and pass, keeping
118
+ the four words as *examples*;
119
+ - and a relocated section was reported as a deletion.
120
+
121
+ **Four doctrinal defects, not guard defects:**
122
+
123
+ - *"at both boundaries"* named a pair this file defines as something else three sections
124
+ above — a reader resolving it there writes a hand-back at task start, where TASK is the
125
+ only field with content;
126
+ - **the four ambiguity sources had no commands**, though the section claimed *"each read
127
+ by a command"* — and one of them would have grepped for a string the source ledger's own
128
+ doctrine never writes, returning a false zero;
129
+ - **one register is structurally zero at the gated boundary**: stage 10's own gate already
130
+ forbids an unresolved carry-over row, so that count is zero because a sibling clause
131
+ compelled it. The section now says to print *why*;
132
+ - and **`acceptance.md` — the file stage 10 actually opens — never mentioned the
133
+ hand-back**, while carrying every other criterion. Two surfaces were updated where four
134
+ state this gate.
135
+
136
+ **Still true and stated rather than fixed:** `SURFACED` has no register behind it, and the
137
+ doctrine calls it the section that earns the hand-back. *"Nothing surfaced"* remains a
138
+ quiet decision. The `hand:` line records that a hand-back happened, never that it was
139
+ complete.
140
+
141
+ ### Six predicates answered by their neighbours, all caught by their own probes
142
+
143
+ - the four section names were read from the whole section, and `SURFACED` appears in the
144
+ sentence explaining why SURFACED matters — so renaming the template row left the guard
145
+ green. It now reads the **fenced template**;
146
+ - `asked` appears in `SURFACED`'s own description (*"nobody **asked** for"*), so the
147
+ decisions check was answered by a neighbour;
148
+ - and the section span was narrowed to `#{2,3}` by reflex, which cut the guard off from
149
+ the `###` subsection holding four of the things it checks. **The span follows the
150
+ subject, not a house style** — v1.42.0 narrowed a different span for the opposite
151
+ reason.
152
+
153
+ Not one of these needed a reader. The neighbour-probe habit shipped one release earlier
154
+ caught all three, which is the first evidence it does what it was written for.
155
+
156
+ - Guards: 253 → **261**.
157
+
3
158
  ## v1.42.0 — a probe proves the phrasing its author had in mind
4
159
 
5
160
  Six times in one session a guard was defeated by **text that was not its subject**, and
package/SKILL-CARD.md CHANGED
@@ -12,7 +12,7 @@ harmless.
12
12
  |---|---|
13
13
  | **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
14
14
  | **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
15
- | **Version** | 1.42.0 |
15
+ | **Version** | 1.44.0 |
16
16
  | **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
17
17
  | **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
18
18
  | **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-pipeline-skill",
3
- "version": "1.42.0",
3
+ "version": "1.44.0",
4
4
  "description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
5
5
  "bin": {
6
6
  "task-pipeline": "bin/task-pipeline.js"
@@ -2,7 +2,7 @@
2
2
  "name": "task-pipeline",
3
3
  "displayName": "Task Pipeline",
4
4
  "description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
5
- "version": "1.42.0",
5
+ "version": "1.44.0",
6
6
  "author": {
7
7
  "name": "ssheleg",
8
8
  "url": "https://x.com/sshlg93"
@@ -273,7 +273,7 @@ capable available — see `references/model-tiering.md`).
273
273
  | 7 | Lint + deploy | host lint → deploy per host convention | lint clean + suite green before deploy; deploy needs a go (or the brief's specific standing authorization) | manual |
274
274
  | 8 | Post-deploy | tail deploy logs / health-check | clean boot or honest degradation report; **a deployed web target is opened, not curled** — a `200` proves the server answered and says nothing about a 404'd bundle or a console full of errors on load (`chrome-devtools`; absent → call it an HTTP response, which is its honest name) | auto |
275
275
  | 9 | Docs + wiki | host module docs/runbook rules → `wiki-update` ([obsidian-wiki](https://github.com/ar9av/obsidian-wiki), recommended) → `/graphify . --update` ([`references/knowledge-graph.md`](references/knowledge-graph.md), recommended) | every stale row of the stage-0 source ledger updated; **the propagation matrix walked for every change type this run produced** — the ledger names what you read, the matrix names what you owe — every settled thing recorded with an id, every answered question resolved, and **the documentation gate green with its ratchet counts printed**; docs synced; wiki synced; **the code graph refreshed where one exists** and checked against the docs (a hub no doc names, a doc naming a node the graph lost); **every number computed rather than restated, every named command or file resolvable** ([`references/learned.md`](references/learned.md)); the carry-over count printed beside the verdict | auto |
276
- | 10 | **Acceptance** | built in: [`references/audit.md`](references/audit.md) (ladder walk) → [`references/acceptance.md`](references/acceptance.md) (coverage table) → [`references/retrospective.md`](references/retrospective.md) (retro: stamp, prune, entry) | ladder walk ran, its absences became REQ rows; every REQ accounted for with evidence from a check seen failing once; ledger has no unresolved row; **axis rotation recorded** (new findings vs self-inflicted, rule 1 of [`references/learned.md`](references/learned.md)), **every closure verified against the artefact rather than the document describing it**, **each correction swept across its class**, **every deferral a printed ratchet rather than a TODO**; **in a multi-repository project, every repository is clean, pushed and pointed at** (below); operator signs off; **every check this close-out leans on — the documentation gate included — has been seen failing once against a planted defect, and its ratchet counts are printed beside the verdict**; **the retrospective written last, and in order — the run stamped with its commit FIRST (the cold-retirement trigger reads that stamp), then the prune with the list at or under its cap and every deletion logged, then the entry; every deletion and every entry carrying its commit, entries older than five stamps rotated into the archive, counts printed** ; **both disclosures printed beside the verdict** — `abstained` (what the run declined to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither with a floor, neither ever a target ([`references/gates.md`](references/gates.md) → *Disclosures*) | manual |
276
+ | 10 | **Acceptance** | built in: [`references/audit.md`](references/audit.md) (ladder walk) → [`references/acceptance.md`](references/acceptance.md) (coverage table) → [`references/retrospective.md`](references/retrospective.md) (retro: stamp, prune, entry) | ladder walk ran, its absences became REQ rows; every REQ accounted for with evidence from a check seen failing once; ledger has no unresolved row; **axis rotation recorded** (new findings vs self-inflicted, rule 1 of [`references/learned.md`](references/learned.md)), **every closure verified against the artefact rather than the document describing it**, **each correction swept across its class**, **every deferral a printed ratchet rather than a TODO**; **in a multi-repository project, every repository is clean, pushed and pointed at** (below); **the hand-back is written** — the request quoted as given, progress against it, what was solved, what surfaced unasked, waiting decisions asked here, and the ambiguity count computed ([`references/progress.md`](references/progress.md)); operator signs off; **every check this close-out leans on — the documentation gate included — has been seen failing once against a planted defect, and its ratchet counts are printed beside the verdict**; **the retrospective written last, and in order — the run stamped with its commit FIRST (the cold-retirement trigger reads that stamp), then the prune with the list at or under its cap and every deletion logged, then the entry; every deletion and every entry carrying its commit, entries older than five stamps rotated into the archive, counts printed** ; **both disclosures printed beside the verdict** — `abstained` (what the run declined to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither with a floor, neither ever a target ([`references/gates.md`](references/gates.md) → *Disclosures*) | manual |
277
277
 
278
278
 
279
279
  ### Stage 10 in a project of several repositories
@@ -166,7 +166,7 @@
166
166
  ],
167
167
  "gate": {
168
168
  "type": "manual",
169
- "check": "Close the circle. FIRST the LADDER WALK (references/audit.md), because the REQ table can only find what was named and lost — a comparison needs two sides and an absence has one: walk each REQ bottom-up through its rungs (decision -> spec section -> contract AND its failure behavior -> plan task -> change -> executed test -> surface/docs), check the seam at each step, order findings BY SEAM not by file, and turn every absence into a new REQ row with its check BEFORE the table is written; findings belonging to a lower layer go back to that layer (spec -> stage 3, plan -> stage 4); record the pass's two counts (new findings vs findings caused by this run's own fixes) so the next pass can tell whether the axis is exhausted. THEN the coverage table: every REQ has a status (verified / partial / deferred / dropped) — none unknown; every verified carries evidence (a passing test name, file:line, a command and its output, or a scenario ID) — 'done' without evidence is downgraded to partial, not upgraded, and a green from a check nobody has watched fail against a planted defect is not evidence at all; every partial names what is missing and where it is tracked; every deferred/dropped has the operator's agreement and, for deferred, a tracker entry; no carry-over row is left unresolved and the ledger's counts are printed beside this verdict, so 'green' never reads as 'verified'; EVERY REPOSITORY IS CLOSED, THE PARENT INCLUDED — a submodule is finished only when its parent points at it, so 'git submodule status' shows no line starting with '+' and every repo is clean and pushed ('git -C <repo> status --porcelain' and 'git -C <repo> log @{u}..HEAD' both empty), because a parent records a submodule as a pointer to one commit and moving the submodule does not move the pointer: neither repo looks wrong alone and the disagreement survives every check that runs inside one; and the operator answers the closing question — here is what you asked for, here is what shipped, here is what is deferred, what is missing? — and signs off. LAST ACT, THE RETROSPECTIVE (references/retrospective.md, written to docs/superpowers/retro.md — one file per project, not per run, because every gate in this flow is good at THIS run and blind across runs): PRUNE BEFORE YOU ADD — every standing instruction checked against its three retirement triggers (it became a check; every path/command/stage it names is gone; it has not fired in the last five run stamps), the list held to its hard cap of ten (at eleven the oldest never-fired row goes — 'they all matter' is the state in which the list stopped being read), and EVERY DELETION LOGGED as one line, never silent; THEN stamp the run (date, topic, verdict, counts); THEN, only if the run diverged, write the entry — symptom with evidence, the stage it surfaced at, the stage that OWNED it, the root cause ('the agent was careless' is not one), the fix by grade (mechanical check > standing instruction with its retire-when written at birth > a note that expires in two runs), and the check that catches it the first time from now on. A retro left empty after a messy run is the failure this file exists to stop, and the retro counts are printed beside this gate's verdict like the carry-over ledger's, so a list that quietly grew back is visible where it happened. EVERY LESSON CARRIES ITS COMMIT: each standing instruction has the SHA that introduced it and the SHA of the run in which it last fired, each log entry and each retirement carries one, the run stamp carries the run's own — a file:line rots at the next edit while 'git show <sha>' reconstructs the whole incident two months later — and every SHA must resolve, which the documentation gate checks with 'git rev-parse --verify'. ROTATION: entries older than the last five run stamps MOVE into docs/superpowers/retro/YYYY-QN.md, which is append-only and QUERIED rather than read, so the in-force file stays short enough to be read in full and pruning costs no knowledge. AND THE GATE ITSELF IS PROVEN: every check this close-out leans on — the documentation gate included — has been seen failing once against a planted defect, with the probe recorded, and its ratchet counts are printed beside this verdict (references/gates.md)."
169
+ "check": "Close the circle. FIRST the LADDER WALK (references/audit.md), because the REQ table can only find what was named and lost — a comparison needs two sides and an absence has one: walk each REQ bottom-up through its rungs (decision -> spec section -> contract AND its failure behavior -> plan task -> change -> executed test -> surface/docs), check the seam at each step, order findings BY SEAM not by file, and turn every absence into a new REQ row with its check BEFORE the table is written; findings belonging to a lower layer go back to that layer (spec -> stage 3, plan -> stage 4); record the pass's two counts (new findings vs findings caused by this run's own fixes) so the next pass can tell whether the axis is exhausted. THEN the coverage table: every REQ has a status (verified / partial / deferred / dropped) — none unknown; every verified carries evidence (a passing test name, file:line, a command and its output, or a scenario ID) — 'done' without evidence is downgraded to partial, not upgraded, and a green from a check nobody has watched fail against a planted defect is not evidence at all; every partial names what is missing and where it is tracked; every deferred/dropped has the operator's agreement and, for deferred, a tracker entry; no carry-over row is left unresolved and the ledger's counts are printed beside this verdict, so 'green' never reads as 'verified'; EVERY REPOSITORY IS CLOSED, THE PARENT INCLUDED — a submodule is finished only when its parent points at it, so 'git submodule status' shows no line starting with '+' and every repo is clean and pushed ('git -C <repo> status --porcelain' and 'git -C <repo> log @{u}..HEAD' both empty), because a parent records a submodule as a pointer to one commit and moving the submodule does not move the pointer: neither repo looks wrong alone and the disagreement survives every check that runs inside one; and the operator answers the closing question — here is what you asked for, here is what shipped, here is what is deferred, what is missing? — and signs off. LAST ACT, THE RETROSPECTIVE (references/retrospective.md, written to docs/superpowers/retro.md — one file per project, not per run, because every gate in this flow is good at THIS run and blind across runs): PRUNE BEFORE YOU ADD — every standing instruction checked against its three retirement triggers (it became a check; every path/command/stage it names is gone; it has not fired in the last five run stamps), the list held to its hard cap of ten (at eleven the oldest never-fired row goes — 'they all matter' is the state in which the list stopped being read), and EVERY DELETION LOGGED as one line, never silent; THEN stamp the run (date, topic, verdict, counts); THEN, only if the run diverged, write the entry — symptom with evidence, the stage it surfaced at, the stage that OWNED it, the root cause ('the agent was careless' is not one), the fix by grade (mechanical check > standing instruction with its retire-when written at birth > a note that expires in two runs), and the check that catches it the first time from now on. A retro left empty after a messy run is the failure this file exists to stop, and the retro counts are printed beside this gate's verdict like the carry-over ledger's, so a list that quietly grew back is visible where it happened. EVERY LESSON CARRIES ITS COMMIT: each standing instruction has the SHA that introduced it and the SHA of the run in which it last fired, each log entry and each retirement carries one, the run stamp carries the run's own — a file:line rots at the next edit while 'git show <sha>' reconstructs the whole incident two months later — and every SHA must resolve, which the documentation gate checks with 'git rev-parse --verify'. ROTATION: entries older than the last five run stamps MOVE into docs/superpowers/retro/YYYY-QN.md, which is append-only and QUERIED rather than read, so the in-force file stays short enough to be read in full and pruning costs no knowledge. AND THE GATE ITSELF IS PROVEN: every check this close-out leans on — the documentation gate included — has been seen failing once against a planted defect, with the probe recorded, and its ratchet counts are printed beside this verdict (references/gates.md). THE HAND-BACK IS WRITTEN — the request quoted as GIVEN, progress against it, what was solved with evidence, what surfaced unasked, every waiting decision ASKED here with options, and the ambiguity count computed from the four registers; zero prints as zero."
170
170
  }
171
171
  }
172
172
  ],
@@ -17,6 +17,8 @@ requirement.** It is what turns the pipeline from a funnel into a circle.
17
17
  - Several repositories — a submodule is finished when its parent says so
18
18
  - The closing question
19
19
  - The retrospective — the run's last act
20
+ - A `verified by` name is a claim until it resolves
21
+ - A seam is not a deliverable, and REQ rows are written against deliverables
20
22
  - GATE (manual)
21
23
  - When the answer is "something's missing"
22
24
 
@@ -201,6 +203,56 @@ GATE 10 acceptance: PASS — 14/14 REQ verified
201
203
  abstained: 2 (1 partial · 1 cannot-verify) · unlooked: 3 dormant
202
204
  ```
203
205
 
206
+ ## A `verified by` name is a claim until it resolves
207
+
208
+ Reported from another project. Two rows in one run named checks that did not exist — a
209
+ locale-parity test for a project with ten locales and no such test, an index-resolution
210
+ test that had never been written. Both rows carried a status, an owner and an evidence
211
+ cell. **Nothing in the artefact distinguishes *"this check exists and passed"* from *"this
212
+ is the name a check would have if someone wrote it"*.**
213
+
214
+ This file already requires the evidence to come from a check seen failing once. That
215
+ requirement is about the **check**; nothing walks back from the **name** to ask whether a
216
+ check by that name is on disk. The ladder walk found both, because it re-derives coverage
217
+ from the artefact instead of reading the table — which also means the table was wrong for
218
+ the whole run until its last gate.
219
+
220
+ **So every name in a `verified by` cell resolves before the table is accepted** — to a
221
+ file, a test name a runner will select, or a command that exits. A cell naming nothing is
222
+ a REQ with status **`unknown`**, never `verified`.
223
+
224
+ The coverage table is this pipeline's own record of what was proven. When it can carry an
225
+ unresolvable name it stops measuring the run and starts recording the author's intent,
226
+ which is [`gates.md`](gates.md)'s false success living inside the pipeline's own artefact.
227
+
228
+ ## A seam is not a deliverable, and REQ rows are written against deliverables
229
+
230
+ Also reported. Two halves of a feature shipped in one run, each correct alone, each with a
231
+ passing unit test. Together they formed a closed loop: a guard turned away users who had
232
+ not reached a state, and the new flow that would put them into that state sat behind the
233
+ guard. **The defect was in the seam, and a seam has no file.** The coverage table had a
234
+ row per artefact and both rows were green.
235
+
236
+ The blindness one layer down is already named — a handler test proves the handler, not the
237
+ request path. This is that shape one layer up.
238
+
239
+ **So when a run replaces a component that another component branches on, stage 2 writes an
240
+ explicit REQ for the boundary** —
241
+ not *"A works"* and *"B works"* but **"a user in state X reaches Y"**. Phrased as a
242
+ journey it is testable; phrased as two artefacts it is not.
243
+
244
+ **This does not contradict [`decomposition.md`](decomposition.md), and the wording matters
245
+ because a first draft did.** That file says a REQ appearing in two modules means the seam
246
+ runs *through* a requirement, and tells you to re-cut. A boundary REQ is not that: it is a
247
+ single requirement about the transition, owned by **one** module — the one that consumes
248
+ the boundary — and it maps to exactly one module like every other. Cite it as a journey
249
+ owned by the downstream module, and both rules hold.
250
+
251
+ **And where no check can span the seam** — a server-rendered redirect on one side, a
252
+ client write on the other — the table says so under `unlooked` rather than showing two
253
+ green rows. Two green halves reporting a working whole is exactly the shape this file
254
+ spends its length refusing.
255
+
204
256
  ## GATE (manual)
205
257
 
206
258
  All of:
@@ -251,6 +303,14 @@ All of:
251
303
  Manual by design. An automated check can prove the table is *well-formed*; only
252
304
  the person who asked can confirm it is *what they asked for*. Do not let a green
253
305
  table substitute for that answer.
306
+ 12. **The hand-back is written** ([`progress.md`](progress.md) → *The hand-back*) —
307
+ the request quoted as it was GIVEN, where the run stands against it, what was solved
308
+ with its evidence, what surfaced that nobody asked for, every decision still waiting
309
+ **asked here with options rather than listed**, and the ambiguity count computed from
310
+ its four registers with their ids. A run that cannot say what happened has not
311
+ finished; it has stopped. This file is the one stage 10 opens, and it carried every
312
+ other criterion while omitting this one for a release.
313
+
254
314
 
255
315
  ## When the answer is "something's missing"
256
316
 
@@ -31,6 +31,8 @@ elsewhere and is not restated here:
31
31
  - Writing the check itself
32
32
  - Probing — plant, run, restore
33
33
  - The neighbour probe — plant the evidence outside the subject
34
+ - A ratchet's matcher is itself a check, and it needs a near-miss
35
+ - A green probe is evidence only if the mutation is known to have landed
34
36
  - The false-positive budget
35
37
  - Ratchets
36
38
  - Disclosures — counted like a ratchet, and deliberately not monotone
@@ -347,6 +349,79 @@ the item, then match on flattened text so an emphasis marker cannot hide the bou
347
349
  where that ends*. It costs nothing and it is the only part of a check a later reader can
348
350
  disagree with before the defect arrives.
349
351
 
352
+ ## A ratchet's matcher is itself a check, and it needs a near-miss
353
+
354
+ Reported from another project through `retro.publish`, and it is the neighbour probe's
355
+ own class arrived at independently — which is the strongest evidence either has.
356
+
357
+ A run built a ratchet to hold a coverage debt: a list of units with no test, a guard that
358
+ fails when the list grows, a count printed at the gate. Exactly the shape
359
+ [`audit.md`](audit.md) asks for instead of a deferred TODO. The guard decided whether a
360
+ unit was covered by asking whether its identifier appeared **anywhere** in the test
361
+ corpus. The identifiers were path-like and many were prefixes of longer ones, so every
362
+ unit that happened to be the parent of another was credited with its child's coverage.
363
+
364
+ **A ratchet whose matcher is looser than its subject shrinks itself.** It reports progress
365
+ for work nobody did, and because a ratchet is trusted precisely so that nobody re-derives
366
+ it, the error compounds for as long as the ratchet exists.
367
+
368
+ Both existing rules were satisfied. The ratchet was printed. The guard had been seen going
369
+ red when the list grew. Neither asks whether the matcher can tell its subject from a near
370
+ neighbour, and that is the only question that would have caught it.
371
+
372
+ **So before a ratchet is kept, feed its matcher a near-miss it must reject** — the prefix,
373
+ the parent, the same name in a comment or an import, the longer extension. Seeing a guard
374
+ go red on a real change proves it **reacts**; seeing it stay green on a look-alike proves
375
+ it **discriminates**. Only the second makes its number worth trusting.
376
+
377
+ **And when a matcher is corrected, re-derive the whole ratchet and print both numbers with
378
+ the reason.** In the reporting project the corrected count was *identical* to the old one
379
+ and the composition was not: rows credited falsely came back in as rows genuinely paid off
380
+ went out. A single number with no delta reads as a run where nothing happened.
381
+
382
+ ## A green probe is evidence only if the mutation is known to have landed
383
+
384
+ Also reported from another project, three times in one day, each caught only because the
385
+ result was too good:
386
+
387
+ 1. a scripted substitution missed on indentation — the file was unchanged and the probe
388
+ measured nothing;
389
+ 2. an assertion written against a bare identifier kept matching the **import line** after
390
+ the field it guarded was deleted;
391
+ 3. a file-extension alternation matched the longer extension as though it were the
392
+ shorter, reporting nine live files as missing.
393
+
394
+ In all three the observable was identical to success. *"See it fail once"* has an unstated
395
+ precondition — **that the thing you changed is the thing the check reads** — and a planted
396
+ defect that did not land produces the same green as a check that cannot fail.
397
+
398
+ **So a probe that mutates an existing file asserts its plant landed, in the same breath as
399
+ planting it.** A probe that writes a whole file has no such question: the file exists or
400
+ the command failed. This repository measured itself while writing this section and got the
401
+ number wrong three times. A hand-rolled classifier said *206 of 206 already carry it*.
402
+ The guard written from the rule said **22 did not** — and was itself too narrow, matching
403
+ one spelling of the assertion, so six probes that already had it in lower case were
404
+ called defective. A sweep then "fixed" those six and **corrupted five**, splitting live
405
+ statements. The true figure was **16**, and it took the guard, a compile check and a
406
+ restore from git to find it.
407
+
408
+ Two things are worth keeping from that. **The check corrected the measurement that
409
+ motivated it** — which is the argument for writing checks rather than counting by hand.
410
+ And **a check keyed to one spelling of a rule is the class two sections above**: it
411
+ reported as defective the probes that obeyed the rule in different words. **Every**
412
+ mutating probe carries the assertion now — the figure is deliberately not
413
+ written here. A first draft said *201*, which was true of the branch point and false in
414
+ the same commit, because the twelve probes added for this release are themselves mutating
415
+ probes. The guard computes it; a number in prose beside a check that can count is the
416
+ class this bundle calls restating instead of computing. Probes that write a whole file
417
+ need none: the file exists or the command
418
+ failed.
419
+
420
+ **Prefer an assertion that names the construct over one that names a substring of it.** A
421
+ guard written against a bare identifier survives the deletion of everything it guarded,
422
+ because the identifier still appears in an import. That is case 2 above and it is the same
423
+ class as the section before this one, one level down.
424
+
350
425
  ## The false-positive budget
351
426
 
352
427
  Run a new heuristic over the **real corpus** before shipping it and count the false
@@ -25,6 +25,7 @@ maintains them and the next run reads them as current.
25
25
  - The iteration line
26
26
  - The rail is computed, never eleven
27
27
  - What each glyph means
28
+ - The hand-back — what the operator reads when you stop
28
29
  - Every number is borrowed
29
30
  - Absent is a word, never a zero
30
31
  - The run ledger this reads from
@@ -119,6 +120,101 @@ the verdict the gate wrote, in the run ledger, and from nothing else.
119
120
  **`⊘` may never be silent.** A skipped stage with no recorded reason is exactly what a
120
121
  `·` looks like from outside, and the two mean opposite things.
121
122
 
123
+ ## The hand-back — what the operator reads when you stop
124
+
125
+ The rail says **where** the run is. It does not say what happened, and a reader who was
126
+ away cannot reconstruct that from a glyph. Measured on this project: a fourteen-iteration
127
+ session where the operator returned to a one-line rail each time and had to ask.
128
+
129
+ **At the close of an iteration, and again at stage 10.** This is *not* the pair named
130
+ three sections above: *The two boundaries, and only those two* governs the **rail**, and
131
+ its pair is task start and iteration close. The hand-back shares one and adds the run's
132
+ end — a rail at task start has nothing to report, and a run that ends without a hand-back
133
+ is the case this section exists for. A reader resolving *"both boundaries"* against the
134
+ other section wrote one at task start, where TASK is the only field with content. The run
135
+ writes a hand-back with **four sections and two lists**. It is a gate criterion **at stage
136
+ 10**, not a good intention: this file already carried one instruction with no gate behind
137
+ it (*"copy it, tick it"*), and the v1.37.0 audit found no run had ever obeyed it.
138
+
139
+ **The iteration-close instance has no gate, and that is a weakness rather than an
140
+ oversight** — an iteration boundary has no verdict to hang a criterion on. It is
141
+ therefore the very shape the sentence above indicts, written inside it. What keeps it
142
+ from being *"copy it, tick it"* is the run ledger: the iteration line already lands there,
143
+ and the hand-back lands beside it, so a later audit has something to read. Where a project
144
+ keeps no ledger, the iteration hand-back is prose discipline, and the run says which of
145
+ the two it is running.
146
+
147
+ ```
148
+ ── hand-back · <topic> · iteration <n> ───────────────────────────
149
+ TASK the request as it was GIVEN, quoted from the brief — not
150
+ as it looks now that you understand it
151
+ PROGRESS where the run stands against that request: gates passed,
152
+ what remains, and the board id it is heading for
153
+ DONE what was solved this iteration, each with its evidence
154
+ SURFACED what came up that nobody asked for — findings, corrections,
155
+ things that turned out to be other than assumed
156
+
157
+ DECISIONS WAITING <n> each as a question with options, asked HERE
158
+ AMBIGUITIES <n> computed, below
159
+ ```
160
+
161
+ **Where there is no brief** — `checkup`, `setup`, a short path — TASK quotes the
162
+ operator's own sentence instead, marked as such. An unquotable TASK is a run that cannot
163
+ say what it was asked, which is worth its own line.
164
+
165
+ **Where it lands.** The narrative goes to the operator; the trace goes to the run
166
+ ledger as a `hand:` line ([`../templates/run.md`](../templates/run.md)). Without it the
167
+ hand-back is a gate criterion with no artefact — a reader proved that of v1.43.0's
168
+ first draft: every guard could check the instruction was still written, none could
169
+ check a run obeyed it, and an audit a year later could reach no verdict either way.
170
+ `grep -c '^hand:'` against `grep -c '^iter:'` is what makes the difference readable.
171
+
172
+ **TASK is quoted, never paraphrased.** A run that restates the request in its own words
173
+ after eight iterations has rewritten it, and the operator cannot see that happen. The
174
+ quote is the one line the drift shows against.
175
+
176
+ **SURFACED is the section that earns the hand-back.** Everything else is recoverable from
177
+ the artefacts; what a run *learned by accident* is recoverable from nothing. A run that
178
+ found a stale claim, corrected a number, or discovered a rule was never enforced puts it
179
+ here even when it was fixed in passing — especially then.
180
+
181
+ **DECISIONS WAITING are asked, not listed.** A question parked in a report is a question
182
+ the operator answers days later, if at all. Ask it at the boundary, with options and a
183
+ recommendation, in the same breath as the report. If there are none, the field prints
184
+ `0` — [`gates.md`](gates.md)'s rule about absence applies here too.
185
+
186
+ ### AMBIGUITIES are computed from four registers the run already keeps
187
+
188
+ Not judgement, and not a prompt to think harder — an unbounded *"is anything unclear?"*
189
+ becomes a ritual sentence within three runs. Four sources, each read by a command:
190
+
191
+ | Source | What it means | Read by |
192
+ |---|---|---|
193
+ | open `OQ-####` rows ([`documentation.md`](documentation.md)) | a question raised and never answered | `grep -cE '^\| OQ-[0-9]+' docs/OPEN_QUESTIONS.md` — **no file prints `— no register`, never `0`** |
194
+ | carry-over rows whose home is unsettled | deferred into nothing ([`../templates/carryover.md`](../templates/carryover.md): `open`, `unresolved`, or a bare `backlog`) | `grep -cEi '\\|[[:space:]]*(open\\|unresolved\\|backlog)[[:space:]]*\\|' <ledger>` |
195
+ | REQ rows whose check is `review` rather than a command | shipped on judgement, unverifiable by a machine | the brief's REQ table, *Verified by* column. The count `spec.md` prints is **checks**, not REQ rows — different units, and quoting one for the other is a borrowed number that does not fit |
196
+ | source-ledger rows with **no source** | the run built on the absence of a document | the brief's ledger, rows whose *Source* cell is empty or parenthesised. `knowledge-sources.md` writes them `(none for X)` while `templates/brief.md` writes `none found`, so **a grep for either string alone returns a false zero** |
197
+
198
+ The `Read by` column is the point of the table. Without it, *"each read by a command"* is a
199
+ claim the section makes about itself and cannot keep — and one of the four greps would
200
+ have returned zero for searching a string the source ledger's own doctrine never writes.
201
+
202
+ Each prints its count **and its ids**. A count with no ids is a number nobody can act on,
203
+ and **zero prints as zero** — silence and "I looked and found none" are the two states
204
+ this file exists to keep apart.
205
+
206
+ **One of the four is structurally zero at the gated boundary.** Stage 10's own gate
207
+ already requires that no carry-over row is left unresolved, so there that count is zero
208
+ **because a sibling clause compelled it**, not because the run looked. At an iteration
209
+ close it is a real measurement. Print it either way, and at stage 10 print *why* it is
210
+ zero — a number that had no choice is not evidence.
211
+
212
+ **Why these four and not a fifth.** Every one is already written down by an earlier stage,
213
+ so the hand-back reports rather than re-derives, and a run cannot quietly decide that
214
+ nothing was unclear. Where a project keeps no open-questions register, that row prints
215
+ `— no register` rather than `0`: an absent register and an empty one are different facts,
216
+ and the second is the one worth acting on.
217
+
122
218
  ## Every number is borrowed
123
219
 
124
220
  | Field | Its home |
@@ -33,6 +33,7 @@ file exists to stop.
33
33
  - Write the entry only for a divergence — and name the layer that owned it
34
34
  - Every lesson carries its commit
35
35
  - The stamp table is capped at ten, and *one line per run* was never a cap
36
+ - `publish:` is a line in the verdict, not a silence
36
37
  - Rotation — the archive is how pruning stops losing things
37
38
  - Three grades of fix — take the highest one that can work
38
39
  - Stamp first, then prune, then write
@@ -100,6 +101,42 @@ like every other rotation. **The count is printed at the prune**, beside the sta
100
101
  instructions' own count, so a table that stops rotating is visible rather than merely
101
102
  large.
102
103
 
104
+ ## `publish:` is a line in the verdict, not a silence
105
+
106
+ Reported from another project, and the report is about this file: an operator asked, after
107
+ many runs, why nothing had ever been published.
108
+
109
+ The floor is right and does not move — publishing is opt-in per project, off by default,
110
+ because an outward act taken from a generic flag is an outward act nobody authorized. The
111
+ gap is what happens next. A project with no configuration produces, run after run,
112
+ retrospective entries carrying lessons about **the skill**, and the mechanism reports
113
+ nothing, because it was never armed. **An unarmed mechanism and a mechanism with nothing
114
+ to say are indistinguishable from the outside** — [`gates.md`](gates.md)'s false success,
115
+ applied to this bundle's own learning path. In the reporting project several runs had
116
+ produced skill-level lessons over months; the count of published insights was zero and no
117
+ gate had ever mentioned it.
118
+
119
+ Stage 10 prints ratchets and two disclosures — what the run declined to claim, and what a
120
+ check never looked at. Publishing is neither, so its absence is not observable at the only
121
+ moment anyone is reading.
122
+
123
+ **So stage 10's block carries one line for publication:**
124
+
125
+ ```
126
+ publish: <issue url> — opened this run
127
+ publish: 0 (configured, nothing insight-grade)
128
+ publish: not configured (N insight-grade entries stayed local)
129
+ ```
130
+
131
+ It arms nothing and authorizes nothing; it makes the silence legible. A count of zero
132
+ beside *configured* is a fine answer. A **blank** where configuration is absent is how an
133
+ instruction went unread for eight releases.
134
+
135
+ **The failure mode survived its own fix, in a quieter form.** This section once said
136
+ *"open an issue upstream"* while naming no repository, no trigger and no authorization,
137
+ and every reader took it as done. The mechanism that replaced it is correct — and until
138
+ this line existed it still had no way to say it never ran.
139
+
103
140
  ## Rotation — the archive is how pruning stops losing things
104
141
 
105
142
  At the prune, entries older than the last five run stamps **move** to
@@ -651,7 +651,12 @@ never that the work was skipped quietly.
651
651
  a messy run is the failure the file exists to stop. Stage 0 reads the standing
652
652
  instructions in full next time, which is why the cap is not negotiable.
653
653
  - **GATE (manual):** the ladder walk ran and its absences became REQ rows before
654
- the table was written; **both disclosures printed beside the verdict** — `abstained` (what the run declined
654
+ the table was written; **the hand-back is written** — the request quoted as it was
655
+ GIVEN, where the run stands against it, what was solved with its evidence, what
656
+ surfaced that nobody asked for, every decision still waiting **asked here with
657
+ options rather than listed**, and the ambiguity count computed from the four
658
+ registers with its ids ([`progress.md`](progress.md) → *The hand-back*) — a run
659
+ that cannot say what happened has not finished, it has stopped; **both disclosures printed beside the verdict** — `abstained` (what the run declined
655
660
  to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither
656
661
  with a floor, neither ever a target ([`gates.md`](gates.md) → *Disclosures*); **the
657
662
  retrospective is written — stamped first, then pruned, then the entry; the
@@ -667,7 +672,12 @@ never that the work was skipped quietly.
667
672
  string, and the five redaction rules applied
668
673
  ([`retrospective.md`](retrospective.md) → *What may leave the project*). Absent, the
669
674
  step does not exist and is not asked about: publishing to another repository is an
670
- outward act and silence authorizes none**; **the documentation gate has been seen
675
+ outward act and silence authorizes none. **Either way the verdict carries a `publish:`
676
+ line** — the issue url, `0 (configured, nothing insight-grade)`, or `not configured
677
+ (N insight-grade entries stayed local)`: an unarmed path and one with nothing to say
678
+ are otherwise indistinguishable, which is how this instruction went unread for eight
679
+ releases** ([`retrospective.md`](retrospective.md) → *`publish:` is a line in the
680
+ verdict*)**; **the documentation gate has been seen
671
681
  failing once against a planted defect and its ratchet counts are printed**
672
682
  ([`gates.md`](gates.md)); **every repository is closed — the parent included:
673
683
  `git submodule status` shows no `+`, each repo clean and pushed**; **every check this gate leans on has been seen failing
@@ -15,6 +15,7 @@ into this skill; nothing to install.
15
15
  - Tests that stay honest
16
16
  - Stage 6 — consolidation and the suite gate
17
17
  - When stuck
18
+ - What a case consumes, and why a timeout is unclassified
18
19
  - Rationalizations
19
20
  - Red flags — stop and start over
20
21
 
@@ -134,6 +135,52 @@ honestly instead.
134
135
  | Setup is enormous | Extract helpers; if it's still huge, the design is the problem. |
135
136
  | Fixing a bug | Write the failing test that reproduces it first. The test proves the fix and prevents the regression. |
136
137
 
138
+ ## What a case consumes, and why a timeout is unclassified
139
+
140
+ Reported from another project after hours spent reading environmental noise as product
141
+ defects. An end-to-end suite registered a fresh account in every case. The product
142
+ rate-limits registration to a handful per minute per address. **A suite of twenty-odd
143
+ cases cannot avoid tripping its own product's limiter.**
144
+
145
+ A throttled registration does not fail loudly. The form never advances, the case sits
146
+ until its own timeout, and it reports **as a timeout** — which reads exactly like
147
+ slowness. Cold compilation, hydration and a stale cache were each investigated and each
148
+ was independently true; none was the cause.
149
+
150
+ **A check that cannot run to completion in its own environment reports noise, and noise
151
+ costs more than silence, because it looks like data.** Silence gets investigated. Noise
152
+ gets interpreted.
153
+
154
+ The neighbouring rule this bundle already has — *a check counts only where it runs* — is
155
+ about **availability**: does the guard execute on the gate. This is about **capacity**:
156
+ the harness is part of the system under test, and a suite that exhausts a production limit
157
+ is measuring the limit.
158
+
159
+ **So at the tests gate, name what each case consumes from the product** — accounts,
160
+ rate-limited endpoints, external quota, seats, tokens — and confirm the suite's total
161
+ stays under the product's own bound. Where it cannot, the suite **shares** the resource
162
+ across cases instead of acquiring it per case.
163
+
164
+ **Where the bound comes from, and what to do when it does not exist.** In order: the
165
+ product's own configuration or code; the provider's documented limit; the operator. Write
166
+ the answer into the brief's source ledger like any other fetched fact — a limit an agent
167
+ remembered is a limit nobody can check. **Where none of the three answers, the row reads
168
+ `bound: unknown` and the count goes to `unlooked`** rather than to a guess: this file's
169
+ whole argument is that an unmeasured resource reports as a timeout, and an unmeasured
170
+ *bound* does the same one level up.
171
+
172
+ **And it does not override *The green from residue*.** That rule is about state a case
173
+ inherits — a database, a volume, a clone — and it still says acquire fresh. This rule is
174
+ about a resource **the product itself meters**. Where the two meet, the product's bound
175
+ wins and the suite shares that one resource while everything else stays fresh; say which
176
+ resource is shared and why.
177
+
178
+ **And a timeout in an end-to-end suite is an unclassified result, not a slow one.** Before
179
+ it is read as a performance signal the resource question above must have an answer, or the
180
+ run is interpreting its own harness. In the reporting project this was also the most
181
+ likely reason that suite had never once finished inside its CI time cap — so the cost was
182
+ not only the hours, it was every defect the suite never got far enough to find.
183
+
137
184
  ## Rationalizations
138
185
 
139
186
  | Excuse | Reality |
@@ -13,12 +13,13 @@ Run: `<topic>` · started `<YYYY-MM-DD>` · module map: `<path or "none">`
13
13
 
14
14
  ## Lines
15
15
 
16
- Append-only. Three shapes, and nothing else belongs here:
16
+ Append-only. Four shapes, and nothing else belongs here:
17
17
 
18
18
  ```
19
19
  stage: <id> <name> — gate <auto|manual> — verdict <pass|fail|skip> — <ISO-8601>
20
20
  iter: <N> — item <B-NNN or task id> — closed at gate <stage id>
21
21
  touch: <file> — pass <N> (<stage|round|module>) — reason: <finding id / gate item>
22
+ hand: <N|10> — task "<quoted>" — done <n> — surfaced <n> — decisions <n> — amb <n> (<ids or "— no register">)
22
23
  ```
23
24
 
24
25
  - **`stage:`** — written when a gate **returns**, not when the stage is entered. The
@@ -26,6 +27,14 @@ touch: <file> — pass <N> (<stage|round|module>) — reason: <finding id / gate
26
27
  is a summary that is confidently wrong exactly when it matters.
27
28
  - **`iter:`** — one line per iteration closed. The progress line's counter is
28
29
  `grep -c '^iter:'`, never a number anyone remembers.
30
+ - **`hand:`** — one per hand-back, at an iteration's close and at stage 10
31
+ (`references/progress.md` → *The hand-back*, inside the skill). The
32
+ narrative goes to the operator; **this line is the trace it leaves**, and it exists
33
+ because v1.43.0 shipped a gate criterion with no artefact behind it: every guard could
34
+ check that the instruction was still written, and none could check that a run obeyed
35
+ it. A later audit reads `grep -c '^hand:'` against `grep -c '^iter:'` and the two
36
+ should agree, plus one for stage 10.
37
+ **`amb` prints its ids or `— no register`, never a bare `0` with nothing beside it.**
29
38
  - **`touch:`** — one line per file per pass, and the reason names **what forced the
30
39
  edit**: a finding id, a failed gate item, an operator instruction. *"Cleanup"*,
31
40
  *"polish"* and *"while I was there"* are not reasons; they are churn with better
@@ -43,6 +52,7 @@ stage: 1 Docs study — gate auto — verdict pass — 2026-08-10T11:31Z
43
52
  touch: src/export.ts — pass 1 (stage 5) — reason: TASK-3
44
53
  touch: src/export.ts — pass 2 (stage 5) — reason: F-014
45
54
  touch: src/export.ts — pass 3 (stage 5) — reason: F-014
55
+ hand: 3 — task "add CSV export to the orders table" — done 2 — surfaced 1 — decisions 1 — amb 2 (OQ-0007, ledger row 4)
46
56
  ```
47
57
 
48
58
  The last two lines are a **trip**: the same file, two consecutive passes, the same