task-pipeline-skill 1.53.0 → 1.54.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 +30 -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/acceptance.md +26 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/stage-coverage.sh +77 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.54.0 — a run cannot reach acceptance with a stage it never stamped
|
|
4
|
+
|
|
5
|
+
The 2026-08-13 artifact-root run closed at stage 10 with `0,1,2,5,6,7,8,9,10` recorded
|
|
6
|
+
and **3 (spec) and 4 (plan) never stamped**. The status line printed `3· 4·` and 73% and
|
|
7
|
+
was exactly right; nothing read it. Detection existed — `lib/runledger.js` renders that
|
|
8
|
+
rail — and no gate refused on it, which is the difference between a display and a check.
|
|
9
|
+
|
|
10
|
+
Stage 7's release gate could not have caught it either: it fires before 8, 9 and 10
|
|
11
|
+
exist, and it asks only about the tests stage.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`templates/stage-coverage.sh`**, seeded at stage 0 and run at stage 10 before the
|
|
16
|
+
coverage table. It reads the stage ids `pipeline.json` declares and the `stage: <id>
|
|
17
|
+
… verdict` lines the ledger holds, and names every declared stage with no verdict.
|
|
18
|
+
Last verdict per id wins — a stage re-entered after a fix has the outcome of the
|
|
19
|
+
re-entry, not of the failure that caused it.
|
|
20
|
+
- **Both remedies are legitimate, and the refusal says so.** Stamp what happened,
|
|
21
|
+
because a merged stage still has an outcome; or stop declaring in `pipeline.json` a
|
|
22
|
+
stage this project folds into another. What is not legitimate is a flow that declares
|
|
23
|
+
eleven stages against a ledger that accounts for nine.
|
|
24
|
+
- **Exit 2 when it cannot look** — no config, no ledger — and that is not a pass.
|
|
25
|
+
Standing instruction #1: a component that never received its input refuses rather than
|
|
26
|
+
approves. It has its own negative self-test, because "no input" is the state in which
|
|
27
|
+
a checker most easily agrees with everything.
|
|
28
|
+
|
|
29
|
+
Guards: 313 → **315**. Property checks: 9 → 9. The first new one plants the incident
|
|
30
|
+
itself — a five-stage flow whose ledger stamps four — and requires the refusal to name
|
|
31
|
+
stage 3.
|
|
32
|
+
|
|
3
33
|
## v1.53.0 — the artifact root stops carrying another pack's name
|
|
4
34
|
|
|
5
35
|
The paperwork directory was called `docs/superpowers/`. The name came from an unrelated
|
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.54.0 |
|
|
16
16
|
| **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
|
|
17
17
|
| **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
|
|
18
18
|
| **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.54.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 closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.54.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -12,6 +12,7 @@ requirement.** It is what turns the pipeline from a funnel into a circle.
|
|
|
12
12
|
- Why a stage and not a gate
|
|
13
13
|
- First, the ladder walk — what the list itself is missing
|
|
14
14
|
- Inputs
|
|
15
|
+
- Every declared stage is accounted for
|
|
15
16
|
- Output — the coverage table
|
|
16
17
|
- Evidence, not assertion
|
|
17
18
|
- Several repositories — a submodule is finished when its parent says so
|
|
@@ -68,6 +69,31 @@ Read all of them before writing anything:
|
|
|
68
69
|
- stage 8's post-deploy notes; stage 9's doc/wiki changes
|
|
69
70
|
- for UI tasks: `docs/ux/scenarios.md` statuses and the `/ux-lint` result
|
|
70
71
|
|
|
72
|
+
## Every declared stage is accounted for
|
|
73
|
+
|
|
74
|
+
Before the coverage table, one cheaper question: **does the ledger account for every
|
|
75
|
+
stage the flow declares?**
|
|
76
|
+
|
|
77
|
+
A run can reach acceptance with stages that never happened and never said so. On
|
|
78
|
+
2026-08-13 one closed with `0,1,2,5,6,7,8,9,10` recorded and **3 (spec) and 4 (plan)
|
|
79
|
+
never stamped** — the artifacts existed, folded into the brief, but their verdicts did
|
|
80
|
+
not. The status line printed `3· 4·` and 73% and was right; nothing read it. Stage 7's
|
|
81
|
+
release gate could not have caught it: that gate fires before 8, 9 and 10 exist, and it
|
|
82
|
+
asks only about the tests stage.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
bash scripts/stage-coverage.sh
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Exit 1 names each declared stage with no verdict. **Both remedies are legitimate** —
|
|
89
|
+
stamp what actually happened, because a merged stage still has an outcome; or stop
|
|
90
|
+
declaring a stage this project folds into another, in `pipeline.json`, where the flow
|
|
91
|
+
describes itself. What is not legitimate is a flow that declares eleven stages and a
|
|
92
|
+
ledger that accounts for nine.
|
|
93
|
+
|
|
94
|
+
Exit 2 means it could not look — no config, or no ledger. That is **not** a pass: a
|
|
95
|
+
check that cannot run says so rather than agreeing.
|
|
96
|
+
|
|
71
97
|
## Output — the coverage table
|
|
72
98
|
|
|
73
99
|
Write `<artifacts>/specs/YYYY-MM-DD-<topic>-acceptance.md`:
|
|
@@ -21,6 +21,7 @@ from `super-ux`.
|
|
|
21
21
|
| `open-questions.md` | `docs/OPEN_QUESTIONS.md` | 0 seeds it, the Doc Loop resolves rows |
|
|
22
22
|
| `docgate.sh` | `scripts/check-docs.sh` | 0 seeds it · 9 runs it · 10 proves it |
|
|
23
23
|
| `hygiene.sh` | `scripts/check-hygiene.sh` | 0 seeds it · **5 runs it after every task** · 6 and 9 run it · 10 proves it |
|
|
24
|
+
| `stage-coverage.sh` | `scripts/stage-coverage.sh` | 0 seeds it · **10 runs it before the coverage table** — every stage the flow declares must carry a verdict, or the flow stops declaring one it merges |
|
|
24
25
|
| `hooks.example.json` | the project's `.claude/settings.json` | 0 — offered, never installed silently |
|
|
25
26
|
| `routing-rule.md` | the operator's `CLAUDE.md` — **offered by `setup`, never written silently** | 0 / `setup` |
|
|
26
27
|
| `retro.md` | `docs/evidence/retro.md` — **one per project, not per run** | 10 writes (stamp → prune → entry), 0 reads it in full |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Stage 10: does the ledger account for every stage the flow declares?
|
|
3
|
+
#
|
|
4
|
+
# A run can reach acceptance with stages that never happened and never said so. On
|
|
5
|
+
# 2026-08-13 one closed with 0,1,2,5,6,7,8,9,10 recorded and **3 (spec) and 4 (plan)
|
|
6
|
+
# never stamped** — the artifacts existed, folded into the brief, but their verdicts did
|
|
7
|
+
# not. The status line printed `3· 4·` and 73% and was right; nothing read it. Stage 7's
|
|
8
|
+
# release gate could not have caught this: it fires before 8, 9 and 10 exist, and it asks
|
|
9
|
+
# only for the tests stage.
|
|
10
|
+
#
|
|
11
|
+
# So this is the check stage 10 owes: every declared stage carries a verdict, or the flow
|
|
12
|
+
# stops declaring a stage it merges. Both are legitimate — a project whose spec and plan
|
|
13
|
+
# genuinely live inside the brief should say so in `pipeline.json` rather than record a
|
|
14
|
+
# verdict nobody produced. What is not legitimate is a flow that declares eleven stages
|
|
15
|
+
# and a ledger that accounts for nine.
|
|
16
|
+
#
|
|
17
|
+
# bash scripts/stage-coverage.sh # the project's own flow and ledger
|
|
18
|
+
# bash scripts/stage-coverage.sh --ledger X --config Y
|
|
19
|
+
#
|
|
20
|
+
# Exit 0 = every declared stage has a verdict. Exit 1 = it does not, and each missing one
|
|
21
|
+
# is named. Exit 2 = it could not look (no config, no ledger) — which is NOT a pass:
|
|
22
|
+
# a check that cannot run must say so rather than agree.
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
LEDGER=".task-pipeline/run.md"
|
|
26
|
+
CONFIG="pipeline.json"
|
|
27
|
+
while [ $# -gt 0 ]; do
|
|
28
|
+
case "$1" in
|
|
29
|
+
--ledger) LEDGER="$2"; shift 2 ;;
|
|
30
|
+
--config) CONFIG="$2"; shift 2 ;;
|
|
31
|
+
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
|
32
|
+
esac
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
[ -f "$CONFIG" ] || { echo "STAGE COVERAGE CANNOT RUN: no $CONFIG — the flow does not say what it declares" >&2; exit 2; }
|
|
36
|
+
[ -f "$LEDGER" ] || { echo "STAGE COVERAGE CANNOT RUN: no $LEDGER — there is no run to account for" >&2; exit 2; }
|
|
37
|
+
|
|
38
|
+
python3 - "$CONFIG" "$LEDGER" <<'PY'
|
|
39
|
+
import json, re, sys
|
|
40
|
+
|
|
41
|
+
cfg_p, led_p = sys.argv[1], sys.argv[2]
|
|
42
|
+
cfg = json.load(open(cfg_p, encoding="utf-8"))
|
|
43
|
+
declared = [s["id"] for s in cfg.get("stages", []) if "id" in s]
|
|
44
|
+
names = {s["id"]: s.get("name", "") for s in cfg.get("stages", [])}
|
|
45
|
+
if not declared:
|
|
46
|
+
print(f"STAGE COVERAGE CANNOT RUN: {cfg_p} declares no stages", file=sys.stderr)
|
|
47
|
+
raise SystemExit(2)
|
|
48
|
+
|
|
49
|
+
led = open(led_p, encoding="utf-8").read()
|
|
50
|
+
# `stage: <id> <name> — gate <type> — verdict <v> — <when>`; the LAST verdict for an id
|
|
51
|
+
# wins, because a stage re-entered after a fix is the stage's real outcome.
|
|
52
|
+
seen = {}
|
|
53
|
+
for m in re.finditer(r"^stage:\s*(\d+)\b[^\n]*?verdict\s+(\w+)", led, re.M):
|
|
54
|
+
seen[int(m.group(1))] = m.group(2)
|
|
55
|
+
|
|
56
|
+
missing = [i for i in declared if i not in seen]
|
|
57
|
+
unpassed = [(i, v) for i, v in sorted(seen.items()) if v not in ("pass", "skip")]
|
|
58
|
+
|
|
59
|
+
for i in missing:
|
|
60
|
+
print(f" stage {i} ({names.get(i,'')}) — DECLARED BY {cfg_p}, NO VERDICT IN THE LEDGER")
|
|
61
|
+
for i, v in unpassed:
|
|
62
|
+
print(f" stage {i} ({names.get(i,'')}) — last verdict is '{v}'")
|
|
63
|
+
|
|
64
|
+
covered = len(declared) - len(missing)
|
|
65
|
+
print(f"\nstages declared {len(declared)} · accounted for {covered} · "
|
|
66
|
+
f"{round(100*covered/len(declared))}%")
|
|
67
|
+
|
|
68
|
+
if missing:
|
|
69
|
+
print("\nA run that reaches acceptance with a stage unaccounted for is a run whose own\n"
|
|
70
|
+
"record disagrees with its flow. Either stamp what actually happened — a merged\n"
|
|
71
|
+
"stage still has an outcome — or stop declaring a stage this project folds into\n"
|
|
72
|
+
"another, in pipeline.json, where the flow describes itself.")
|
|
73
|
+
raise SystemExit(1)
|
|
74
|
+
if unpassed:
|
|
75
|
+
raise SystemExit(1)
|
|
76
|
+
print("every declared stage carries a verdict")
|
|
77
|
+
PY
|