task-pipeline-skill 1.45.0 → 1.46.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,82 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.46.0 — what a run leaves running, what "done" costs to say, and what a check is for
4
+
5
+ Three rules this pipeline had been following by disposition rather than by doctrine,
6
+ and one it had not been following at all.
7
+
8
+ **`evidence-docs` can now be reached in Russian.** It shipped without Russian triggers
9
+ while `task-pipeline`, beside it in the same plugin, had carried them since v0.14.0 — a
10
+ navigator nobody can summon is a navigator nobody reads. Its description now opens with
11
+ `Use when …`, names twelve triggers on both sides, and keeps the `без доков` opt-out the
12
+ body always documented. `task-pipeline`'s own description is deliberately unchanged: the
13
+ house auditor requires every description to open with `Use when …`, this repository's
14
+ validator requires the opposite — capability first, trigger second — and fails the build
15
+ on anything else. Measured in both directions; which of the two rules is wrong is a
16
+ decision, not a fix to slip into a release.
17
+
18
+ **A run is not only a diff — it is also everything it left running.** A background
19
+ shell, a monitor polling an API, a scheduled loop, a coordination lease, a worktree,
20
+ a container, scratch files, a draft PR. `references/residue.md` names eight classes
21
+ and requires each to be enumerated **by class, never by one tool** — because the
22
+ measured case that produced this file was a task inventory reporting *"No tasks
23
+ found"* while `ps` showed the monitor alive and polling every thirty seconds. An
24
+ inventory that does not contain the thing that leaks is a green light with no lamp
25
+ behind it.
26
+
27
+ Every gate now prints `holds: N` beside its verdict, the run ledger gains a fifth
28
+ declared line shape, and stage 10 gains criterion 13: give the environment back.
29
+ The asymmetry is the point — **end what this run started, report what it did not**.
30
+ The inventory is machine-wide and the authority is not, so a stale-looking lease
31
+ belonging to another agent is named, never released.
32
+
33
+ The field is `holds:` rather than `residue:` because `gates.md` already prints
34
+ `unmarked residue: 0` for documentation items, and `residue: 0` is a substring of
35
+ it. A check written for the new field would have been answered by the old line — the
36
+ class this repository has now met nine times, caught here before it shipped.
37
+
38
+ **"Done" is a claim, and it names what makes it true.** Every disclosure in this
39
+ bundle asks *what does it print when it did not look?* — of checks. `progress.md`
40
+ now asks it of the run's own sentences, which reach the operator where the check
41
+ does not. Three shapes, each requiring no intent to mislead: the plan reported as
42
+ the outcome, the reply reported as the result, the part reported as the whole. And
43
+ the honest negative is a result: *"not done, the fixture needs a credential I do not
44
+ have"* is a complete report where *"done, with a small caveat"* is not.
45
+
46
+ **The result is the goal; the check is how you know.** Every other line in
47
+ `gates.md` pushes one way — prove more, assume less — and read alone it produces a
48
+ run that spends an afternoon proving a one-character change. Verification now scales
49
+ to what breaking costs, using the `sev × blast` the board already computes, with
50
+ four named signals that you have crossed over. This never licenses skipping a gate:
51
+ the floor is not proportionate to anything, and cutting it to go faster is the
52
+ failure the file exists to prevent, arriving on schedule.
53
+
54
+ **Publishing was half a loop.** `retrospective.md` closes it: an issue resolves when
55
+ the **behaviour** changed and its closing comment names the file, the line and the
56
+ guard; an issue nobody worked stays open rather than being triaged into silence;
57
+ nothing is deleted, because the number is what the CHANGELOG points at. The queue a
58
+ run pulls from when it finishes early is that pile, then the board, then the open
59
+ questions.
60
+
61
+ Guards: 275 → **291**, each still proven against a planted defect — including a
62
+ neighbour probe that caught a defect in one of this release's own guards on its
63
+ first use: the criterion-13 check scoped *to the next heading* rather than *to the
64
+ item*, so a needle parked in between answered for the rule.
65
+
66
+ ## v1.45.1
67
+
68
+ ### Fixed
69
+
70
+ - **The v1.45.0 entry had no `Guards: N → **M**` line**, so the negative
71
+ self-test that plants a stale count had nothing to plant into and failed with
72
+ `PLANT DID NOT LAND`. The count is a claim about *now* and every release
73
+ section is required to restate it — a release that omits it silently disarms
74
+ the check that keeps the number honest.
75
+
76
+ ### Counts
77
+
78
+ - Guards: 275 → **275**.
79
+
3
80
  ## v1.45.0
4
81
 
5
82
  ### Changed
@@ -17,6 +94,11 @@
17
94
  from the 2026-08-03 design, and refused two rewordings before accepting one
18
95
  in text nothing had locked.
19
96
 
97
+ ### Counts
98
+
99
+ - Guards: 275 → **275** — this release adds none; it removes duplication from
100
+ the body and touches no check.
101
+
20
102
  ### Known gap
21
103
 
22
104
  - **The body is still 6088 tokens against a 5000 cap.** What remains is a
