task-pipeline-skill 1.59.0 → 1.60.1

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,5 +1,66 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.60.1 — the gate can see an invariant it breaks elsewhere
4
+
5
+ **This gate can now see an invariant it breaks one repository away.** The family umbrella
6
+ routes work by matching a prompt against a table in `lib/triggers.js`, and every trigger
7
+ there must be a word this skill's own `description` advertises. Nothing here knew that
8
+ table existed. On 2026-08-16 `sheleg-design` 1.37.0 shipped green having dropped a phrase
9
+ that was still a live trigger, the umbrella found out minutes after the tag, and it cost a
10
+ patch release — because the member releases FIRST and the umbrella re-pins after.
11
+
12
+ `test/validate.py` now asks the umbrella's own checker (`test/advertised_check.js`), which
13
+ reads the module the hook itself calls. **No copy of the table lives here**, so there is
14
+ nothing to drift. With no umbrella above this checkout — a standalone clone, and CI — it
15
+ discloses rather than passing, because a check that cannot look must never read as one
16
+ that looked.
17
+
18
+ Guards: 344 → **344**, and the reason no plant joins this repository's own suite is the
19
+ check's shape. It only sees anything when an umbrella checkout sits above this one, which
20
+ is never true in this repository's CI — a negative self-test here would have to assert a
21
+ refusal that cannot happen. The plant lives where the submodules exist: `sshlg-skills`
22
+ runs one against every member's own gate.
23
+
24
+ Watched refusing a real drop before shipping: every one of the seven members carrying
25
+ routed triggers had one of its own advertised phrases removed and every one of them failed
26
+ its own gate.
27
+
28
+ ## v1.60.0 — the gate this skill ships had never run on this skill
29
+
30
+ Wiring it in was one line. Running it once found five things, and each was silent in a
31
+ different way:
32
+
33
+ - **It was skipping itself in every submodule checkout.** The section asked `[ -d .git ]`,
34
+ and a submodule's `.git` is a *file* holding a `gitdir:` pointer — the same shape that
35
+ disarmed two negative self-tests in v1.58.0, now found a third time in two days, in the
36
+ shipped gate. It asks `git rev-parse --is-inside-work-tree` now, which knows all three
37
+ shapes.
38
+ - **Its corpus default still named the artifact root as it was before the 2026-08-13
39
+ rename**, so in every migrated project the SHA and propagation sections found nothing and
40
+ reported **dormant** — which reads exactly like having nothing to check. The root is
41
+ resolved now, new name first.
42
+ - **Eleven commit references could not be followed.** Nine are pre-gate history rewritten
43
+ early in this project's life, one is a documentation placeholder that never named a
44
+ commit, and two were branch commits a **squash merge** had replaced — which is the same
45
+ class as the amend above, arriving from a different direction. The two were repointed to
46
+ the commits that carry their work on `main`; the other nine are **enumerated by name**
47
+ in the archive with their date and reason, so the gate passes over exactly those and
48
+ fails on the twelfth. An exception with names, never a floor.
49
+ - **Two decisions named documents that never cited them.** `DEC-0001` and `DEC-0004` are
50
+ now cited in `progress.md` and `companion-skills.md` — which is the propagation contract
51
+ working the moment anything checked it.
52
+ - **One id was reported undefined because the checker could not tell a plant from a
53
+ claim.** A retro entry recording *planted `DEC-0009` while the highest defined id was
54
+ `DEC-0001`* was read as a citation. A line describing a planted defect is sample content
55
+ by the same argument as a fenced block, and `strip_asides` now treats it as one.
56
+
57
+ `npm run test:docs` is a script, and `test:all` calls it, and a guard requires both — a
58
+ gate nobody's aggregate command runs is a gate that goes quiet the first busy week.
59
+
60
+ Guards: 344 → **344**. The change is a gate script and its wiring; every finding above
61
+ was watched being produced by the gate itself, which is the only plant a script that
62
+ reads a project's own git history can have.
63
+
3
64
  ## v1.59.0 — never amend a commit a record already names
