task-pipeline-skill 1.96.0 → 1.98.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/HOW-IT-WORKS.md +17 -13
  3. package/README.md +23 -17
  4. package/SKILL-CARD.md +2 -2
  5. package/cursor/rules/task-pipeline.mdc +33 -21
  6. package/evals/task-pipeline.evals.json +3 -3
  7. package/package.json +1 -1
  8. package/plugins/task-pipeline/.claude-plugin/plugin.json +2 -2
  9. package/plugins/task-pipeline/commands/task-pipeline.md +14 -219
  10. package/plugins/task-pipeline/skills/evidence-docs/SKILL.md +8 -1
  11. package/plugins/task-pipeline/skills/evidence-docs/references/GENERATED.md +1 -1
  12. package/plugins/task-pipeline/skills/evidence-docs/references/learned.md +24 -1
  13. package/plugins/task-pipeline/skills/evidence-docs/references/retrospective.md +21 -576
  14. package/plugins/task-pipeline/skills/project-audit/SKILL.md +8 -1
  15. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +162 -230
  16. package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +1 -1
  17. package/plugins/task-pipeline/skills/task-pipeline/pipeline.example.json +9 -9
  18. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +10 -3
  19. package/plugins/task-pipeline/skills/task-pipeline/references/acceptance.md +2 -2
  20. package/plugins/task-pipeline/skills/task-pipeline/references/brainstorm.md +3 -3
  21. package/plugins/task-pipeline/skills/task-pipeline/references/browser.md +48 -11
  22. package/plugins/task-pipeline/skills/task-pipeline/references/build.md +7 -7
  23. package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +49 -44
  24. package/plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md +32 -24
  25. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -1
  26. package/plugins/task-pipeline/skills/task-pipeline/references/finish-line.md +13 -8
  27. package/plugins/task-pipeline/skills/task-pipeline/references/iteration.md +20 -23
  28. package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +5 -3
  29. package/plugins/task-pipeline/skills/task-pipeline/references/learned.md +24 -1
  30. package/plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md +17 -7
  31. package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +47 -1
  32. package/plugins/task-pipeline/skills/task-pipeline/references/spec.md +5 -4
  33. package/plugins/task-pipeline/skills/task-pipeline/references/stage-00-intake.md +39 -25
  34. package/plugins/task-pipeline/skills/task-pipeline/references/stage-05-dev.md +3 -3
  35. package/plugins/task-pipeline/skills/task-pipeline/references/stage-08-post-deploy.md +3 -2
  36. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +34 -22
  37. package/plugins/task-pipeline/skills/task-pipeline/references/tdd.md +3 -2
  38. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +6 -4
  39. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +77 -21
  40. package/plugins/task-pipeline/skills/task-pipeline/scripts/retro_budget.py +305 -0
  41. package/plugins/task-pipeline/skills/task-pipeline/scripts/short_path.py +70 -0
  42. package/plugins/task-pipeline/skills/task-pipeline/scripts/waves.py +22 -10
  43. package/plugins/task-pipeline/skills/task-pipeline/templates/browser-claims.json +5 -5
  44. package/plugins/task-pipeline/skills/task-pipeline/templates/canvas.md +1 -1
  45. package/plugins/task-pipeline/skills/task-pipeline/templates/retro-archive.md +9 -0
  46. package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +10 -1
@@ -159,28 +159,25 @@ its slowest node before checking its fastest.
159
159
 
160
160
  **The number of rounds follows the node's risk class.** The class is recorded on the node
161
161
  as `risk` (R1–R3, [`work-graph.md`](work-graph.md)), computed from what the node touches.
162
- It is never lowered to save time. **A round is the three blind tiers of
163
- [`certification.md`](certification.md) plus one fix cycle**, and the first round is always
164
- the full three tiers — there is no lighter first reading. The class sets how many rounds
165
- the node owes:
166
-
167
- | Class | Touches | Rounds |
168
- |---|---|---|
169
- | R1 | docs, config, a mechanical change, one isolated file | 1: that first round |
170
- | R2 | an ordinary feature or fix inside one module | 2: the first round, then a second over the fix diff with its regression tests |
171
- | R3 | security, cryptography, money, a data migration, a public contract, a seam across repositories, concurrency | 3, one of them recorded adversarial — a round that plants defects and tries abuse cases, on another model where one is available |
172
-
173
- - Each round's fix cycle stays inside [`loop-guard.md`](loop-guard.md)'s caps. A finding
174
- that cannot be fixed in the node is parked with a board row.
175
- - `graph.py close` refuses a node until its owed rounds have passed, and an R3 node until
176
- one of them was recorded adversarial ([`certification.md`](certification.md) → *Rounds
177
- owed by risk class*, which also says what a round after a clean one reads and how the
178
- adversarial round is run).
179
- - Every owed round runs, and every round re-runs all three tiers: a tier that passed in an
180
- earlier round read a tree the fix has since moved ([`certification.md`](certification.md)
181
- → a passing tier is re-run). A clean round does not cancel the next one, and only passing
182
- rounds count. R3's adversarial round asks a different question — it hunts for a planted
183
- defect — and always runs; it counts only when it passes.
162
+ It is never lowered to save time. **A round is the blind tiers the class owes, plus one
163
+ fix cycle** ([`certification.md`](certification.md)), and a clean round ends the node
164
+ unless the class is R3 or the surface is flagship:
165
+
166
+ | Class | Touches | Tiers | Rounds |
167
+ |---|---|---|---|
168
+ | R1 | docs, config, a mechanical change, one isolated file | one | 1 |
169
+ | R2 | an ordinary feature or fix inside one module | three | 1 |
170
+ | R3 | security, cryptography, money, a data migration, a public contract, a seam across repositories, concurrency | three | 2: one blind, one adversarial (plants defects, tries abuse cases, on another model where one is available) |
171
+
172
+ A flagship surface owes four tiers and two rounds, one adversarial, whatever its class.
173
+
174
+ - Each round's fix cycle stays inside [`loop-guard.md`](loop-guard.md)'s caps, and the
175
+ certification ceiling stops the node: it is parked with its evidence and a board row.
176
+ - `graph.py close` refuses a node until its owed rounds have passed, and an R3 or
177
+ flagship node until one of them was recorded adversarial
178
+ ([`certification.md`](certification.md) → *Rounds owed by risk class*).
179
+ - A round after a fix re-runs every tier the class owes; a round on an unchanged tree is
180
+ refused unless it is the other kind. Only passing rounds count.
184
181
  - Readers stay blind ([`certification.md`](certification.md) → *Blind*). Each reads the