@@ -0,0 +1,346 @@
1
+ # How task-pipeline works
2
+
3
+ **The living high-level view.** This file is rewritten with every release. It
4
+ explains the machine — what routes a request into it, what each stage refuses to
5
+ let past, and what makes any claim it prints believable. The README sells it and
6
+ tells you how to install it; this file tells you how it thinks.
7
+
8
+ > **Version 1.45.0.** The "What changed" section at the bottom carries the last
9
+ > few releases. Everything above it describes the pipeline as it is *now*, not as
10
+ > it was designed.
11
+
12
+ ---
13
+
14
+ ## The one-sentence version
15
+
16
+ A coding agent takes a substantial task, interrogates it into a complete brief,
17
+ then walks it through **ten gated stages** and refuses to advance until each
18
+ gate passes — closing by accounting for every requirement from a list rather than
19
+ from memory.
20
+
21
+ The reason it exists: agents write code well and judge *when to stop asking you
22
+ things* badly. Left alone, a substantial task becomes twenty interruptions, or a
23
+ confident build that skipped the tests and quietly delivered two thirds of what
24
+ you asked for.
25
+
26
+ ---
27
+
28
+ ## 1. How a request finds the pipeline
29
+
30
+ An agent choosing skills sees exactly one thing: the `description` field in
31
+ `SKILL.md`. It is capped at **1024 characters** and currently uses **1008** — that
32
+ headroom is the budget every future addition pays from, which is why it is
33
+ tracked as a board row rather than left to be discovered.
34
+
35
+ It is written in three parts, and the middle one was learned the hard way:
36
+
37
+ - **Work that changes the repository** — a feature, fix, refactor, migration,
38
+ integration, rewrite, adoption or hardening, in English and Russian both.
39
+ - **Work whose *output* lands in the repository** — `audit`, `bug hunt`,
40
+ `production check`, `PR review`. Before this clause existed, agents facing
41
+ "проверь, нет ли ошибок" **quoted this skill's own exclusion line as their
42
+ reason to refuse**. The measurement is in `evals/routing/RESULTS.md`.
43
+ - **What it is not for** — answering a question, explaining code, a typo, a
44
+ one-line edit. The boundary runs in both directions on purpose: running ten
45
+ stages for one character is the fastest way to teach an agent to route around
46
+ the pipeline entirely.
47
+
48
+ Two modes need no task at all. `checkup` reports what has shipped without anyone
49
+ confirming it. `setup` audits the documentation a project already has.
50
+
51
+ **Honest limit:** this measures the *description's* discriminating power, not the
52
+ host's selection machinery. Three measured runs scored 7/10, 9/10 and 8/10 — and
53
+ one sample per query cannot separate an effect from noise, which the measurement
54
+ discovered about itself by being run twice.
55
+
56
+ ---
57
+
58
+ ## 2. Preflight — two things settled once
59
+
60
+ **Model.** The most capable tier the environment offers, named as a *tier*, never
61
+ as a vendor id. A hardcoded model id in shipped doctrine is a validator failure,
62
+ because it rots the moment the vendor ships a new one.
63
+
64
+ **Companions.** `super-ux`, `copywriting`, `sheleg-design`, `graphify`, the wiki.
65
+ The detection block prints once. A missing companion states its fallback and
66
+ **does not block** — the single exception being the stage-3 UX track on
67
+ user-facing work, where shipping without it is a decision someone has to make out
68
+ loud.
69
+
70
+ ---
71
+
72
+ ## 3. Stage 0 — where the run is won or lost
73
+
74
+ This is the heaviest stage and that is deliberate. Everything downstream is an
75
+ attempt to execute a brief; a bad brief cannot be rescued by good execution.
76
+
77
+ ### The harvest runs before the first question
78
+
79
+ Pull what the project already knows about *this task*:
80
+
81
+ | Source | What it uniquely answers |
82
+ |---|---|
83
+ | the code | what is there |
84
+ | **the code graph** (`graphify-out/graph.json`) | **reach** — what calls this, what breaks if it moves. `grep` cannot answer this |
85
+ | `CLAUDE.md`, ADRs, `docs/`, `docs/ux/` | what was decided and why |
86
+ | **the retro, read in full** | the standing instructions that *bind this run* |
87
+ | the knowledge wiki | what past runs distilled |
88
+ | the board and the verification ledger | what is open, and what shipped unverified |
89
+
90
+ The output is a **source ledger** — a row per source, or an explicit *none found*.
91
+ An absent source that is never named looks identical to a source that was read.
92
+
93
+ ### Then the grill, and it is mandatory
94
+
95
+ One question per turn, each with a recommended answer, exploring the codebase
96
+ before asking, until every decision branch is resolved.
97
+
98
+ - **Every answer is validated against the harvested sources.** The operator
99
+ outranks any document — but only *out loud*, and a document the run proves stale
100
+ is logged for stage 9 rather than silently ignored.
101
+ - **The autonomy sweep** pre-resolves what would otherwise stop stages 1→10: test
102
+ and lint commands, branch and tracker policy, deploy target and authorization,
103
+ where the logs live. Every question asked here is an interruption that does not
104
+ happen later.
105
+ - **UI work adds the design surface** — Figma connected or text-only, and *which
106
+ file*, named before the first frame. A destination decided at drawing time is
107
+ how a project ends up with three design files and no way to tell which is real.
108
+
109
+ ### The brief closes on the REQ table
110
+
111
+ The request as an **addressable list**, where every row names how it will be
112
+ verified. Frozen from here: adding is free, removing needs the operator. Anything
113
+ deferred enters the carry-over ledger the moment it is said, not at the end when
114
+ it has been forgotten.
115
+
116
+ ---
117
+
118
+ ## 4. Stages 1→10
119
+
120
+ | | Stage | What must be true to leave it | Gate |
121
+ |---|---|---|---|
122
+ | 1 | Docs study | every contract the design will lock is grounded on **fetched** docs, not recall | auto |
123
+ | 2 | Brainstorm + decompose | design approved, every REQ answered by it. A platform is cut into modules, **walking skeleton first**, every REQ in exactly one module | manual |
124
+ | 3 | Spec | contracts locked. User-facing work runs three tracks — what it **does**, how it **sounds**, how it **looks**. A declined track is recorded, never silent | manual |
125
+ | 4 | Plan | the REQ set-comparison holds: brief REQs == union of `Implements:` | auto |
126
+ | 5 | Build | TDD per task, a review after each, findings fixed or parked **with a ruling** | auto |
127
+ | 6 | Tests | the **full** suite green; a web surface checked in a browser, not in the diff | auto |
128
+ | 7 | Lint + deploy | the authorization is specific, and the CI verdict is **read** before any tag | manual |
129
+ | 8 | Post-deploy | the verification trio, not one of three; a verification row per shipped REQ | auto |
130
+ | 9 | Docs + wiki | **three** artifacts — module docs, the wiki, and the code graph | auto |
131
+ | 10 | Acceptance | the ladder walk first, then the table, then the retrospective | manual |
132
+
133
+ ### Why the manual gates are where they are
134
+
135
+ `auto` means the agent verifies the check itself and proceeds. `manual` means it
136
+ waits for an explicit go. The four manual gates sit at the four places where a
137
+ wrong turn is expensive and hard to reverse: **what we are building** (2), **the
138
+ contracts** (3), **the outside world** (7), and **whether it is done** (10).
139
+ Everywhere else, stopping to ask costs more than it saves.
140
+
141
+ ---
142
+
143
+ ## 5. The three rules that fire at any stage
144
+
145
+ **The loop guard.** If a pass starts undoing an earlier one — the same file edited
146
+ twice for the same reason, a closed finding returning, a third entry into one
147
+ stage — editing stops. Name both shapes, escalate to the layer that owns the
148
+ conflict, re-plan as an ordered list, then go item by item. "Cleanup" and "polish"
149
+ are explicitly *not* valid reasons for an edit; every change needs one traceable
150
+ cause.
151
+
152
+ **The audit's exit.** If a searching pass starts finding mostly what the previous
153
+ pass's own fixes broke, the axis is exhausted. **Rotate the axis — do not look
154
+ harder.**
155
+
156
+ **Evidence.** A green from a check nobody has watched fail against a planted
157
+ defect is not evidence. A finding class seen twice becomes a script, not a third
158
+ ledger row.
159
+
160
+ ---
161
+
162
+ ## 6. The loop — walking a queue without asking permission
163
+
164
+ Recorded in `pipeline.json` → `run.loop`:
165
+
166
+ ```
167
+ loop:
168
+ mode: off | interval | dynamic
169
+ queue: module-map | plan-tasks | none
170
+ arm: preflight | after-decomposition
171
+ ```
172
+
173
+ **A loop with no queue is a timer.** The queue belongs to stage 2 — the module map
174
+ or the plan's task list. Nothing third is invented. The loop arms at the *close of
175
+ stage 2*, when the mode is recorded and the queue holds more than one item.
176
+ Between items the goal is re-read, so tasks can be re-prioritised or moved to the
177
+ board as the run learns.
178
+
179
+ The rule that keeps this safe: **arming is the execution of a recorded decision,
180
+ not a fresh request. Where nothing is recorded, nothing arms.** Default off.
181
+ Silence arms nothing.
182
+
183
+ ---
184
+
185
+ ## 7. The hand-back — what a run says when it stops
186
+
187
+ Long iterations lose context. So at the end of every iteration, and at stage 10,
188
+ the run reports in a fixed shape:
189
+
190
+ ```
191
+ TASK the request AS IT WAS GIVEN, quoted from the brief
192
+ PROGRESS where the run stands against that request
193
+ DONE what was solved, each with its evidence
194
+ SURFACED what came up that nobody asked for
195
+ DECISIONS WAITING <n> each as a question with options, asked HERE
196
+ AMBIGUITIES <n> computed from the registers, below
197
+ ```
198
+
199
+ Three details carry the weight:
200
+
201
+ - `TASK` is **quoted, not paraphrased** — the paraphrase is exactly what drifts.
202
+ - `DECISIONS WAITING` are asked **here**, not deferred. A missing decision, a
203
+ missing document or an ambiguity left standing is what turns into a large
204
+ consequence three stages later.
205
+ - `AMBIGUITIES` is **computed from four registers that already exist** — not a
206
+ fifth document nobody maintains.
207
+
208
+ It is traced by a `hand:` line in `.task-pipeline/run.md`, beside `stage:`,
209
+ `iter:`, `touch:` and `holds:`. That is what makes it a check rather than an intention.
210
+
211
+ ---
212
+
213
+ ## 8. Stage 10 — the close-out, in order
214
+
215
+ 1. **The ladder walk, first.** The REQ table finds what was named and lost; it
216
+ **cannot** find what was never named, because a comparison needs two sides and
217
+ an absence has one. So every REQ is walked bottom-up — decision → spec section
218
+ → contract *and its failure behaviour* → task → change → executed test →
219
+ surface and docs — checking the seam at each step. Findings are ordered **by
220
+ seam, not by file**. Every absence becomes a new REQ row *before* the table.
221
+ 2. **The coverage table** — one row per REQ, each with evidence. Four statuses
222
+ only: verified, partial, deferred, dropped. `unknown` fails the gate.
223
+ 3. **The ledgers close.** Every carry-over row still open leaves with a board id,
224
+ and priorities are re-derived. The counts print beside every gate verdict, so
225
+ *green* never reads as *verified*.
226
+ 4. **Several repositories? The parent closes too.** A submodule can be committed,
227
+ pushed and green while a clone of the parent still gets the commit before it,
228
+ and neither repo looks wrong alone.
229
+ 5. **The retrospective is the run's last act**, in this order: stamp the run →
230
+ prune every standing instruction against its retirement triggers (list held to
231
+ ten, every deletion logged) → write an entry **only if the run diverged**.
232
+
233
+ ---
234
+
235
+ ## 9. Why you should believe anything it prints
236
+
237
+ This is the part most pipelines skip, and it is the reason this one is trustworthy
238
+ rather than merely tidy.
239
+
240
+ **Every guard is proven against a planted defect.** `npm run test:all` breaks the
241
+ thing each of the **291** checks is about, and requires that check to reject it. A
242
+ guard that has never been watched failing is not a guard; it is a comment.
243
+
244
+ **The neighbour probe.** A check has a *subject* — the rule it is about — and
245
+ *evidence* — the text it actually reads. When those differ, it goes green for
246
+ reasons unrelated to the rule and no ordinary probe can tell. So: break the
247
+ subject, plant the guard's **current** needle next door, and require it to still
248
+ fail. Six guards in one session were defeated this way — none of them by their own
249
+ probes, all of them by a reader.
250
+
251
+ **Disclosures are not ratchets.** Alongside every verdict the suite prints what it
252
+ *could not* look at — `unlooked: N`, listed by name; `abstained` where a check's
253
+ precondition was absent. No floor, no direction, **never a target**. A number that
254
+ becomes a target stops being a measurement.
255
+
256
+ **Corpora are discovered, not listed.** Three hand-written lists each missed a
257
+ shipped surface, and none of the misses was found by the guard holding the list. A
258
+ new surface joins a check by *existing*.
259
+
260
+ **The scaffold's own gate runs.** One guard executes `templates/docgate.sh` over a
261
+ scratch project seeded from the templates and requires exit `0`. A scaffold whose
262
+ gate rejects its own seeds teaches every new project that the gate is noise.
263
+
264
+ ---
265
+
266
+ ## 10. The improvement iteration
267
+
268
+ The pipeline improves itself on a loop, and the loop is mechanical rather than
269
+ aspirational:
270
+
271
+ ```
272
+ a run diverges → retro entry → retro.publish → upstream issue
273
+
274
+ board row ← measured against the tree ← triaged next cycle
275
+
276
+ doctrine change + a guard that proves it → release → the run reads it
277
+ ```
278
+
279
+ - **`retro.publish`** turns a lesson that is bigger than one project into a GitHub
280
+ issue on the skill itself. Six such insights arrived in a single day.
281
+ - **Issues are resolved, never deleted.** Ones we have worked through are closed
282
+ with a comment naming what they changed. Ones we have not accumulate visibly and
283
+ are picked up in the next cycle. The pile is the queue, and a deleted issue takes
284
+ its number — the one the CHANGELOG points at — with it.
285
+ - **A finding closes when behaviour changes**, not when it is understood.
286
+ - **A board row is measured against the tree, not read.** Rows have been found
287
+ already closed for two days, and rows whose text was true while the thing they
288
+ described had moved.
289
+
290
+ ---
291
+
292
+ ## What changed, by version
293
+
294
+ ### v1.45.0 — what a run leaves running, what "done" costs to say, what a check is for
295
+ Four rules the pipeline had been following by disposition rather than by doctrine.
296
+ **Residue**: eight classes of thing a run leaves running or leaves behind, enumerated
297
+ by class and never by one tool — the case that produced it was a task inventory
298
+ reporting *"No tasks found"* over a live, polling monitor. `holds: N` beside every
299
+ gate verdict, a fifth run-ledger line shape, and stage-10 criterion 13: end what this
300
+ run started, **report** what it did not. **Completion honesty**: *"done"* names what
301
+ makes it true, and the honest negative is a result. **Proportionate verification**:
302
+ the deliverable is the working result and the check is how you know — scaled to
303
+ `sev × blast`, never by cutting the floor. **The improvement iteration**: a published
304
+ issue resolves when behaviour changed and its close names the address; unworked ones
305
+ accumulate visibly rather than being triaged into silence. Guards: 275 → 291.
306
+
307
+ ### v1.44.0 — six lessons from other projects, and the guards that hold them
308
+ Six issues published by runs in other repositories were worked into doctrine:
309
+ seam testing at stage 6, `verified by` names that must resolve, a probe's green
310
+ being evidence only when the mutation is known to have landed, what a test case
311
+ consumes and why a timeout is unclassified, `publish:` as a line in the verdict
312
+ rather than a silence, and a ratchet's matcher being itself a check. Twelve new
313
+ guards; the suite reached 275. An independent review found eight further defects
314
+ in the implementation, all closed before merge.
315
+
316
+ ### v1.43.0 — the hand-back
317
+ Long iterations lose the original request. Stage 10 and every iteration boundary
318
+ now report TASK / PROGRESS / DONE / SURFACED with decisions and ambiguities
319
+ counted, traced by a `hand:` line in the run ledger.
320
+
321
+ ### v1.42.0 — the neighbour probe
322
+ Four consecutive releases had guards defeated by independent readers 15, 6, 6 and
323
+ 8 times, and the trend did not decline. The class: a check answered by text that
324
+ is not its subject. The mechanism, with its honest limit stated as a number.
325
+
326
+ ### v1.40.0 — the loop got a queue
327
+ `run.loop` previously said *how often* without ever naming *what* the loop walks.
328
+ The queue is stage 2's, and the loop arms on it.
329
+
330
+ ### v1.39.0 — findings-shaped work got an entry
331
+ Audits, bug hunts, production checks and PR reviews produce output that lands in
332
+ the repository, but the routing surface pointed away from them — agents quoted the
333
+ exclusion clause as their reason to refuse.
334
+
335
+ ---
336
+
337
+ ## Where to read further
338
+
339
+ | You want | Read |
340
+ |---|---|
341
+ | install it, use it | [`README.md`](README.md) |
342
+ | change it | [`CONTRIBUTING.md`](CONTRIBUTING.md) — the invariants live there |
343
+ | why a release happened | [`CHANGELOG.md`](CHANGELOG.md) |
344
+ | the stage doctrine itself | `plugins/task-pipeline/skills/task-pipeline/references/` |
345
+ | what is open | [`docs/superpowers/backlog.md`](docs/superpowers/backlog.md) |
346
+ | what is genuinely unresolved | [`docs/OPEN_QUESTIONS.md`](docs/OPEN_QUESTIONS.md) |
package/README.md CHANGED
@@ -20,6 +20,12 @@ Built for **Claude Code**, and installable into any agent that reads skills
20
20
  no companion plugin, nothing to resolve, nothing that breaks when a dependency is
