task-pipeline-skill 1.94.1 → 1.96.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/CONTRIBUTING.md +32 -0
  3. package/HOW-IT-WORKS.md +4 -3
  4. package/README.md +19 -7
  5. package/SKILL-CARD.md +2 -2
  6. package/evals/RESULTS.md +55 -8
  7. package/evals/cases/task-pipeline.json +139 -0
  8. package/evals/fixtures/lessons/expect-match.sh +30 -0
  9. package/evals/fixtures/lessons/index.jsonl +2 -0
  10. package/evals/fixtures/waves-unclaimed/expect-refusal.sh +26 -0
  11. package/evals/fixtures/waves-unclaimed/inventory.json +33 -0
  12. package/evals/fixtures/waves-unclaimed/modules.json +4 -0
  13. package/evals/fixtures/waves-unclaimed/plan.json +5 -0
  14. package/evals/task-pipeline.evals.json +104 -0
  15. package/package.json +1 -1
  16. package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
  17. package/plugins/task-pipeline/agents/verifier.md +1 -1
  18. package/plugins/task-pipeline/commands/task-pipeline.md +3 -2
  19. package/plugins/task-pipeline/hooks/release-gate.sh +1 -1
  20. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +16 -11
  21. package/plugins/task-pipeline/skills/task-pipeline/pipeline.example.json +4 -0
  22. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +19 -0
  23. package/plugins/task-pipeline/skills/task-pipeline/references/artifacts.md +1 -1
  24. package/plugins/task-pipeline/skills/task-pipeline/references/audit.md +5 -2
  25. package/plugins/task-pipeline/skills/task-pipeline/references/brainstorm.md +1 -1
  26. package/plugins/task-pipeline/skills/task-pipeline/references/browser.md +1 -1
  27. package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +1 -1
  28. package/plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md +3 -2
  29. package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +10 -2
  30. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +20 -2
  31. package/plugins/task-pipeline/skills/task-pipeline/references/finish-line.md +145 -0
  32. package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +1 -1
  33. package/plugins/task-pipeline/skills/task-pipeline/references/iteration.md +9 -5
  34. package/plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md +5 -0
  35. package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +13 -1
  36. package/plugins/task-pipeline/skills/task-pipeline/references/progress.md +8 -0
  37. package/plugins/task-pipeline/skills/task-pipeline/references/review.md +7 -2
  38. package/plugins/task-pipeline/skills/task-pipeline/references/spec.md +7 -5
  39. package/plugins/task-pipeline/skills/task-pipeline/references/stage-00-intake.md +158 -0
  40. package/plugins/task-pipeline/skills/task-pipeline/references/stage-01-docs-study.md +10 -0
  41. package/plugins/task-pipeline/skills/task-pipeline/references/stage-02-brainstorm.md +52 -0
  42. package/plugins/task-pipeline/skills/task-pipeline/references/stage-03-spec.md +66 -0
  43. package/plugins/task-pipeline/skills/task-pipeline/references/stage-04-plan.md +11 -0
  44. package/plugins/task-pipeline/skills/task-pipeline/references/stage-05-dev.md +55 -0
  45. package/plugins/task-pipeline/skills/task-pipeline/references/stage-06-tests.md +11 -0
  46. package/plugins/task-pipeline/skills/task-pipeline/references/stage-07-lint-deploy.md +15 -0
  47. package/plugins/task-pipeline/skills/task-pipeline/references/stage-08-post-deploy.md +29 -0
  48. package/plugins/task-pipeline/skills/task-pipeline/references/stage-09-docs-wiki.md +45 -0
  49. package/plugins/task-pipeline/skills/task-pipeline/references/stage-10-acceptance.md +91 -0
  50. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +49 -484
  51. package/plugins/task-pipeline/skills/task-pipeline/references/verification.md +1 -1
  52. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +9 -6
  53. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +1 -1
  54. package/plugins/task-pipeline/skills/task-pipeline/scripts/stage_checkpoint.py +156 -33
  55. package/plugins/task-pipeline/skills/task-pipeline/scripts/waves.py +219 -3
  56. package/plugins/task-pipeline/skills/task-pipeline/templates/brief.md +14 -0
  57. package/plugins/task-pipeline/skills/task-pipeline/templates/inventory.schema.json +15 -1
  58. package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +26 -2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,76 @@