185
182
  diff, the packet and the contract, never the builder's reasoning.
186
183
 
@@ -384,7 +381,7 @@ release run performs, not unrelated deployments, messages or human-only actions.
384
381
  |---|---|
385
382
  | "This bug is tiny, fix it now" | Tiny fixes are what move a seam twice. It joins the inventory, or it is one of the hotfix lane's five entries |
386
383
  | "Wait for the whole wave, then verify" | A barrier idles every finished node. Each node is certified when it lands |
387
- | "R3 found nothing in round 2, skip the adversarial round" | The adversarial round, in any position, asks a different question: it hunts for a planted defect. A clean blind round does not answer it |
384
+ | "R3 found nothing in its blind round, skip the adversarial round" | The adversarial round, in any position, asks a different question: it hunts for a planted defect. A clean blind round does not answer it |
388
385
  | "Ask the operator now, it is quick" | Each question is a human round. Queue it and take another node |
389
386
  | "The agent hit a rate limit, start it again" | Resume it with its context. Relaunching pays for the same reading twice |
390
387
  | "No Observatory here, so no learning loop" | The project retro and learned.md are the loop's first layer, and every install has them |
@@ -51,7 +51,7 @@ makes the grill's answers *checkable* instead of merely confident.
51
51
  | 4b | **The task register, for its *state*** | `docs/ROADMAP.md`, a board, a backlog, the tracker `CLAUDE.md` names | **what is open right now** — read with a command, never from memory; see *Carried-in claims* |
52
52
  | 5 | **Product/UX docs** | `docs/ux/` (super-ux chain), `README`, runbooks | user-facing behavior that is already specified |
53
53
  | 6 | **Pipeline history** | `<artifacts>/specs/`, `plans/`, past `-carryover.md` | what a previous run of this pipeline decided or deferred |
54
- | 7 | **The retro, in force** | `<artifacts>/retro.md` ([`retrospective.md`](retrospective.md)) | what previous runs got wrong here — **read in full**: standing instructions (capped at ten) and run stamps (one line each), both bounded by construction; the *Recent log* is **queried** by the task's nouns, like the archive — nothing caps it |
54
+ | 7 | **The retro, in force** | `<artifacts>/retro.md` ([`retrospective.md`](retrospective.md)) | what previous runs got wrong here — **read in full**: standing instructions (capped at ten) and run stamps (one line each), both under the floor's 12 000-byte budget, whose bytes and bytes/4 tokens `scripts/retro_budget.py check` prints into this row; the *Recent log* is **queried** by the task's nouns, like the archive — nothing caps it |
55
55
  | 7a | **The retro archive** | `<artifacts>/retro/YYYY-QN.md` | *have we been bitten by this class before?* — **queried** by the task's nouns, never read end to end |
56
56
  | 7b | **Lessons from other projects** | the local index every install has (`scripts/lessons.py query`), and a shared lesson store only where the session lists one — an Observatory — detected by its tools, never by a path ([`iteration.md`](iteration.md) → *The learning loop*, the read recipe) | *what did other projects' agents learn about this class?* — **queried** by the task's 3–6 nouns, at most ten lines from both; a lesson that fires is cited `[lesson L-…]` or `[lesson mem:…]`. The ledger names each layer's state: `local lessons: N match | absent | unavailable (no python3)`; `shared lessons: N match | 0 match (filter unknown) | unfilterable | absent`, where the first `observatory_search` call is the probe — and nothing else changes |
57
57
  | 8 | **The knowledge wiki** | see below | distilled cross-project knowledge, prior sessions, why decisions were made |
@@ -79,8 +79,10 @@ Rules for the list:
79
79
 
80
80
  `<artifacts>/retro.md` ([`retrospective.md`](retrospective.md)) is the one
81
81
  harvested source whose binding part is **read in full rather than queried**: the
82
- standing instructions are capped at ten precisely so that this is cheap, and the run
83
- stamps are one line each. Its narrative log is queried, not read — an uncapped section
82
+ standing instructions are capped at ten rows of at most 600 characters, the run stamps
83
+ at ten lines of at most 300, and the two together at 12 000 bytes
84
+ ([`retrospective.md`](retrospective.md) → *The floor has a byte budget*), precisely so
85
+ that this is cheap. Its narrative log is queried, not read — an uncapped section
84
86
  inside a source that binds is how the capped part stops being read. They are what
85
87
  previous runs of this pipeline got wrong *in this project* — the rules no check
86
88
  could decide — and they bind this run.
@@ -58,6 +58,13 @@ to be enforced and is not is the same failure as a gate that prints `FAIL` and e
58
58
  | 30 | **A gate scoped by exclusion judges every newcomer silently** | any lint, format or check configured with an ignore list rather than an include list | scope by what it COVERS; where the tool has no such switch, assert the covered set and fail on additions, deriving the allowlist by measuring the tool's own reach | the failure message names the intruder and the remedy, because the operator meets it mid-release |
59
59
  | 31 | **A gate needs a third verdict — could not measure** | any check that can time out, lose a dependency, or run on a contended machine | distinguish *failed* from *could not measure* with different exit codes, and say which; neither is a verdict about the code | the refusal names its remedy, and a test that waits for a DURATION rather than an event is treated as a defect in the test |
60
60
  | 32 | **A test whose assertion is implied by compilation is not a test** | any test whose name promises a behaviour | delete the subject: if that is a type or import error rather than a red test, the test is decoration | removing one asks what the name PROMISED and whether anything checks it — four of five such cases here were covered elsewhere and the fifth was a real gap only visible because the name was read as a claim |