4
65
 
5
66
  ### Fixed
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.59.0 |
15
+ | **Version** | 1.60.1 |
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.59.0",
3
+ "version": "1.60.1",
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"
@@ -9,9 +9,10 @@
9
9
  "test": "python3 test/validate.py",
10
10
  "test:negatives": "python3 test/negatives.py",
11
11
  "test:probe": "python3 test/probe.py --self-test",
12
- "test:all": "python3 test/validate.py && python3 test/negatives.py && npm run test:probe && npm run test:hooks && npm run test:artifacts",
12
+ "test:all": "python3 test/validate.py && python3 test/negatives.py && npm run test:probe && npm run test:hooks && npm run test:artifacts && npm run test:docs",
13
13
  "test:hooks": "python3 test/release_gate_test.py",
14
- "test:artifacts": "python3 test/artifact_root_test.py && python3 test/migrate_artifacts_test.py"
14
+ "test:artifacts": "python3 test/artifact_root_test.py && python3 test/migrate_artifacts_test.py",
15
+ "test:docs": "bash plugins/task-pipeline/skills/task-pipeline/templates/docgate.sh"
15
16
  },
16
17
  "files": [
17
18
  "bin",
@@ -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.59.0",
5
+ "version": "1.60.1",
6
6
  "author": {
7
7
  "name": "ssheleg",
8
8
  "url": "https://x.com/sshlg93"
@@ -8,6 +8,12 @@ something isn't installed.
8
8
  What remains is a short list of **optional** companions that make individual stages
9
9
  better, plus one that is required only for user-facing work.
10
10
 
11
+
12
+ > **Decision `DEC-0004`** — two browser channels ranked by nothing, one detection rule,
13
+ > stop at the first that answers. The step stays **recommended and never a gate**: a gate
14
+ > an environment cannot satisfy is one an agent learns to report around, and *verified by
15
+ > reading the diff* already prices the absence honestly (`docs/DECISIONS.md`).
16
+
11
17
  ## Contents
12
18
 
13
19
  - Built in — nothing to install
@@ -18,6 +18,12 @@ maintains them and the next run reads them as current.
18
18
 
19
19
  ---
20
20
 
21
+
22
+ > **Decision `DEC-0001`** — the hand-back names what this run filed, and the join from a
23
+ > run to its rows already exists: the board's `Source` column. It deliberately buys no
24
+ > coverage number, because a required minimum is a run filing a throwaway row to make
25
+ > the count agree (`docs/DECISIONS.md`).
26
+
21
27
  ## Contents
22
28
 
23
29
  - The two boundaries, and only those two
@@ -34,7 +34,18 @@ DEC_FILE=${DEC_FILE:-$DOCS_DIR/DECISIONS.md}
34
34
  ADR_DIR=${ADR_DIR:-$DOCS_DIR/adr}
35
35
  OQ_FILE=${OQ_FILE:-$DOCS_DIR/OPEN_QUESTIONS.md}
36
36
  MAP_FILE=${MAP_FILE:-$DOCS_DIR/DOCMAP.md}
37
- RETRO_GLOB=${RETRO_GLOB:-$DOCS_DIR/superpowers}
37
+ # The artifact root is RESOLVED, not assumed. It was renamed `superpowers` → `evidence`
38
+ # on 2026-08-13 (v1.53.0 made it resolvable, v0.46.0 moved the family), and this default
39
+ # still named the old one — so in every migrated project the SHA and propagation sections
40
+ # below found no corpus and went **dormant**, which reads exactly like having nothing to
41
+ # check. Measured 2026-08-16 on this skill's own repository. Prefer the new name, fall
42
+ # back to the old, and a project that has neither gets the dormant message it deserves.
43
+ if [ -z "${RETRO_GLOB:-}" ]; then
44
+ if [ -d "$DOCS_DIR/evidence" ]; then RETRO_GLOB="$DOCS_DIR/evidence"
45
+ elif [ -d "$DOCS_DIR/superpowers" ]; then RETRO_GLOB="$DOCS_DIR/superpowers"
46
+ else RETRO_GLOB="$DOCS_DIR/evidence"
47
+ fi
48
+ fi
38
49
 
39
50
  # ---------- ratchets: a floor may only fall. Raising one is a decision. ----------
40
51
  # THE TWO FLOORS ARE DIFFERENT KINDS. Mixing them up is why this is spelled out.
@@ -68,6 +79,13 @@ strip_asides() {
68
79
  awk '
69
80
  /^[ \t]*(```|~~~)/ { infence = !infence; print ""; next }
70
81
  infence { print ""; next }
82
+ # A line describing a PLANTED defect quotes ids that were never meant to exist —
83
+ # that is the payload of a negative self-test, written down so the incident can be
84
+ # read later. It is sample content by the same argument as a fenced block, and the
85
+ # checker cannot otherwise tell an id being USED from an id being DISCUSSED. Found
86
+ # 2026-08-16: a retro entry recording `planted DEC-0009 while the highest defined id
87
+ # was DEC-0001` was reported as citing an undefined decision.
88
+ /planted/ { print ""; next }
71
89
  {
72
90
  line = $0
73
91
  # A comment carried over from an earlier line.
@@ -430,17 +448,29 @@ fi
430
448
  # ---------- 9. every commit SHA named in the retro resolves ----------
431
449
  # A file:line rots at the next edit; a SHA carries the diff, the message and the
432
450
  # parent forever. A document may not send a reader to something absent.
433
- if [ ! -d .git ]; then
451
+ # `[ -d .git ]` is the wrong question and it silently disabled this whole section for
452
+ # every submodule and every linked worktree — where `.git` is a FILE holding a `gitdir:`
453
+ # pointer. Measured 2026-08-16 on this skill's own repository, checked out as a submodule:
454
+ # the section printed `skip` while five SHAs in the archive did not resolve at all. Ask git
455
+ # whether it is inside a work tree; it knows about all three shapes and this does not.
456
+ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
434
457
  skipmsg "commit-SHA resolution — not a git working tree"
435
458
  elif [ ! -d "$RETRO_GLOB" ]; then
436
459
  dormant "commit-SHA resolution — no $RETRO_GLOB yet"
437
460
  else
438
461
  : > "$TMP/sha"
462
+ # An enumerated exception, never a floor. A commit whose history was rewritten before any
463
+ # of this was gated cannot be repaired without inventing a mapping, and a frozen record of
464
+ # a past run is not rewritten. Such SHAs are listed by name in a `docgate:known-dead`
465
+ # marker inside the retro corpus itself — one home, with the reason in prose beside it —
466
+ # so this passes over exactly those and still fails on the next one.
467
+ DEAD=$(grep -rho 'docgate:known-dead[^>]*' "$RETRO_GLOB" 2>/dev/null | sed 's/docgate:known-dead//' | tr -s ' \n' ' ')
439
468
  find "$RETRO_GLOB" -type f -name '*.md' 2>/dev/null | sort | while IFS= read -r f; do
440
469
  grep -n -o '`[0-9a-f][0-9a-f]*`' "$(flat_of "$f")" 2>/dev/null |
441
470
  while IFS=: read -r ln tok; do
442
471
  s=$(echo "$tok" | tr -d '`')
443
472
  case ${#s} in 7|8|9|10|11|12|40) ;; *) continue ;; esac
473
+ case " $DEAD " in *" $s "*) continue ;; esac
444
474
  if ! git rev-parse --verify --quiet "$s^{commit}" >/dev/null 2>&1; then
445
475
  echo "$f:$ln: commit \`$s\` does not resolve" >> "$TMP/sha"
446
476
  # Resolving is the weaker half. A commit that was AMENDED AWAY still resolves on