1
+ ## v1.96.0 — 2026-10-15
2
+
3
+ Source candidate; not published.
4
+
5
+ Guards: 439 → **447**; property checks 15 → **15**.
6
+
7
+ An iteration now stops at a finish line instead of when a search runs dry. The new
8
+ `references/finish-line.md` fixes a contract at intake — objective, exit checks run on
9
+ the released, installed or deployed artefact, scope, budget and base — in the brief's
10
+ `## Finish line`. Every finding is triaged when found: blocking only by one of four
11
+ tests (a red exit check, a hotfix-lane entry, a regression against base, a verified
12
+ REQ or published claim false on the artefact), deferred to the board with its
13
+ evidence, or noise as one ledger line. Severity words and effort never change the
14
+ class. An iteration is done after two consecutive rounds with no new blocking
15
+ finding; it stops at `run.finish.maxRounds` (default 3) or `maxReleases` (default 2)
16
+ with each open blocker handed back as a `needs-operator` row, and diverging rounds go
17
+ to the loop guard. Stopping is not idle: the next iteration starts from the board by
18
+ priority, never by re-opening the closed one.
19
+
20
+ `scripts/waves.py finish` computes the verdict from the inventory's new optional item
21
+ fields (`triage`, `test`, `round`, `base_repro`, plus `blast` and `rung` for known
22
+ risks) and prints the finish block; deferred and noise items never change it. The round
23
+ count is explicit — `--rounds` or the run ledger's new `round:` lines, which must agree
24
+ with the inventory — because a clean round leaves no item to count. Done needs the exit
25
+ checks supplied and green (`--checks`), stays within `maxRounds` (at least 2) unless the
26
+ operator's go is passed, and `next:` ranks every open non-blocking row by priority,
27
+ never by freshness. B2 also covers a defect that would be a hotfix-lane entry once
28
+ released; a defect in a node's own diff stays with review. Stage 0's
29
+ gate requires the finish line filled; stage 10's requires the `finish:` line printed.
30
+ Iteration, waves, loop-guard, audit, continuity, review and progress doctrine point to
31
+ the one rule, and seven validator guards hold its vocabulary, budgets, hotfix set,
32
+ brief fields, hand-back field and script enums equal across their surfaces.
33
+
34
+ ## v1.95.0 — 2026-10-13
35
+
36
+ Source candidate; not published.
37
+
38
+ Guards: 438 → **439**; property checks 15 → **15**.
39
+
40
+ The default stage list keeps every full gate and routes each stage to its own
41
+ procedure before work on entry or resume. Custom profiles keep their own stages
42
+ and doctrine. The split preserves the original stage text and reduces the measured
43
+ entry reading component; it does not claim a native-host or billed-token result.
44
+ Scenario artifacts remain mandatory for user-facing work, while an equivalent
45
+ provider or the documented inline fallback can supply them without installing a
46
+ specific companion plugin. The new route refusal and relocated source checks keep
47
+ these obligations addressable after the split.
48
+
49
+ Checkpoint recovery now follows the selected project profile's declared stage order,
50
+ including custom names and nonconsecutive ids. Malformed or changed profiles refuse
51
+ instead of silently injecting default stages into a saved workflow. Run-local profile
52
+ binding survives record/retry; relocated ledgers can name their project root explicitly.
53
+ This is an offline-tested payload correction, not a live Observatory acceptance claim.
54
+
55
+ Owner release preparation now records an unpublished local annotated tag before the
56
+ complete suite, binds its exact source/context/evidence, and publishes only the
57
+ verified annotation to one destination. The existing release hook recognizes
58
+ explicit tag-destination refspecs. Mechanical evidence does not confer external
59
+ authority, native interception or successful registry publication.
60
+
61
+ Test runners use one safely opened family scratch lock across TMPDIR settings and
62
+ owners, matching their shared fixed scratch paths. The lock now stays held while a
63
+ plant's Bash or its synchronously writing child is alive, even if the runner itself is
64
+ killed; an interrupted runner signals and drains its own process groups before it
65
+ closes its copy, and on macOS a group of exited-but-unreaped members no longer aborts
66
+ that cancellation. An interrupted run no longer leaves its repository snapshot in
67
+ TMPDIR. Existing older runner versions, deliberately detached descendants and direct
68
+ plant invocation remain outside that mechanism.
69
+
70
+ The owner-gate helpers' seam headers declare `diverges: none` with their extraction
71
+ scope on a separate line, so the umbrella's shared-copy check reads them as identical
72
+ to the other members' copies.
73
+
1
74
  ## v1.94.1 — 2026-10-13
2
75
 
3
76
  Records the missing retrospective declarations that stopped the v1.94.0 release
package/CONTRIBUTING.md CHANGED
@@ -51,6 +51,38 @@ To try your change in a real agent:
51
51
  node bin/task-pipeline.js --force # the same, through the npm installer
