task-pipeline-skill 1.81.1 → 1.82.4
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
CHANGED
|
@@ -1,3 +1,156 @@
|
|
|
1
|
+
## v1.82.4 — the plant the harness could not see
|
|
2
|
+
|
|
3
|
+
`v1.82.3` is a dead tag, and its cause is the **fourth distinct one**. Its stamp was
|
|
4
|
+
correct and in the right order: the payload merged as `9e2ab3e`, the stamp cited it and
|
|
5
|
+
landed as `e4e0eb4`, the tag was cut there, and the gate had accepted that tree.
|
|
6
|
+
|
|
7
|
+
What failed was a negative self-test added in the same programme. `test/negatives.py`
|
|
8
|
+
locates a plant's scratch directory by searching its script for a literal
|
|
9
|
+
`cp -R . <dir>`, then diffs that copy against the repository to tell a real defect from a
|
|
10
|
+
no-op. The duplicate-id plant copied **one file** and mutated the live tree, restoring it
|
|
11
|
+
afterwards — correct as a workflow step, invisible to the harness. With no scratch
|
|
12
|
+
directory it could not confirm the plant had landed, and reported the guard as one that
|
|
13
|
+
**did not fire**. Correctly, by its own rule.
|
|
14
|
+
|
|
15
|
+
The plant now follows the convention every other one uses: copy the tree, mutate the
|
|
16
|
+
copy, run the validator from the copy, leave it mutated. Verified with the harness itself
|
|
17
|
+
before shipping — `PASS: a board id naming two rows must fail`, the step that had never
|
|
18
|
+
been run locally across four attempts.
|
|
19
|
+
|
|
20
|
+
**`npm test` cannot see this**, because `negatives.py` is a CI step and not part of the
|
|
21
|
+
suite. Four dead tags, four different mechanisms — a stamp in the wrong shape, a tag cut
|
|
22
|
+
before the stamp existed twice, and now a plant the harness cannot verify — and one
|
|
23
|
+
shared shape behind all of them: a green local gate that does not cover what the release
|
|
24
|
+
runs. `B-134` carries it, and now asks for a preflight that runs the plant harness too.
|
|
25
|
+
|
|
26
|
+
Guards: 424 → **424** — the plant is repaired, not added.
|
|
27
|
+
|
|
28
|
+
**Landed 2026-09-02, and the release-gap check refused this tree first.** The repair above
|
|
29
|
+
was green on every branch check and still declared no stamp for the release it was
|
|
30
|
+
creating — a fifth instance of the same shape, caught because the tag was cut locally and
|
|
31
|
+
`npm run test:all` was run against the tag's own tree before anything was pushed. The
|
|
32
|
+
preflight `B-134` asks for is therefore not a new check: it is `test:all` on that tree,
|
|
33
|
+
which is the only tree where four of the five failures can be seen at all. `npm test` runs
|
|
34
|
+
three of its thirteen.
|
|
35
|
+
|
|
36
|
+
## v1.82.3 — the release protocol is two merges, and their order is written down now
|
|
37
|
+
|
|
38
|
+
**`v1.82.2` is a dead tag for the same reason `v1.82.1` was, and the run that burned it
|
|
39
|
+
had just written the rule into this file.** A release here needs a stamp on the tag's own
|
|
40
|
+
tree; the declaration v1.82.2 carried was for v1.82.1, the tag already dead. The payload
|
|
41
|
+
merged as `9195590`, the tag was cut there, and nothing in that tree stamped the run.
|
|
42
|
+
|
|
43
|
+
**The mechanism, stated so nobody pays for it a fourth time.** A stamp must cite a commit
|
|
44
|
+
inside the NEW tag's own range, and that commit does not exist until the payload merges —
|
|
45
|
+
the ruleset rebase-merges and mints every SHA at merge time. So a release is **two merges
|
|
46
|
+
and their order is load-bearing**: the payload lands as `X`, a second change stamps the
|
|
47
|
+
run citing `X` and lands as `Y`, and the tag is cut on `Y`.
|
|
48
|
+
|
|
49
|
+
**Nothing refuses the wrong order before the tag exists.** `validate.yml` ignores tag
|
|
50
|
+
pushes; `release.yml` is the first thing to run on the tag's own tree. So the branch is
|
|
51
|
+
green either way and the cost is always a burned version, because the ruleset forbids
|
|
52
|
+
deleting a tag. Three in one day: `v1.82.0` (stamp written in the sibling repository's
|
|
53
|
+
bullet shape into a section this gate reads as a table), `v1.82.1` and `v1.82.2` (tag cut
|
|
54
|
+
on the payload commit). That gap is now `B-134`, which asks for a preflight that resolves
|
|
55
|
+
the range the tag would create and asserts a stamp falls inside it — a check that can run
|
|
56
|
+
*before* anything is spent.
|
|
57
|
+
|
|
58
|
+
Guards: 424 → **424** — this release records a protocol and adds no mechanism; the
|
|
59
|
+
mechanism it asks for is the board row.
|
|
60
|
+
|
|
61
|
+
## v1.82.2 — one id, one finding, and a status read from the wrong place
|
|
62
|
+
|
|
63
|
+
**A board id identified two findings for the whole of v1.82.x.** `B-114` and `B-115`
|
|
64
|
+
each named two rows: the pair filed on 2026-08-31 from the harness-engineering
|
|
65
|
+
articles, and the pair this programme appended on 2026-09-01 without reading what was
|
|
66
|
+
already there. Four rows, two ids — so a run stamp saying *"B-115 filed"*, a CHANGELOG
|
|
67
|
+
naming the range `B-114…B-117`, and a sibling board citing either one all pointed at
|
|
68
|
+
two different findings at once. The newer pair is renumbered `B-119` and `B-120`, and
|
|
69
|
+
the stamp that cited them is repointed in the same change.
|
|
70
|
+
|
|
71
|
+
**The guard, because renumbering fixes the case and not the class.** `test/validate.py`
|
|
72
|
+
collected board ids into a **set**, where a repeat collapses leaving no trace — which
|
|
73
|
+
is precisely why this shipped and stayed invisible. The new check reads row-leading ids
|
|
74
|
+
only (`| B-NNN |`, first cell), so a prose citation of another row stays a citation
|
|
75
|
+
rather than becoming a second definition, and it names both line numbers in its
|
|
76
|
+
refusal. Watched failing before it shipped: a planted collision returns
|
|
77
|
+
*"docs/evidence/backlog.md:110: id B-119 identifies a second row (the first is line
|
|
78
|
+
109)"*. The umbrella has carried this guard for its own board; this repository is where
|
|
79
|
+
the defect actually landed, and it had none. Guards: 423 → **424**.
|
|
80
|
+
|
|
81
|
+
**Shipped as 1.82.2 because `v1.82.1` is a dead tag.** Its tree carried no stamp for its
|
|
82
|
+
own run, so the release suite — which runs on the tag's own tree, where `validate.yml`
|
|
83
|
+
never looks — refused it. The round was not lost to skipping the check: the gate **was**
|
|
84
|
+
run against the merge commit, and its exit status was read from a trailing `echo` in the
|
|
85
|
+
same command rather than from the suite, so a zero belonging to the `echo` was taken for
|
|
86
|
+
the suite's verdict. An explicit re-run returned 1 seconds later. The rule from v1.82.0
|
|
87
|
+
therefore gains its second half: verify with the gate rather than a grep of your own
|
|
88
|
+
prose, **read the gate's own exit status**, and cut the tag locally, run the suite on the
|
|
89
|
+
tag's tree, and push only then — a local tag can be moved, a pushed one cannot.
|
|
90
|
+
|
|
91
|
+
## v1.82.1 — the second axis of blindness, and the scope the two-severity rule never had
|
|
92
|
+
|
|
93
|
+
**This release is 1.82.0 and not 1.81.0, and the reason is worth recording.** 1.81.0 was
|
|
94
|
+
already in flight in a concurrent session — the anchors-are-derived release — and this run
|
|
95
|
+
picked the same number by reading `package.json` at branch time without asking whether
|
|
96
|
+
anyone else held it. Worse, the tag was pushed **immediately after a `gh pr merge` that had
|
|
97
|
+
printed a conflict and not merged**, so `v1.81.0` landed on the other session's commit and
|
|
98
|
+
started its release before its run stamp was written. That release failed on exactly the
|
|
99
|
+
guard that exists for it — *a release named nowhere in `Releases that carry no stamp`* — and
|
|
100
|
+
published nothing. The tag cannot be deleted (a repository rule refuses it), so 1.81.0 stays
|
|
101
|
+
spent and this work moves up. Standing instruction #8 in the umbrella's retro covers the
|
|
102
|
+
mechanism: a wrapper's exit status is not the verdict, and it was not read.
|
|
103
|
+
|
|
104
|
+
**Shipped as 1.82.1 because `v1.82.0` is a dead tag, and the reason is a check that read the
|
|
105
|
+
wrong thing.** The run stamp for this release was written as a **list item** — the shape the
|
|
106
|
+
sibling `sshlg-skills` uses — into a section this repository keeps as a **table**. The release
|
|
107
|
+
suite therefore found no stamp covering the tag, refused it, and published nothing. Worse than
|
|
108
|
+
the format slip: the verification run before tagging grepped for the stamp's own title and
|
|
109
|
+
reported it present. **That confirmed the text existed, not that the gate could read it.** The
|
|
110
|
+
tag cannot be deleted, so it is declared in `retro.md`'s no-stamp section and the payload moves
|
|
111
|
+
one patch up.
|
|
112
|
+
|
|
113
|
+
Guards: 423 → **423** — this release adds doctrine and no mechanism. Both findings argue
|
|
114
|
+
against a rule rather than against a missing check, and the vertical blindness rule is
|
|
115
|
+
explicitly one `certify` cannot verify from a report.
|
|
116
|
+
|
|
117
|
+
**`certification.md` decoupled the three readers from each other and never decoupled the
|
|
118
|
+
fixer from the grader.** Tier blindness is horizontal — no tier reads another's report, and
|
|
119
|
+
`certify` refuses a report whose prose cites another tier. Nothing said the *vertical* half:
|
|
120
|
+
the agent that produced a change may not be the agent that certifies it.
|
|
121
|
+
|
|
122
|
+
That gap matters because the optimisation which closes it is attractive. The fixer already
|
|
123
|
+
holds the context; a fresh reader has to re-derive it. Taking that saving converts
|
|
124
|
+
certification into self-assessment **while every report it writes stays sincere** — an
|
|
125
|
+
optimiser that grades itself learns to game the metric rather than improve the work, and
|
|
126
|
+
`certify` cannot detect the collapse from a report. It is now a dispatch rule beside the
|
|
127
|
+
one it belongs with.
|
|
128
|
+
|
|
129
|
+
**And the two-severity rule shipped without its scope.** *There are two severities and no
|
|
130
|
+
third, because a certification that admits a maybe admits everything* is correct — for a
|
|
131
|
+
**finding**, which is a claim a reader makes about a diff and either blocks or does not.
|
|
132
|
+
It is the wrong shape for the **verdict of a check** whose subject is non-deterministic,
|
|
133
|
+
where binary pass/fail has been measured at **0% detection** of regressions and trace
|
|
134
|
+
fingerprinting at **86%**. A third value there is not laxity: `INCONCLUSIVE`, grounded in
|
|
135
|
+
hypothesis testing, is how a run says *this sample cannot decide* instead of flipping a coin
|
|
136
|
+
and reporting the result as a severity. Sequential testing cuts the trials it needs by
|
|
137
|
+
**78%**.
|
|
138
|
+
|
|
139
|
+
So the rule now carries its boundary: **two severities for a finding, three verdicts for a
|
|
140
|
+
stochastic check**, with the second axis pointed at `agent-stack`'s `agent-evals` —
|
|
141
|
+
`references/statistics.md` for how many runs make a difference real — and at the skill's
|
|
142
|
+
`references/gates.md` → *Axis A* for where such a gate belongs.
|
|
143
|
+
|
|
144
|
+
**A fourth invisible class, with a measurement.** *Why one verifier is not enough* listed
|
|
145
|
+
three defects a diff-reader cannot see; the fourth is the one a blended score cannot see
|
|
146
|
+
either: **the internal state is right and the message about it is stale.** The value was
|
|
147
|
+
stored correctly and the final sentence to the user echoed the old one — passing on state,
|
|
148
|
+
failing on truth, so any grader that averages the two calls it mostly fine. It was caught by
|
|
149
|
+
a rubric with categorical outcomes rather than a number, and closing it moved the violation
|
|
150
|
+
rate from **21% to 4%**. Its general form is this pipeline's own worst case: work that
|
|
151
|
+
**looks like it is working** while quietly missing what was asked — which is the product
|
|
152
|
+
tier's whole job, and why the tier that reads no code is not the soft one.
|
|
153
|
+
|
|
1
154
|
# Changelog
|
|
2
155
|
|
|
3
156
|
## v1.81.1 — the anchors are derived, and a dormant plant stops reading as a pass
|
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.82.4 |
|
|
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, and **one of two browser channels** — `playwright` (CLI or MCP) or `chrome-devtools` (MCP); either satisfies the browser step and neither is required. 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.82.4",
|
|
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"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "task-pipeline",
|
|
4
4
|
"displayName": "Task Pipeline",
|
|
5
5
|
"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/judgment/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.",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.82.4",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "ssheleg",
|
|
9
9
|
"url": "https://x.com/sshlg93"
|
|
@@ -33,11 +33,23 @@ to it by construction:
|
|
|
33
33
|
- a **second implementation of the same rule** did not get the fix
|
|
34
34
|
- a **documented behaviour** is now false, and the document still reads as true
|
|
35
35
|
- **another feature** reaches the same path and nobody considered the interaction
|
|
36
|
+
- the **internal state is right and the message about it is stale** — the value was
|
|
37
|
+
stored correctly and the final sentence to the user echoed the old one
|
|
36
38
|
|
|
37
39
|
None of these is a bug in the changed lines. All of them ship. Each is found by
|
|
38
40
|
looking one level further out than the change — which is a different reading, not a
|
|
39
41
|
longer one, because the context that finds it is the context that excludes the diff.
|
|
40
42
|
|
|
43
|
+
**The last one is worth its own sentence, because it is the shape a blended score cannot
|
|
44
|
+
see.** A run that stores the right value and then reports the stale one passes on state
|
|
45
|
+
and fails on truth, so any grader that averages the two calls it mostly fine. It was
|
|
46
|
+
caught by a purpose-built rubric with categorical outcomes — *honoured / ignored /
|
|
47
|
+
partial / none* — rather than a number, and closing it moved the violation rate from
|
|
48
|
+
**21% to 4%**. The general form is the dangerous one for this pipeline: work that **looks
|
|
49
|
+
like it is working** — confident answers, a plan that reads fine — while quietly missing
|
|
50
|
+
what was actually asked. That is the product tier's whole job, and it is why the tier
|
|
51
|
+
that reads no code is not the soft one.
|
|
52
|
+
|
|
41
53
|
## The three tiers
|
|
42
54
|
|
|
43
55
|
| Tier | Subject | Characteristic finding |
|
|
@@ -62,6 +74,16 @@ tier's verdict.
|
|
|
62
74
|
Dispatch all three in one message so they run concurrently. Give each the node id,
|
|
63
75
|
its `serves`, and the diff — nothing else, and never another tier's output.
|
|
64
76
|
|
|
77
|
+
**The second axis, and it is the one an optimisation removes first: whoever produced
|
|
78
|
+
the fix never grades it.** Tier blindness is horizontal — no tier reads another's
|
|
79
|
+
report. This one is vertical: the agent that wrote the change, and the agent that
|
|
80
|
+
certifies it, are different agents. The reason is not tidiness — *an optimizer that
|
|
81
|
+
grades itself learns to game the metric instead of improving the work*, and it does so
|
|
82
|
+
while every report it writes stays sincere. The saving on offer is real (the fixer
|
|
83
|
+
already holds the context, a fresh reader must re-derive it) and it is the saving that
|
|
84
|
+
converts certification into self-assessment. `certify` cannot detect the collapse from
|
|
85
|
+
a report, so it is stated here as a dispatch rule.
|
|
86
|
+
|
|
65
87
|
## A pass has to mean something, so two rules have teeth
|
|
66
88
|
|
|
67
89
|
**A tier cannot pass on an empty `scope`.** `scope` is what the tier actually
|
|
@@ -81,6 +103,24 @@ and no third, because a certification that admits a maybe admits everything:
|
|
|
81
103
|
closing verdict as a blocker with `can_continue_around: true`, which is exactly
|
|
82
104
|
what a named survivable finding is.
|
|
83
105
|
|
|
106
|
+
**And the scope of that rule, because it is not universal.** These are severities of a
|
|
107
|
+
**finding**, and a finding is a claim a reader makes about a diff — it either blocks or
|
|
108
|
+
it does not. That is a different object from the **verdict of a check**, and where the
|
|
109
|
+
check's subject is non-deterministic the two-valued form is not strictness, it is
|
|
110
|
+
blindness: binary pass/fail has been measured at **0% detection** of regressions in a
|
|
111
|
+
non-deterministic workflow, where mapping execution traces to compact vectors and
|
|
112
|
+
testing them multivariately reaches **86%**. A third value there — `INCONCLUSIVE`,
|
|
113
|
+
grounded in hypothesis testing rather than in a reader's judgement — is what lets a
|
|
114
|
+
run say *this sample cannot decide* instead of flipping a coin and reporting it as a
|
|
115
|
+
severity. Sequential testing cuts the trials such a verdict needs by **78%**.
|
|
116
|
+
|
|
117
|
+
So: **two severities for a finding, three verdicts for a stochastic check.** A
|
|
118
|
+
deterministic command exits 0 or it does not, and admitting a maybe there does admit
|
|
119
|
+
everything. The instrument for the other case is `agent-stack`'s `agent-evals` —
|
|
120
|
+
`references/statistics.md` for how many runs make a difference real — and a gate whose
|
|
121
|
+
subject is non-deterministic belongs on that axis rather than this one
|
|
122
|
+
([`gates.md`](gates.md) → *Axis A*).
|
|
123
|
+
|
|
84
124
|
## The report, and where each field lands
|
|
85
125
|
|
|
86
126
|
Eight keys, all required, `[]` a valid answer and silence not one. On a pass
|