61
+ | 33 | **Snapshot before you undo** | any `git checkout`, `git restore`, `git stash` or `reset` in a tree that may hold uncommitted work you did not write | copy the affected files first (to a dated folder, or `git diff > <file>.patch`) and restore from that copy, never from git | the run names the copy it took before the first destructive command |
62
+ | 34 | **One answer for inputs that should differ is a broken instrument** | any shell measurement, zsh above all | quote every expansion (`"$var"`, `'*.py'`), read data from files rather than inline literals, and feed it two inputs that should answer differently | the two answers differ, or the instrument is rewritten before its answer is used |
63
+ | 35 | **Release the tree you tested** | any tag or release | run the release workflow's own suite on the exact commit the tag will name, and select the CI run by that tag, never by branch | the run the tag triggered is green and its head SHA is the tagged commit |
64
+ | 36 | **A fix after a passing review is unreviewed** | any change made after a review or verifier passed | re-read the delta (`git diff <reviewed>..HEAD`) before merge | the merge names the reviewed SHA and who read the delta |
65
+ | 37 | **Call the real service once before writing its fake** | any mock, stub or fixture of an external API, CLI or service | make one real call, or read a recorded real response, and shape the fake from it | the fake cites the response it was shaped from |
66
+ | 38 | **Close blockers yourself; park only human gates** | any blocker about to be handed back | try every route the run holds (an API, a CLI, a credential door) first; park only a sign-in, consent, payment, typed secret or recorded operator decision | every handed-back item is a human gate, listed in one block with the route that failed |
67
+ | 39 | **Never retry an unchanged failing action** | any failed command, check or approach | change the input or the approach before trying again; after two failed approaches, change approach or record a blocker | no identical retry in the run ledger, and a third attempt names what changed |
61
68
 
62
69
  ---
63
70
 
@@ -163,6 +170,17 @@ that document is checked. This one governs a fact that crossed a **session bound
163
170
  reported as current — the case where there is no document to check, only a memory that reads like
164
171
  one.
165
172
 
