task-pipeline-skill 1.97.1 → 1.99.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 (44) hide show
  1. package/CHANGELOG.md +283 -0
  2. package/HOW-IT-WORKS.md +17 -13
  3. package/README.md +13 -10
  4. package/SKILL-CARD.md +1 -1
  5. package/cursor/rules/task-pipeline.mdc +22 -14
  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 +11 -4
  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/build.md +22 -7
  22. package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +49 -44
  23. package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +6 -3
  24. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -1
  25. package/plugins/task-pipeline/skills/task-pipeline/references/finish-line.md +13 -8
  26. package/plugins/task-pipeline/skills/task-pipeline/references/iteration.md +188 -32
  27. package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +5 -3
  28. package/plugins/task-pipeline/skills/task-pipeline/references/learned.md +24 -1
  29. package/plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md +17 -7
  30. package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +49 -2
  31. package/plugins/task-pipeline/skills/task-pipeline/references/spec.md +5 -4
  32. package/plugins/task-pipeline/skills/task-pipeline/references/stage-00-intake.md +39 -25
  33. package/plugins/task-pipeline/skills/task-pipeline/references/stage-05-dev.md +1 -1
  34. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +36 -28
  35. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +8 -5
  36. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +79 -22
  37. package/plugins/task-pipeline/skills/task-pipeline/scripts/lessons.py +1229 -110
  38. package/plugins/task-pipeline/skills/task-pipeline/scripts/retro_budget.py +305 -0
  39. package/plugins/task-pipeline/skills/task-pipeline/scripts/short_path.py +70 -0
  40. package/plugins/task-pipeline/skills/task-pipeline/scripts/waves.py +22 -10
  41. package/plugins/task-pipeline/skills/task-pipeline/templates/canvas.md +1 -1
  42. package/plugins/task-pipeline/skills/task-pipeline/templates/lesson.schema.json +38 -10
  43. package/plugins/task-pipeline/skills/task-pipeline/templates/retro-archive.md +9 -0
  44. package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +10 -1