52
52
  ```
53
53
 
54
+ ## Owner release admission
55
+
56
+ For this repository's release, the unpublished annotated candidate tag must exist
57
+ locally on the accepted commit **before** the complete suite runs. A green untagged
58
+ run is insufficient: inspect whether release-stamp checks actually looked.
59
+ `pipeline.json` stage7 and standing instruction R-010 in `docs/evidence/retro.md`
60
+ use this same order; R-004 requires the next operation to depend on gate success.
61
+
62
+ In a standalone full clone of the owning source repository, use the owner-only
63
+ `scripts/release_candidate.py`. Set `candidate_tag` to the chosen unpublished
64
+ version and `actual_project_root` to the same-source project holding the real
65
+ current run context. These are operator/run inputs, not generated approval:
66
+
67
+ ```bash
68
+ python3 scripts/release_candidate.py prepare --tag "$candidate_tag" --context-root "$actual_project_root" &&
69
+ python3 scripts/release_candidate.py check --tag "$candidate_tag" &&
70
+ python3 scripts/release_candidate.py publish --tag "$candidate_tag"
71
+ ```
72
+
73
+ `prepare` creates and binds the owned local annotation; `check` runs the fixed
74
+ `npm run test:all` with that tag visible and retains its exact evidence.
75
+ `publish` requires faithful bound context, the existing release hook, unchanged
76
+ source/tag/evidence and the verified single destination/ref. The helper does not
77
+ verify external authorization or create a ledger. Without faithful context,
78
+ prepare/check remain usable and publication refuses. Never move a published tag;
79
+ changed or ambiguous state requires read-only reconciliation before another action.
80
+
81
+ Its PUBLISHED state confirms the tag's remote object and peel, not successful npm
82
+ publication. Watch every release job and verify the published payload separately.
83
+ The helper and private Git-directory receipts belong to the owner checkout and
84
+ are not a plugin API or part of the installed skill.
85
+
54
86
  ## Repository layout
55
87
 
56
88
  | Path | What it is |
package/HOW-IT-WORKS.md CHANGED
@@ -65,9 +65,10 @@ because it rots the moment the vendor ships a new one.
65
65
 
66
66
  **Companions.** `super-ux`, `copywriting`, `sheleg-design`, `graphify`, the wiki.
67
67
  The detection block prints once. A missing companion states its fallback and
68
- **does not block** — the single exception being the stage-3 UX track on
69
- user-facing work, where shipping without it is a decision someone has to make out
70
- loud.
68
+ **does not block on installation**. For user-facing work, stage 3 requires a valid
69
+ scenario artifact under the [provider rule](plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md).
70
+ Unavailable checks are named as NOT_RUN; a fallback is not evidence that a missing
71
+ tool ran.
71
72
 
72
73
  ---
73
74
 
package/README.md CHANGED
@@ -167,9 +167,9 @@ ledgers, so the link is the repository's rather than the package's.
167
167
  The doctrine each stage runs on ships inside the skill. Nothing to install for it,
168
168
  nothing to resolve at preflight, no version skew with someone else's repo, and
169
169
  **no stage blocks on an install** — stage 1 falls back to web search, the wiki and
170
- the code graph are recommendations. The one exception is deliberate and named: on a
171
- user-facing task the stage-3 UX track requires super-ux, and the spec gate stops
172
- until it is installed.
170
+ the code graph are recommendations. On user-facing tasks the stage-3 UX gate
171
+ requires a valid scenario artifact. The preferred provider, an equivalent provider
172
+ and the inline fallback satisfy the same [provider contract](plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md).
173
173
 
174
174
  | Stage | Built-in doctrine |
175
175
  |---|---|
@@ -189,6 +189,7 @@ until it is installed.
189
189
  | 10 Acceptance | [`acceptance.md`](plugins/task-pipeline/skills/task-pipeline/references/acceptance.md) — REQ coverage table, evidence rules, the closing question |
190
190
  | 10 + any audit | [`audit.md`](plugins/task-pipeline/skills/task-pipeline/references/audit.md) — the L0→L7 ladder and its seams, axis rotation, ratchets, proven checks |
191
191
  | any loop | [`loop-guard.md`](plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md) — churn detection, caps, the break protocol |
192
+ | when an iteration stops | [`finish-line.md`](plugins/task-pipeline/skills/task-pipeline/references/finish-line.md) — a contract fixed at intake (objective, exit checks on the artefact, scope, budget, base), every finding triaged when found — blocking, deferred or noise — and a stop at two rounds with no new blocking finding or at the budget, computed by `waves.py finish` |
192
193
  | every gate + stage 10 | [`residue.md`](plugins/task-pipeline/skills/task-pipeline/references/residue.md) — what the run leaves **running** and leaves **behind**: eight classes enumerated by class rather than by one tool, `holds: N` beside every verdict, and a teardown that ends what this run started and only reports what it did not |
193
194
  | run-wide reporting | [`progress.md`](plugins/task-pipeline/skills/task-pipeline/references/progress.md) — the header block at task start and the one-line iteration close: the stage rail computed from the project's own `pipeline.json`, every number borrowed from the gate that measured it |
194
195
  | run-wide pacing | [`continuity.md`](plugins/task-pipeline/skills/task-pipeline/references/continuity.md) — the loop mode (`run.loop`, default off, never collapses a manual gate) and the context budget (fires on a harness signal, never on an estimate) |
@@ -634,8 +635,8 @@ must say so.
634
635
  ### Held to Anthropic's own Skill authoring guidance
635
636
 
636
637
  Audited against the four Agent Skills pages. Most of it already held — `name`
637
- 13/64 chars, `description` 887/1024 chars, `SKILL.md` 270/500 lines, all 41 references
638
- linked **directly** from `SKILL.md`, and the bundle far under the 30 MB ceiling. What
638
+ 13/64 chars, `description` 887/1024 chars, `SKILL.md` 275/500 lines, all 53 references
639
+ reachable from `SKILL.md` through explicit reference routes, and the bundle far under the 30 MB ceiling. What
639
640
  did not, now does:
640
641
 
641
642
  - **Every reference over 100 lines carries a `## Contents` list**, and the list is
