task-pipeline-skill 1.86.1 → 1.86.3

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,41 @@
1
+ ## v1.86.3 — the release declares the stamp it does not carry, eighth time
2
+
3
+ `v1.86.2` was tagged and refused by its own release workflow: `npm run test:all` against
4
+ the tag's tree found the version named nowhere in `retro.md`'s `## Releases that carry no
5
+ stamp`. Nothing published under it — the tag exists, the release does not, npm never
6
+ served it. The tree had passed `npm test` locally and CI's `validate` job; the release
7
+ runs `test:all`, and `R-010` says to run exactly that against the tree you are about to
8
+ tag. Read that evening, skipped that evening.
9
+
10
+ The v1.86.2 payload is unchanged. This release adds the declaration for both versions.
11
+
12
+ ## v1.86.2 — the filter this skill exported filtered nothing
13
+
14
+ Claude Code 2.1.270 started printing `hooks.json: unknown key "if" … ignored` at session
15
+ start for a sibling plugin. The same shape has been in this skill's one shipped template
16
+ since 2026-08-03, and every project that copied it into `.claude/settings.json` got a
17
+ documentation gate that ran on **every** Bash call — a red gate refused `ls`, not commits.
18
+
19
+ Guards: 429 → **429**, property checks 15 → **15** — the regression for this release is
20
+ `test/audit_regressions/fix-hk-02.py`, run by `npm test`, and NOT a workflow step:
21
+ `validate.yml` sits at 511,941 of GitHub's 512,000 bytes (#91), and a 59-byte headroom holds
22
+ no step. It plants the old shape into a copy and requires the validator to refuse it by name.
23
+
24
+ - **`"if": "Bash(git commit *)"` sat beside `matcher`, and a matcher group is only
25
+ `matcher` + `hooks`.** Read out of the 2.1.270 binary's schema: `if` exists on a command
26
+ handler only. Moved there in `templates/hooks.example.json`; the group's `_note` moved to
27
+ a top-level `_filter_note` for the same reason, since the block is copied verbatim into a
28
+ settings file.
29
+ - **`references/hooks.md` said "beside `matcher`" and now says "inside the handler,
30
+ beside `type` and `command`"** — the worked example too; the evidence-docs mirror was
31
+ regenerated with `fix-ed-01.01.py --sync`. The dated 2026-08-03 documentation-track plan
32
+ keeps its wording.
33
+ - **A new validator check refuses any key the hook schema does not know** at either level
34
+ and requires exactly one handler-level `Bash(git commit *)`; `fix-hk-02.py` plants the
35
+ pre-v1.86.2 shape back and watches the check fire. `claude plugin validate
36
+ --strict` passes the defective file, so a repo gate is the only place this fails before a
37
+ session start.
38
+
1
39
  ## v1.86.1 — the release declares the stamp it does not carry
2
40
 
3
41
  `v1.86.0` was tagged and refused: the run-stamp gate reads the tag's own tree, a
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.86.1 |
15
+ | **Version** | 1.86.3 |
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.86.1",
3
+ "version": "1.86.3",
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.86.1",
6
+ "version": "1.86.3",
7
7
  "author": {
8
8
  "name": "ssheleg",
9
9
  "url": "https://x.com/sshlg93"
@@ -129,8 +129,13 @@ machine, and the first surprising denial is debugged in the wrong project.
129
129
  ```
130
130
 
131
131
  - a tool-name pattern (`Edit|Write|…`), or `"*"` for every call;
132
- - for a specific shell command, add `"if": "Bash(git commit *)"` beside
133
- `"matcher": "Bash"`.
132
+ - for a specific shell command, add `"if": "Bash(git commit *)"` **inside the
133
+ handler object**, beside `"type"` and `"command"` — never beside `"matcher"`.
134
+ A matcher group is only `matcher` + `hooks`; a key Claude Code does not know
135
+ there is ignored, and from 2.1.270 announced at every session start as
136
+ `hooks.json: unknown key "if" … ignored`. This skill's own template carried it
137
+ at group level until v1.86.2, so its gate filtered nothing and ran on every
138
+ Bash call.
134
139
 
135
140
  `if` uses **permission-rule syntax** (`Bash(git *)`, `Edit(*.ts)`) and is evaluated
136
141
  **only on tool events** — `PreToolUse`, `PostToolUse`, `PostToolUseFailure`,
@@ -177,9 +182,9 @@ the project's `.claude/settings.json`.
177
182
 
178
183
  ```json
179
184
  { "hooks": { "PreToolUse": [
180
- { "matcher": "Bash", "if": "Bash(git commit *)",
181
- "hooks": [{ "type": "command", "shell": "bash", "timeout": 60,
182
- "command": "bash scripts/check-docs.sh >&2 || exit 2" }] } ] } }
185
+ { "matcher": "Bash",
186
+ "hooks": [{ "type": "command", "if": "Bash(git commit *)", "shell": "bash",
187
+ "timeout": 60, "command": "bash scripts/check-docs.sh >&2 || exit 2" }] } ] } }
183
188
  ```
184
189
 
185
190
  `|| exit 2` is the contract, not a flourish: without it the gate's own `exit 1`
@@ -129,8 +129,13 @@ machine, and the first surprising denial is debugged in the wrong project.
129
129
  ```