21
21
  missing.
22
22
 
23
+ > **Want the machine rather than the pitch?**
24
+ > [**`HOW-IT-WORKS.md`**](HOW-IT-WORKS.md) is the living high-level view
25
+ > — what routes a request in, what each gate refuses to let past, why the manual
26
+ > gates sit where they do, and what makes any claim this pipeline prints
27
+ > believable. Rewritten every release.
28
+
23
29
  ---
24
30
 
25
31
  ## The flow
@@ -128,6 +134,7 @@ until it is installed.
128
134
  | 10 Acceptance | [`acceptance.md`](plugins/task-pipeline/skills/task-pipeline/references/acceptance.md) — REQ coverage table, evidence rules, the closing question |
129
135
  | 10 + any audit | [`audit.md`](plugins/task-pipeline/skills/task-pipeline/references/audit.md) — the L0→L7 ladder and its seams, axis rotation, ratchets, proven checks |
130
136
  | any loop | [`loop-guard.md`](plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md) — churn detection, caps, the break protocol |
137
+ | every gate + stage 10 | [`residue.md`](plugins/task-pipeline/skills/task-pipeline/references/residue.md) — what the run leaves **running** and leaves **behind**: eight classes enumerated by class rather than by one tool, `holds: N` beside every verdict, and a teardown that ends what this run started and only reports what it did not |
131
138
  | run-wide reporting | [`progress.md`](plugins/task-pipeline/skills/task-pipeline/references/progress.md) — the header block at task start and the one-line iteration close: the stage rail computed from the project's own `pipeline.json`, every number borrowed from the gate that measured it |
