task-pipeline-skill 1.22.0 → 1.23.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 +27 -0
- package/SKILL-CARD.md +1 -1
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/learned.md +3 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +44 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.23.0
|
|
4
|
+
|
|
5
|
+
### A step that consumes what a later step produces is a deadlock — `learned.md` rule 21
|
|
6
|
+
|
|
7
|
+
The retrospective stage said **prune first, then stamp**. One of the prune's three retirement
|
|
8
|
+
triggers is *it has not fired in the last five run stamps* — so the trigger read a counter the same
|
|
9
|
+
stage wrote afterwards. On any list it had never run on real data, and it stays unreadable for
|
|
10
|
+
exactly as long as nobody stamps.
|
|
11
|
+
|
|
12
|
+
Measured on a real project: last entry five days old; stamps per day 33, 20, 26, **3, 0** — the zero
|
|
13
|
+
on a day with 107 commits — and the list sitting at **10 of 10**. Every run arrived at a stage that
|
|
14
|
+
opened with a full list, an unusable trigger and a mandatory deletion. It was not skipped out of
|
|
15
|
+
laziness: its first step could not be performed, and the cheap step that would have made it
|
|
16
|
+
performable was queued behind it.
|
|
17
|
+
|
|
18
|
+
Two changes, and the second only works because of the first:
|
|
19
|
+
|
|
20
|
+
- **Stamp first, then prune, then write.** The stamp is one line and costs nothing; it is also the
|
|
21
|
+
only thing that makes the cold trigger computable.
|
|
22
|
+
- **Each trigger is a command, not a judgement.** All three are now runnable — grep for the rule's
|
|
23
|
+
words in anything that executes, resolve every path and tool it names, count its firings across
|
|
24
|
+
the last five stamps. A retirement condition nobody can run is one nobody applies, which is how a
|
|
25
|
+
list reaches ten and stops being read.
|
|
26
|
+
|
|
27
|
+
`test/validate.py` guards all three: the new ordering, the absence of the old "runs BEFORE" wording,
|
|
28
|
+
and the triggers being expressed as commands. Watched failing against two planted defects.
|
|
29
|
+
|
|
3
30
|
## v1.22.0
|
|
4
31
|
|
|
5
32
|
### When a thing exists twice, ask which one is used — `learned.md` rule 20
|
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.23.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 (15 evals, 5 categories). **Never executed** — see [`evals/RESULTS.md`](evals/RESULTS.md) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.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.23.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -45,6 +45,7 @@ to be enforced and is not is the same failure as a gate that prints `FAIL` and e
|
|
|
45
45
|
| 18 | **State that accumulates locally is created from nothing everywhere else** | any run whose tests, migrations or fixtures read a database, a cache or a checkout that persists between runs on this machine | run the suite once against a **freshly created** instance of it, not the one that has been here for weeks | the run names the fresh instance it used, or the green is a green from residue |
|
|
46
46
|
| 19 | **An empty measurement is a refused measurement** | any command run to establish a fact — a count, a probe, a query, a suite | assert the output is **non-empty and shaped as expected** before reading meaning into it; a command that printed nothing did not answer | the run quotes the output it read, not the conclusion it drew from silence |
|
|
47
47
|
| 20 | **When a thing exists twice, ask which one is used — not whether they agree** | any artifact with a second copy: two build files, a vendored library, a schema and its mirror, doctrine in two documents | find the **consumer** and read what it names; the copies cannot answer this about themselves | the run names the file the build/test/deploy actually reads, quoted from the consumer |
|
|
48
|
+
| 21 | **A step that consumes what a later step produces is a deadlock, not an ordering** | any sequence where a check reads state another step writes — a prune reading stamps, a gate reading a ledger, a report reading counts | trace each input to the step that writes it; if that step is downstream, the check has never run on real data | every check names the step that produces its input, and that step is upstream of it |
|
|
48
49
|
|
|
49
50
|
---
|
|
50
51
|
|
|
@@ -136,6 +137,8 @@ run's belief about the work-list against the register; the claim only ever appea
|
|
|
136
137
|
|
|
137
138
|
**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.
|
|
138
139
|
|
|
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 is *it has not fired in the last five run stamps*. 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
|
+
|
|
139
142
|
The same class had already bitten that project twice from the other side, and its roadmap names the
|
|
140
143
|
property exactly: seven rows read `blocked` on producers the dependency board recorded as delivered,
|
|
141
144
|
and *"no gate can catch it because it breaks nothing — it only removes work from consideration"*;
|
|
@@ -26,7 +26,8 @@ file exists to stop.
|
|
|
26
26
|
- Every lesson carries its commit
|
|
27
27
|
- Rotation — the archive is how pruning stops losing things
|
|
28
28
|
- Three grades of fix — take the highest one that can work
|
|
29
|
-
-
|
|
29
|
+
- Stamp first, then prune, then write
|
|
30
|
+
- The prune — mandatory, and it runs after the stamp
|
|
30
31
|
- The loop closes at stage 0
|
|
31
32
|
- Where a lesson goes when it is not about this project
|
|
32
33
|
- Rationalizations
|
|
@@ -100,10 +101,30 @@ Prefer grade 1 whenever a check can decide it. This is the same law as
|
|
|
100
101
|
[`audit.md`](audit.md) → *A class that repeats twice becomes a gate, not a note*: a
|
|
101
102
|
rule that could have been a check gets read twice and obeyed once.
|
|
102
103
|
|
|
103
|
-
##
|
|
104
|
+
## Stamp first, then prune, then write
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
`learned.md` rule 21. This order used to be *prune first*, and that was a **deadlock**, not a
|
|
107
|
+
preference: the cold trigger below reads *the last five run stamps*, and the stamp was written after
|
|
108
|
+
the prune. The trigger read a counter the same stage produced later, so on any list it had never run
|
|
109
|
+
on real data — and it stays unreadable for exactly as long as nobody stamps.
|
|
110
|
+
|
|
111
|
+
Measured on a real project: last entry five days old; stamps per day 33, 20, 26, **3, 0** — the zero
|
|
112
|
+
on a day with 107 commits — and the list sitting at **10 of 10**. Every run arrived at a stage that
|
|
113
|
+
opened with a full list, an unusable trigger and a mandatory deletion. It was not skipped out of
|
|
114
|
+
laziness; its first step could not be performed, and the cheap step that would have made it
|
|
115
|
+
performable was queued behind it.
|
|
116
|
+
|
|
117
|
+
**The stamp is one line and costs nothing.** It is also the only thing that makes the prune
|
|
118
|
+
computable, which is why it goes first:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
printf '%s · %s\n' "$(date +%F)" "$(git rev-parse --short HEAD)" >> docs/superpowers/retro.md
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## The prune — mandatory, and it runs after the stamp
|
|
125
|
+
|
|
126
|
+
A lesson that lands in a cluttered file is a lesson nobody will reach — so the prune still runs
|
|
127
|
+
before the entry is written. It runs *after* the stamp, because it reads it.
|
|
107
128
|
|
|
108
129
|
Every row carries its own trigger in a **`Retire when`** column, written at birth —
|
|
109
130
|
a rule whose retirement condition is decided later is a rule the prune can only
|
|
@@ -115,6 +136,25 @@ argue about. Check **every** standing instruction against three triggers:
|
|
|
115
136
|
| **Its surface is gone** | resolve every path, command, stage and tool it names; any that no longer exists | delete it — it now describes a system nobody is running |
|
|
116
137
|
| **It went cold** | it has not fired in the last **five run stamps** | delete it — five runs without firing is the evidence that it was situational |
|
|
117
138
|
|
|
139
|
+
**Each trigger is a command, not a judgement.** A retirement condition nobody can run is a
|
|
140
|
+
condition nobody applies, which is how a list reaches ten and stops being read:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# became a check — the rule's own words appear in something that runs
|
|
144
|
+
grep -rl "$RULE_KEYWORD" scripts/ test/ .github/workflows/ Makefile* 2>/dev/null
|
|
145
|
+
|
|
146
|
+
# surface is gone — every path, command and tool it names, resolved
|
|
147
|
+
grep -oE '`[^`]+`' <<<"$RULE_TEXT" | tr -d '`' | while read -r t; do
|
|
148
|
+
[ -e "$t" ] || command -v "$t" >/dev/null || echo "MISSING: $t"; done
|
|
149
|
+
|
|
150
|
+
# went cold — fired in none of the last five stamps
|
|
151
|
+
tail -n 200 docs/superpowers/retro.md | grep -c "$RULE_ID"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Anything the first two print is a deletion; a zero from the third across five stamps is a deletion.
|
|
155
|
+
What survives all three stays, and the run states the three counts rather than the conclusion
|
|
156
|
+
(`learned.md` rule 19 — an empty result and an unrun command look identical).
|
|
157
|
+
|
|
118
158
|
Then the cap: **ten standing instructions, hard.** At eleven you do not get to keep
|
|
119
159
|
them all — the oldest never-fired one goes. "But all of them matter" is precisely
|
|
120
160
|
the state in which the list stopped being read, and the ninth stale rule is what
|