130
130
 
131
131
  - a tool-name pattern (`Edit|Write|…`), or `"*"` for every call;
132
- - for a specific shell command, add `"if": "Bash(git commit *)"` beside
133
- `"matcher": "Bash"`.
132
+ - for a specific shell command, add `"if": "Bash(git commit *)"` **inside the
133
+ handler object**, beside `"type"` and `"command"` — never beside `"matcher"`.
134
+ A matcher group is only `matcher` + `hooks`; a key Claude Code does not know
135
+ there is ignored, and from 2.1.270 announced at every session start as
136
+ `hooks.json: unknown key "if" … ignored`. This skill's own template carried it
137
+ at group level until v1.86.2, so its gate filtered nothing and ran on every
138
+ Bash call.
134
139
 
135
140
  `if` uses **permission-rule syntax** (`Bash(git *)`, `Edit(*.ts)`) and is evaluated
136
141
  **only on tool events** — `PreToolUse`, `PostToolUse`, `PostToolUseFailure`,
@@ -177,9 +182,9 @@ the project's `.claude/settings.json`.
177
182
 
178
183
  ```json
179
184
  { "hooks": { "PreToolUse": [
180
- { "matcher": "Bash", "if": "Bash(git commit *)",
181
- "hooks": [{ "type": "command", "shell": "bash", "timeout": 60,
182
- "command": "bash scripts/check-docs.sh >&2 || exit 2" }] } ] } }
185
+ { "matcher": "Bash",
186
+ "hooks": [{ "type": "command", "if": "Bash(git commit *)", "shell": "bash",
187
+ "timeout": 60, "command": "bash scripts/check-docs.sh >&2 || exit 2" }] } ] } }
183
188
  ```
184
189
 
185
190
  `|| exit 2` is the contract, not a flourish: without it the gate's own `exit 1`
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "_note": "EXAMPLE — copy this block into the project's .claude/settings.json. Doctrine: references/hooks.md. Hooks exist ONLY in Claude Code; on any other agent the same rule runs as a self-check and the run is recorded 'ungated'. Never describe a project as protected when its agents run elsewhere.",
3
3
  "_contract": "A PreToolUse hook blocks in one of two ways: exit 2 with the reason on stderr (stdout is ignored), or exit 0 with {\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"...\"}} on stdout. ANY OTHER EXIT CODE IS NON-BLOCKING, so a crashing guard fails open and stops guarding without announcing it. That is why the command below ends in '|| exit 2' — the gate's own 'exit 1' would otherwise land in the non-blocking branch and the commit would proceed.",
4
+ "_filter_note": "Refuse a commit while the documentation gate is red. Matched narrowly: the matcher is free, the script is not. The `if` filter sits ON THE HANDLER, beside `type`/`command` — never beside `matcher`: a matcher group is only `matcher` + `hooks`, and a key Claude Code does not know there is ignored (and reported at session start from 2.1.270). Until v1.86.2 this template carried `if` at group level, so the gate ran on EVERY Bash call in every project that copied it, and a red docs gate refused every shell command rather than the commit.",
4
5
  "hooks": {
5
6
  "PreToolUse": [
6
7
  {
7
- "_note": "Refuse a commit while the documentation gate is red. Matched narrowly: the matcher is free, the script is not.",
8
8
  "matcher": "Bash",
9
- "if": "Bash(git commit *)",
10
9
  "hooks": [
11
10
  {
12
11
  "type": "command",
12
+ "if": "Bash(git commit *)",
13
13
  "shell": "bash",
14
14
  "timeout": 60,
15
15
  "command": "bash scripts/check-docs.sh >&2 || exit 2"