@@ -1,576 +1,21 @@
1
- # Retrospective — the run teaches the next run, and the list stays short
2
-
3
- The last act of stage 10, after the coverage table and before the run is called
4
- done. It exists because the pipeline's gates are good at *this* run and blind
5
- across runs: the same class of failure can be caught, fixed and forgotten five
6
- times, and nothing in the flow notices it is the same one.
7
-
8
- **The cap here is not a general rule about doctrine files.** It applies because these
9
- instructions are read *in full* every run. [`learned.md`](learned.md) →
10
- *What leaves this file, and why there is no cap* is the other case: a file entered by
11
- citation, where the index must be right rather than the length short, and where a rule
12
- retires on two triggers that are not counts. Proposing this cap for that file is a
13
- recurring idea, and it is answered there with the measurement rather than an opinion.
14
-
15
- **Two artifacts, and the split is the point.** A file that is read *in full* every
16
- run may not contain anything that grows without limit — otherwise the cap that
17
- justifies reading it protects one section while the file below it doubles.
18
-
19
- | Artifact | Parts | How it is read |
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 |
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
- | `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
-
25
- Seed the archive from [`../templates/retro-archive.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/templates/retro-archive.md).
26
-
27
- Every run writes a **stamp** and runs the **prune**. Only a run that *diverged*
28
- writes an entry. A retro that is empty after a messy run is the exact failure this
29
- file exists to stop.
30
-
31
- ## Contents
32
-
33
- - Write the entry only for a divergence — and name the layer that owned it
34
- - Every lesson carries its commit
35
- - Never amend a commit a record already names
36
- - A release stamp names the TAG, and the merge commit — never the branch's own SHA
37
- - The stamp table is capped at ten, and *one line per run* was never a cap
38
- - `publish:` is a line in the verdict, not a silence
39
- - Rotation — the archive is how pruning stops losing things
40
- - Three grades of fix — take the highest one that can work
41
- - Stamp first, then prune, then write
42
- - The prune — mandatory, and it runs after the stamp
43
- - When the prune cannot run, say so — it is not the same as nothing to prune
44
- - A fix to one call site closes a call site, not a class
45
- - The loop closes at stage 0
46
- - Where a lesson goes when it is not about this project
47
- - Recording to a shared lesson store, where the host has one
48
- - Publishing the insight — the skill learns from every project that runs it
49
- - The improvement iteration — what happens to a published insight next
50
- - What may leave the project — the redaction list
51
- - Rationalizations
52
-
53
- ## Write the entry only for a divergence — and name the layer that owned it
54
-
55
- An entry is owed when the run did not go as planned: a gate reopened, a stage was
56
- re-entered, a fix broke something it wasn't touching, an estimate was wrong by a
57
- factor, the operator had to intervene where the brief said they wouldn't.
58
-
59
- Required fields, and none of them is optional:
60
-
61
- | Field | The rule |
62
- |---|---|
63
- | **Symptom** | what actually happened, in one line, with the evidence (a command, a `file:line`, the gate that reopened) |
64
- | **Surfaced at** | the stage where it became visible |
65
- | **Owned by** | the stage that *let it through* — usually an earlier one. A finding belongs to the layer that owns it; recording it against the stage that tripped over it is how the same defect returns |
66
- | **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
- | **Fix** | one of the three grades below |
68
- | **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 |
69
- | **Commit** | the short SHA of the change that fixed it |
70
-
71
- ## Every lesson carries its commit
72
-
73
- A standing instruction carries **two** SHAs — `Commit` (the change that introduced
74
- it) and `Fired at` (the last run in which it fired) — and every log entry and every
75
- retirement carries one.
76
-
77
- **Why a SHA and not a `file:line`.** A line number rots at the next edit, and then
78
- the evidence points at something that has moved or gone; the reader is left with a
79
- claim and no way to check it. A commit is immutable and carries the diff, the
80
- message and the parent, so `git show <sha>` reconstructs the entire incident two
81
- months later — which is exactly when the same class comes back and somebody needs
82
- to know whether this was already understood.
83
-
84
- **Every SHA must resolve — and resolving is not enough.** This is
85
- [`learned.md`](learned.md) rule 14 — *a document may not send a reader to something
86
- absent* — applied to history, and it is mechanical: the documentation gate runs
87
- `git rev-parse --verify --quiet <sha>^{commit}` over every backticked SHA in the retro
88
- and its archive ([`gates.md`](gates.md)).
89
-
90
- **But a commit that was amended away still resolves on the machine that amended it**,
91
- and exists in no clone. The gate therefore also requires each SHA to be **reachable
92
- from `HEAD`** — `git merge-base --is-ancestor <sha> HEAD` — because that is the
93
- question a reader two months from now is actually asking, and the weaker one passes
94
- for as long as the object survives locally.
95
-
96
- ## Never amend a commit a record already names
97
-
98
- Measured 2026-08-16, twice in one close-out and twenty minutes apart. The sequence is
99
- seductive because each step is right on its own: stamp the run with its commit → the
100
- stamp is part of the run, so fold it in with `--amend` → the amend mints a new SHA →
101
- the stamp now names a commit that will never reach the remote.
102
-
103
- The rule is one line and it is absolute: **once a file names a SHA, that commit is
104
- frozen.** A correction goes in a *follow-up commit*, never a second amend — amending to
105
- repair a stamp is the loop that produced the problem, and the second attempt lands in the
106
- same place as the first.
107
-
108
- Practically, that makes the order:
109
-
110
- 1. commit the work;
111
- 2. **then** stamp, in a commit of its own, naming the commit from step 1;
112
- 3. prune and write the entry in that same second commit, or a third.
113
-
114
- The stamp costs one line and one commit. A run that folds it back into the work to keep
115
- the history tidy is trading a reader's ability to find the incident for the appearance of
116
- tidiness — and the reader is the entire reason the stamp exists.
117
-
118
- ## A release stamp names the TAG, and the merge commit — never the branch's own SHA
119
-
120
- The sibling of the amend rule, one level up, and it recurred three times after the amend
121
- rule was written because each step is right on its own: stamp the run on the PR branch →
122
- the stamp cites that branch's HEAD → `main` is **rebase-merge-only** by ruleset → the
123
- rebase mints new SHAs → the object the stamp names dies with the branch.
124
-
125
- Measured across `v1.79.1` (twice) and `v1.80.0`, and again on 2026-09-05 in the umbrella
126
- repository, where it burned **two tags** in one afternoon. Each recurrence costs the same
127
- two refusals, both of them correct:
128
-
129
- 1. the **unstamped-release guard** reads the tag's own commit range, finds no stamp that
130
- resolves, and refuses the release;
131
- 2. the **documentation gate** resolves every backticked commit reference against a *fresh
132
- clone*, where the branch SHA has never existed, and refuses again.
133
-
134
- Then it costs one extra PR and one full CI round — measured at 57–97 minutes here.
135
-
136
- **The shape that survives a rebase-merge is the tag.** A SHA the author can know before
137
- the merge is precisely the SHA the merge is about to destroy, so the rule cannot be
138
- "write a better SHA". Two spellings are allowed and nothing else:
139
-
140
- - **cite the release tag** — `v1.84.1` is immutable, it is the thing being released, and
141
- it resolves in any clone;
142
- - **or write the stamp AFTER the merge**, in a second PR, naming the **merge commit**.
143
- This is the default, because it is what the amend rule already forces one level down:
144
- once a file names a SHA, that commit is frozen, so the SHA has to exist first.
145
-
146
- The order for a release run is therefore:
147
-
148
- 1. merge the work; the merge commit is now a real object on `main`;
149
- 2. **then** stamp, in a second PR, naming that merge commit;
150
- 3. cut the tag **locally**, run `npm run test:all` against the tag's own tree, and push
151
- the tag only if that run is green — `git merge-base --is-ancestor <stamp-sha> HEAD`
152
- is what the release gate will ask, so ask it first.
153
-
154
- Step 3 is not optional and it is not the same as a green branch build: the branch tree
155
- and the tag's tree differ by whatever the merge did, and **a tag cannot be repaired** —
156
- deleting or re-pointing one is refused by repository rule, correctly, because a tag is a
157
- promise about a tree. A tag pushed on a green branch build is a promise about a tree
158
- nobody ran.
159
-
160
- ## The stamp table is capped at ten, and *one line per run* was never a cap
161
-
162
- Measured 2026-08-10: standing instructions **~1 234 tok** behind a cap of ten, run stamps
163
- **~2 099 tok over 27 rows** behind nothing. Both are read in full at stage 0 and both
164
- were described as *bounded by construction*. One line per run is a **slope**: at a
165
- hundred runs the stamp table alone is ~7 800 tokens of a floor the doctrine believes is
166
- bounded.
167
-
168
- This is the same shape the 2026-08-10 audit found in the narrative log and moved out of
169
- the floor — and it left the neighbour in the same file, with the same property, because
170
- the neighbour's growth is *tidy*. A tidy slope is still a slope.
171
-
172
- **The cap is ten and the trigger is why.** The cold rule reads *the last five run
173
- stamps*; ten is that with a margin, so a stamp rotating out can never be one the trigger
174
- needed. At the eleventh, the oldest row moves — whole, with its verdict and its retro
175
- column — into `docs/evidence/retro/YYYY-QN.md` under `## Run stamps`, append-only,
176
- like every other rotation. **The count is printed at the prune**, beside the standing
177
- instructions' own count, so a table that stops rotating is visible rather than merely
178
- large.
179
-
180
- ## `publish:` is a line in the verdict, not a silence
181
-
182
- Reported from another project, and the report is about this file: an operator asked, after
183
- many runs, why nothing had ever been published.
184
-
185
- The floor is right and does not move — publishing is opt-in per project, off by default,
186
- because an outward act taken from a generic flag is an outward act nobody authorized. The
187
- gap is what happens next. A project with no configuration produces, run after run,
188
- retrospective entries carrying lessons about **the skill**, and the mechanism reports
189
- nothing, because it was never armed. **An unarmed mechanism and a mechanism with nothing
190
- to say are indistinguishable from the outside** — [`gates.md`](gates.md)'s false success,
191
- applied to this bundle's own learning path. In the reporting project several runs had
192
- produced skill-level lessons over months; the count of published insights was zero and no
193
- gate had ever mentioned it.
194
-
195
- Stage 10 prints ratchets and two disclosures — what the run declined to claim, and what a
196
- check never looked at. Publishing is neither, so its absence is not observable at the only
197
- moment anyone is reading.
198
-
199
- **So stage 10's block carries one line for publication:**
200
-
201
- ```
202
- publish: <issue url> — opened this run
203
- publish: 0 (configured, nothing insight-grade)
204
- publish: not configured (N insight-grade entries stayed local)
205
- ```
206
-
207
- It arms nothing and authorizes nothing; it makes the silence legible. A count of zero
208
- beside *configured* is a fine answer. A **blank** where configuration is absent is how an
209
- instruction went unread for eight releases.
210
-
211
- **The failure mode survived its own fix, in a quieter form.** This section once said
212
- *"open an issue upstream"* while naming no repository, no trigger and no authorization,
213
- and every reader took it as done. The mechanism that replaced it is correct — and until
214
- this line existed it still had no way to say it never ran.
215
-
216
- ## Rotation — the archive is how pruning stops losing things
217
-
218
- At the prune, entries older than the last five run stamps **move** to
219
- `docs/evidence/retro/YYYY-QN.md`. Moving is not deleting.
220
-
221
- - The archive is **append-only**, and a retirement writes its line **there**, with
222
- the trigger that retired it and the commit.
223
- - A retired rule that comes back as a real failure is a grade-1 fix — **with its
224
- history attached**, which is the whole return on having archived it.
225
- - Nothing is ever removed from the archive to keep it tidy. It is not read in full,
226
- so its size costs nothing; its completeness is what it is for.
227
-
228
- ## Three grades of fix — take the highest one that can work
229
-
230
- **Grade 1 — mechanical.** A test, a lint rule, a gate criterion, a CI step, a hook.
231
- The check *is* the memory: nothing has to be read, remembered or pruned later. Log
232
- it as `landed` and move on — it never becomes a standing instruction and never
233
- costs a slot.
234
-
235
- **Grade 2 — a standing instruction.** A rule an agent must read, for the cases no
236
- check can decide (a judgement, a precedence, a "ask before X"). It costs one of the
237
- ten slots and it is **only accepted with its retirement trigger written at birth**
238
- (below).
239
-
240
- **Grade 3 — a note with an expiry.** For something still being understood. Maximum
241
- **two runs**. At the second stamp it is promoted to grade 1 or 2, or deleted. A note
242
- with no expiry is how a file becomes unreadable one honest line at a time.
243
-
244
- Prefer grade 1 whenever a check can decide it. This is the same law as
245
- [`audit.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/audit.md) → *A class that repeats twice becomes a gate, not a note*: a
246
- rule that could have been a check gets read twice and obeyed once.
247
-
248
- ## Stamp first, then prune, then write
249
-
250
- `learned.md` rule 21. This order used to be *prune first*, and that was a **deadlock**, not a
251
- preference: the cold trigger below reads *the last five run stamps*, and the stamp was written after
252
- the prune. The trigger read a counter the same stage produced later, so on any list it had never run
253
- on real data — and it stays unreadable for exactly as long as nobody stamps.
254
-
255
- Measured on a real project: last entry five days old; stamps per day 33, 20, 26, **3, 0** — the zero
256
- on a day with 107 commits — and the list sitting at **10 of 10**. Every run arrived at a stage that
257
- opened with a full list, an unusable trigger and a mandatory deletion. It was not skipped out of
258
- laziness; its first step could not be performed, and the cheap step that would have made it
259
- performable was queued behind it.
260
-
261
- **The stamp is one line and costs nothing.** It is also the only thing that makes the prune
262
- computable, which is why it goes first:
263
-
264
- ```bash
265
- printf '%s · %s\n' "$(date +%F)" "$(git rev-parse --short HEAD)" >> docs/evidence/retro.md
266
- ```
267
-
268
- ## The prune — mandatory, and it runs after the stamp
269
-
270
- A lesson that lands in a cluttered file is a lesson nobody will reach — so the prune still runs
271
- before the entry is written. It runs *after* the stamp, because it reads it.
272
-
273
- Every row carries its own trigger in a **`Retire when`** column AND a **class**,
274
- both written at birth — a rule whose retirement condition is decided later is a
275
- rule the prune can only argue about. Three classes, because coldness means
276
- three different things:
277
-
278
- - **permanent** — a safety invariant, a contract, a recovery procedure. The
279
- absence of the rare event it guards is not absence of value: **coldness never
280
- retires a permanent rule** — only *became a check* or *surface gone* do.
281
- - **situational** — fires when a named EXPOSURE occurs (a payment run, a
282
- migration, a release). Its row names the exposure, and the prune counts
283
- **exposure opportunities, not raw runs**: five runs that never touched
284
- payments say nothing about a payment rule.
285
- - **temporary** — a workaround with a **TTL** and the replacing mechanism named
286
- at birth. TTL only exists on this class.
287
-
288
- Check **every** standing instruction against three triggers:
289
-
290
- | Trigger | Test | Then |
291
- |---|---|---|
292
- | **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 |
293
- | **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 |
294
- | **It went cold** | *situational only*: it fired in none of the last **five exposure opportunities** — or no exposure occurred in **sixty days** | mark **review-needed** and put the question to the operator with the exposure counts — cold is evidence worth reviewing, never an automatic deletion. *temporary*: TTL expired → archive it **once the replacing mechanism is verified present** (its check resolves and runs); an expired workaround whose replacement is absent is a live defect, not a retirement. *permanent*: not applicable |
295
-
296
- Every removal stays explainable: the archive line names the class, the trigger
297
- and the evidence (the exposure counts, or the replacing mechanism's check).
298
-
299
- **Each trigger is a command, not a judgement.** A retirement condition nobody can run is a
300
- condition nobody applies, which is how a list reaches ten and stops being read:
301
-
302
- ```bash
303
- # became a check — the rule's own words appear in something that runs
304
- grep -rl "$RULE_KEYWORD" scripts/ test/ .github/workflows/ Makefile* 2>/dev/null
305
-
306
- # surface is gone — every path, command and tool it names, resolved
307
- grep -oE '`[^`]+`' <<<"$RULE_TEXT" | tr -d '`' | while read -r t; do
308
- [ -e "$t" ] || command -v "$t" >/dev/null || echo "MISSING: $t"; done
309
-
310
- # went cold — fired in none of the last five stamps
311
- tail -n 200 docs/evidence/retro.md | grep -c "$RULE_ID"
312
-
313
- # ...OR in the last 60 days, whichever comes first — see below for why both
314
- git log -1 --format=%cd --date=short -S"$RULE_ID" -- docs/evidence/retro.md
315
- ```
316
-
317
- Anything the first two print is a deletion. A zero from the third — counted against
318
- **exposure opportunities** for a situational rule (`grep -c "$EXPOSURE_MARK"` over the same
319
- stamps, so the denominator is runs that COULD have fired it) — marks **review-needed**, and the
320
- run states the counts rather than the conclusion (`learned.md` rule 19 — an empty result and an
321
- unrun command look identical). Only the operator's answer, or a temporary rule's verified
322
- replacement, turns review-needed into a removal.
323
-
324
- **Why the cold trigger needs two units, and it is not belt-and-braces.** A run stamp is written by
325
- a run *of this pipeline*. Where a project ships some of its work another way, the stamp counter
326
- stops while the work does not — so "the last five stamps" can span an arbitrary amount of change,
327
- and a rule sits unexamined for exactly as long as the pipeline goes unused. Measured on this
328
- repository: **ten consecutive releases, `v1.16.0` through `v1.23.0`, carry no stamp at all.** Over
329
- that stretch the trigger was not strict or lenient; it was **unreadable**, and a list capped at ten
330
- with an unreadable retirement condition fills up and stops being pruned.
331
-
332
- The wall-clock alternative fires on elapsed time, which nothing can stall. Keep both: the stamp
333
- count is the better signal when the pipeline is in use, and the date is the one that still works
334
- when it is not.
335
-
336
- **The stamp gap is itself a number worth printing.** A retro whose newest stamp is far behind the
337
- repository's newest release is telling you the retro is describing a smaller world than the one
338
- that shipped — the same failure `learned.md` rule 16 records for a work-list. State it beside the
339
- retro counts:
340
-
341
- ```bash
342
- git tag --sort=-v:refname | head -1 # newest release
343
- grep -m1 -oE '`[0-9a-f]{7,}`' docs/evidence/retro.md # newest stamped commit
344
- ```
345
-
346
- Then the cap: **ten standing instructions, hard.** At eleven you do not get to keep
347
- them all — the oldest never-fired one goes. "But all of them matter" is precisely
348
- the state in which the list stopped being read, and the ninth stale rule is what
349
- discredits the two that are load-bearing.
350
-
351
- **Every deletion writes one line in the archive** — id, date, which trigger fired,
352
- and the commit. Silent deletion is forbidden: the record is what survives, the
353
- instruction is what leaves.
354
-
355
- **Print the counts beside the gate verdict**, the same way the carry-over ledger
356
- does ([`audit.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/audit.md) → *What can't be fixed now becomes a ratchet, never a TODO*):
357
-
358
- ```
359
- GATE 10 acceptance: PASS — 14/14 REQ verified
360
- carry-over: 0 unresolved · retro: 7 standing (was 9) · retired 3 · added 1
361
- abstained: 2 · unlooked: 3
362
- holds: 10 — none — enumerated 8/8 classes
363
- ```
364
-
365
- A pruned list that nobody prints is a list that quietly grows back.
366
-
367
- ## When the prune cannot run, say so — it is not the same as nothing to prune
368
-
369
- The prune retires a standing instruction against its triggers, and the cold trigger counts
370
- run stamps. Meeting a list whose rows carry **no id and no retirement condition**, the
371
- honest behaviour was undefined — so a careful run printed counts and stopped while a
372
- careless one could delete nine rules, and both looked like *the prune ran*.
373
-
374
- - **Backfill first, once.** On meeting rows with no id, the prune's first act is to mint
375
- ids and propose a retirement condition per row **from the row's own text**, printed for
376
- the operator to accept. One pass, and the trigger works forever after.
377
- - **`blocked` is a named outcome**, printed like any other: what could not be evaluated
378
- and why. An undefined case is where the spread between two runs lives.
379
- - **A hard cap plus an unrunnable retirement condition is a deadlock.** Either the cap
380
- yields until the backfill is done, or the backfill is a precondition of enforcing it —
381
- but not both, and the file says which.
382
-
383
- ## A fix to one call site closes a call site, not a class
384
-
385
- - **A fix other call sites will need is exported before it is used.** The test is
386
- mechanical: if the same defect could exist in a second file, the fix does not stay
387
- private to the first.
388
- - **Closing a defect includes a census of its siblings, by BEHAVIOUR rather than by a list
389
- of names** — *every script that spawns a browser*, found by searching for the spawn, not
390
- by remembering the five. A list of names is how the previous pass missed four of them.
391
- - **The entry states how many call sites the class had and how many were fixed.** *Fixed*
392
- and *fixed in one of five* currently read identically, and only one of them closes a row.
393
-
394
- ## The loop closes at stage 0
395
-
396
- The standing instructions are an **instruction source**, not background reading:
397
- [`knowledge-sources.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md) reads them in full at the harvest —
398
- they are short by construction — and records the file as a ledger row. Every
399
- instruction that actually *fires* during the run gets its **last-fired date and
400
- commit stamped** as it fires. That stamp is the only thing that makes the cold-rule
401
- honest; without it "five runs without firing" is a guess, and the prune becomes a
402
- mood.
403
-
404
- **The archive is queried at the same moment**, by the task's own nouns. It is the
405
- one source that answers *"have we been bitten by this class before?"* — and that
406
- question is worth asking precisely when the in-force list says nothing, because a
407
- rule that was retired for going cold is exactly the rule about to be re-learned.
408
-
409
- ## Where a lesson goes when it is not about this project
410
-
411
- A lesson that would be true in any repository does not belong in one project's
412
- retro — it belongs in the pipeline's own doctrine
413
- ([`learned.md`](learned.md), which is exactly that list, earned the same way). A local
414
- file that accumulates universal rules is a fork of the skill that nobody named.
415
-
416
- **This said *"open an issue upstream"* for eight releases and named no repository, no
417
- trigger and no authorization** — an instruction on rung 1 that everybody read as done.
418
- The rest of this section is the mechanism.
419
-
420
- ## Recording to a shared lesson store, where the host has one
421
-
422
- **One job: let the next agent on another project read this lesson at its stage 0.** An
423
- entry whose class would be true in another project carries a `**Lesson:**` line — the class
424
- key, the class in one sentence, when it applies, 3–8 search nouns. That line makes it a
425
- *lesson* ([`lesson.schema.json`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/templates/lesson.schema.json), lesson/1): with task-pipeline installed, its `scripts/lessons.py add` puts it in the
426
- local index every install has, and where the session lists a shared lesson store (an
427
- Observatory) it is also recorded there, as a proposal. An entry without the line stays
428
- private to this project.
429
-
430
- **A lesson is not a publication, but the redaction list below binds it too — with one
431
- relaxation.** On this machine or estate (the local index, a shared store), rule 2 is relaxed
432
- for exactly two fields: the evidence commit and the pseudonymous project key (`p-` and 12 hex
433
- of the root commit, the same key in the store, never the repository's name or a
434
- `project:<slug>` id). A private repository's SHA names nothing; a public repository's SHA is
435
- searchable, so it stays in its field and never in text. Rules 1, 3, 4 and 5 still bind every
436
- text field: no path at all, no code or value, no person's, company's, customer's or
437
- product's name, a title that states the class. `retro.publish` strips the whole origin.
438
- The read side is source 7b of [`knowledge-sources.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md). Where no store exists the run
439
- says `shared lessons: absent` rather than nothing.
440
- Mechanics and the read and write recipes: [`iteration.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/iteration.md) → *The learning loop*.
441
-
442
- ## Publishing the insight — the skill learns from every project that runs it
443
-
444
- **One job: stop a lesson dying in the repository that learned it.**
445
-
446
- A retro entry is written per project and read by that project's next stage 0. The
447
- pipeline itself never sees it. So a defect in the **skill** — a gate that loops, a
448
- doctrine promising what nothing enforces, a rule firing on the wrong shape — is
449
- rediscovered independently in every project and fixed in none of them.
450
-
451
- **Opt-in, per project, off by default** — `pipeline.json` → `retro.publish`:
452
-
453
- ```json
454
- "retro": {
455
- "publish": {
456
- "repo": "ssheleg/task-pipeline",
457
- "label": "retro-insight",
458
- "redact": "strict"
459
- }
460
- }
461
- ```
462
-
463
- Absent, nothing is published, and nothing is asked. **Silence arms nothing** — the same
464
- floor deploy authorization uses, and for the same reason: this is an **outward act**,
465
- and an outward act taken from a generic flag is an outward act nobody authorized
466
- ([`continuity.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/continuity.md) → *The limit, before the capability*).
467
-
468
- **The body is printed in full before the issue is opened, every time.** Not a summary
469
- of it, not its title — the string that will be sent. The operator standing at stage
470
- 10's manual gate is already reading; showing them what leaves the machine costs one
471
- block and is the only moment anyone can stop it.
472
-
473
- ```
474
- ── would open issue ──────────────────────────────────────────
475
- repo: ssheleg/task-pipeline
476
- label: retro-insight
477
- title: [retro] a queue is not a diagnosis
478
- <the whole body, verbatim>
479
- ──────────────────────────────────────────────────────────────
480
- opening… → #24
481
- ```
482
-
483
- **No `gh`, no network, no permission?** Print the body, say the issue was **not**
484
- opened, and carry the exact text in the carry-over ledger. That is the honest
485
- degradation; a second transport is not.
486
-
487
- ## The improvement iteration — what happens to a published insight next
488
-
489
- Publishing is half a loop. An issue that is opened and never triaged is a lesson
490
- that cost a run and bought nothing, and a tracker full of those teaches everyone
491
- that publishing is where findings go to be filed.
492
-
493
- **The loop, and every arrow in it is somebody's obligation:**
494
-
495
- ```
496
- a run diverges → a retro entry → retro.publish → an issue on the skill
497
- ↓
498
- a board row ← measured against the tree ← triaged in a later cycle
499
- ↓
500
- doctrine + the guard that proves it → a release → the next run reads it
501
- ```
502
-
503
- **Resolve what you worked, let the rest accumulate — visibly.** At the close of a
504
- cycle that consumed published issues:
505
-
506
- - **An issue closes when the behaviour changed**, not when the lesson was
507
- understood (that is R-006, and it applies to issues exactly as it applies to
508
- findings). The closing comment names **where** it landed — a file and a line —
509
- and the guard that now holds it. A close with no address is a close nobody can
510
- audit.
511
- - **An issue nobody worked stays open.** It is not triaged into silence, not
512
- relabelled, not closed as stale. The pile is the queue, and its depth is the
513
- honest measure of how far behind the doctrine is.
514
- - **Nothing is deleted.** A closed issue keeps its number, and the number is what
515
- the CHANGELOG and the retro entry point at. Deleting one severs both, and the
516
- cost lands on whoever next asks *why is this rule here*.
517
-
518
- **Where the queue comes from at the start of a cycle**, in this order: open issues
519
- published by any project running this skill, then the board's open rows by computed
520
- priority, then the open-questions register. A run that finishes its brief early
521
- takes the top of that list rather than inventing work — and a run that *cannot*
522
- take it says so, which is a fuller queue rather than a quiet one.
523
-
524
- **The measurement that keeps this honest.** Print, at the close: issues consumed,
525
- issues resolved with an address, issues left open. Three numbers, no floor, no
526
- target, and the third one rising is information rather than a failure — it means
527
- the projects running this skill are finding more than one cycle can absorb, which
528
- is what you want them to do.
529
-
530
- ## What may leave the project — the redaction list
531
-
532
- An issue is a **public artefact in someone else's repository**. What travels is the
533
- *class*; what stays is everything that identifies where it happened. This list binds
534
- whatever leaves the estate, and every lesson too; *Recording to a shared lesson store*
535
- above names the one relaxation a lesson kept on this machine or estate gets.
536
-
537
- | Goes | Stays |
538
- |---|---|
539
- | the class of failure, stated in the abstract | the file, the function, the line it happened in |
540
- | which stage owned it and which stage surfaced it | the repository, organisation, branch or commit |
541
- | the doctrine or guard that missed it, by its name **in this skill** | any host path, absolute or relative |
542
- | the fix by grade, and the check that would catch it | the code, the config values, the data |
543
- | whether an existing standing instruction fired | any person, company, customer or product name |
544
-
545
- Five rules, numbered so a reader can point at one:
546
-
547
- 1. **No host paths.** Only paths inside task-pipeline itself — `references/…`,
548
- `templates/…`, `test/validate.py`. An absolute path names a machine.
549
- 2. **No host identifiers**: repository, organisation, branch, commit, tag, issue or PR
550
- number belonging to the project the run happened in.
551
- 3. **No code, no configuration values, no data** — not a snippet, not a redacted
552
- snippet. A shape can be described in a sentence.
553
- 4. **No names**: person, company, customer, employer, product.
554
- 5. **The title states the class, not the incident** — *"a queue is not a diagnosis"*,
555
- never *"our export job looped"*.
556
-
557
- **The printed text and the sent text are one string.** Redacting after the print, or
558
- printing a cleaned-up version of what is actually sent, is the false-success shape this
559
- bundle names outright ([`gates.md`](gates.md) → *False success*): a mechanism reporting
560
- on itself rather than on what it did.
561
-
562
- **When in doubt the rule is subtraction, not judgement.** An insight that survives
563
- losing a detail is still an insight; a detail that leaks cannot be recalled from an
564
- index. If removing it makes the entry incomprehensible, the entry was about the project
565
- and not about the skill — keep it local.
566
-
567
- ## Rationalizations
568
-
569
- | Excuse | Reality |
570
- |---|---|
571
- | "Nothing really went wrong this run" | Then the stamp says so in one line and you are done in ten seconds. The runs that "went fine" are where a repeated class hides — it never cost enough to remember. |
572
- | "I'll write the retro later, with a clear head" | Later is when you remember the outcome and not the seam. The cause is legible for about an hour after the run. |
573
- | "Don't delete it, it might still be useful" | That sentence is the entire failure mode. Every rule kept "just in case" spends attention that the load-bearing ones needed, and the file stops being read at all. |
574
- | "Pruning loses knowledge" | The Log keeps the incident forever; only the *instruction* leaves. If it recurs you get a grade-1 fix with its own history attached. |
575
- | "The list is at eleven but they're all important" | Then one of them is doctrine and belongs in `CLAUDE.md`, one has become a check, and one has not fired in a year. Ten is the budget precisely because ranking is uncomfortable. |
576
- | "I'll note it as a reminder for next time" | A note is grade 3 and expires in two runs. If it is worth remembering it is worth a check or a slot; if it is worth neither, it was never going to be read. |
1
+ # Retrospective: pointer
2
+
3
+ The retrospective doctrine has one home:
4
+ [task-pipeline's `references/retrospective.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md).
5
+ With the task-pipeline plugin installed, the same file sits beside this skill at
6
+ `skills/task-pipeline/references/retrospective.md`. Until 1.98.0 this file was a
7
+ 34.7 KB copy of it with no delta of its own; a copy is a second thing to keep true.
8
+
9
+ What evidence-docs relies on from it, in short:
10
+
11
+ - **One file per project**, `docs/evidence/retro.md`, written as stage 10's last act:
12
+ stamp the run first, then prune, then write an entry only if the run diverged.
13
+ - **The floor stage 0 reads in full** (standing instructions, max ten rows; run stamps,
14
+ max ten lines) stays under a 12 000-byte budget: a standing row at most 600
15
+ characters, a stamp at most 300. `scripts/retro_budget.py check` measures it.
16
+ - **Every lesson carries its commit**, and every SHA must resolve from `HEAD`.
17
+ - **Each entry names its Class and its Cost**; recurrence is counted by class.
18
+ - **A universal rule is cited by its [`learned.md`](learned.md) number**, never
19
+ restated; a lesson standing in two projects goes upstream in the same run.
20
+
21
+ evidence-docs-specific delta: none.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: project-audit
3
- description: "Use when someone asks what is actually true of a whole project right now — what is finished, what is half-built, what is broken, and what nobody has looked at. Walks a cold start: discover what the project is, run a registry of probes chosen from that, read production evidence (published artefact against source, CI history, telemetry present or absent), then leave a JSON sidecar so the next audit can say what moved, and a self-contained HTML report on request. Read-only: it proposes board rows and commits nothing. Triggers - 'project audit', 'audit the project', 'codebase audit', 'state of the project', 'what is unfinished', 'project health check', 'аудит проекта', 'проаудируй проект', 'состояние проекта', 'что не доделано', 'аудит кодовой базы'. Not for: auditing one deliverable inside a run (that is the pipeline's own ladder), reviewing a diff, or checking a skill's construction — say 'без диагностики' to opt out."
3
+ description: "Use when someone asks what is true of a whole project: finished, half-built, broken, unexplored ('project audit', 'аудит проекта'). Discovers the project, runs probes, reads production evidence, leaves a JSON sidecar, an HTML report on request. Read-only: proposes board rows, commits nothing. Not for: one deliverable inside a run, a diff review, a skill's construction; 'без диагностики' opts out."
4
4
  license: MIT
5
5
  compatibility: "The collector (scripts/audit.py) needs python3 and reads committed state, so it needs git. Probes needing gh, npm, network or a browser declare it and report blind when it is absent — degraded, never silent."
6
6
  ---
@@ -318,3 +318,10 @@ requested, not a fixed page-and-browser:
318
318
  | "Findings should just be fixed while I'm in there" | An audit that edits while it reads cannot re-run to check itself, and the next run cannot tell a fix from a rewording. |
319
319
  | "It's the same nine checks every time, so I can skip discovery" | Then the instrument returns the same answer for every input, which is a fact about the instrument and not about the project. |
320
320
  | "No findings — clean bill" | Only against the probes that ran. Read the blind list before saying that sentence out loud. |
321
+
322
+ ## Triggers
323
+
324
+ The description is the short form. The full trigger list it carried until 1.98.0,
325
+ moved here verbatim, still routes to this skill:
326
+
327
+ "Use when someone asks what is actually true of a whole project right now — what is finished, what is half-built, what is broken, and what nobody has looked at. Walks a cold start: discover what the project is, run a registry of probes chosen from that, read production evidence (published artefact against source, CI history, telemetry present or absent), then leave a JSON sidecar so the next audit can say what moved, and a self-contained HTML report on request. Read-only: it proposes board rows and commits nothing. Triggers - 'project audit', 'audit the project', 'codebase audit', 'state of the project', 'what is unfinished', 'project health check', 'аудит проекта', 'проаудируй проект', 'состояние проекта', 'что не доделано', 'аудит кодовой базы'. Not for: auditing one deliverable inside a run (that is the pipeline's own ladder), reviewing a diff, or checking a skill's construction — say 'без диагностики' to opt out."