task-pipeline-skill 1.29.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +144 -0
- package/CONTRIBUTING.md +26 -1
- package/README.md +6 -3
- package/SKILL-CARD.md +1 -1
- package/cursor/rules/task-pipeline.mdc +5 -3
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/learned.md +70 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,149 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.30.0 — the cap that would have measured the wrong axis
|
|
4
|
+
|
|
5
|
+
The audit's last finding was that `references/learned.md` has no retirement rule while
|
|
6
|
+
`retro.md` caps its standing instructions at ten. Four measurements, each with a
|
|
7
|
+
differently-shaped command — the rotation axis shipped one release ago, turned on the
|
|
8
|
+
backlog that proposed it:
|
|
9
|
+
|
|
10
|
+
| The belief | The command | Result |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| rules accumulate | table rows per tag: 15 → 18 → 21 → 21 | **flat for four releases** |
|
|
13
|
+
| growth *is* rules | words per section, v1.23.0 → HEAD | **+223, every word in the binding map** |
|
|
14
|
+
| the long incidents duplicate the retro | each incident's distinctive tokens against the whole retro corpus | **zero hits** — they are other projects' events, held nowhere else here |
|
|
15
|
+
|
|
16
|
+
A cap of N would have squeezed the axis that had not moved in four releases. A word
|
|
17
|
+
budget would have cut the incidents, which are the only record of those events anywhere
|
|
18
|
+
in this repository. **The finding was right that something was missing and wrong about
|
|
19
|
+
what.**
|
|
20
|
+
|
|
21
|
+
**Why the retro is capped and this file is not**, now written down where the proposal
|
|
22
|
+
keeps arriving: a cap belongs to a file you must *finish reading*. The retro's standing
|
|
23
|
+
instructions are read in full at stage 0 — bounded by construction, or the last one is
|
|
24
|
+
never reached. `learned.md` is entered by citation from twenty-three surfaces and its
|
|
25
|
+
binding map is that entrance. **A file you enter through an index needs its index to be
|
|
26
|
+
right, not its length to be short.**
|
|
27
|
+
|
|
28
|
+
**Two triggers retire a rule, and neither is a count:** the conditions can no longer
|
|
29
|
+
occur in any project the skill runs on, or the rule is **subsumed** — a merge, where the
|
|
30
|
+
absorbing rule names the absorbed one and every binding-map row is repointed in the same
|
|
31
|
+
change. Explicitly *not* "it became a check": that trigger is right for a standing
|
|
32
|
+
instruction, whose job is to be read until the machine takes over, but here the rule is
|
|
33
|
+
the **reason** the check exists, and a check whose reason was deleted is the next thing
|
|
34
|
+
somebody removes as noise.
|
|
35
|
+
|
|
36
|
+
Numbers are never reused and never closed up, so a departure shows as a **gap**, and a
|
|
37
|
+
gap the `### Retired` log does not name now fails the build. The log exists while empty
|
|
38
|
+
and says so — an absent log and an empty one are indistinguishable from outside, and
|
|
39
|
+
only one of them means nothing has been retired.
|
|
40
|
+
|
|
41
|
+
And the file's **shape** is now printed beside the validator's verdict — rules,
|
|
42
|
+
incidents, incident words, binding rows — as a disclosure: computed, no floor, no
|
|
43
|
+
direction, **never a target**. Growth becomes visible without becoming a lever.
|
|
44
|
+
|
|
45
|
+
**The review found a guard that could not catch the thing it was built for.** Deleting
|
|
46
|
+
the **highest-numbered** rule shrinks `max()` with it, so no gap ever opens — reproduced
|
|
47
|
+
by deleting rule 21 and getting a clean pass. My own probe had planted in the middle of
|
|
48
|
+
the list, which is the shape the author imagines. The mark now comes from the file
|
|
49
|
+
(`Numbers issued so far: N`, the one number this file states about itself), and the log
|
|
50
|
+
match is anchored to each line's leading number, because a bare digit anywhere in the
|
|
51
|
+
body — *"subsumed by 9"* — masked a genuine deletion of rule 9.
|
|
52
|
+
|
|
53
|
+
The disclosure was also wrong before it was right: one write-up covers two rules
|
|
54
|
+
(*"4 and 5 · Probes"*), so it printed 18 where the file has 19 write-ups covering 20
|
|
55
|
+
rules. It now says **rules with an incident**, because a label that does not say what
|
|
56
|
+
it counts is a number nobody can check.
|
|
57
|
+
|
|
58
|
+
**Swept the same class one level out.** The cold-retirement guard's corpus was a
|
|
59
|
+
hand-written list of seven files. Made **discovered** instead — any shipped surface that
|
|
60
|
+
states the condition must state both units — and it immediately found **thirteen**,
|
|
61
|
+
including `README.md`, the Cursor rule, `gates.md` and `learned.md` itself. A narration
|
|
62
|
+
of the old wording is exempt by the repository's existing convention: a double-quoted
|
|
63
|
+
span is a citation, and rule 21's incident is left as it happened.
|
|
64
|
+
|
|
65
|
+
**The class turned out to be the module.** Three guards in this file held
|
|
66
|
+
hand-written corpora; all three had missed a shipped surface, and each miss was found
|
|
67
|
+
by a reader or by a sweep rather than by the guard. All three are now **discovered**:
|
|
68
|
+
the cold trigger (7 listed → 13 found), the disclosure verdicts (5 listed → README's
|
|
69
|
+
worked `GATE 10` block found), and the claim registry (widened in v1.29.0 after the
|
|
70
|
+
same shape). *Nobody notices a corpus that is too small, because everything inside it
|
|
71
|
+
passes.*
|
|
72
|
+
|
|
73
|
+
**A high-water mark the same change can lower is not one.** A reader found the residual
|
|
74
|
+
hole and named why a file-only validator cannot see it: the evidence is in the previous
|
|
75
|
+
commit. Deleting rule 21 *and* editing the mark to 20 makes both numbers agree and no
|
|
76
|
+
gap opens. The check now reads the mark at `HEAD` through git — and where git cannot
|
|
77
|
+
answer, it **prints** the skip as an `unlooked` disclosure rather than going quiet,
|
|
78
|
+
because a check that falls silent outside a checkout reads exactly like a check that
|
|
79
|
+
passed. That assertion is a property, not a rejection, so it lives outside the negative
|
|
80
|
+
suite: the suite requires each of its tests to watch a guard *reject* something, and it
|
|
81
|
+
reported the mismatch itself.
|
|
82
|
+
|
|
83
|
+
**A citation naming two guards was checked as zero.** The extractor matched a single
|
|
84
|
+
backtick span followed by `)*`, so invariant 43 — the one this release added, naming
|
|
85
|
+
two — contributed nothing to the checked set and sat silently exempt from the invariant
|
|
86
|
+
that every citation must resolve. Found by a reader, on the invariant whose subject is
|
|
87
|
+
exactly that. Every literal inside a `*(guard: …)*` parenthetical is now checked, and
|
|
88
|
+
one branch that had shipped unprobed (a rule numbered above the mark) now has its plant.
|
|
89
|
+
|
|
90
|
+
The two discovered corpora also collapsed into one `_discover_md(skip, predicate)` —
|
|
91
|
+
second occurrence of the walk, and this file's own rule promotes a class at the second,
|
|
92
|
+
not the third.
|
|
93
|
+
|
|
94
|
+
**A check that only worked in the window its own test used.** The cross-commit
|
|
95
|
+
comparison read the mark at `HEAD` — identical to the working tree on a *committed*
|
|
96
|
+
checkout, which is what CI runs. It fired only in the local pre-commit window, and the
|
|
97
|
+
self-test exercised exactly that window. A reader committed the coordinated edit and
|
|
98
|
+
watched it pass. The mark is now compared against **every value this file's history has
|
|
99
|
+
held**, and the test commits its plant.
|
|
100
|
+
|
|
101
|
+
Two more from the same round: emptying the rules table wholesale made the list falsy and
|
|
102
|
+
skipped the entire check (`rules 0`, PASS), and `docs/superpowers/plans/` was missing
|
|
103
|
+
from the frozen-record exclusions its two siblings carry.
|
|
104
|
+
|
|
105
|
+
**CI caught what the local gate could not see.** Renaming the skip's message left the
|
|
106
|
+
property check grepping for the old string — and that step lives only in the workflow,
|
|
107
|
+
because it asserts something *is printed* rather than watching a guard reject. The local
|
|
108
|
+
runner had no way to run it, so `npm run test:all` was green while CI failed on a string
|
|
109
|
+
this same change had renamed. `test/negatives.py` now runs property checks too: a step
|
|
110
|
+
that exists only in CI is a step the author's gate is blind to.
|
|
111
|
+
|
|
112
|
+
**Both directions, on the guard about both directions.** The check found gaps the log
|
|
113
|
+
did not name, and never the reverse: a number *listed as retired* whose row is still in
|
|
114
|
+
the table — the log naming the wrong rule, or a retired rule quietly back. A gap has one
|
|
115
|
+
side and so does a resurrection; only the second pass sees it. This is `learned.md`'s own
|
|
116
|
+
rule 2 applied to the guard that guards `learned.md`.
|
|
117
|
+
|
|
118
|
+
**And the number the exclusion moved.** Adding `docs/superpowers/plans/` to the frozen
|
|
119
|
+
records took the discovered corpus from fourteen to thirteen, and two documents kept the
|
|
120
|
+
old number — so the corpus's own size is now a claim-registry class, computed from the
|
|
121
|
+
walk. The registry's evaluation moved below the walks that feed it: declared early,
|
|
122
|
+
computed late.
|
|
123
|
+
|
|
124
|
+
The local runner also learned to treat property checks as their own category — selected
|
|
125
|
+
by `-k`, shown by `--list`, and reported under their own heading rather than as *"the
|
|
126
|
+
validator accepted a planted defect"*, which is false for a check that plants nothing.
|
|
127
|
+
Its verdict now names what ran: `PASS: all 0 guards` over an empty selection is the
|
|
128
|
+
refused measurement this repository has a rule about.
|
|
129
|
+
|
|
130
|
+
**A probe that could no longer fail for its own reason.** The anchor test planted a log
|
|
131
|
+
line whose *body* held the digit it was about — and the high-water mark lives in that
|
|
132
|
+
same section, so a bare-digit scan picked up `21`, tripped a different check, and the
|
|
133
|
+
test failed either way. It could not tell a working anchor from a regressed one, which a
|
|
134
|
+
reader demonstrated by reverting the anchor. The mark is now stripped before the log is
|
|
135
|
+
parsed (it was never a log entry), the plant uses a number that is not a live row, and
|
|
136
|
+
reverting the anchor makes the test pass again — which is what "this test measures that"
|
|
137
|
+
means.
|
|
138
|
+
|
|
139
|
+
Two more of the same family: the rule-row regex existed twice, byte-identical, one for
|
|
140
|
+
the registry and one for the disclosure — rule 8's class inside the file that enforces
|
|
141
|
+
it, now one pattern with two readers. And property checks got the floor the negative
|
|
142
|
+
suite has had for releases: rename the only one and the category empties in silence,
|
|
143
|
+
which is the failure property checks were added to close, one level up.
|
|
144
|
+
|
|
145
|
+
Guards: 144 → **156**, plus 1 property check now covered locally.
|
|
146
|
+
|
|
3
147
|
## v1.29.0 — a sixth axis, and three summaries that each read as complete
|
|
4
148
|
|
|
5
149
|
**Re-derivation** joins the rotation axes in `references/audit.md`: take a number the
|
package/CONTRIBUTING.md
CHANGED
|
@@ -349,7 +349,32 @@ claim-registry classes, separated by the qualifier, so a guard cannot report dri
|
|
|
349
349
|
between two things that were never the same list.
|
|
350
350
|
*(guard: `gates.md's own axes`)*
|
|
351
351
|
|
|
352
|
-
**41.
|
|
352
|
+
**41. A rule leaves `learned.md` only on a logged line, and the log exists while
|
|
353
|
+
empty.** Numbers are never reused and never closed up, so a departure shows as a gap in
|
|
354
|
+
the table; a gap the `### Retired` log does not name is a rule that vanished with its
|
|
355
|
+
incident, and the next run re-learns it at full price. The log is present and says
|
|
356
|
+
*none yet*, because an absent log and an empty one look identical from outside.
|
|
357
|
+
*(guard: `named in no line of`)*
|
|
358
|
+
|
|
359
|
+
**42. `learned.md` has no cap, and the reason is written down where the cap keeps being
|
|
360
|
+
proposed.** A cap belongs to a file read *in full* every run — that is the retro's
|
|
361
|
+
standing instructions. This one is entered by citation from twenty-three surfaces.
|
|
362
|
+
Measured before deciding: rules flat at 21 across four releases while the file grew, and
|
|
363
|
+
every word of the growth in the binding map. Its shape prints beside the verdict as a
|
|
364
|
+
**disclosure** — computed, no floor, no direction, never a target.
|
|
365
|
+
*(guard: `learned.md — rules `)*
|
|
366
|
+
|
|
367
|
+
**43. A guard's corpus is discovered, not hand-listed.** Three in `test/validate.py`
|
|
368
|
+
held written lists, and all three had missed a shipped surface: the cold trigger named
|
|
369
|
+
seven files where thirteen state the condition, the disclosure check named five where
|
|
370
|
+
`README.md` also prints a worked verdict, and the claim registry excluded the Cursor
|
|
371
|
+
rule and the command. Every miss was found by a reader or a sweep, never by the guard —
|
|
372
|
+
**nobody notices a corpus that is too small, because everything inside it passes.**
|
|
373
|
+
Exclusions are allowed and must each carry a reason in the code: a changelog narrates
|
|
374
|
+
old formats, `docs/superpowers/specs/` are point-in-time records.
|
|
375
|
+
*(guard: `a worked GATE verdict omits ` and `states the cold-retirement condition as` — both now run over corpora walked from disk, so a new surface joins by existing)*
|
|
376
|
+
|
|
377
|
+
**44. Every invariant above names the guard that enforces it, and that guard exists.**This list claims to be *what the validator enforces*; it was eight guards behind when
|
|
353
378
|
an audit measured it. A claim of enforcement is now checked like any other claim.
|
|
354
379
|
*(guard: `whose message does not appear in`)* — and a cited literal must lie inside
|
|
355
380
|
a **single** string in `test/validate.py`: the check reads that file as text, so a
|
package/README.md
CHANGED
|
@@ -576,8 +576,10 @@ The last act of stage 10 is therefore a **retrospective**, written to
|
|
|
576
576
|
`docs/superpowers/retro.md` — **one file per project, not per run**
|
|
577
577
|
([`retrospective.md`](plugins/task-pipeline/skills/task-pipeline/references/retrospective.md)).
|
|
578
578
|
Every run **stamps and prunes** — in that order, because one retirement trigger
|
|
579
|
-
counts firings across the last five run stamps
|
|
580
|
-
|
|
579
|
+
counts firings across the last five run stamps **or sixty days**, whichever comes
|
|
580
|
+
first, and a prune ahead of the stamp reads a counter its own stage writes afterwards.
|
|
581
|
+
The calendar is the unit that keeps moving when the stamp counter has stopped, which is
|
|
582
|
+
exactly when a stale rule matters most. Only a run that *diverged* writes an entry:
|
|
581
583
|
symptom with evidence, the stage it surfaced at, the stage that **owned** it, the
|
|
582
584
|
root cause, the fix, and the check that catches it the first time from now on.
|
|
583
585
|
|
|
@@ -593,7 +595,7 @@ root cause, the fix, and the check that catches it the first time from now on.
|
|
|
593
595
|
Every standing
|
|
594
596
|
instruction is checked against three retirement triggers — *it became a check* ·
|
|
595
597
|
*every path or command it names is gone* · *it has not fired in the last five run
|
|
596
|
-
stamps* — and the list is held to a **hard cap of ten**. At eleven, the oldest
|
|
598
|
+
stamps, or in sixty days* — and the list is held to a **hard cap of ten**. At eleven, the oldest
|
|
597
599
|
never-fired rule goes; "but they all matter" is exactly the state in which the list
|
|
598
600
|
stopped being read, and the ninth stale rule is what discredits the two that are
|
|
599
601
|
load-bearing.
|
|
@@ -606,6 +608,7 @@ visible where it happened:
|
|
|
606
608
|
```
|
|
607
609
|
GATE 10 acceptance: PASS — 14/14 REQ verified
|
|
608
610
|
carry-over: 0 unresolved · retro: 7 standing (was 9) · retired 3 · added 1
|
|
611
|
+
abstained: 1 (1 cannot-verify) · unlooked: 0
|
|
609
612
|
```
|
|
610
613
|
|
|
611
614
|
Stage 0 reads those standing instructions **in full** on the next run — which is
|
package/SKILL-CARD.md
CHANGED
|
@@ -12,7 +12,7 @@ harmless.
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
|
|
14
14
|
| **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
|
|
15
|
-
| **Version** | 1.
|
|
15
|
+
| **Version** | 1.30.0 |
|
|
16
16
|
| **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
|
|
17
17
|
| **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
|
|
18
18
|
| **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
|
|
@@ -336,9 +336,11 @@ not authorize an outward, irreversible action — stage 7 stops and asks.
|
|
|
336
336
|
times and nothing notices it is the same one. So, in this order —
|
|
337
337
|
**1. Stamp the run first** — date, topic, commit, verdict, counts. It costs one
|
|
338
338
|
line and it is the only thing that makes the next step computable: one retirement
|
|
339
|
-
trigger counts firings across the last five run stamps
|
|
340
|
-
|
|
341
|
-
data.
|
|
339
|
+
trigger counts firings across the last five run stamps **or sixty days**, whichever
|
|
340
|
+
comes first, so a prune placed ahead of the stamp reads a counter its own stage
|
|
341
|
+
writes afterwards and can never run on real data. The calendar unit exists because
|
|
342
|
+
the stamp counter only moves when this pipeline runs — ten consecutive releases of
|
|
343
|
+
this repository carry no stamp at all.
|
|
342
344
|
**2. Then prune.** Check every standing instruction against three
|
|
343
345
|
retirement triggers: it became a check (a test, a lint rule, a gate, a hook →
|
|
344
346
|
delete it; the check is the memory, and keeping both means it is read twice and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
4
4
|
"description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"task-pipeline": "bin/task-pipeline.js"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "task-pipeline",
|
|
3
3
|
"displayName": "Task Pipeline",
|
|
4
4
|
"description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/manual gates, a frozen requirement spine that must close with evidence, a loop guard that breaks churn, one provider-agnostic model confirmed up front, and an optional super-ux UX track for user-facing work.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.30.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -20,6 +20,7 @@ to be enforced and is not is the same failure as a gate that prints `FAIL` and e
|
|
|
20
20
|
- The two that are not in the table, and why
|
|
21
21
|
- The one instruction that would have prevented the most
|
|
22
22
|
- Where these bind in the pipeline
|
|
23
|
+
- What leaves this file, and why there is no cap
|
|
23
24
|
|
|
24
25
|
## The table — trigger · check · exit criterion
|
|
25
26
|
|
|
@@ -137,7 +138,7 @@ run's belief about the work-list against the register; the claim only ever appea
|
|
|
137
138
|
|
|
138
139
|
**20 · The copy that wins.** A service had **two Dockerfiles**. One was added at the repository root by a run that checked whether a Dockerfile existed by looking where it expected one; `docker/Dockerfile` had been there all along, and `.github/workflows/ci.yml` says `file: docker/Dockerfile`. They disagreed about the port — 8080 at the root, 8000 in `docker/` — and the disagreement surfaced two days later as a **deployed service that answered nothing**, while `docker ps` said `Up` and `systemctl` said `active`. The built one also ran as root and copied the whole context, including `.git` and any `.env`; the hardened one was the one nobody built. Comparing the two files would have found the difference and not the direction. Only the workflow line says which one ships, and it is one grep. The same session hit this three more times: an autonomy sweep row added to the file that ASKS and not the file that RECORDS, twice, caught by a validator that knew to look at both.
|
|
139
140
|
|
|
140
|
-
**21 · The prune that could not run.** A retrospective's standing-instruction list has a hard cap of ten and three retirement triggers, one of which
|
|
141
|
+
**21 · The prune that could not run.** A retrospective's standing-instruction list has a hard cap of ten and three retirement triggers, one of which was, at the time of this incident, "it has not fired in the last five run stamps" — it has since gained a second unit, and the incident is left as it happened. The stage's own instruction was **prune first, then stamp**. So the trigger read a counter the same stage wrote afterwards: on a fresh list it is unreadable, and it stays unreadable for as long as nobody stamps. Measured on a real project: the last retro entry was five days old, stamps per day ran 33, 20, 26, **3, 0** — the zero on a day with 107 commits — and the list sat at exactly **10 of 10**, so every run arrived at a stage that opened with a full list, an unusable trigger and a mandatory deletion. It was not skipped out of laziness. It was skipped because its first step could not be performed, and the cheap step that would have made it performable was queued behind it.
|
|
141
142
|
|
|
142
143
|
The same class had already bitten that project twice from the other side, and its roadmap names the
|
|
143
144
|
property exactly: seven rows read `blocked` on producers the dependency board recorded as delivered,
|
|
@@ -209,3 +210,71 @@ project buys go in its retro ([`retrospective.md`](retrospective.md) →
|
|
|
209
210
|
lesson there that would be true in any repository belongs here instead, as an issue
|
|
210
211
|
upstream. A local file that accumulates universal rules is a fork of this one that
|
|
211
212
|
nobody named.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## What leaves this file, and why there is no cap
|
|
217
|
+
|
|
218
|
+
`docs/superpowers/retro.md` caps its standing instructions at **ten** and retires them
|
|
219
|
+
on three triggers. Somebody proposes the same cap here about once a programme. It is
|
|
220
|
+
the wrong instrument, and the reason is worth more than the rule.
|
|
221
|
+
|
|
222
|
+
**A cap belongs to a file you must finish reading.** The retro's standing instructions
|
|
223
|
+
are read *in full* at stage 0 of every run — bounded by construction, or the last one
|
|
224
|
+
is never reached. This file is never read in full: it is entered by citation from the
|
|
225
|
+
stages, and *Where these bind in the pipeline* is that entrance. **A file you enter
|
|
226
|
+
through an index needs its index to be right, not its length to be short.**
|
|
227
|
+
|
|
228
|
+
And the cap would have measured the axis that is not moving. Re-derived across releases
|
|
229
|
+
rather than recalled — **measured at each tag**, so these rows are history and cannot
|
|
230
|
+
go stale; the live shape is printed by `npm test` beside its verdict, and this file
|
|
231
|
+
states no number about itself:
|
|
232
|
+
|
|
233
|
+
| | v1.14.1 | v1.20.0 | v1.23.0 | v1.29.0 |
|
|
234
|
+
|---|---|---|---|---|
|
|
235
|
+
| rules in the table | 15 | 18 | 21 | **21** |
|
|
236
|
+
| words in the file | 2165 | 2987 | 3696 | **3919** |
|
|
237
|
+
|
|
238
|
+
Rules have been flat for four releases while the file grew — and every word of that
|
|
239
|
+
growth is in the binding map, the section that makes a rule *reachable*. Cutting there
|
|
240
|
+
shortens the index. The largest section by far is the incidents, and those are the only
|
|
241
|
+
record of those events anywhere in this repository — checked by taking each incident's
|
|
242
|
+
distinctive tokens against the whole retro corpus, which returned nothing. They are not
|
|
243
|
+
a compression target; they are the thing the rules are made of.
|
|
244
|
+
|
|
245
|
+
**Two triggers retire a rule, and neither is a count:**
|
|
246
|
+
|
|
247
|
+
1. **The conditions cannot occur.** The tool, the layer, or the failure mode it names
|
|
248
|
+
is gone from every project the skill runs on — not "we have not hit it lately".
|
|
249
|
+
2. **It is subsumed.** Another rule covers it entirely. This is a **merge**, not a
|
|
250
|
+
delete: the absorbing rule names the absorbed one, and every binding-map row that
|
|
251
|
+
pointed at the old number is repointed in the same change, or the map now sends a
|
|
252
|
+
stage to a rule that is not there.
|
|
253
|
+
|
|
254
|
+
Never *"it became a check"* — that trigger is right for a standing instruction, whose
|
|
255
|
+
whole purpose is to be read until the machine takes over. Here the rule is the reason
|
|
256
|
+
the check exists, and a check whose reason has been deleted is the next thing somebody
|
|
257
|
+
removes as noise.
|
|
258
|
+
|
|
259
|
+
**Every deletion is logged as one line**, in the same change, the same discipline as
|
|
260
|
+
the retro's prune: the rule's number, its name, which trigger fired, and the commit.
|
|
261
|
+
A rule that vanishes silently takes its incident with it, and the next run re-learns it
|
|
262
|
+
at full price. Numbers are never reused and never closed up — a gap in the table is the
|
|
263
|
+
evidence that something left, and the log below says what.
|
|
264
|
+
|
|
265
|
+
### Retired
|
|
266
|
+
|
|
267
|
+
**Numbers issued so far: 21.** This is the high-water mark, and it is the only number
|
|
268
|
+
this file states about itself — deliberately, because the gap that proves a rule left
|
|
269
|
+
cannot be computed from the table alone: **deleting the highest-numbered rule shrinks
|
|
270
|
+
the maximum with it, and no gap ever opens.** That false negative shipped in the first
|
|
271
|
+
draft of this very section's guard and was found by a reader, not by its probe, which
|
|
272
|
+
had planted in the middle of the list.
|
|
273
|
+
|
|
274
|
+
*None retired yet.* Stated rather than omitted: an empty log and a missing log look
|
|
275
|
+
identical from outside, and only one of them means nothing has been retired. Each
|
|
276
|
+
retirement is one line, starting with the rule's number:
|
|
277
|
+
|
|
278
|
+
<!-- - **N · Name** — trigger: subsumed by M | conditions gone; `<commit>` -->
|
|
279
|
+
|
|
280
|
+
---
|
|
@@ -5,6 +5,13 @@ done. It exists because the pipeline's gates are good at *this* run and blind
|
|
|
5
5
|
across runs: the same class of failure can be caught, fixed and forgotten five
|
|
6
6
|
times, and nothing in the flow notices it is the same one.
|
|
7
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
|
+
|
|
8
15
|
**Two artifacts, and the split is the point.** A file that is read *in full* every
|
|
9
16
|
run may not contain anything that grows without limit — otherwise the cap that
|
|
10
17
|
justifies reading it protects one section while the file below it doubles.
|