@@ -971,7 +972,7 @@ skill. Four optional companions make individual stages better:
971
972
 
972
973
  | Companion | For | Required? |
973
974
  |---|---|---|
974
- | [super-ux](https://github.com/ssheleg/super-ux) | the stage-3 UX track | only for user-facing tasks |
975
+ | [super-ux](https://github.com/ssheleg/super-ux) | the stage-3 UX track | preferred provider; valid scenario artifact required for user-facing tasks |
975
976
  | context7 (MCP) | stage-1 docs study | recommended — web-search fallback |
976
977
  | [obsidian-wiki](https://github.com/ar9av/obsidian-wiki) | stage-0 harvest + stage-9 sync | recommended — never a gate |
977
978
  | [graphify](https://github.com/Graphify-Labs/graphify) | stage-0 reach queries + stage-9 refresh + the graph↔docs divergence check | recommended — never a gate |
@@ -987,7 +988,18 @@ recommendation, so you arm the whole run in one exchange. Detail:
987
988
  | File | What's in it |
988
989
  |---|---|
989
990
  | [`SKILL.md`](plugins/task-pipeline/skills/task-pipeline/SKILL.md) | the orchestrator: how to run, the stage table, the model decision |
990
- | [`references/stages.md`](plugins/task-pipeline/skills/task-pipeline/references/stages.md) | per-stage detail and the exact gate criteria |
991
+ | [`references/stages.md`](plugins/task-pipeline/skills/task-pipeline/references/stages.md) | complete gate criteria and exact per-stage detail routes |
992
+ | [`references/stage-00-intake.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-00-intake.md) | stage 0 procedure, read on entry or resume |
993
+ | [`references/stage-01-docs-study.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-01-docs-study.md) | stage 1 procedure, read on entry or resume |
994
+ | [`references/stage-02-brainstorm.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-02-brainstorm.md) | stage 2 procedure, read on entry or resume |
995
+ | [`references/stage-03-spec.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-03-spec.md) | stage 3 procedure, read on entry or resume |
996
+ | [`references/stage-04-plan.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-04-plan.md) | stage 4 procedure, read on entry or resume |
997
+ | [`references/stage-05-dev.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-05-dev.md) | stage 5 procedure, read on entry or resume |
998
+ | [`references/stage-06-tests.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-06-tests.md) | stage 6 procedure, read on entry or resume |
999
+ | [`references/stage-07-lint-deploy.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-07-lint-deploy.md) | stage 7 procedure, read on entry or resume |
1000
+ | [`references/stage-08-post-deploy.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-08-post-deploy.md) | stage 8 procedure, read on entry or resume |
1001
+ | [`references/stage-09-docs-wiki.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-09-docs-wiki.md) | stage 9 procedure, read on entry or resume |
1002
+ | [`references/stage-10-acceptance.md`](plugins/task-pipeline/skills/task-pipeline/references/stage-10-acceptance.md) | stage 10 procedure, read on entry or resume |
991
1003
  | [`references/doctrine-map.md`](plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md) | which reference owns which stage — the map SKILL.md used to carry inline |
992
1004
  | [`references/artifacts.md`](plugins/task-pipeline/skills/task-pipeline/references/artifacts.md) | the canonical document layout each stage writes to |
993
1005
  | [`references/conventions.md`](plugins/task-pipeline/skills/task-pipeline/references/conventions.md) | how stages 6–10 read the host project's `CLAUDE.md`, and how the documentation regime is detected |
package/SKILL-CARD.md CHANGED
@@ -12,9 +12,9 @@ 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.94.1 |
15
+ | **Version** | 1.96.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
- | **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 |
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; user-facing stage 3 requires a valid scenario artifact; super-ux is preferred, with equivalent-provider and inline-fallback paths under the provider contract |
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` |
19
19
 
20
20
  ## Risk-tier disclosure
package/evals/RESULTS.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # Evaluation results — task-pipeline
2
2
 
3
3
  **Status: three suites authored (task-pipeline, evidence-docs, project-audit);
4
- one self-observed run and, since 2026-08-31, three blind trigger runs — one per
5
- model (haiku, sonnet, opus).** The instruction-following cases remain unexecuted
6
- and say so per run, because they need a full interactive session — a skip is not
7
- a pass, and a guessed verdict is worse than a vacant row.
4
+ one self-observed run, three blind trigger runs on 2026-08-31 — one per model
5
+ (haiku, sonnet, opus) — and three more on 2026-10-14 over the release-iteration
6
+ phrasings (TRIG-11, TRIG-12, NOTRIG-09), one per model.** The instruction-following
7
+ cases remain unexecuted and say so per run, because they need a full interactive
8
+ session — a skip is not a pass, and a guessed verdict is worse than a vacant row.
8
9
 
9
10
  **The numbers below are computed, not asserted.** `python3 evals/run.py` counts the
10
11
  suite and the dated run headings in this file. A value typed here that disagrees with
@@ -40,11 +41,11 @@ or it belongs in a check.
40
41
 
41
42
  | Metric | Value | Computed by | As of |
42
43
  |---|---|---|---|
43
- | Evals authored | 48 (three suites: task-pipeline 30, evidence-docs 9, project-audit 9) | `python3 evals/run.py` → `suite: N evals` | 2026-10-12 |
44
+ | Evals authored | 55 (three suites: task-pipeline 37, evidence-docs 9, project-audit 9) | `python3 evals/run.py` → `suite: N evals` | 2026-10-14 |
44
45
  | Categories covered | 5 of 5, per suite | the suite's own `category` fields | 2026-08-31 |
45
- | Dated runs recorded | **4** | `python3 evals/run.py` → `recorded runs: N` | 2026-08-31 |
46
- | …of those, **blind** | **3** | run headings not marked `self-observed` | 2026-08-31 |
47
- | Models exercised blind | **3 of 3** | distinct models across blind runs | 2026-08-31 |
46
+ | Dated runs recorded | **7** | `python3 evals/run.py` → `recorded runs: N` | 2026-10-14 |
47
+ | …of those, **blind** | **6** | run headings not marked `self-observed` | 2026-10-14 |
48
+ | Models exercised blind | **3 of 3** | distinct models across blind runs | 2026-10-14 |
48
49
 
49
50
  **The last three rows are the honest state of this skill's behavioural evidence**, and
50
51
  the split matters more than the total: a run the author watched, knowing the expected
@@ -84,6 +85,52 @@ model NAMED the skill; it does not prove a full session loaded and obeyed the
84
85
  doctrine — the INSTR cases need exactly that and are recorded as **not
85
86
  reproducible from this harness**, not guessed.
86
87
 
88
+ ## 2026-10-14 · haiku · blind trigger probes, subagent protocol
89
+
90
+ **3 of 3 scored cases passed** — the two release-iteration triggers and their
91
+ explanation control, added by release iteration 1 (node M-4, USR-015). Method as
92
+ 2026-08-31 below, with two differences, stated rather than implied: the offered
93
+ list was the family's **38** skills (the family grew from 28), built once from the
94
+ members' `SKILL.md` frontmatters on 2026-10-14 (sha256 `12115a8b24f1…`); and each
95
+ subagent reported the model id from its own system context, recorded here as the
96
+ model that answered: `claude-haiku-5-5`. The other new cases of that node
97
+ (INSTR-09…13, TP-OUT-006/007) were not run: the INSTR cases need a full interactive
98
+ session, and the two outcome cases need an executor driving an arm in a sandbox —
99
+ their fixtures' command checks are proven to pass and to fail by
100
+ `test/audit_regressions/usr_015_evals.py`, which is not a run of the case.
101
+
102
+ | id | verdict | what happened |
103
+ |---|---|---|
104
+ | TRIG-11 | pass | named `task-pipeline` — cited the description's 'waves'/'волнами' |
105
+ | TRIG-12 | pass | named `task-pipeline` — cited 'итерация релиза' in the description |
106
+ | NOTRIG-09 | pass | answered `none` — the description excludes explaining |
107
+
108
+ ## 2026-10-14 · sonnet · blind trigger probes, subagent protocol
109
+
110
+ **3 of 3 scored cases passed.** Same protocol and list as the haiku run above;
111
+ the answering model reported `claude-sonnet-5-5`.
112
+
113
+ | id | verdict | what happened |
114
+ |---|---|---|
115
+ | TRIG-11 | pass | named `task-pipeline` — matched «закрой их волнами» to the waves mode |
116
+ | TRIG-12 | pass | named `task-pipeline` — matched the 'release iteration' trigger |
117
+ | NOTRIG-09 | pass | answered `none` — a plain explanation question |
118
+
119
+ ## 2026-10-14 · opus · blind trigger probes, subagent protocol
120
+
121
+ **3 of 3 scored cases passed.** Same protocol and list as the haiku run above;
122
+ the answering model reported `claude-opus-5-5[1m]`.
123
+
124
+ | id | verdict | what happened |
125
+ |---|---|---|
126
+ | TRIG-11 | pass | named `task-pipeline` — the board closed «волнами» |
127
+ | TRIG-12 | pass | named `task-pipeline` — the board-closing release loop |
128
+ | NOTRIG-09 | pass | answered `none` — named the trigger phrase and the explaining exclusion |
129
+
130
+ INSTR-09…13 and TP-OUT-006/007: **not run** in any of the three 2026-10-14 runs,
131
+ for the reasons given under the haiku run. A trigger `pass` still means only that
132
+ the model NAMED the skill.
133
+
87
134
  ## 2026-08-31 · haiku · blind trigger probes, subagent protocol
88
135
 
89
136
  **39 of 42 scored cases passed** across the three suites' trigger-shaped
@@ -186,6 +186,145 @@
186
186
  }
187
187
  ]
188
188
  }
189
+ },
190
+ {
191
+ "schema_version": "outcome-case/1",
192
+ "id": "TP-OUT-006-waves-validate-refuses-unclaimed-item",
193
+ "skill": "task-pipeline",
194
+ "prompt": {
195
+ "text": "Wave 0 of `/task-pipeline waves`: the inventory, module table and wave plan are the frozen files under evals/fixtures/waves-unclaimed/. Check that every item lands on a node with the skill's own inventory validator, without editing the fixture, and write waves-validate.md with the command you ran, its exit code and what it reported (USR-015).",
196
+ "files": [
197
+ {
198
+ "path": "evals/fixtures/waves-unclaimed/inventory.json",
199
+ "sha256": "8ffb7e0f291c8cfb5b77910424b3dac55459e8f6b58f7e63343fcef258bb2102"
200
+ },
201
+ {
202
+ "path": "evals/fixtures/waves-unclaimed/modules.json",
203
+ "sha256": "9d13ac48c1c49d0bd315ed5643b68de993d1f33ee125e1e23718f6c60fe296d5"
204
+ },
205
+ {
206
+ "path": "evals/fixtures/waves-unclaimed/plan.json",
207
+ "sha256": "cc42a367ac8a966214beb21d8459c04e3704c461f220dd3a34d7f5fca315dbc8"
208
+ },
209
+ {
210
+ "path": "evals/fixtures/waves-unclaimed/expect-refusal.sh",
211
+ "sha256": "857a48783bdb89ff82c4d16d5adb93dc2159e3d89cb5b8dea069fa0439d60517"
212
+ }
213
+ ]
214
+ },
215
+ "environment": {
216
+ "model": "inherit",
217
+ "host": "any",
218
+ "case_digest": "480a16d5aef3efa8ae30e872e15948d2fa4906fd50211803295e5084d7403fe8"
219
+ },
220
+ "checks": {
221
+ "tool": [
222
+ {
223
+ "name": "python3 present",
224
+ "command": "python3 -c 'pass'"
225
+ },
226
+ {
227
+ "name": "bash present",
228
+ "command": "bash -c 'true'"
229
+ }
230
+ ],
231
+ "load_trace": {
232
+ "expect_loaded": [
233
+ "task-pipeline"
234
+ ],
235
+ "expect_not_loaded": []
236
+ },
237
+ "outcome": [
238
+ {
239
+ "name": "the validator still refuses the frozen fixture (inverted through the wrapper)",
240
+ "kind": "command-exit-0",
241
+ "target": "bash evals/fixtures/waves-unclaimed/expect-refusal.sh"
242
+ },
243
+ {
244
+ "name": "the record exists",
245
+ "kind": "artifact-exists",
246
+ "target": "waves-validate.md"
247
+ },
248
+ {
249
+ "name": "the record names the item that lands nowhere",
250
+ "kind": "artifact-contains",
251
+ "target": "waves-validate.md",
252
+ "expect": "B-103"
253
+ },
254
+ {
255
+ "name": "the record carries the refusal's exit code",
256
+ "kind": "artifact-contains",
257
+ "target": "waves-validate.md",
258
+ "expect": "exit 1"
259
+ }
260
+ ]
261
+ }
262
+ },
263
+ {
264
+ "schema_version": "outcome-case/1",
265
+ "id": "TP-OUT-007-lessons-query-fires-on-fixture",
266
+ "skill": "task-pipeline",
267
+ "prompt": {
268
+ "text": "Stage 0 of a run for 'add a retry policy to the webhook handler'. The machine's local lesson index is the frozen file evals/fixtures/lessons/index.jsonl and the session lists no shared lesson store. Read the lessons source the way the skill's harvest does, and write ledger.md with the source-ledger lines for both lesson layers and the citation of every lesson that fires (USR-015).",
269
+ "files": [
270
+ {
271
+ "path": "evals/fixtures/lessons/index.jsonl",
272
+ "sha256": "6b73a4345e8f361a565e15a93a1fa204a141f791b82946a08260d475b2aef28d"
273
+ },
274
+ {
275
+ "path": "evals/fixtures/lessons/expect-match.sh",
276
+ "sha256": "bed8b0b6363128108ff6a6985240d4b1fdeda01448ddc32ef32caa43c4e2a814"
277
+ }
278
+ ]
279
+ },
280
+ "environment": {
281
+ "model": "inherit",
282
+ "host": "any",
283
+ "case_digest": "eef134f07ba724082236b6a5977009dd744076ca7391fd562fe562bdd171cd88"
284
+ },
285
+ "checks": {
286
+ "tool": [
287
+ {
288
+ "name": "python3 present",
289
+ "command": "python3 -c 'pass'"
290
+ },
291
+ {
292
+ "name": "bash present",
293
+ "command": "bash -c 'true'"
294
+ }
295
+ ],
296
+ "load_trace": {
297
+ "expect_loaded": [
298
+ "task-pipeline"
299
+ ],
300
+ "expect_not_loaded": []
301
+ },
302
+ "outcome": [
303
+ {
304
+ "name": "the query over a copy of the fixture fires the webhook lesson only",
305
+ "kind": "command-exit-0",
306
+ "target": "bash evals/fixtures/lessons/expect-match.sh"
307
+ },
308
+ {
309
+ "name": "the ledger cites the lesson that fires",
310
+ "kind": "artifact-contains",
311
+ "target": "ledger.md",
312
+ "expect": "[lesson L-70cf4d4825df]"
313
+ },
314
+ {
315
+ "name": "the ledger states the local layer's count",
316
+ "kind": "artifact-contains",
317
+ "target": "ledger.md",
318
+ "expect": "local lessons: 1 match"
319
+ },
320
+ {
321
+ "name": "the ledger states the shared layer is absent",
322
+ "kind": "artifact-contains",
323
+ "target": "ledger.md",
324
+ "expect": "shared lessons: absent"
325
+ }
326
+ ]
327
+ }
189
328
  }
190
329
  ]
191
330
  }
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env bash
2
+ # TP-OUT-007's command check: `lessons.py query` over this fixture index must
3
+ # fire the webhook lesson (L-70cf4d4825df) on the task's nouns and leave the
4
+ # unrelated cache lesson (L-8487303c010c) out. The index is queried from a
5
+ # temporary copy, because the script takes a lock file beside the index and a
6
+ # check must not write into the tree it reads.
7
+ set -u
8
+ here="$(cd "$(dirname "$0")" && pwd)"
9
+ scripts="${TASK_PIPELINE_SCRIPTS:-$here/../../../plugins/task-pipeline/skills/task-pipeline/scripts}"
10
+ if [ ! -f "$scripts/lessons.py" ]; then
11
+ echo "expect-match: lessons.py not found under $scripts (set TASK_PIPELINE_SCRIPTS)" >&2
12
+ exit 2
13
+ fi
14
+ tmp="$(mktemp -d)"
15
+ cp "$here/index.jsonl" "$tmp/index.jsonl"
16
+ out="$(python3 "$scripts/lessons.py" query webhook retry handler --index "$tmp/index.jsonl")"
17
+ rc=$?
18
+ rm -f "$tmp/index.jsonl" "$tmp/.lock"
19
+ rmdir "$tmp"
20
+ if [ "$rc" -ne 0 ]; then
21
+ echo "expect-match: lessons.py query exited $rc" >&2
22
+ exit 1
23
+ fi
24
+ case "$out" in
25
+ *"[lesson L-8487303c010c]"*) echo "expect-match: the unrelated lesson fired" >&2; exit 1 ;;
26
+ esac
27
+ case "$out" in
28
+ *"[lesson L-70cf4d4825df]"*) exit 0 ;;
29
+ *) echo "expect-match: the webhook lesson did not fire: $out" >&2; exit 1 ;;
30
+ esac
@@ -0,0 +1,2 @@
1
+ {"check": "a test that renames and reads back through the cache", "classKey": "cache-invalidation-on-rename", "grade": 2, "id": "L-8487303c010c", "nouns": ["cache", "invalidation", "rename"], "origins": [{"commit": "2222222222222222222222222222222222222222", "lesson": {"check": "a test that renames and reads back through the cache", "classKey": "cache-invalidation-on-rename", "grade": 2, "nouns": ["cache", "rename", "invalidation"], "stages": {"owned": 4, "surfaced": 6}, "title": "a renamed record kept serving its old cached name", "trigger": "a rename that does not touch the cache key"}, "project": "p-0a1b2c3d4e5f", "retro": "docs/evidence/retro.md#cache-rename"}], "projects": 1, "schema": "lesson-index/1", "seen": 1, "stages": {"owned": 4, "surfaced": 6}, "status": "local", "title": "a renamed record kept serving its old cached name", "trigger": "a rename that does not touch the cache key"}
2
+ {"check": "a test that delivers the same event twice and asserts one effect", "classKey": "webhook-retry-without-idempotency-key", "grade": 2, "id": "L-70cf4d4825df", "nouns": ["delivery", "idempotency", "retry", "webhook"], "origins": [{"commit": "1111111111111111111111111111111111111111", "lesson": {"check": "a test that delivers the same event twice and asserts one effect", "classKey": "webhook-retry-without-idempotency-key", "grade": 2, "nouns": ["webhook", "retry", "idempotency", "delivery"], "stages": {"owned": 4, "surfaced": 6}, "title": "a retried delivery applied twice because the handler kept no idempotency key", "trigger": "a handler that retries or receives redelivered events"}, "project": "p-0a1b2c3d4e5f", "retro": "docs/evidence/retro.md#webhook-retry"}], "projects": 1, "schema": "lesson-index/1", "seen": 1, "stages": {"owned": 4, "surfaced": 6}, "status": "local", "title": "a retried delivery applied twice because the handler kept no idempotency key", "trigger": "a handler that retries or receives redelivered events"}
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+ # TP-OUT-006's command check: `waves.py validate` must REFUSE this fixture.
3
+ # The inventory holds three open items; the plan's only node closes two, so
4
+ # B-103 lands nowhere. Exit 0 means the refusal happened and named B-103;
5
+ # any other result — including the validator accepting the fixture, or the
6
+ # script not being found — is non-zero, so a missing tool can never pass.
7
+ set -u
8
+ here="$(cd "$(dirname "$0")" && pwd)"
9
+ scripts="${TASK_PIPELINE_SCRIPTS:-$here/../../../plugins/task-pipeline/skills/task-pipeline/scripts}"
10
+ if [ ! -f "$scripts/waves.py" ]; then
11
+ echo "expect-refusal: waves.py not found under $scripts (set TASK_PIPELINE_SCRIPTS)" >&2
12
+ exit 2
13
+ fi
14
+ err="$(python3 "$scripts/waves.py" validate \
15
+ --inventory "$here/inventory.json" \
16
+ --modules "$here/modules.json" \
17
+ --plan "$here/plan.json" 2>&1 >/dev/null)"
18
+ rc=$?
19
+ if [ "$rc" -ne 1 ]; then
20
+ echo "expect-refusal: waves.py validate exited $rc, expected 1" >&2
21
+ exit 1
22
+ fi
23
+ case "$err" in
24
+ *B-103*) exit 0 ;;
25
+ *) echo "expect-refusal: the refusal did not name B-103: $err" >&2; exit 1 ;;
26
+ esac
@@ -0,0 +1,33 @@
1
+ {
2
+ "schema": "inventory/1",
3
+ "topic": "eval-fixture-unclaimed-item",
4
+ "items": [
5
+ {
6
+ "id": "B-101",
7
+ "title": "export endpoint times out past ten thousand rows",
8
+ "area": "export",
9
+ "kind": "bug",
10
+ "severity": "high",
11
+ "evidence": "src/export.py:42 buffers the whole result set before the first byte",
12
+ "proposed_fix": "stream rows in pages"
13
+ },
14
+ {
15
+ "id": "B-102",
16
+ "title": "export CSV header omits the timezone",
17
+ "area": "export",
18
+ "kind": "gap",
19
+ "severity": "low",
20
+ "evidence": "src/export.py:17 writes created_at without an offset",
21
+ "proposed_fix": "write ISO 8601 with offset"
22
+ },
23
+ {
24
+ "id": "B-103",
25
+ "title": "settings page loses unsaved edits on navigation",
26
+ "area": "settings",
27
+ "kind": "bug",
28
+ "severity": "medium",
29
+ "evidence": "web/settings.tsx:88 drops the draft on route change",
30
+ "proposed_fix": "keep the draft in route state"
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "export": ["B-101", "B-102"],
3
+ "settings": ["B-103"]
4
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "nodes": [
3
+ {"id": "N-001", "wave": 1, "closes": ["B-101", "B-102"]}
4
+ ]
5
+ }