173
+ **33 to 39 · The 2026-10-20 retro audit.** Read across ~54 retrospectives from ~50
174
+ projects, the same lessons recurred under different words, each in at least the number
175
+ of runs given: uncommitted work overwritten by a checkout, restore or stash with no copy
176
+ taken (17); a zsh glob or `=` left unquoted, so a command failed or a loop printed one
177
+ count for every file (8; this release's own run hit both); a tag cut from a tree the
178
+ release suite never ran on, or a CI run picked by branch rather than by tag (24, with
179
+ immutable tags burned); a fix landed after the review passed and merged unread; a fake
180
+ shaped from documentation that the real service contradicted (11); a hand-back listing
181
+ steps the agent could have done itself (12); and the same failing action retried
182
+ unchanged, round after round. None of them was new to the project that hit it again.
183
+
166
184
  ---
167
185
 
168
186
  ## The two that are not in the table, and why
@@ -214,6 +232,11 @@ answer would have exposed it in a minute.
214
232
  | any command run to establish a fact — 6 Tests · 9 Docs · 10 Acceptance · 5 review | 19 — the output asserted non-empty and shaped as expected, and **quoted** rather than concluded from, [`audit.md`](audit.md) → *Silence is not a reading*; the reviewer's half is in [`review.md`](review.md) |
215
233
  | 0 Harvest · 10 Acceptance | 20 — the **consumer** read to learn which copy ships, never the copies compared against each other, [`audit.md`](audit.md) → *Two copies, and which one wins*; asked as row `0 Duplicates` of [`grill.md`](grill.md) → *The autonomy sweep* |
216
234
  | 10 Retro · **any gate or check you order** | 21 — each input traced to the step that writes it, and that step proven upstream, [`retrospective.md`](retrospective.md) → *Stamp first, then prune, then write* |
235
+ | any stage · a destructive git command · a shell measurement | 33, 34 |
236
+ | 7 Release · 5 Dev after review | 35, 36 |
237
+ | 5 Dev · 6 Tests · a fake of an external service | 37 |
238
+ | 10 Acceptance · the hand-back | 38 |
239
+ | every stage · any retry | 39, [`loop-guard.md`](loop-guard.md) |
217
240
 
218
241
  **This file is the shipped list; a project keeps its own.** Every rule in the table
219
242
  above was earned on someone else's build and travels with the skill. The lessons *your*
@@ -276,7 +299,7 @@ evidence that something left, and the log below says what.
276
299
 
277
300
  ### Retired
278
301
 
279
- **Numbers issued so far: 32.** This is the high-water mark, and it is the only number
302
+ **Numbers issued so far: 39.** This is the high-water mark, and it is the only number
280
303
  this file states about itself — deliberately, because the gap that proves a rule left
281
304
  cannot be computed from the table alone: **deleting the highest-numbered rule shrinks
282
305
  the maximum with it, and no gap ever opens.** That false negative shipped in the first
@@ -22,7 +22,7 @@ searches.
22
22
 
23
23
  - Bookkeeping — the thing that makes detection mechanical
24
24
  - Detection — any one of these trips the guard
25
- - The review loop — a cap that measures rather than stops
25
+ - The review loop: a cap that stops, and says why
26
26
  - The re-render loop — a budget of one, two at most
27
27
  - The break protocol
28
28
  - When to stop and hand back
@@ -66,12 +66,20 @@ stage's gate — which is the whole difference between a rule and a rule that ru
66
66
  loop (another task, another module) already closed in this run — two owners for
67
67
  one file.
68
68
 
69
- Caps that trip the guard by themselves: **5 fix rounds** per task
69
+ Caps that trip the guard by themselves: **3 fix rounds** per task
70
70
  ([`build.md`](build.md)), **2 re-entries** per stage per artifact, **3 passes** per
71
- module in the program loop, and **3 review rounds** per artifact — which is not a stop
72
- but a measurement, below.
71
+ module in the program loop, **3 review rounds** per artifact, and **3 failing
72
+ certification rounds** per node ([`certification.md`](certification.md)). Each one
73
+ **stops**: the remaining findings become blocker rows with their evidence and the run
74
+ moves on (since 1.98.0; the review cap used to measure only).
73
75
 
74
- ## The review loop — a cap that measures rather than stops
76
+ **Two rules hold under every cap.** Never retry an unchanged failing action: the same
77
+ command on the same input gives the same answer, so a retry is a loop with no
78
+ information in it. After two failed approaches to one problem, change the approach or
79
+ record a blocker; a third attempt of the same shape is the loop this file exists to
80
+ end ([`learned.md`](learned.md) rule 39).
81
+
82
+ ## The review loop: a cap that stops, and says why
75
83
 
76
84
  The caps above govern loops that **edit**. A review loop does both: the reader finds,
77
85
  the run fixes, the reader reads again. It had no cap at all until 2026-08-10, and this
@@ -98,8 +106,10 @@ review cap reached — 3 rounds — artifact: test/validate.py
98
106
  - **Self-inflicted ≥ new** — the axis is exhausted ([`audit.md`](audit.md) → *Every
99
107
  pass changes the axis*). Stop. Every remaining finding becomes a board row with its
100
108
  evidence ([`backlog.md`](backlog.md)); none is dropped.
101
- - **New > self-inflicted** — the reader is still paying. Continuing is then the
102
- operator's call, made with the numbers in hand rather than out of fatigue.
109
+ - **New > self-inflicted** — the reader is still paying, and the loop still stops: the
110
+ open findings become board rows with the numbers beside them. A further round runs
111
+ only on the operator's explicit request, which is read when given and never waited
112
+ for.
103
113
 
104
114
  At the level of a whole iteration only new **blocking** findings argue for continuing; a
105
115
  deferred or noise finding is paid for on the board, not with another round
@@ -18,7 +18,7 @@ justifies reading it protects one section while the file below it doubles.
18
18
 
19
19
  | Artifact | Parts | How it is read |
20
20
  |---|---|---|
21
- | `docs/evidence/retro.md` — **one per project** | **Standing instructions** (max **10**) · **Run stamps** (max **10**, oldest rotate out) | stage 0, **in full** — both are bounded by a **cap**, which *one line each* never was |
21
+ | `docs/evidence/retro.md` — **one per project** | **Standing instructions** (max **10**) · **Run stamps** (max **10**, oldest rotate out) | stage 0, **in full**: both are bounded by a **cap** and, since 1.98.0, by a **byte budget** (*The floor has a byte budget*) |
22
22
  | the same file's **Recent log** | narrative entries, **uncapped by design** — the heading said *entries from the last five run stamps* until 2026-08-20 while the section held 25 going back nine days, a bound in a heading that nothing enforced | stage 0, **queried** by the task's nouns. It said *in full* until 2026-08-10, when it measured **74%** of the file: an uncapped section inside a binding source is what makes the capped part get skimmed |
23
23
  | `docs/evidence/retro/YYYY-QN.md` — the archive | every entry and every retirement ever written, append-only | **queried** by the task's nouns; never read end to end |
24
24
 
@@ -35,6 +35,8 @@ file exists to stop.
35
35
  - Never amend a commit a record already names
36
36
  - A release stamp names the TAG, and the merge commit — never the branch's own SHA
37
37
  - The stamp table is capped at ten, and *one line per run* was never a cap
38
+ - The floor has a byte budget
39
+ - Before a standing row: search, cite, send upstream
38
40
  - `publish:` is a line in the verdict, not a silence
39
41
  - Rotation — the archive is how pruning stops losing things
40
42
  - Three grades of fix — take the highest one that can work
@@ -66,8 +68,16 @@ Required fields, and none of them is optional:
66
68
  | **Root cause** | why the pipeline permitted it. "The agent was careless" is not a cause — it is the absence of one, and it produces no fix |
67
69
  | **Fix** | one of the three grades below |
68
70
  | **The check** | what would have caught this the first time. If the honest answer is "nothing yet", that is the fix, and it is grade 1 |
71
+ | **Class** | one of: `exit-code`, `unwatched-check`, `release`, `collision`, `destructive-undo`, `claim-by-say-so`, `stale-doc`, `wrong-copy`, `sibling`, `truncated-output`, `shell-instrument`, `handback`, `loop`. **Recurrence is counted by class**, so a class seen before is named as such |
72
+ | **Cost** | what it cost: rounds, burned tags, time. An entry with no cost cannot be weighed against the check that would prevent it |
69
73
  | **Commit** | the short SHA of the change that fixed it |
70
74
 
75
+ The classes come from the 2026-10-20 audit of ~54 retrospectives across ~50 projects,
76
+ where the same lessons recurred under different words: a gate's exit code read through
77
+ a pipe (≥26 runs), a check trusted before it was seen failing (≥26), a tag cut from a
78
+ tree the release suite never ran on (≥24), a shared checkout (≥20), uncommitted work
79
+ overwritten (≥17). Words hid the recurrence; a class key makes it a count.
80
+
71
81
  ## Every lesson carries its commit
72
82
 
73
83
  A standing instruction carries **two** SHAs — `Commit` (the change that introduced
@@ -177,6 +187,38 @@ like every other rotation. **The count is printed at the prune**, beside the sta
177
187
  instructions' own count, so a table that stops rotating is visible rather than merely
178
188
  large.
179
189
 
190
+ ## The floor has a byte budget
191
+
192
+ A cap of ten rows never bounded their **size**. Measured 2026-10-20 across ~50
193
+ projects, the floor stage 0 reads in full (standing instructions plus run stamps) ran
194
+ from ~3k to **~76k tokens**; one floor was 304 KB, and this repository's own was
195
+ 27 620 bytes. A row that carries its incident and a stamp that carries its release
196
+ narrative are how a capped list grows anyway.
197
+
198
+ - **Budget:** the floor stays under **12 000 bytes**. A standing row is at most **600
199
+ characters**: the rule, why (one clause), the retire-when trigger and the id; the
200
+ story lives in the archive. A run stamp is **one line of at most 300 characters**.
201
+ - **Stage 0 prints it:** `python3 scripts/retro_budget.py check` gives the floor's bytes
202
+ and bytes/4 tokens, beside the source ledger's retro row.
203
+ - **Gate 10 fails over budget.** Before the new entry is written, `retro_budget.py
204
+ migrate --write` moves the narrative (an over-long stamp's verdict, a standing row's
205
+ `Because`) **verbatim** into the quarter's archive, each block carrying the sha256 of
206
+ its text, and leaves a pointer; `retro_budget.py verify` proves every pointer. An
207
+ instruction still over 600 characters after its story moved is rewritten by hand.
208
+ - **A prune that retires nothing writes its count into the stamp row**, as
209
+ `prune: 0 retired`, and no paragraph. Repeated "nothing to prune" notes were a
210
+ measured share of the floor.
211
+
212
+ ## Before a standing row: search, cite, send upstream
213
+
214
+ - **Search first:** `references/learned.md` and the lesson index
215
+ (`scripts/lessons.py query`, by the class key and the nouns). A rule already there is
216
+ **cited by its number** (`learned.md` rule 22), never restated in a row.
217
+ - **A lesson standing in two projects goes upstream in the same run:** the entry gets
218
+ its `**Lesson:**` line and `scripts/lessons.py add`, and a universal rule is proposed
219
+ for `learned.md` (*Publishing the insight*, below). Two projects holding one rule is
220
+ a fork nobody named.
221
+
180
222
  ## `publish:` is a line in the verdict, not a silence
181
223
 
182
224
  Reported from another project, and the report is about this file: an operator asked, after
@@ -265,6 +307,10 @@ computable, which is why it goes first:
265
307
  printf '%s · %s\n' "$(date +%F)" "$(git rev-parse --short HEAD)" >> docs/evidence/retro.md
266
308
  ```
267
309
 
310
+ **The budget runs between the prune and the entry:** stamp, prune, `retro_budget.py
311
+ check` (and `migrate --write` when it fails), then write. An entry written onto a floor
312
+ already over budget is the growth the budget exists to stop.
313
+
268
314
  ## The prune — mandatory, and it runs after the stamp
269
315
 
270
316
  A lesson that lands in a cluttered file is a lesson nobody will reach — so the prune still runs
@@ -18,7 +18,7 @@ Writing the approved design down so a zero-context implementer — human or suba
18
18
  - Module dossier — when the run is one brick of a platform
19
19
  - Self-review — before showing it
20
20
  - Locked contracts are decisions — the register, not only the spec
21
- - GATE (manual)
21
+ - GATE (auto)
22
22
 
23
23
  ## Order of operations
24
24
 
@@ -280,13 +280,14 @@ spec section instead of restating the reasoning there.
280
280
  and the next one supersedes it; an id survives. If this stage settled something and
281
281
  no entry names it, the run has agreed to decide it again later.
282
282
 
283
- ## GATE (manual)
283
+ ## GATE (auto)
284
284
 
285
285
  > "Spec written and committed to `<path>`. Review it and tell me if anything should
286
286
  > change before I write the implementation plan."
287
287
 
288
- Wait for the operator. Changes requested → apply, re-run the self-review, ask
289
- again.
288
+ Where the brief records a standing authorization (the default gate is `auto` since
289
+ 1.98.0), an independent reader reviews the spec and the run continues; otherwise wait
290
+ for the operator. Changes requested → apply, re-run the self-review, and review again.
290
291
 
291
292
  The gate is not only the operator's word: **every section carries `covers: REQ-…`
292
293
  and every REQ in the brief appears in at least one section.** For UI tasks it
@@ -7,13 +7,13 @@ The full gate and freedom level remain in [stages.md](stages.md).
7
7
  - 0 — Intake grill — MANDATORY
8
8
 
9
9
  ## 0 — Intake grill — MANDATORY
10
- - **Stage 0 is not optional and not skippable.** There is no "small enough task"
11
- exemption, no "the request was already clear" exemption, no starting stage 1
12
- "while the operator thinks". The only sanctioned bypass is the
13
- entry-from-super-ux short-circuit below, and even that still requires a scope
14
- confirmation and a record of what was adopted vs skipped. A run that reaches
15
- stage 1 without a committed, operator-confirmed brief is a **failed run** —
16
- stop and go back.
10
+ - **Stage 0 always runs, and its depth is proportional.** The gap check, the
11
+ harvest and the brief are never skipped; the interview, the committed brief file
12
+ and stages 1-4 are what a small change does without (Phase 1d below, the
13
+ *proportional run*). A run that starts building without a brief and its REQ rows
14
+ (in the brief file, or on the short path in the run ledger) is a **failed run**:
15
+ stop and go back. The entry-from-super-ux short-circuit below is the other
16
+ sanctioned shortening.
17
17
  - **Entry-from-super-ux short-circuit (check FIRST).** task-pipeline is often
18
18
  launched *from* super-ux — its `/ux` action menu offers "execute autonomously
19
19
  via the task-pipeline plugin" once the UX chain (and often a
@@ -40,8 +40,9 @@ The full gate and freedom level remain in [stages.md](stages.md).
40
40
  `affected` / `god-nodes` answer *reach*, which is what grep cannot), `CLAUDE.md`,
41
41
  `CONTEXT.md`/ADRs, `docs/` + `docs/ux/`, past pipeline briefs and carry-over
42
42
  ledgers, **the retro's standing instructions and run stamps** (`<artifacts>/retro.md`,
43
- read **in full** — ten standing rows and ten stamps, both bounded **by a cap**, and they bind this
44
- run; stamp each instruction as it fires. Its *Recent log* is **queried** by the
43
+ read **in full**: ten standing rows and ten stamps, bounded by a cap and by a byte
44
+ budget; print `scripts/retro_budget.py check` first, which states the floor's bytes and
45
+ bytes/4 tokens. They bind this run; stamp each instruction as it fires. Its *Recent log* is **queried** by the
45
46
  task's nouns, not read: uncapped narrative inside a binding source is what makes the
46
47
  capped part get skimmed, [`retrospective.md`](retrospective.md)), **lessons from other
47
48
  projects** (source 7b, [`knowledge-sources.md`](knowledge-sources.md): `scripts/lessons.py
@@ -81,30 +82,43 @@ The full gate and freedom level remain in [stages.md](stages.md).
81
82
  or they genuinely disagree and that is a decision. There is no fourth option, and
82
83
  starting on an unresolved divergence means building against a system that does
83
84
  not exist.
84
- - **Phase 1d — the short-path triage: printed, proposed, never taken silently.** This
85
- pipeline's own boundary exempts a typo, a one-line fix and a mechanical rename — and
86
- nothing measured that until 2026-08-10, so the exemption depended on an agent
87
- remembering it while eleven stages and four manual gates stood in front of a
88
- one-paragraph edit. Three questions, each with something behind it:
85
+ - **Phase 1d — the short-path triage, and the proportional run: a small change
86
+ takes the short path by default.** This pipeline's boundary exempts a typo and a one-line edit; until 1.98.0
87
+ the next size up still met eleven stages and five manual gates, because the short
88
+ path was only *proposed* and silence took the full flow. Under a standing "decide and
89
+ act" instruction silence is the normal answer, so a proposal was the full flow every
90
+ time. The triage now **decides**, from five answers with something behind each:
89
91
 
90
92
  ```
91
- 1. files the request names, resolved git ls-files -- <paths> -> N
93
+ 1. files the change touches, resolved git ls-files -- <paths> -> N
92
94
  2. any of them a public contract the surfaces the host's release
93
95
  syncs, its schema or config
94
96
  contracts, a shipped command,
95
97
  its README -> yes/no
96
- 3. behaviour a user or a caller observes changes -> yes/no
98
+ 3. behaviour a user observes changes a UI, a message, an output -> yes/no
99
+ 4. a deploy target in the brief stage 7's target exists -> yes/no
100
+ 5. risk class work-graph.md R1-R3 -> R1/R2/R3
97
101
  ```
98
102
 
99
- Few files, no contract, no observable change ⇒ **propose** the short path: stages 1,
100
- 2, 3 and 4 marked `⊘` with the triage answer as the reason, and 5→10 running
101
- unchanged. **Propose, never take.** The answer goes in the brief's autonomy sweep and
102
- silence takes the full flow — the same floor deploy authorization uses. The glyph is
103
- what makes it safe: a skipped stage is printed on the rail **with its reason**
104
- ([`progress.md`](progress.md)), and a skip nobody can see is indistinguishable from a
105
- stage that was never entered.
106
- - **How it runs: [`grill.md`](grill.md)** — the full doctrine, built into this
107
- skill (nothing to install). In short: close what the sources can, then ONE batch
103
+ **Small** means all of: the gap check left zero material unknowns, N ≤ 5, no public
104
+ contract, no user-observable change, no deploy, and risk **R1**. Small ⇒ the run takes
105
+ the short path and prints one line:
106
+ `short path: R1 · N files · no contract · no user-facing change · no deploy`.
107
+ `scripts/short_path.py` computes the decision from the five answers (exit 0 short,
108
+ 3 full) and prints that line.
109
+ The short path is: the brief and its REQ rows written into the run ledger (no grill,
110
+ no committed brief file) → stage 5, build with tests → stage 6, the suite plus **one**
111
+ verification (one blind tier, [`certification.md`](certification.md)) → stage 9, the
112
+ docs the change makes false and the handoff → stage 10, the hand-back and a run stamp;
113
+ a retro entry only when the run taught a new lesson. Stages 1-4, 7 and 8 print `⊘`
114
+ with the triage line as their reason ([`progress.md`](progress.md)).
115
+ **Triggers that bring a skipped stage back:** a deploy target appears (7, 8); a wiki or
116
+ code graph exists and the change touched what it indexes (9 in full); a check reveals a
117
+ contract or a user-facing effect (leave the short path, resume at stage 2); the
118
+ operator asks for the full cycle. Any answer outside *small* takes the full flow,
119
+ printed the same way with the failing answer as its reason.
120
+ - **How it runs: [`grill.md`](grill.md)**, read only when the gap check leaves a
121
+ material unknown (a complete brief asks nothing). In short: close what the sources can, then ONE batch
108
122
  of the material unknowns, ordered by dependency, a recommended answer with each —
109
123
  one at a time only where answers depend on each other or the operator asks;
110
124
  contradictions reconciled on the spot; **every answer that touches
@@ -7,7 +7,7 @@ The full gate and freedom level remain in [stages.md](stages.md).
7
7
  workspace (native worktree tool first, git fallback, baseline tests), keep a
8
8
  ledger under `.task-pipeline/build/<plan>/` so a compacted context can resume,
9
9
  then one fresh implementer subagent per task with a file-based brief and report,
10
- a review after every task ([`review.md`](review.md)), and a five-round fix loop
10
+ a review after every task ([`review.md`](review.md)), and a three-round fix loop
11
11
  with an explicit breaker. TDD per task ([`tdd.md`](tdd.md)): failing test →
12
12
  watch it fail → minimal impl → watch it pass → commit. Pin subagents to the
13
13
  run's confirmed model (`model-tiering.md`). The plan's parallel groups fan out
@@ -19,8 +19,8 @@ The full gate and freedom level remain in [stages.md](stages.md).
19
19
  contradiction that exists only between two of them.
20
20
  - **Web front end? The task's own surface is checked in a browser, not in the diff.**
21
21
  Where a browser channel is connected — `playwright` **or** `chrome-devtools`, either
22
- one, whichever answers first (**how**: [`browser.md`](browser.md); which:
23
- [`companion-skills.md`](companion-skills.md)): after a
22
+ one, on WebKit first with Chromium a stated exception (**how**, and the engine order:
23
+ [`browser.md`](browser.md); which: [`companion-skills.md`](companion-skills.md)): after a
24
24
  task that changes a rendered surface, load it, take a snapshot and read the
25
25
  console and the network log **before the task is marked DONE** — a component can be
26
26
  correct and land under a fixed header, and a review of the diff cannot see that.
@@ -13,8 +13,9 @@ The full gate and freedom level remain in [stages.md](stages.md).
13
13
  - **A deployed web target is opened, not curled.** A `200` proves the server
14
14
  answered; it says nothing about whether the page rendered, whether a bundle 404'd,
15
15
  or whether the console filled with errors on load — all three ship green past a
16
- health check. Where a browser channel is connected — `playwright` **or**
17
- `chrome-devtools`, either one ([`browser.md`](browser.md)) — load the deployed URL and read
16
+ health check. Where a browser channel is connected — `playwright` on WebKit first
17
+ **or** `chrome-devtools` as the stated Chromium exception, and a Chromium-only look
18
+ is reported as such; either one ([`browser.md`](browser.md)) — load the deployed URL and read
18
19
  the console and the network log; quote what you read, not that you looked
19
20
  ([`companion-skills.md`](companion-skills.md)). Absent → say the check was an HTTP
20
21
  response only, which is the honest name for it.
@@ -1,9 +1,10 @@
1
1
  # Stages — detail & gates
2
2
 
3
- For the selected **default profile**, read this spine at entry, then the one detail
4
- linked in the current stage before work on every entry or resume, including wave
5
- iterations and approved short paths. Do not preload all stage details. Missing or
6
- unreadable detail means stop that stage and repair its route, never guess. A custom
3
+ For the selected **default profile**, read **one stage section of this file when that
4
+ stage starts** (the stage table in `SKILL.md` is the index), then the one detail it
5
+ links, on every entry or resume, including wave iterations and approved short paths
6
+ (the triage approves the short path itself since 1.98.0). Never read this file end to
7
+ end. Do not preload all stage details. Missing or unreadable detail means stop that stage and repair its route, never guess. A custom
7
8
  profile uses its own declared doctrine and stages; numeric ids do not select these
8
9
  default details, and the kernel still applies.
9
10
 
@@ -14,7 +15,10 @@ orchestrator verifies the check itself, pass/fail), `judgment` (a named judge
14
15
  rules where no complete deterministic check exists — [`gates.md`](gates.md) →
15
16
  *The judgment gate*) or `manual` (requires the operator's explicit go, including a
16
17
  specific standing authorization naming the act, cited with its source and scope;
17
- otherwise wait). These stages (0 intake + 1→10) are the plugin's
18
+ otherwise wait). **This example ships every gate `auto`** (since 1.98.0): where it
19
+ names an approval, the operator's answer or the standing authorization recorded in the
20
+ brief satisfies it without a pause. A project makes a gate `manual` in its own
21
+ `pipeline.json`. These stages (0 intake + 1→10) are the plugin's
18
22
  **example** flow, encoded in `pipeline.example.json` against the universal contract