132
139
  | run-wide pacing | [`continuity.md`](plugins/task-pipeline/skills/task-pipeline/references/continuity.md) — the loop mode (`run.loop`, default off, never collapses a manual gate) and the context budget (fires on a harness signal, never on an estimate) |
133
140
  | the board between runs | [`backlog.md`](plugins/task-pipeline/skills/task-pipeline/references/backlog.md) — the work-list that outlives a run: seeded at stage 0 or picked up, priority **computed** from three stated inputs rather than assigned, and the seam where the carry-over ledger's `backlog` pointer finally resolves |
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.45.0 |
15
+ | **Version** | 1.46.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.45.0",
3
+ "version": "1.46.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"
@@ -17,6 +17,7 @@
17
17
  "cursor",
18
18
  "evals",
19
19
  "README.md",
20
+ "HOW-IT-WORKS.md",
20
21
  "SKILL-CARD.md",
21
22
  "LICENSE",
22
23
  "CHANGELOG.md",
@@ -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.45.0",
5
+ "version": "1.46.0",
6
6
  "author": {
7
7
  "name": "ssheleg",
8
8
  "url": "https://x.com/sshlg93"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: evidence-docs
3
- description: Applies the ten canons of evidence-backed documentation — what makes a claim documentation rather than an assertion — and routes to the doctrine that enforces each one. Use when writing or reviewing anything that will be read as true — a decision record, a README, an acceptance report, a runbook, a changelog entry, an audit finding, or any claim that something was verified. Also use when a project needs a documentation gate, a decision register, a propagation matrix, or a retrospective that outlives its author. Not for drafts, chat answers, commit messages or code comments.
3
+ description: "Use when writing or reviewing anything that will be read as true — a decision record, a README, an acceptance report, a runbook, a changelog entry, an audit finding, or any claim that something was verified. Applies the ten canons of evidence-backed documentation — what makes a claim documentation rather than an assertion — and routes to the doctrine that enforces each one. Also use when a project needs a documentation gate, a decision register, a propagation matrix, or a retrospective that outlives its author. Triggers - 'documentation gate', 'decision record', 'ADR', 'acceptance report', 'runbook', 'is this verified', 'доказательная документация', 'записать решение', 'отчёт о приёмке', 'раннбук', 'чем это подтверждено', 'доки в синхроне'. Not for: drafts, chat answers, commit messages or code comments — say 'без доков' to opt out."
4
4
  ---
5
5
 
6
6
  # Evidence-backed documentation
@@ -67,6 +67,7 @@ gate stops until it is installed.
67
67
  | **first run · the entry audit** (offered once) | `references/setup.md` |
68
68
  | **what travels with the bundle vs stays in a project** | `references/portability.md` |
69
69
  | any repeating loop | `references/loop-guard.md` |
70
+ | run-wide · what the run **leaves running and leaves behind** — every gate, and stage 10 | `references/residue.md` |
70
71
  | run-wide · what the run **prints about itself** — the rail, the iteration line | `references/progress.md` |
71
72
  | run-wide · how a run keeps going (the loop mode + the context budget) | `references/continuity.md` |
72
73
  | run-wide · the work-list **between** runs, and how its priority is computed | `references/backlog.md` |
@@ -248,7 +249,12 @@ Three things the grill does beyond clarifying the request:
248
249
  owns the conflict, re-plan the check as an ordered list, then go through it one
249
250
  item at a time; **when a pass is *searching* rather than editing and starts
250
251
  finding mostly what the previous pass's own fixes broke, the axis is exhausted —
251
- rotate it, don't look harder** (`references/audit.md`), and remember that a
252
+ rotate it, don't look harder** (`references/audit.md`); **every gate
253
+ prints `holds: N` — what this run left running** across the eight classes
254
+ (background shells, monitors, scheduled loops, coordination leases, worktrees,
255
+ containers, scratch files, remote state), enumerated **by class and never by a
256
+ single tool**, and stage 10 does not close while this run's residue is live and
257
+ unaccounted (`references/residue.md`); and remember that a
252
258
  green from a check nobody has watched fail is not evidence; task
253
259
  tracker + conventional commits per host conventions; worktree isolation for the
254
260
  build, integrated back per the brief's branch policy before stage 7; honest
@@ -277,7 +283,7 @@ capable available — see `references/model-tiering.md`).
277
283
  | 7 | Lint + deploy | lint clean + suite green before deploy; deploy needs a go (or the brief's specific standing authorization) | manual |
278
284
  | 8 | Post-deploy | 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 |
279
285
  | 9 | Docs + wiki | 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 |
280
- | 10 | **Acceptance** | 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 |
286
+ | 10 | **Acceptance** | 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)); **the environment is given back** — all eight classes enumerated, what this run started ended and verified by re-enumerating rather than by the teardown's reply, an earlier run of this project ended only when **provably spent**, anything this project does not own reported rather than ended, written as a `holds:` line (`references/residue.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** ; **every disclosure 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 |
281
287
 
282
288
 
283
289
  ### Stage 10 in a project of several repositories
@@ -201,6 +201,7 @@ ledger's, so a list that quietly grew back is visible at the moment it happened:
201
201
  GATE 10 acceptance: PASS — 14/14 REQ verified
202
202
  carry-over: 0 unresolved · retro: 7 standing (was 9) · retired 3 · added 1
203
203
  abstained: 2 (1 partial · 1 cannot-verify) · unlooked: 3 dormant
