task-pipeline-skill 1.26.0 → 1.28.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 +87 -0
- package/CONTRIBUTING.md +24 -1
- package/SKILL-CARD.md +1 -1
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/commands/task-pipeline.md +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +3 -2
- package/plugins/task-pipeline/skills/task-pipeline/references/acceptance.md +10 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/audit.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/gates.md +67 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +31 -4
- package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +9 -3
- package/plugins/task-pipeline/skills/task-pipeline/templates/carryover.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.28.0
|
|
4
|
+
|
|
5
|
+
### Eight ways to say "I don't know", and no way to count them
|
|
6
|
+
|
|
7
|
+
This bundle has eight vocabularies for declining to claim — `partial`, `unknown`,
|
|
8
|
+
`cannot verify from diff`, `review`, `dormant`, `skip`, `recalled`, `ungated` — spread
|
|
9
|
+
across sixteen reference files. Only one of them, `unknown`, blocks anything. **None of
|
|
10
|
+
them appeared beside a verdict**, and `grep` for a counter returned zero.
|
|
11
|
+
|
|
12
|
+
So `PASS` read as *verified*. It never read as *"green, and here is what nobody claimed
|
|
13
|
+
and what nothing looked at"*, which is the only thing a gate can honestly mean.
|
|
14
|
+
|
|
15
|
+
**The obvious fix is a ratchet, and it is wrong.** A ratchet may only shrink. A count of
|
|
16
|
+
abstentions under that rule puts pressure on exactly one thing: **claiming more**. A run
|
|
17
|
+
that reaches `abstained: 0` is not more careful — it has stopped saying *I don't know*,
|
|
18
|
+
which is the cheapest way to make the number fall. Refusals and wrong answers are
|
|
19
|
+
communicating vessels; squeeze one column and it reappears in the other, silently, because
|
|
20
|
+
a wrong claim looks like a claim.
|
|
21
|
+
|
|
22
|
+
`gates.md` therefore gains a second kind of counted set — a **disclosure**. Printed beside
|
|
23
|
+
the verdict exactly like a ratchet, and carrying the opposite rule: **no floor, no
|
|
24
|
+
direction, and never a target.** A target on an abstention count is an instruction to guess.
|
|
25
|
+
|
|
26
|
+
Two of them, kept apart because they are different facts:
|
|
27
|
+
|
|
28
|
+
| | Counts | How to read it |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `abstained` | 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 |
|
|
31
|
+
| `unlooked` | checks that **did not look** — `dormant`, `skip` | a **state of the corpus**, not a decision; it falls as the project grows the inputs |
|
|
32
|
+
|
|
33
|
+
`recalled` and `ungated` are deliberately not counted: the first is a property of one claim
|
|
34
|
+
and already lives in the ledger, the second a property of the whole run and said once in
|
|
35
|
+
words. Collapsing all eight into one number would be the false precision this change exists
|
|
36
|
+
to avoid — a figure nobody can act on.
|
|
37
|
+
|
|
38
|
+
Both print beside every worked verdict in the doctrine, both are required by the stage-6 and
|
|
39
|
+
stage-10 gates, and a guard holds the four verdict formats together — one statement on four
|
|
40
|
+
surfaces is this repository's most recurrent defect.
|
|
41
|
+
|
|
42
|
+
**Where this came from.** The programme that produced it started from a review of the
|
|
43
|
+
hallucination-mitigation literature, whose one directly importable idea was that
|
|
44
|
+
*uncertain refusals* belong in the results table **next to** factual errors, because the two
|
|
45
|
+
trade off. Everything else in that literature the doctrine already had. This is the import.
|
|
46
|
+
|
|
47
|
+
## v1.27.0
|
|
48
|
+
|
|
49
|
+
### A retirement trigger whose counter only some work moves
|
|
50
|
+
|
|
51
|
+
A standing instruction retires when it has not fired **in the last five run stamps**. A run
|
|
52
|
+
stamp is written by a run *of this pipeline*. Those two facts are fine apart and defective
|
|
53
|
+
together: where a project ships some of its work another way, the counter stops while the
|
|
54
|
+
work does not, so "the last five stamps" spans an arbitrary amount of change.
|
|
55
|
+
|
|
56
|
+
Measured on this repository: **ten consecutive releases, `v1.16.0` through `v1.23.0`, carry
|
|
57
|
+
no stamp at all** — four of the last fourteen tags moved the counter. Across that stretch the
|
|
58
|
+
trigger was not strict and not lenient. It was **unreadable**, and a list capped at ten whose
|
|
59
|
+
retirement condition cannot be read fills up and stops being pruned. That is the whole failure
|
|
60
|
+
mode: not a wrong answer, an absent one.
|
|
61
|
+
|
|
62
|
+
**The condition now carries a second unit — sixty days — and it is not belt-and-braces.** The
|
|
63
|
+
stamp count is the better signal while the pipeline is in use; the calendar is the one that
|
|
64
|
+
still works when it is not, which is precisely the state in which a stale rule does the most
|
|
65
|
+
damage. Both units are stated on every surface that states the condition, and a guard holds
|
|
66
|
+
them together: correcting the rule where somebody was looking and leaving it everywhere else
|
|
67
|
+
is the class `v1.24.0` shipped a guard for.
|
|
68
|
+
|
|
69
|
+
Entry **rotation** — *entries older than five stamps move to the archive* — is a different
|
|
70
|
+
mechanism and is deliberately out of scope, said in the guard's own comment so the exclusion
|
|
71
|
+
is a decision rather than an oversight.
|
|
72
|
+
|
|
73
|
+
### The ten releases are recorded, not stamped
|
|
74
|
+
|
|
75
|
+
`docs/superpowers/retro.md` now carries the gap as a section, with the command that produces
|
|
76
|
+
it. **No stamps were written for those ten releases.** A stamp asserts that a run happened and
|
|
77
|
+
that its gates were walked; writing ten to make the table continuous would be the exact defect
|
|
78
|
+
this file exists to catch, committed in the file that catches it.
|
|
79
|
+
|
|
80
|
+
Two consequences are stated there rather than left to be rediscovered: the cold trigger was
|
|
81
|
+
unreadable across that stretch, and the lessons of those releases live in `CHANGELOG.md` and
|
|
82
|
+
nowhere the next run's stage 0 looks — which is why rules 17–21 of `learned.md` sat outside
|
|
83
|
+
the *Where these bind* map until `v1.23.1` found them.
|
|
84
|
+
|
|
85
|
+
**A correction to this program's own ledger, made at the moment of use.** Its first row said
|
|
86
|
+
*"seven releases (v1.17.0–v1.23.0)"*. Re-measured before being acted on: **ten**, reaching
|
|
87
|
+
back to `v1.16.0`. The original was a filtered subset that had lost its filter — `learned.md`
|
|
88
|
+
rule 16, in the ledger of the run that ships rule 16's neighbours.
|
|
89
|
+
|
|
3
90
|
## v1.26.0
|
|
4
91
|
|
|
5
92
|
### A green suite is not a rendered page
|
package/CONTRIBUTING.md
CHANGED
|
@@ -306,7 +306,30 @@ copies are used, which is what makes this `learned.md` rule 20 rather than a sty
|
|
|
306
306
|
Found while adding `chrome-devtools`, which would have been the first to drift.
|
|
307
307
|
*(guard: `a companion is in the matrix and not in the `)*
|
|
308
308
|
|
|
309
|
-
**37.
|
|
309
|
+
**37. The cold-retirement condition carries both its units on every surface that states
|
|
310
|
+
it.** A standing instruction retires when it has not fired in five run stamps **or** in sixty
|
|
311
|
+
days. The stamp counter is written only by a run of this pipeline, so where a project ships
|
|
312
|
+
some of its work another way the counter stops while the work does not — measured here, ten
|
|
313
|
+
consecutive releases (`v1.16.0`–`v1.23.0`) carry no stamp, and across that stretch the trigger
|
|
314
|
+
was neither strict nor lenient but **unreadable**. A list capped at ten whose retirement
|
|
315
|
+
condition cannot be read fills up and stops being pruned. The calendar is the unit nothing can
|
|
316
|
+
stall, which is why it is not belt-and-braces. Entry **rotation** ("entries older than five
|
|
317
|
+
stamps move to the archive") is a different mechanism and is deliberately out of scope.
|
|
318
|
+
*(guard: `states the cold-retirement condition as five run stamp`)*
|
|
319
|
+
|
|
320
|
+
**38. Every worked GATE verdict prints both disclosures.** `abstained` — what the run
|
|
321
|
+
declined to claim — and `unlooked` — what a check never looked at. Without them a `PASS`
|
|
322
|
+
reads as *verified* rather than as *"green, and here is what nobody claimed"*. They are
|
|
323
|
+
**not** ratchets and the distinction is load-bearing: a ratchet may only shrink, and an
|
|
324
|
+
abstention count under that rule pressures exactly one thing — claiming more. A run
|
|
325
|
+
reporting `abstained: 0` is not more careful; it stopped saying *I don't know*. Refusals
|
|
326
|
+
and wrong answers are communicating vessels, so a disclosure has no floor, no direction,
|
|
327
|
+
and **may never be given a target** — a target on an abstention count is an instruction to
|
|
328
|
+
guess. This repository had eight vocabularies for declining to claim and, until v1.28.0,
|
|
329
|
+
zero counters.
|
|
330
|
+
*(guard: `a worked GATE verdict omits `)*
|
|
331
|
+
|
|
332
|
+
**39. Every invariant above names the guard that enforces it, and that guard exists.**This list claims to be *what the validator enforces*; it was eight guards behind when
|
|
310
333
|
an audit measured it. A claim of enforcement is now checked like any other claim.
|
|
311
334
|
*(guard: `whose message does not appear in`)* — and a cited literal must lie inside
|
|
312
335
|
a **single** string in `test/validate.py`: the check reads that file as text, so a
|
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.
|
|
15
|
+
| **Version** | 1.28.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.
|
|
3
|
+
"version": "1.28.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 must close with evidence, a loop guard that breaks churn, one provider-agnostic model confirmed up front, and an optional super-ux UX track for user-facing work.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.28.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -31,7 +31,7 @@ language, ADRs for hard-to-reverse calls) and covering the **autonomy sweep** (w
|
|
|
31
31
|
would otherwise stop stages 1→10: docs sources incl. doc repos, the wiki and the code graph, branch/tracker
|
|
32
32
|
policy, test and lint commands, deploy target and authorization, log locations, docs/wiki/graph targets, and for UI tasks whether the design is done visually in Figma or text-only, whether the Figma MCP is connected, and — if it isn't — whether to ship text-only or stop and connect it, since the UX chain degrades on its own and never blocks; **and with Figma on, the design destination: which team/org by name and which file** — the recorded one, a URL the operator gives, or creation in that named team explicitly authorized, written into the project's canonical record before the first frame, because a destination decided at drawing time is how a project ends up with three design files and no way to tell which is real. **Never create while a recorded file resolves; if it doesn't resolve, stop and ask — never create a replacement**) —
|
|
33
33
|
until the brief is locked — including the **REQ table**, the request as an addressable list where every row names how it is verified — so the rest runs autonomously and the final stage can account for all of it. The list is frozen: adding is free, removing needs the operator's agreement. Anything deferred goes into the carry-over ledger the moment it's said. For any user-facing task, recommend/use
|
|
34
|
-
**super-ux**. **If the brief describes a platform rather than a change**, stage 2 also cuts it into modules (`references/decomposition.md`) — module map committed, walking skeleton first, every REQ in exactly one module — and stages 3→10 then run per module, one brick at a time. **If any loop starts undoing an earlier pass** (same file edited twice for the same reason, a closed finding returning, a third entry into one stage), stop and run the loop guard (`references/loop-guard.md`): name both shapes, escalate to the layer that owns the conflict, re-plan the check as an ordered list, then go item by item. **The closing stage opens with the ladder walk** (`references/audit.md`): the REQ table finds what was named and lost, but a comparison needs two sides and an absence has one — so walk each REQ bottom-up through its rungs (decision → spec section → contract *and its failure behavior* → task → change → executed test → surface/docs), check the seam at each step, order findings by seam rather than by file, and turn every absence into a new REQ row **before** the coverage table is written. A green from a check nobody has watched fail against a planted defect is not evidence; a finding class seen twice becomes a script rather than a third ledger row; and the carry-over ledger's counts are printed beside every gate verdict, so "green" never reads as "verified". If a searching pass starts finding mostly what the previous pass's own fixes broke, the axis is exhausted — rotate it, don't look harder. **The docs stage closes three artifacts, not two:** module docs, the wiki, **and the code graph** (`/graphify . --update` where `graphify-out/` exists — `references/knowledge-graph.md`), because the graph is what the next run's harvest queries first and a stale one is a false premise carrying the authority of a machine. Then check the graph against the docs: a hub `graphify god-nodes` reports that no document names is an undocumented seam; an edge the docs deny is a leak in the code or a lie in the docs; a doc naming a module the graph no longer has is stale. Doc-side findings are fixed there, absences become REQ rows in the closing stage. **In a project of several repositories, stage 10 closes on the parent too:** a parent records each submodule as a pointer to one commit, and moving the submodule does not move the pointer — so the work can be committed, pushed and green while a clone of the parent still gets the commit before it. Neither repo looks wrong alone, which is why it survives every check that runs inside one. Require `git submodule status` with no line starting `+`, and every repo clean and pushed (`git -C <repo> status --porcelain`, `git -C <repo> log @{u}..HEAD`). The fix is two commands and the second gets forgotten: push the submodule, then `git add <submodule> && git commit`. **The run's last act is the retrospective** (`references/retrospective.md` → `docs/superpowers/retro.md`, one file per project): **stamp the run first** (its commit is what makes the cold-retirement trigger computable), **then prune** — every standing instruction against its three retirement triggers (it became a check; the paths/commands it names are gone; it hasn't fired in five run stamps), the list held to a hard cap of ten, every deletion logged as one line and never silent — 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 fix by grade (mechanical check > standing instruction > note that expires in two runs), and the check that catches it next time. Stage 0 reads those standing instructions in full, so the prune is a gate criterion, not a good intention: a rule nobody reads to the end is worse than no rule, because everyone believes it is covered. Honor every stage gate by its type (`auto` = verify yourself;
|
|
34
|
+
**super-ux**. **If the brief describes a platform rather than a change**, stage 2 also cuts it into modules (`references/decomposition.md`) — module map committed, walking skeleton first, every REQ in exactly one module — and stages 3→10 then run per module, one brick at a time. **If any loop starts undoing an earlier pass** (same file edited twice for the same reason, a closed finding returning, a third entry into one stage), stop and run the loop guard (`references/loop-guard.md`): name both shapes, escalate to the layer that owns the conflict, re-plan the check as an ordered list, then go item by item. **The closing stage opens with the ladder walk** (`references/audit.md`): the REQ table finds what was named and lost, but a comparison needs two sides and an absence has one — so walk each REQ bottom-up through its rungs (decision → spec section → contract *and its failure behavior* → task → change → executed test → surface/docs), check the seam at each step, order findings by seam rather than by file, and turn every absence into a new REQ row **before** the coverage table is written. A green from a check nobody has watched fail against a planted defect is not evidence; a finding class seen twice becomes a script rather than a third ledger row; and the carry-over ledger's counts are printed beside every gate verdict, so "green" never reads as "verified". If a searching pass starts finding mostly what the previous pass's own fixes broke, the axis is exhausted — rotate it, don't look harder. **The docs stage closes three artifacts, not two:** module docs, the wiki, **and the code graph** (`/graphify . --update` where `graphify-out/` exists — `references/knowledge-graph.md`), because the graph is what the next run's harvest queries first and a stale one is a false premise carrying the authority of a machine. Then check the graph against the docs: a hub `graphify god-nodes` reports that no document names is an undocumented seam; an edge the docs deny is a leak in the code or a lie in the docs; a doc naming a module the graph no longer has is stale. Doc-side findings are fixed there, absences become REQ rows in the closing stage. **In a project of several repositories, stage 10 closes on the parent too:** a parent records each submodule as a pointer to one commit, and moving the submodule does not move the pointer — so the work can be committed, pushed and green while a clone of the parent still gets the commit before it. Neither repo looks wrong alone, which is why it survives every check that runs inside one. Require `git submodule status` with no line starting `+`, and every repo clean and pushed (`git -C <repo> status --porcelain`, `git -C <repo> log @{u}..HEAD`). The fix is two commands and the second gets forgotten: push the submodule, then `git add <submodule> && git commit`. **The run's last act is the retrospective** (`references/retrospective.md` → `docs/superpowers/retro.md`, one file per project): **stamp the run first** (its commit is what makes the cold-retirement trigger computable), **then prune** — every standing instruction against its three retirement triggers (it became a check; the paths/commands it names are gone; it hasn't fired in five run stamps, or in sixty days — the calendar is the unit that still moves when the stamp counter has stopped), the list held to a hard cap of ten, every deletion logged as one line and never silent — 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 fix by grade (mechanical check > standing instruction > note that expires in two runs), and the check that catches it next time. Stage 0 reads those standing instructions in full, so the prune is a gate criterion, not a good intention: a rule nobody reads to the end is worse than no rule, because everyone believes it is covered. Honor every stage gate by its type (`auto` = verify yourself;
|
|
35
35
|
`manual` = wait for explicit go). Confirm the **model once at preflight** —
|
|
36
36
|
recommend the most capable one the environment offers, never a hardcoded id — then
|
|
37
37
|
run the whole pipeline on it without re-asking.
|
|
@@ -157,7 +157,8 @@ stage 10 is therefore the **retrospective**
|
|
|
157
157
|
`docs/superpowers/retro.md`): **stamp the run first** — one line, and the only thing
|
|
158
158
|
that makes the next step computable — **then prune**, every standing instruction
|
|
159
159
|
checked against its retirement triggers (it became a check · its surface is gone · it
|
|
160
|
-
hasn't fired in five run stamps
|
|
160
|
+
hasn't fired in five run stamps **or in sixty days** — the calendar is the unit that
|
|
161
|
+
still moves when the stamp counter has stopped), the list held to a hard cap of **ten**, every
|
|
161
162
|
deletion logged, then write an entry **only if the run diverged** (symptom, the
|
|
162
163
|
stage that *owned* it, root cause, fix, and the check that catches it next time).
|
|
163
164
|
Stage 0 reads those standing instructions in full, which is exactly why the prune is
|
|
@@ -268,7 +269,7 @@ capable available — see `references/model-tiering.md`).
|
|
|
268
269
|
| 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 |
|
|
269
270
|
| 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 |
|
|
270
271
|
| 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 |
|
|
271
|
-
| 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** | manual |
|
|
272
|
+
| 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 |
|
|
272
273
|
|
|
273
274
|
|
|
274
275
|
### Stage 10 in a project of several repositories
|
|
@@ -185,7 +185,8 @@ counter step 1 writes ([`learned.md`](learned.md) rule 21):
|
|
|
185
185
|
costs nothing and it is the only thing that makes the next step computable.
|
|
186
186
|
2. **Then prune.** Every standing instruction is checked against its three
|
|
187
187
|
retirement triggers — it became a check, its surface is gone, or it has not
|
|
188
|
-
fired in the last five run stamps — and the list is held
|
|
188
|
+
fired in the last five run stamps **or in the last sixty days** — and the list is held
|
|
189
|
+
to its cap of **ten**.
|
|
189
190
|
Every deletion writes one line in the log; silent deletion is forbidden.
|
|
190
191
|
3. **Write the entry, if the run diverged** — symptom, the stage it surfaced at,
|
|
191
192
|
the stage that *owned* it, the root cause, the fix (mechanical > standing
|
|
@@ -197,6 +198,7 @@ ledger's, so a list that quietly grew back is visible at the moment it happened:
|
|
|
197
198
|
```
|
|
198
199
|
GATE 10 acceptance: PASS — 14/14 REQ verified
|
|
199
200
|
carry-over: 0 unresolved · retro: 7 standing (was 9) · retired 3 · added 1
|
|
201
|
+
abstained: 2 (1 partial · 1 cannot-verify) · unlooked: 3 dormant
|
|
200
202
|
```
|
|
201
203
|
|
|
202
204
|
## GATE (manual)
|
|
@@ -221,6 +223,13 @@ All of:
|
|
|
221
223
|
ledger or here) and, for `deferred`, a tracker entry.
|
|
222
224
|
7. **No carry-over row is left `unresolved`** — every one has a home, and the
|
|
223
225
|
ledger's counts are printed with this verdict, not just filed.
|
|
226
|
+
7a. **Both disclosures are printed** ([`gates.md`](gates.md) → *Disclosures*):
|
|
227
|
+
`abstained` — every REQ closing `partial`, every `unknown`, every ⚠️ *cannot verify
|
|
228
|
+
from diff* the controller could not resolve — and `unlooked`, every check that
|
|
229
|
+
reported `dormant` or `skip`. They are **not** ratchets: no floor, no direction, and
|
|
230
|
+
a movement either way wants one sentence. A run reporting `abstained: 0` is claiming
|
|
231
|
+
it knew everything, which is a stronger statement than any run this stage has ever
|
|
232
|
+
seen close honestly.
|
|
224
233
|
8. **Every repository is closed, the parent included** — `git submodule status`
|
|
225
234
|
shows no `+`, and each repo is clean and pushed. A submodule is finished when
|
|
226
235
|
its parent points at it.
|
|
@@ -310,6 +310,7 @@ beside the verdict**:
|
|
|
310
310
|
```
|
|
311
311
|
GATE 6 tests: PASS — full suite green (247 tests)
|
|
312
312
|
carry-over: 4 open (was 6) · unresolved: 0 · audit findings deferred: 2
|
|
313
|
+
abstained: 1 (1 cannot-verify) · unlooked: 2 dormant
|
|
313
314
|
```
|
|
314
315
|
|
|
315
316
|
The difference from a TODO is not bookkeeping. A TODO is invisible until somebody
|
|
@@ -185,7 +185,7 @@ re-creates exactly that shadow.
|
|
|
185
185
|
|
|
186
186
|
| Signal | What it means |
|
|
187
187
|
|---|---|
|
|
188
|
-
| A standing instruction that has not fired in five run stamps | the rule was situational; the prune retires it ([`retrospective.md`](retrospective.md)) |
|
|
188
|
+
| A standing instruction that has not fired in five run stamps, or in sixty days | the rule was situational; the prune retires it ([`retrospective.md`](retrospective.md)) |
|
|
189
189
|
| A doc map older than the project's last release | the regime was decided for a project that has since changed shape — `setup` offers the entry audit ([`setup.md`](setup.md)) |
|
|
190
190
|
| A ratchet whose count has not moved in months | either the backlog is genuinely frozen, or nobody is looking at the number printed beside every verdict |
|
|
191
191
|
|
|
@@ -32,6 +32,7 @@ elsewhere and is not restated here:
|
|
|
32
32
|
- Probing — plant, run, restore
|
|
33
33
|
- The false-positive budget
|
|
34
34
|
- Ratchets
|
|
35
|
+
- Disclosures — counted like a ratchet, and deliberately not monotone
|
|
35
36
|
- Where a gate runs
|
|
36
37
|
- Adding a check to an existing gate
|
|
37
38
|
- Rationalizations
|
|
@@ -223,6 +224,24 @@ exit 0
|
|
|
223
224
|
in a process command line matched the throwaway shell of every tool call.
|
|
224
225
|
- **Compute the count you print.** A number restated in prose is a number that will
|
|
225
226
|
be wrong; derive it from the source at check time so the two cannot disagree.
|
|
227
|
+
- **Normalise the corpus's own formatting before you match, and say which unit you
|
|
228
|
+
chose.** A predicate written against the sentence you have in mind meets the sentence
|
|
229
|
+
as the file actually stores it: wrapped at some column, with emphasis, inside a table
|
|
230
|
+
cell. Three separate guards in this bundle were defeated that way and none of them by
|
|
231
|
+
its content —
|
|
232
|
+
|
|
233
|
+
| What defeated it | The guard | The fix |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| a citation wrapped across two lines | the section-citation check | normalise whitespace, match over the paragraph |
|
|
236
|
+
| a marker split by the ~80-column wrap | the distrust-marker check | same |
|
|
237
|
+
| `**five run stamps**` — bold inside the phrase | the cold-retirement check | strip emphasis too |
|
|
238
|
+
|
|
239
|
+
Each was silent, which is the expensive part: the guard reported green over a file it
|
|
240
|
+
had never read. Pick the unit deliberately — **line, paragraph, or whole file** — write
|
|
241
|
+
down which, and probe the shape the corpus actually contains rather than the shape you
|
|
242
|
+
typed into the regex. And plant the defect **in the file that defines the thing**, not
|
|
243
|
+
in the most convenient one: a probe against a surface with none of the formatting is a
|
|
244
|
+
probe that cannot fail for this reason.
|
|
226
245
|
|
|
227
246
|
---
|
|
228
247
|
|
|
@@ -282,10 +301,58 @@ A **ratchet** is a named, counted set that may only shrink, printed on every run
|
|
|
282
301
|
|
|
283
302
|
```
|
|
284
303
|
GATE 9 docs: PASS — propagation backlog: 121 (was 162) · unmarked residue: 0
|
|
304
|
+
abstained: 0 · unlooked: 4 (3 dormant · 1 skip — no submodules in this repo)
|
|
285
305
|
```
|
|
286
306
|
|
|
287
307
|
A ratchet nobody prints is a TODO with a better name.
|
|
288
308
|
|
|
309
|
+
## Disclosures — counted like a ratchet, and deliberately not monotone
|
|
310
|
+
|
|
311
|
+
A ratchet may only shrink. **Some numbers must not be**, and printing them under a
|
|
312
|
+
ratchet's discipline inverts the thing they measure.
|
|
313
|
+
|
|
314
|
+
**Abstention is the case that matters.** This bundle has eight vocabularies for declining
|
|
315
|
+
to claim — `partial`, `unknown`, `cannot verify from diff`, `review`, `dormant`, `skip`,
|
|
316
|
+
`recalled`, `ungated` — and until they were counted, none of them appeared beside a
|
|
317
|
+
verdict. So `PASS` read as *verified* rather than as *"green, and here is what nobody
|
|
318
|
+
claimed"*.
|
|
319
|
+
|
|
320
|
+
The obvious fix is a ratchet, and it is wrong. A count of abstentions that may only shrink
|
|
321
|
+
puts pressure on exactly one thing: **claiming more**. A run reaching `abstained: 0` is not
|
|
322
|
+
more careful; it is a run that stopped saying *I don't know*, which is the cheapest way to
|
|
323
|
+
make the number fall. Refusals and wrong answers are communicating vessels — squeeze one
|
|
324
|
+
column and it reappears in the other, silently, because a wrong claim looks like a claim.
|
|
325
|
+
|
|
326
|
+
So a **disclosure** is printed beside the verdict like a ratchet and carries the opposite
|
|
327
|
+
rule: **no floor, no direction, and a movement in either direction wants one sentence.**
|
|
328
|
+
|
|
329
|
+
Two disclosures, kept separate because they are different facts:
|
|
330
|
+
|
|
331
|
+
| Disclosure | Counts | Reading it |
|
|
332
|
+
|---|---|---|
|
|
333
|
+
| `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 |
|
|
334
|
+
| `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 |
|
|
335
|
+
|
|
336
|
+
Three are deliberately **not** counted, and saying which is part of the disclosure:
|
|
337
|
+
|
|
338
|
+
- **`review`** — *no check can decide this* — is an abstention, and it is the one this
|
|
339
|
+
section first listed and then forgot, which is exactly the failure it exists to catch.
|
|
340
|
+
It stays out of `abstained` because it is not a claim the run declined: it is a rule
|
|
341
|
+
that **declined to be mechanical**, recorded once at rung 2 with its reason (→ *Axis B*).
|
|
342
|
+
Counted per run it would report the same standing number every time and say nothing
|
|
343
|
+
about the run.
|
|
344
|
+
- **`recalled`** — a property of one claim, already carried in the ledger beside the
|
|
345
|
+
command that would re-derive it.
|
|
346
|
+
- **`ungated`** — a property of the whole run, said once, in words.
|
|
347
|
+
|
|
348
|
+
A vocabulary that is named and then left out of every bucket is the one that goes
|
|
349
|
+
uncounted forever. So each gets its line, including the one that got missed here.
|
|
350
|
+
|
|
351
|
+
**What makes a disclosure honest rather than decorative** is the same thing that makes a
|
|
352
|
+
ratchet honest: it is *computed*, and it is printed whether or not anyone likes the
|
|
353
|
+
number. What makes it different is that **nobody may set a target for it.** A target on an
|
|
354
|
+
abstention count is an instruction to guess.
|
|
355
|
+
|
|
289
356
|
---
|
|
290
357
|
|
|
291
358
|
## Where a gate runs
|
|
@@ -134,7 +134,7 @@ argue about. Check **every** standing instruction against three triggers:
|
|
|
134
134
|
|---|---|---|
|
|
135
135
|
| **It became a check** | the rule is now enforced by a test, lint, gate or hook | delete it — the check is the memory, and keeping both means it is read twice and obeyed once |
|
|
136
136
|
| **Its surface is gone** | resolve every path, command, stage and tool it names; any that no longer exists | delete it — it now describes a system nobody is running |
|
|
137
|
-
| **It went cold** | it has not fired in the last **five run stamps** | delete it
|
|
137
|
+
| **It went cold** | it has not fired in the last **five run stamps** — **or** in the last **sixty days**, whichever comes first | delete it: five runs without firing is the evidence it was situational, and the calendar is the unit that still moves when the stamp counter has stopped |
|
|
138
138
|
|
|
139
139
|
**Each trigger is a command, not a judgement.** A retirement condition nobody can run is a
|
|
140
140
|
condition nobody applies, which is how a list reaches ten and stops being read:
|
|
@@ -149,11 +149,37 @@ grep -oE '`[^`]+`' <<<"$RULE_TEXT" | tr -d '`' | while read -r t; do
|
|
|
149
149
|
|
|
150
150
|
# went cold — fired in none of the last five stamps
|
|
151
151
|
tail -n 200 docs/superpowers/retro.md | grep -c "$RULE_ID"
|
|
152
|
+
|
|
153
|
+
# ...OR in the last 60 days, whichever comes first — see below for why both
|
|
154
|
+
git log -1 --format=%cd --date=short -S"$RULE_ID" -- docs/superpowers/retro.md
|
|
152
155
|
```
|
|
153
156
|
|
|
154
|
-
Anything the first two print is a deletion; a zero from the third
|
|
155
|
-
What survives all three stays, and the run states the
|
|
156
|
-
(`learned.md` rule 19 — an empty result and an unrun command look
|
|
157
|
+
Anything the first two print is a deletion; a zero from the third **or** a last-fired date more
|
|
158
|
+
than sixty days old is a deletion. What survives all three stays, and the run states the counts
|
|
159
|
+
rather than the conclusion (`learned.md` rule 19 — an empty result and an unrun command look
|
|
160
|
+
identical).
|
|
161
|
+
|
|
162
|
+
**Why the cold trigger needs two units, and it is not belt-and-braces.** A run stamp is written by
|
|
163
|
+
a run *of this pipeline*. Where a project ships some of its work another way, the stamp counter
|
|
164
|
+
stops while the work does not — so "the last five stamps" can span an arbitrary amount of change,
|
|
165
|
+
and a rule sits unexamined for exactly as long as the pipeline goes unused. Measured on this
|
|
166
|
+
repository: **ten consecutive releases, `v1.16.0` through `v1.23.0`, carry no stamp at all.** Over
|
|
167
|
+
that stretch the trigger was not strict or lenient; it was **unreadable**, and a list capped at ten
|
|
168
|
+
with an unreadable retirement condition fills up and stops being pruned.
|
|
169
|
+
|
|
170
|
+
The wall-clock alternative fires on elapsed time, which nothing can stall. Keep both: the stamp
|
|
171
|
+
count is the better signal when the pipeline is in use, and the date is the one that still works
|
|
172
|
+
when it is not.
|
|
173
|
+
|
|
174
|
+
**The stamp gap is itself a number worth printing.** A retro whose newest stamp is far behind the
|
|
175
|
+
repository's newest release is telling you the retro is describing a smaller world than the one
|
|
176
|
+
that shipped — the same failure `learned.md` rule 16 records for a work-list. State it beside the
|
|
177
|
+
retro counts:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
git tag --sort=-v:refname | head -1 # newest release
|
|
181
|
+
grep -m1 -oE '`[0-9a-f]{7,}`' docs/superpowers/retro.md # newest stamped commit
|
|
182
|
+
```
|
|
157
183
|
|
|
158
184
|
Then the cap: **ten standing instructions, hard.** At eleven you do not get to keep
|
|
159
185
|
them all — the oldest never-fired one goes. "But all of them matter" is precisely
|
|
@@ -170,6 +196,7 @@ does ([`audit.md`](audit.md) → *What can't be fixed now becomes a ratchet, nev
|
|
|
170
196
|
```
|
|
171
197
|
GATE 10 acceptance: PASS — 14/14 REQ verified
|
|
172
198
|
carry-over: 0 unresolved · retro: 7 standing (was 9) · retired 3 · added 1
|
|
199
|
+
abstained: 2 · unlooked: 3
|
|
173
200
|
```
|
|
174
201
|
|
|
175
202
|
A pruned list that nobody prints is a list that quietly grows back.
|
|
@@ -330,7 +330,10 @@ never that the work was skipped quietly.
|
|
|
330
330
|
is covered; no `skip`/`xfail` smuggling a red suite past the gate. Never advance
|
|
331
331
|
to deploy on a red or partial run. **The carry-over count is printed beside this
|
|
332
332
|
verdict** — a ratchet nobody prints is a TODO with a better name
|
|
333
|
-
([`audit.md`](audit.md))
|
|
333
|
+
([`audit.md`](audit.md)) — **and so are the two disclosures**, `abstained` and
|
|
334
|
+
`unlooked` ([`gates.md`](gates.md) → *Disclosures*): what the run declined to claim,
|
|
335
|
+
and what a check never looked at. Neither has a floor and neither may be targeted; a
|
|
336
|
+
target on an abstention count is an instruction to guess.
|
|
334
337
|
- **Web front end? Then the surface is checked in a browser, not in the diff.**
|
|
335
338
|
A passing suite proves the code does what its assertions say. It does not prove the
|
|
336
339
|
page rendered — a component can be correct and land under a fixed header, a request
|
|
@@ -504,7 +507,7 @@ never that the work was skipped quietly.
|
|
|
504
507
|
notices it is the same one. So, in this order: **stamp the run first** (one line,
|
|
505
508
|
with its commit — and the only thing that makes the next step computable), **then
|
|
506
509
|
prune** (every standing instruction against its three retirement triggers — it
|
|
507
|
-
became a check, its surface is gone, it hasn't fired in five run stamps — and the
|
|
510
|
+
became a check, its surface is gone, it hasn't fired in five run stamps or in sixty days — and the
|
|
508
511
|
list held to its cap of ten, every deletion logged **in the archive, with the
|
|
509
512
|
commit that retired it**), then **write an entry only if
|
|
510
513
|
the run diverged** (symptom · the stage it surfaced at · the stage that *owned* it
|
|
@@ -513,7 +516,10 @@ never that the work was skipped quietly.
|
|
|
513
516
|
a messy run is the failure the file exists to stop. Stage 0 reads the standing
|
|
514
517
|
instructions in full next time, which is why the cap is not negotiable.
|
|
515
518
|
- **GATE (manual):** the ladder walk ran and its absences became REQ rows before
|
|
516
|
-
the table was written; **
|
|
519
|
+
the table was written; **both disclosures printed beside the verdict** — `abstained` (what the run declined
|
|
520
|
+
to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither
|
|
521
|
+
with a floor, neither ever a target ([`gates.md`](gates.md) → *Disclosures*); **the
|
|
522
|
+
retrospective is written — stamped first, then pruned, then the entry; the
|
|
517
523
|
list at or under its cap, every deletion logged in the archive with its commit,
|
|
518
524
|
entries older than five run stamps rotated into `docs/superpowers/retro/`, the run
|
|
519
525
|
stamped with its commit, every SHA in either file resolvable, and the
|
|
@@ -36,6 +36,7 @@ set that may only shrink, and it is printed beside every gate verdict:**
|
|
|
36
36
|
```
|
|
37
37
|
GATE 6 tests: PASS — full suite green (247 tests)
|
|
38
38
|
carry-over: 4 open (was 6) · unresolved: 0 · audit findings deferred: 2
|
|
39
|
+
abstained: 1 (1 cannot-verify) · unlooked: 2 dormant
|
|
39
40
|
```
|
|
40
41
|
|
|
41
42
|
That one line is the whole mechanism. Without it, `PASS` reads as *verified*; with
|
|
@@ -27,7 +27,8 @@ them.
|
|
|
27
27
|
| R-001 | 2026-05-04 · `<topic>` | `<sha>` | … | … (one line; links the archive entry) | … (e.g. "the export path is covered by a test") | 2026-06-18 | `<sha>` |
|
|
28
28
|
|
|
29
29
|
Retire on **any** of: it became a check · every path/command it names is gone · it
|
|
30
|
-
has not fired in the last five run stamps
|
|
30
|
+
has not fired in the last five run stamps, or in the last sixty days. At eleven
|
|
31
|
+
rows, the oldest never-fired
|
|
31
32
|
row goes — the cap is not negotiable, ranking is.
|
|
32
33
|
|
|
33
34
|
## Recent log — entries from the last five run stamps (newest first)
|