19
23
  `pipeline.schema.json`; a host project replaces it with its own
20
24
  stages/agents/types (see SKILL.md → *Bring your own skills*).
@@ -84,7 +88,11 @@ never that the work was skipped quietly.
84
88
 
85
89
  **On entry or resume:** read [stage-00-intake.md](stage-00-intake.md) before stage work.
86
90
 
87
- - **GATE (manual):** shared understanding reached — **the source ledger is written
91
+ - **On the short path** (`stage-00-intake.md` → Phase 1d) this gate
92
+ is: the triage line printed, the brief and its REQ rows in the run ledger, the retro
93
+ floor read with its byte count, and the source ledger. Everything else below applies
94
+ to the full flow.
95
+ - **GATE (auto):** shared understanding reached — **the source ledger is written
88
96
  (every source consulted, or an explicit "none found")** and **its `Contradictions:`
89
97
  line is written under it** — the harvest is a fan-out that converges on one brief, and
90
98
  nothing else compares the sources *with each other*; `Contradictions: none` is the
@@ -107,8 +115,8 @@ never that the work was skipped quietly.
107
115
  is filled — objective, exit checks on the artefact the operator uses, scope, budget and
108
116
  base** ([`finish-line.md`](finish-line.md)), the carry-over ledger is
109
117
  seeded, **`.task-pipeline/run.md` exists and the header block has been printed**