204
+ holds: 10 — none — enumerated 8/8 classes
204
205
  ```
205
206
 
206
207
  ## A `verified by` name is a claim until it resolves
@@ -280,7 +281,7 @@ All of:
280
281
  ledger or here) and, for `deferred`, a tracker entry.
281
282
  8. **No carry-over row is left `unresolved`** — every one has a home, and the
282
283
  ledger's counts are printed with this verdict, not just filed.
283
- 7a. **Both disclosures are printed** ([`gates.md`](gates.md) → *Disclosures*):
284
+ 7a. **Every disclosure is printed** ([`gates.md`](gates.md) → *Disclosures*):
284
285
  `abstained` — every REQ closing `partial`, every `unknown`, every ⚠️ *cannot verify
285
286
  from diff* the controller could not resolve — and `unlooked`, every check that
286
287
  reported `dormant` or `skip`. They are **not** ratchets: no floor, no direction, and
@@ -310,6 +311,15 @@ table substitute for that answer.
310
311
  its four registers with their ids. A run that cannot say what happened has not
311
312
  finished; it has stopped. This file is the one stage 10 opens, and it carried every
312
313
  other criterion while omitting this one for a release.
314
+ 13. **The run has given the environment back** ([`residue.md`](residue.md)) — all
315
+ eight classes enumerated **by class, never by one tool**, everything this run
316
+ started ended in dependency order, each teardown verified by **re-enumerating
317
+ rather than by the teardown's own reply**, and the result written as a `holds:`
318
+ line. `holds:` reaching zero is required here and **only** here. An item left
319
+ standing on purpose passes with its owner and reason named; an item **this project
320
+ does not own** is **reported, never ended** — the inventory is machine-wide and
321
+ the authority is not. An earlier run of *this* project is a third case, ended only
322
+ when provably spent ([`residue.md`](residue.md) → *Three owners*).
313
323
 
314
324
 
315
325
  ## When the answer is "something's missing"
@@ -35,6 +35,7 @@ elsewhere and is not restated here:
35
35
  - A green probe is evidence only if the mutation is known to have landed
36
36
  - The false-positive budget
37
37
  - Ratchets
38
+ - The result is the goal; the check is how you know
38
39
  - Disclosures — counted like a ratchet, and deliberately not monotone
39
40
  - Where a gate runs
40
41
  - Adding a check to an existing gate
@@ -451,6 +452,49 @@ GATE 9 docs: PASS — propagation backlog: 121 (was 162) · unmarked residue: 0
451
452
 
452
453
  A ratchet nobody prints is a TODO with a better name.
453
454
 
455
+ ## The result is the goal; the check is how you know
456
+
457
+ Everything else in this file pushes one way: prove more, assume less. Read alone it
458
+ has an obvious failure mode — a run that spends its afternoon proving a
459
+ one-character change and never ships the thing it was asked for. **The deliverable
460
+ is the working result, as described in the brief. A check is how the run knows it
461
+ has one. A check that is not buying that knowledge is not diligence; it is the run
462
+ optimising the wrong thing.**
463
+
464
+ **Scale the check to what breaking costs, and the project already computes that.**
465
+ The board ranks by `sev × blast` ([`backlog.md`](backlog.md)). The same two inputs
466
+ size the verification:
467
+
468
+ | What breaking costs | What the check has to be |
469
+ |---|---|
470
+ | an outward, irreversible or shared-state effect — deploy, publish, a lease, another agent's file | proven: watched failing against a planted defect, and re-read rather than trusted from the reply |
471
+ | a contract other code depends on | an executed test, named in the REQ row |
472
+ | behaviour a person will see | observed on the surface — a browser, the actual output — not inferred from a diff |
473
+ | a typo, a comment, a rename the compiler checks | the compiler, the suite already running, and nothing more |
474
+
475
+ **Four things that mean you have crossed over**, and each has cost this project a
476
+ run:
477
+
478
+ - **A third pass over the same axis finds mostly what the last pass's fixes broke.**
479
+ The axis is exhausted — rotate it or stop ([`audit.md`](audit.md)).
480
+ - **The check is being widened after it went green**, with no failure in hand. A
481
+ check widened by imagination is a check whose scope nobody has measured.
482
+ - **The evidence is being gathered for a claim nobody made.** If no REQ row and no
483
+ gate criterion asks for it, it is not evidence — it is browsing.
484
+ - **The run is on its second measurement of the same number.** One measurement plus
485
+ what it does not cover, stated, beats two measurements and no decision.
486
+
487
+ **This never licenses skipping a gate.** The gates are the floor, and the floor is
488
+ not proportionate to anything — a `manual` gate waits, `unknown` fails stage 10, and
489
+ a green nobody watched fail is not evidence at any blast radius. What is
490
+ proportionate is the work *above* the floor: how many axes, how many passes, how
491
+ much of the corpus. Cutting the floor to go faster is not speed; it is the failure
492
+ this whole file exists to prevent, arriving on schedule.
493
+
494
+ **Where it is recorded.** Stages 3 and 4 carry a `Cost:` line —
495
+ `<surfaces>/<guards>/<REQ> now, <…> at stage 2 — <proportionate | grown, and why>`.
496
+ *Grown, and why* is the honest answer often enough that it is written into the form.
497
+
454
498
  ## Disclosures — counted like a ratchet, and deliberately not monotone
455
499
 
456
500
  A ratchet may only shrink. **Some numbers must not be**, and printing them under a
@@ -471,12 +515,13 @@ column and it reappears in the other, silently, because a wrong claim looks like
471
515
  So a **disclosure** is printed beside the verdict like a ratchet and carries the opposite
472
516
  rule: **no floor, no direction, and a movement in either direction wants one sentence.**
473
517
 
474
- Two disclosures, kept separate because they are different facts:
518
+ The disclosures below are kept separate because they are different facts — the list is the count:
475
519
 
476
520
  | Disclosure | Counts | Reading it |
477
521
  |---|---|---|
478
522
  | `abstained: N` | claims the run **declined to make** — `partial`, `unknown`, `cannot verify from diff` | a *choice*. Rising can mean the work got harder or the run got honest; falling can mean either the reverse |
479
523
  | `unlooked: N` | checks that **did not look** — `dormant`, `skip` | a *state of the corpus*, not a decision. It falls as the project grows the inputs those checks need |
524
+ | `holds: N` | what the run left **running or lying about** — the eight classes in `references/residue.md` | a *state of the environment*, not of the corpus or of the run's claims. A legitimate 2 during a build beats a manufactured 0; only stage 10 requires it to reach zero or name an owner per item |
480
525
 
481
526
  Three are deliberately **not** counted, and saying which is part of the disclosure:
482
527
 
@@ -53,6 +53,7 @@ a row pointing outside the bundle is the defect this file exists to catch.
53
53
  | The ladder, seams, axis rotation, ratchets | `references/audit.md` |
54
54
  | Loop detection and its caps | `references/loop-guard.md` |
55
55
  | **What the run prints about itself** — the header block, the rail, the iteration line | `references/progress.md` |
56
+ | **What the run leaves running and leaves behind** — the eight classes, the `holds:` field, the teardown | `references/residue.md` |
56
57
  | **The run mode** — item-by-item pacing, default off, what it never collapses | `references/continuity.md` |
57
58
  | **The context budget** — the evidence rule and what a flush actually updates | `references/continuity.md` |
58
59
  | **The board** — the work-list between runs, its computed priority, and the ledger seam it resolves | `references/backlog.md` |
@@ -26,8 +26,10 @@ maintains them and the next run reads them as current.
26
26
  - The rail is computed, never eleven
27
27
  - What each glyph means
28
28
  - The hand-back — what the operator reads when you stop
29
+ - "Done" is a claim, and it names what makes it true
29
30
  - Every number is borrowed
30
31
  - Absent is a word, never a zero
32
+ - The `holds:` line — what the run is still holding
31
33
  - The run ledger this reads from
32
34
  - Rationalizations
33
35
 
@@ -215,6 +217,38 @@ nothing was unclear. Where a project keeps no open-questions register, that row
215
217
  `— no register` rather than `0`: an absent register and an empty one are different facts,
216
218
  and the second is the one worth acting on.
217
219
 
220
+ ## "Done" is a claim, and it names what makes it true
221
+
222
+ Every disclosure in this bundle answers *what does it print when it did not look?*
223
+ That question is asked of **checks**. It has to be asked of the run's own sentences
224
+ too, because the sentence reaches the operator and the check does not.
225
+
226
+ **A completion claim names what makes it true, or it is not a completion claim.**
227
+ `done: the export writes UTF-8` is a claim. `done: the export writes UTF-8 —
228
+ `test_export_encoding` green at 5f21ac3` is a report. The difference is not
229
+ politeness; it is whether anyone can disagree with you.
230
+
231
+ Three ways a run reports something it did not do, none of them requiring an
232
+ intention to mislead:
233
+
234
+ | The shape | What was actually true | What to write instead |
235
+ |---|---|---|
236
+ | **The plan reported as the outcome** — "added the retry" after writing the code and before running anything | the edit landed | `done` names the executed test, or the item is not `done` |
237
+ | **The reply reported as the result** — a deploy, a teardown, a cancel, an API call that returned success | the call was accepted | re-read the state; the second look is the evidence, the reply is not |
238
+ | **The part reported as the whole** — "tests pass" after running the file you touched | that file's tests pass | say which suite, or run the full one |
239
+
240
+ **And the honest negative is a result.** *"Not done — the fixture needs a
241
+ credential I do not have"* is a complete, useful report. *"Done (with a small
242
+ caveat)"* for the same situation is not. A run that cannot finish something says
243
+ so at the boundary it reached, names what would unblock it, and moves to the next
244
+ item — `deferred` and `partial` exist as statuses precisely so that stopping does
245
+ not have to be dressed up as finishing.
246
+
247
+ **The status vocabulary is closed for the same reason.** Stage 10 takes
248
+ `verified`, `partial`, `deferred`, `dropped` — and `unknown` fails the gate
249
+ ([`acceptance.md`](acceptance.md)). A fifth word invented at write-time is how a
250
+ run reports a state nobody agreed to read.
251
+
218
252
  ## Every number is borrowed
219
253
 
220
254
  | Field | Its home |
@@ -250,6 +284,33 @@ is unconfirmed*, which is the opposite claim, and it is the same inversion
250
284
  `carry-over 0 rows` **is** a real zero and prints as one: the ledger exists and holds
251
285
  nothing.
252
286
 
287
+ ## The `holds:` line — what the run is still holding
288
+
289
+ Beside every gate verdict the run prints `holds: N` — the environment it has not
290
+ given back. It lands in the ledger as a `holds:` line
291
+ ([`../templates/run.md`](../templates/run.md)), one per gate that found anything,
292
+ and one at stage 10 whatever the count.
293
+
294
+ ```
295
+ holds: 5 — 2 (worktree: build-csv-export, this run; container: pg-test, this run) — enumerated 8/8 classes
296
+ holds: 10 — none — enumerated 7/8 classes, unlooked: containers (no docker on this host)
297
+ ```
298
+
299
+ Three things make the line worth writing rather than a habit:
300
+
301
+ - **It names the class and the owner, not just a number.** *"2"* tells the next
302
+ run nothing; *"worktree, this run"* tells it what to end and what to leave.
303
+ - **It records how many classes were enumerated.** `8/8` and `7/8, unlooked:
304
+ containers` are different facts, and a run without container tooling must print
305
+ the second rather than a clean zero it did not earn.
306
+ - **It is a disclosure, never a ratchet.** No floor, no direction, no target. A
307
+ build stage legitimately holding a worktree and a database prints `2` and
308
+ passes; a run that tears its database down to make the number tidy and brings
309
+ it back up next stage has spent time making a measurement lie.
310
+
311
+ Doctrine, including the eight classes and what must **not** be torn down:
312
+ [`residue.md`](residue.md).
313
+
253
314
  ## The run ledger this reads from
254
315
 
255
316
  `.task-pipeline/run.md`, seeded at stage 0 from
@@ -0,0 +1,219 @@
1
+ # Residue — what a run leaves running, and what it leaves behind
2
+
3
+ A run does not only produce a diff. It starts background processes, arms
4
+ monitors, schedules wake-ups, takes leases, creates worktrees, brings up
5
+ containers and writes scratch files. Every one of those outlives the stage that
6
+ created it unless something ends it.
7
+
8
+ **Two shapes, one class.** *Residue in flight* is what is still running while the
9
+ run continues — it corrupts the work, because a stale monitor fires into a run
10
+ that has moved on and a lease held by a finished stage blocks the next one.
11
+ *Residue at rest* is what is still there when the run ends — it corrupts the next
12
+ run, which inherits a dirty environment it did not create and cannot explain.
13
+
14
+ Both are checked the same way and this file covers both.
15
+
16
+ ## Contents
17
+
18
+ - The measured reason this file exists
19
+ - The inventory — eight classes
20
+ - Where the check fires: every gate
21
+ - The teardown, at the end of the run
22
+ - What must **not** be torn down
23
+ - Three owners, not two — and the third is where cleanup actually happens
24
+ - Rationalizations
25
+
26
+ ---
27
+
28
+ ## The measured reason this file exists
29
+
30
+ On 2026-08-11, mid-run, a monitor was armed to watch CI. One minute later the
31
+ harness task inventory was queried:
32
+
33
+ ```
34
+ TaskList → "No tasks found"
35
+ ps -eo pid,etime,cmd → 52693 03:12 /bin/zsh -c … gh pr checks …
36
+ ```
37
+
38
+ The monitor was **alive and polling**, and the inventory tool reported nothing.
39
+
40
+ This is the class this whole doctrine exists to catch: **a check answered by
41
+ something that is not its subject.** An inventory that does not enumerate the
42
+ thing that leaks is not an inventory — it is a green light with no lamp behind
43
+ it. A residue check that calls one tool and trusts its silence will report clean
44
+ over a process that is still making network calls.
45
+
46
+ **So: enumerate by class, never by tool.** Each class below names its own
47
+ enumeration. Silence from one tool is evidence about that tool, not about the
48
+ environment.
49
+
50
+ ---
51
+
52
+ ## The inventory — eight classes
53
+
54
+ Run the enumeration for every class that the run could have created. A class the
55
+ run provably never touched is skipped **by name**, not by omission.
56
+
57
+ | Class | What leaks | How to enumerate |
58
+ |---|---|---|
59
+ | **Background shells** | a task started detached and never exited | the harness's background-task list **and** `ps -eo pid,ppid,etime,command` filtered to this session's shell |
60
+ | **Monitors / watchers** | a poll loop still hitting a remote API | `ps` for the poll command; the harness list may not contain it — see above |
61
+ | **Scheduled wake-ups / loops** | a loop that fires into a finished run | the harness's schedule list; a dynamic loop ends by an explicit stop, never by falling silent |
62
+ | **Coordination leases** | a lease held on a shared register blocks every other agent | `agent-sync status` where `.claude/agent-sync.json` exists |
63
+ | **Worktrees / branches** | an isolated build workspace, and the branch under it | `git worktree list`, `git branch --merged` |
64
+ | **Containers / services** | a database or app brought up for a test | `docker ps`, `docker compose ls`, plus whatever the project's own runbook started |
65
+ | **Scratch files** | temp output, planted-defect copies, generated fixtures | `git status --porcelain` for the tree; the scratch directory for the rest |
66
+ | **Remote state** | a draft PR, a test tag, an uploaded artifact, a feature flag flipped for a check | the tracker and forge; the deploy target's own listing |
67
+
68
+ Two of these bite hardest and are worth naming separately.
69
+
70
+ **A lease is the one that blocks someone else.** Every other class costs this run
71
+ or the next one. A held lease costs a *different agent*, right now, and it looks
72
+ to them like the register is permanently unavailable rather than briefly held.
73
+ Release it at the stage that took it — not at the end.
74
+
75
+ **A container is the one that is invisible and expensive.** Nothing in the diff
76
+ mentions it, no test fails because of it, and it will still be running tomorrow.
77
+
78
+ ---
79
+
80
+ ## Where the check fires: every gate
81
+
82
+ **The residue check is a criterion of every gate, not a stage of its own.** A
83
+ cleanup stage at the end is the design that fails, because the damage from
84
+ residue in flight has already happened by the time the end arrives.
85
+
86
+ Every gate verdict carries the count, in the same line as the rest:
87
+
88
+ ```
89
+ GATE 5 build: PASS — reviews 3 · findings 0 open · holds: 2 (worktree, container)
90
+ abstained: 0 · unlooked: 0
91
+ GATE 6 tests: PASS — suite green · holds: 1 (container: pg-test, this run)
92
+ abstained: 0 · unlooked: 0
93
+ ```
94
+
95
+ Read the line the way the other disclosures on it are read:
96
+
97
+ - **`holds: 0`** — every class enumerated, nothing found.
98
+ - **`holds: N (…)`** — N things are live, each named. This is a **disclosure,
99
+ not a failure**. A build stage that legitimately holds a worktree and a database
100
+ reports `holds: 2` and passes; the count exists so nobody has to remember.
101
+ - **`holds: unlooked (…)`** — a class could not be enumerated, named. A run
102
+ without container tooling says so rather than printing `0`.
103
+
104
+ **Why the field is `holds:` and not `residue:`.** `gates.md` already prints
105
+ `unmarked residue: 0` for a different thing — documentation items left unmarked
106
+ — and `residue: 0` is a substring of it. A check written for this field would
107
+ have been answered by that line. The word stays in the prose because it is the
108
+ right word; the **field** is `holds:`, which is free and joins `stage:`,
109
+ `iter:`, `hand:` and `touch:` in the run ledger.
110
+
111
+ **Its sibling, one file over.** `tdd.md`'s *The green from residue* is the same
112
+ class on the test axis — state left over from an earlier run making a case pass
113
+ that would fail fresh. That rule is about residue **faking a result**; this one
114
+ is about residue **outliving the run**. Neither overrides the other.
115
+
116
+ **`holds: 0` is never a target.** A run that tears down its database to make a
117
+ number look tidy, and then brings it back up next stage, has spent time to make a
118
+ measurement lie. The number describes; it does not instruct.
119
+
120
+ **Only stage 10 requires the count to reach zero** — or every remaining item to
121
+ carry a named owner and a reason, in writing.
122
+
123
+ ---
124
+
125
+ ## The teardown, at the end of the run
126
+
127
+ Stage 10 does not close while this run's residue is live. Walk the inventory once
128
+ more, and for each item either end it or account for it:
129
+
130
+ 1. **Enumerate every class.** Not the ones you remember using — all eight, because
131
+ the one you forgot is the one still running.
132
+ 2. **End what this run started**, in dependency order: remote state first (a draft
133
+ PR or a flipped flag is visible to other people), then services, then
134
+ worktrees, then leases, then scratch files.
135
+ 3. **Verify each teardown by re-reading, not by the reply.** A cancel, delete or
136
+ teardown call will happily accept an id that was never scheduled and return
137
+ success. Enumerate again after tearing down; the second enumeration is the
138
+ evidence, the first reply is not.
139
+ 4. **Write what remains into the run ledger**, with its owner:
140
+
141
+ ```
142
+ holds: 10 — none — enumerated 8/8 classes
143
+ holds: 10 — 1 (container: pg-test, operator asked for it to stay) — enumerated 8/8 classes
144
+ ```
145
+
146
+ An item left standing on purpose is fine. An item left standing silently is how
147
+ the next run starts against a database somebody else's test seeded.
148
+
149
+ ---
150
+
151
+ ## What must **not** be torn down
152
+
153
+ **Tear down what this run started. Report what it did not.**
154
+
155
+ The inventory is machine-wide; the authority is not. Another session's monitor,
156
+ another agent's lease, a container that was up before this run began — killing
157
+ any of those is a run reaching outside its own boundary to make its own number
158
+ look better, and it will break work that is going fine.
159
+
160
+ - **If the run did not start it, it does not end it.** Name it in the ledger as
161
+ *foreign*, with whatever identifies its owner.
162
+ - **A lease held by another agent is never released by this run**, no matter how
163
+ stale it looks. Stale is a judgment; the holder is a fact.
164
+ - **Ambiguous ownership is reported, not resolved.** A worktree with no obvious
165
+ creator is `holds: 1 (worktree, owner unknown)` — which is honest — rather
166
+ than deleted, which is irreversible.
167
+
168
+ The asymmetry is deliberate: leaving something running costs a little, and killing
169
+ something someone else owns costs a lot.
170
+
171
+ ---
172
+
173
+ ## Three owners, not two — and the third is where cleanup actually happens
174
+
175
+ The rule above splits the world in two: what this run started, and what it did not.
176
+ **Dry-running this doctrine on its own project found the state it has no slot for.**
177
+
178
+ Measured 2026-08-11, enumerating the eight classes on a live run:
179
+
180
+ ```
181
+ worktrees/branches : 3 feature branches, all merged into main, from earlier runs
182
+ containers : 18 running, none started by this run, oldest 3 days,
183
+ across four unrelated projects
184
+ ```
185
+
186
+ The branches are not this run's, so *end what you started* does not reach them. They
187
+ are not foreign either — the project owns them, and reporting them every run forever
188
+ is how a report becomes wallpaper. So:
189
+
190
+ | Owner | What to do | Why |
191
+ |---|---|---|
192
+ | **this run** | end it, in dependency order | it exists because of work that is now finished |
193
+ | **an earlier run of this project** | end it **when it is provably spent**, and say you did — a branch merged into the default branch, a worktree with no diff, a scratch file from a completed run. Otherwise report it | this is the accumulation nobody is otherwise responsible for, and *provably spent* is a fact rather than a judgement |
194
+ | **anything else** | **report, never end** | see the section above; the asymmetry is not negotiable |
195
+
196
+ **"Provably spent" is the whole load-bearing phrase.** A branch merged into the
197
+ default branch is spent — `git merge-base --is-ancestor` says so, and nothing is lost
198
+ by removing it. A branch that merely *looks* abandoned is not spent, and the run that
199
+ deletes it is guessing about someone's work in progress. **If the proof needs a
200
+ judgement, the item is reported, not ended** — which puts it back under the rule
201
+ above rather than creating an exception to it.
202
+
203
+ **A foreign item never becomes spent.** The 18 containers above belong to other
204
+ projects; that they have been up for three days is information for whoever owns them,
205
+ not permission. The third owner state widens what a run may clean **inside its own
206
+ project** and widens nothing at all outside it.
207
+
208
+ ## Rationalizations
209
+
210
+ | The excuse | What it actually means |
211
+ |---|---|
212
+ | "The task list is empty, so nothing is running." | The measured case above: the list was empty and the process was polling. Silence from one tool is evidence about that tool. |
213
+ | "It will exit on its own." | Some do. The ones that leak are exactly the ones that do not, and you cannot tell which is which without enumerating. |
214
+ | "I will clean up at the end." | Residue in flight has already corrupted the run by then. That is why this is a gate criterion, not a final stage. |
215
+ | "The container is tiny." | Its cost is not its size. It is invisible, it holds state, and it will still be there tomorrow. |
216
+ | "I did not start any background work this stage." | Then the enumeration takes ten seconds and prints `holds: 0`. The cheap case is not the reason to skip the check. |
217
+ | "The lease is obviously stale." | Stale is your judgment about someone else's work. Report it; do not release it. |
218
+ | "Tearing it down returned success." | So does tearing down an id that never existed. Verify by re-enumerating. |
219
+ | "`holds: 0` looks better in the ledger." | Then the number has become a target and has stopped being a measurement. A legitimate 2 is worth more than a manufactured 0. |
@@ -41,6 +41,7 @@ file exists to stop.
41
41
  - The loop closes at stage 0
42
42
  - Where a lesson goes when it is not about this project
43
43
  - Publishing the insight — the skill learns from every project that runs it
44
+ - The improvement iteration — what happens to a published insight next
44
45
  - What may leave the project — the redaction list
45
46
  - Rationalizations
46
47
 
@@ -265,6 +266,7 @@ does ([`audit.md`](audit.md) → *What can't be fixed now becomes a ratchet, nev
265
266
  GATE 10 acceptance: PASS — 14/14 REQ verified
266
267
  carry-over: 0 unresolved · retro: 7 standing (was 9) · retired 3 · added 1
267
268
  abstained: 2 · unlooked: 3
269
+ holds: 10 — none — enumerated 8/8 classes
268
270
  ```
269
271
 
270
272
  A pruned list that nobody prints is a list that quietly grows back.
@@ -340,6 +342,49 @@ opening… → #24
340
342
  opened, and carry the exact text in the carry-over ledger. That is the honest
341
343
  degradation; a second transport is not.
342
344
 
345
+ ## The improvement iteration — what happens to a published insight next
346
+
347
+ Publishing is half a loop. An issue that is opened and never triaged is a lesson
348
+ that cost a run and bought nothing, and a tracker full of those teaches everyone
349
+ that publishing is where findings go to be filed.
350
+
351
+ **The loop, and every arrow in it is somebody's obligation:**
352
+
353
+ ```
354
+ a run diverges → a retro entry → retro.publish → an issue on the skill
355
+
356
+ a board row ← measured against the tree ← triaged in a later cycle
357
+
358
+ doctrine + the guard that proves it → a release → the next run reads it
359
+ ```
360
+
361
+ **Resolve what you worked, let the rest accumulate — visibly.** At the close of a
362
+ cycle that consumed published issues:
363
+
364
+ - **An issue closes when the behaviour changed**, not when the lesson was
365
+ understood (that is R-006, and it applies to issues exactly as it applies to
366
+ findings). The closing comment names **where** it landed — a file and a line —
367
+ and the guard that now holds it. A close with no address is a close nobody can
368
+ audit.
369
+ - **An issue nobody worked stays open.** It is not triaged into silence, not
370
+ relabelled, not closed as stale. The pile is the queue, and its depth is the
371
+ honest measure of how far behind the doctrine is.
372
+ - **Nothing is deleted.** A closed issue keeps its number, and the number is what
373
+ the CHANGELOG and the retro entry point at. Deleting one severs both, and the
374
+ cost lands on whoever next asks *why is this rule here*.
375
+
376
+ **Where the queue comes from at the start of a cycle**, in this order: open issues
377
+ published by any project running this skill, then the board's open rows by computed
378
+ priority, then the open-questions register. A run that finishes its brief early
379
+ takes the top of that list rather than inventing work — and a run that *cannot*
380
+ take it says so, which is a fuller queue rather than a quiet one.
381
+
382
+ **The measurement that keeps this honest.** Print, at the close: issues consumed,
383
+ issues resolved with an address, issues left open. Three numbers, no floor, no
384
+ target, and the third one rising is information rather than a failure — it means
385
+ the projects running this skill are finding more than one cycle can absorb, which
386
+ is what you want them to do.
387
+
343
388
  ## What may leave the project — the redaction list