110
- ([`progress.md`](progress.md)), the model decision is recorded, and the operator
111
- confirms the brief. Stop when a
118
+ ([`progress.md`](progress.md)), the model decision is recorded, and the brief is
119
+ confirmed: the operator's answer, or the standing authorization recorded in it. Stop when a
112
120
  re-scan surfaces no new branches (don't grill past diminishing returns;
113
121
  reversible calls can be deferred with a note). Only then start stage 1.
114
122
  - **The verification ledger is read.** `<artifacts>/verification.md` — the harvest
@@ -140,7 +148,8 @@ never that the work was skipped quietly.
140
148
 
141
149
  **On entry or resume:** read [stage-02-brainstorm.md](stage-02-brainstorm.md) before stage work.
142
150
 
143
- - **GATE (manual):** the user approves the design, the UI verdict is recorded, **the
151
+ - **GATE (auto):** the design is approved (the operator's go, or the brief's standing
152
+ authorization), the UI verdict is recorded, **the
144
153
  queue is an artifact rather than a recollection** — where it is a work graph,
145
154
  `graph.py validate` exits 0 and `graph.py coverage` names any requirement no node serves,
146
155
  **every REQ is answered by the design** — a requirement the design doesn't
@@ -156,10 +165,11 @@ never that the work was skipped quietly.
156
165
 