344
389
 
345
390
  An issue is a **public artefact in someone else's repository**. What travels is the
@@ -430,7 +430,7 @@ never that the work was skipped quietly.
430
430
  is covered; no `skip`/`xfail` smuggling a red suite past the gate. Never advance
431
431
  to deploy on a red or partial run. **The carry-over count is printed beside this
432
432
  verdict** — a ratchet nobody prints is a TODO with a better name
433
- ([`audit.md`](audit.md)) — **and so are the two disclosures**, `abstained` and
433
+ ([`audit.md`](audit.md)) — **and so are the disclosures**, `abstained` and
434
434
  `unlooked` ([`gates.md`](gates.md) → *Disclosures*): what the run declined to claim,
435
435
  and what a check never looked at. Neither has a floor and neither may be targeted; a
436
436
  target on an abstention count is an instruction to guess.
@@ -656,7 +656,12 @@ never that the work was skipped quietly.
656
656
  surfaced that nobody asked for, every decision still waiting **asked here with
657
657
  options rather than listed**, and the ambiguity count computed from the four
658
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
659
+ that cannot say what happened has not finished, it has stopped; **the environment is
660
+ given back** — all eight classes enumerated, everything this run started ended and
661
+ verified by re-enumerating rather than by the teardown's reply, an earlier run of
662
+ this project ended only when **provably spent**, an item this project does not own
663
+ reported rather than ended, and the result written as a `holds:` line
664
+ ([`residue.md`](residue.md)); **every disclosure printed beside the verdict** — `abstained` (what the run declined
660
665
  to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither
661
666
  with a floor, neither ever a target ([`gates.md`](gates.md) → *Disclosures*); **the
662
667
  retrospective is written — stamped first, then pruned, then the entry; the
@@ -20,6 +20,7 @@ stage: <id> <name> — gate <auto|manual> — verdict <pass|fail|skip> — <ISO-
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
22
  hand: <N|10> — task "<quoted>" — done <n> — surfaced <n> — decisions <n> — amb <n> (<ids or "— no register">)
23
+ holds: <stage id> — <n> (<class: what, owner>; … or "none") — enumerated <n>/8 classes, <unlooked: classes not enumerable>
23
24
  ```
24
25
 
25
26
  - **`stage:`** — written when a gate **returns**, not when the stage is entered. The
@@ -53,6 +54,8 @@ touch: src/export.ts — pass 1 (stage 5) — reason: TASK-3
53
54
  touch: src/export.ts — pass 2 (stage 5) — reason: F-014
54
55
  touch: src/export.ts — pass 3 (stage 5) — reason: F-014
55
56
  hand: 3 — task "add CSV export to the orders table" — done 2 — surfaced 1 — decisions 1 — amb 2 (OQ-0007, ledger row 4)
57
+ holds: 5 — 2 (worktree: build-csv-export, this run; container: pg-test, this run) — enumerated 8/8 classes
58
+ holds: 10 — none — enumerated 7/8 classes, unlooked: containers (no docker on this host)
56
59
  ```
57
60
 
58
61
  The last two lines are a **trip**: the same file, two consecutive passes, the same