157
166
  **On entry or resume:** read [stage-03-spec.md](stage-03-spec.md) before stage work.
158
167
 
159
- - **GATE (manual):** the **`## Self-review` section written and committed with
168
+ - **GATE (auto):** the **`## Self-review` section written and committed with
160
169
  computed values** — every check the spec names resolving or marked `review`, the
161
170
  brief's decisions and stage 2's rejected options read back with no unresolved
162
- contradiction, and the cost delta printed; spec committed **and** user-reviewed; **every section carries
171
+ contradiction, and the cost delta printed; spec committed **and** reviewed (by the
172
+ operator, or under the brief's standing authorization by an independent reader); **every section carries
163
173
  `covers: REQ-…` and every REQ appears in at least one section**; for UI tasks
164
174
  additionally: the super-ux chain (foundation → flows → screens → scenarios) is
165
175
  designed, validated and approved; scenarios validated in `docs/ux/scenarios.md`;
@@ -254,8 +264,9 @@ never that the work was skipped quietly.
254
264
  page rendered — a component can be correct and land under a fixed header, a request
255
265
  can 404 while every unit test mocks it, and a console error costs nothing at test
256
266
  time. Where a browser channel is connected — `playwright` **or** `chrome-devtools`,
257
- either one ([`browser.md`](browser.md) is the four commands this sentence means;
258
- [`companion-skills.md`](companion-skills.md) is which channel):
267
+ either one, on WebKit first with Chromium a stated exception
268
+ ([`browser.md`](browser.md) is the four commands this sentence means and the engine
269
+ order; [`companion-skills.md`](companion-skills.md) is which channel):
259
270
  load the surface, take a snapshot, and read **the console and the network log**
260
271
  before calling it green. Absent, say the surface was verified **by reading the
261
272
  diff** — that is a weaker claim and the close-out records it as one, rather than
@@ -298,10 +309,10 @@ never that the work was skipped quietly.
298
309
 
299
310
  **On entry or resume:** read [stage-07-lint-deploy.md](stage-07-lint-deploy.md) before stage work.
300
311
 
301
- - **GATE (manual):** lint clean (host linter **and**, for UI projects, the super-ux
312
+ - **GATE (auto):** lint clean (host linter **and**, for UI projects, the super-ux
302
313
  linter) **and** suite green **before** deploy, **and no REQ is still `open`** — a
303
314
  `partial` ships only with the operator's explicit acceptance. A gap is cheapest to
304
- close before it ships, and the operator is already present at this gate. **The
315
+ close before it ships. **The
305
316
  carry-over count is printed beside this verdict.** Deploy is outward → explicit
306
317
  operator go, or a specific standing authorization naming that act, cited with its source
307
318
  and scope. Authorization to release does not silently authorize a separate deploy. If
@@ -375,7 +386,7 @@ never that the work was skipped quietly.
375
386
 
376
387
  **On entry or resume:** read [stage-10-acceptance.md](stage-10-acceptance.md) before stage work.
377
388
 
378
- - **GATE (manual):** the ladder walk ran and its absences became REQ rows before
389
+ - **GATE (auto):** the ladder walk ran and its absences became REQ rows before
379
390
  the table was written; **the hand-back is written** — the request quoted as it was
380
391
  GIVEN, where the run stands against it, what was solved with its evidence, what
381
392
  surfaced that nobody asked for, every decision still waiting **asked here with
@@ -421,10 +432,11 @@ never that the work was skipped quietly.
421
432
  carries evidence; every `partial` names what's missing and where it's tracked;
422
433
  every `deferred`/`dropped` has the operator's agreement and, for `deferred`, a
423
434
  tracker entry; no carry-over row left `unresolved`, and the ledger's counts are
424
- printed with the verdict; the operator answers the
425
- closing question and signs off. Manual by design — an automated check can prove
426
- the table is well-formed, only the person who asked can confirm it is what they
427
- asked for.
435
+ printed with the verdict; the hand-back asks the closing question and carries
436
+ the answer the operator can give at any time. `auto` by default since 1.98.0: a
437
+ check proves the table well-formed, and only the person who asked can confirm it is
438
+ what they asked for, so the run hands that question back rather than waiting on it.
439
+ A project that wants the wait sets this gate `manual`.
428
440
 
429
441
  ## The program loop — a platform, one brick at a time
430
442
 
@@ -485,8 +497,8 @@ cycle.
485
497
  a feeling, and the ledger is what survives compaction.
486
498
  - **Trips on:** revert-oscillation (A→B→A); the same file edited twice for the same
487
499
  reason; a finding already ADDRESSED or parked coming back; a stage entered a third
488
- time for one artifact; two loops editing one file. Hard caps: 5 fix rounds per
489
- task, 2 re-entries per stage per artifact, 3 passes per module.
500
+ time for one artifact; two loops editing one file. Hard caps, each a stop: 3 fix
501
+ rounds per task, 2 re-entries per stage per artifact, 3 passes per module.
490
502
  - **On a trip: stop editing.** Name shapes A and B with their evidence, escalate to
491
503
  the layer that owns the conflict (rubric → operator → plan → spec → module map),
492
504
  re-plan the check as an ordered one-item-per-line checklist, then go through it in
@@ -102,8 +102,9 @@ database created ten seconds ago" are different claims, and only the second one
102
102
  code does what its assertions say; it cannot see a component that renders correctly
103
103
  and lands under a fixed header, a request that 404s while every unit test mocks it,
104
104
  or a console error that costs nothing at test time. Where a browser channel is
105
- connected — `playwright` **or** `chrome-devtools`, either one
106
- ([`companion-skills.md`](companion-skills.md)) — open the surface and read
105
+ connected — `playwright` **or** `chrome-devtools`, either one, on WebKit first with
106
+ Chromium a stated exception ([`companion-skills.md`](companion-skills.md);
107
+ [`browser.md`](browser.md) → *Engine order*) — open the surface and read
107
108
  the console and the network log before calling it done — and **quote what you read**,
108
109
  not that you looked. Absent, the honest sentence is *"verified by reading the diff"*,
109
110
  which is a weaker claim and is recorded as one. Same family as a test that passes
@@ -57,10 +57,12 @@ on real agents, tasks and users rather than on the first guess.
57
57
  | 5–8 Build → post-deploy | per wave, then the close pass. A wave's stage 7 integrates to the main branch **without tagging**; the release's tag, its approval mode and its go are stage 7's full gate, run once at the release ([`iteration.md`](iteration.md) → *The cycle*, step 10), and stage 8's trio follows on what was released (step 11) |
58
58
  | 9 Docs + wiki · 10 Acceptance | once, to close the release, over everything the waves shipped |
59
59
 
60
- **One planning gate, not three prompts.** The manual gates of stages 0, 2 and 3 are
61
- presented together at the end of planning: the brief, the canvas, the wave plan and the
62
- question batch in one message. Each gate's criteria are still checked and printed; the
63
- operator is asked once, and the go names the gates it closes. Silence closes none.
60
+ **One planning gate, not three prompts.** The gates of stages 0, 2 and 3 are presented
61
+ together at the end of planning: the brief, the canvas, the wave plan and the question
62
+ batch in one message. Each gate's criteria are still checked and printed. They are `auto`
63
+ by default (since 1.98.0): the standing authorization recorded in the brief closes them
64
+ and the run continues; where the project made them `manual`, the operator is asked once,
65
+ the go names the gates it closes, and silence closes none.
64
66
 
65
67
  ## Wave 0 — the survey and the inventory
66
68