task-pipeline-skill 1.72.0 → 1.74.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 +176 -0
- package/CONTRIBUTING.md +61 -0
- package/README.md +1 -0
- package/SKILL-CARD.md +1 -1
- package/package.json +4 -3
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/agents/verifier-product.md +96 -0
- package/plugins/task-pipeline/agents/verifier-seam.md +98 -0
- package/plugins/task-pipeline/agents/verifier-unit.md +86 -0
- package/plugins/task-pipeline/agents/verifier.md +9 -0
- package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +167 -72
- package/plugins/task-pipeline/skills/task-pipeline/references/acceptance.md +23 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/audit.md +15 -6
- package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +146 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/gates.md +9 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/progress.md +9 -3
- package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +6 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +3 -0
- package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +326 -6
- package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +22 -8
- package/plugins/task-pipeline/skills/task-pipeline/templates/verification.md +38 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,181 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.74.0 — 2026-08-20 — a node is closed by three readings, not one
|
|
4
|
+
|
|
5
|
+
**A verifier reads the diff it was handed, and that is the definition of its context, not a
|
|
6
|
+
shortcoming.** It also means a class of defect is invisible to it by construction: the change is
|
|
7
|
+
correct where it was made and a caller's contract moved under it; a second implementation of the
|
|
8
|
+
same rule did not get the fix; a documented behaviour is now false and the document still reads
|
|
9
|
+
as true; another feature reaches the same path and nobody considered the interaction. None of
|
|
10
|
+
those is a bug in the changed lines. All of them ship.
|
|
11
|
+
|
|
12
|
+
A node is now closed by **three independent readings at escalating visibility**, and the run may
|
|
13
|
+
not advance until all three pass.
|
|
14
|
+
|
|
15
|
+
| Tier | Subject | Characteristic finding |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `unit` | the changed functions, classes and branches, plus the node's own `check` | a branch nothing exercises; a boundary that moved |
|
|
18
|
+
| `seam` | everything that can reach the change — callers, callees, implementors, shared state, the neighbours' tests | a contract that moved under a dependent; the duplicate that did not get the fix |
|
|
19
|
+
| `product` | documentation, scenarios, user-visible strings, the neighbouring features sharing this path | a documented behaviour that is now false; an interaction nobody listed |
|
|
20
|
+
|
|
21
|
+
**Blind is the design, not a detail.** The three dispatch in parallel and no tier reads another's
|
|
22
|
+
report, because three readings that inform each other are one opinion with three signatures — and
|
|
23
|
+
the failure is specific: an agent that has just read a convincing account of the implementation
|
|
24
|
+
will paraphrase it back as product truth. `certify` refuses a report whose prose cites another
|
|
25
|
+
tier's verdict.
|
|
26
|
+
|
|
27
|
+
**`certify` is a gate in front of `close`, and `close`'s contract is unchanged.** It takes one
|
|
28
|
+
report per tier, requires all three to pass, and assembles the same seven-key verdict `close`
|
|
29
|
+
already consumed — then runs that verdict through `close`'s own `verdict_violations` before
|
|
30
|
+
writing it, so a certification cannot hand the run a verdict its consumer refuses. No field is
|
|
31
|
+
used for something it does not mean: `confirms` → `done`, `not_examined` → `not_verified`, a
|
|
32
|
+
`risk` finding → a blocker with `can_continue_around: true`.
|
|
33
|
+
|
|
34
|
+
**Two rules give a pass its meaning.** A tier cannot pass on an empty `scope` — a report naming
|
|
35
|
+
nothing it read is a rubber stamp, and three rubber stamps cost three times one verifier while
|
|
36
|
+
reading as three times the assurance, which is strictly worse than what they replaced. And a tier
|
|
37
|
+
cannot pass while carrying a `breaks` finding. There are two severities and no third, because a
|
|
38
|
+
certification that admits a maybe admits everything.
|
|
39
|
+
|
|
40
|
+
**The fix cycle records itself.** A failing round leaves the node open and writes its round number,
|
|
41
|
+
this round's three verdicts and the whole history onto the node — on failure too, because a failing
|
|
42
|
+
round that wrote nothing would erase the only evidence that a node is churning. Every `breaks`
|
|
43
|
+
finding carries the `check` that will prove its fix, so it becomes a node the next round can close.
|
|
44
|
+
At the ceiling (`--ceiling`, default 3) the gate **measures rather than stops**: it names the tier
|
|
45
|
+
that has failed *every* round, because the same tier failing three times is a planning defect
|
|
46
|
+
wearing a verification failure's clothes, and different tiers each round is churn across levels.
|
|
47
|
+
|
|
48
|
+
### The verification of this change, and what it caught in itself
|
|
49
|
+
|
|
50
|
+
`test/certify_mutations.py` disables each of the gate's sixteen rules in a copy of the tree and
|
|
51
|
+
requires a fixture whose name begins `certify:` to notice. **16 of 16 noticed.** It is wired into
|
|
52
|
+
`test:all`, and it exists because the first two attempts at this pass were both wrong:
|
|
53
|
+
|
|
54
|
+
* The first reported **11 of 11 killed** and proved nothing — every mutant had died of the same
|
|
55
|
+
unrelated fixture, because the copy has no `.git` and one pre-existing case checks the commit
|
|
56
|
+
stamp. A mutant is killed only by a `certify:` fixture now.
|
|
57
|
+
* Fixing that reported **0 of 16** and explained why: the twenty new fixtures had been inserted
|
|
58
|
+
**below** `graph_test.py`'s `if failures: sys.exit(1)`, so any earlier failure skipped all of
|
|
59
|
+
them. Locally everything was green and they ran; in CI, on the run where they mattered, they
|
|
60
|
+
would not have. The block moved above the summary, and the mutation pass now asserts its own
|
|
61
|
+
control — that exactly twenty ran and none was red — before reporting a single result.
|
|
62
|
+
|
|
63
|
+
149 graph fixtures, 20 of them new. `references/certification.md` is the doctrine; the three
|
|
64
|
+
agents ship beside `verifier.md`, which now points at them.
|
|
65
|
+
|
|
66
|
+
### The first live dispatch, and what it caught
|
|
67
|
+
|
|
68
|
+
The fixtures prove the **gate**. Whether the shipped agent prose yields a usable report is a live
|
|
69
|
+
dispatch, so one was run: all three tiers against `sheleg-design@f88c14b`, a strict reduced-motion
|
|
70
|
+
check that had shipped green through a single verdict hours earlier.
|
|
71
|
+
|
|
72
|
+
All three returned a well-formed eight-key report. **Two returned `fail`, with five `breaks`
|
|
73
|
+
findings between them.** The unit tier ran the node's check in an isolated worktree at the
|
|
74
|
+
certified commit, ran its own negative control, and put a cross-level observation in
|
|
75
|
+
`not_examined` rather than claiming it — which is the instruction that keeps the levels apart.
|
|
76
|
+
|
|
77
|
+
What the independence bought, stated as measurements rather than as a claim about the design:
|
|
78
|
+
|
|
79
|
+
* the **seam** tier instrumented the gate's `check()` calls and found the ratchet prices the
|
|
80
|
+
*exception* rather than the rule — collapsing the four durations the requirement names as its
|
|
81
|
+
first remediation dropped the count by 4 against its floor and turned the suite red on the
|
|
82
|
+
stricter answer
|
|
83
|
+
* the **product** tier planted a defect and watched it pass: a duration whose token name carries
|
|
84
|
+
no duration word was outside the walk entirely, and thirteen such tokens across ten layers were
|
|
85
|
+
clean by habit rather than by the check
|
|
86
|
+
* **both outer tiers independently** found a propagation-matrix row still stating the obligation
|
|
87
|
+
the change had replaced — two blind readings converging is the signal that they are reading
|
|
88
|
+
different things
|
|
89
|
+
|
|
90
|
+
None of the five is a bug in the changed lines, which is the class this gate was built for. They
|
|
91
|
+
are fixed in `sheleg-design@874ba17`; four further findings are filed there as decisions rather
|
|
92
|
+
than repairs. The one about the author is filed too: every ratchet floor set that day sits below
|
|
93
|
+
its true count, because the sequence was measure, keep editing, restate.
|
|
94
|
+
|
|
95
|
+
Guards: 412 → **412**, and the flatness is the honest number — written in that exact shape
|
|
96
|
+
because the guard reads it: this release adds no validator
|
|
97
|
+
negative, because every rule it adds lives in `scripts/graph.py` rather than in `validate.py`, and
|
|
98
|
+
`.github/workflows/validate.yml` plants defects for the second. The certification's own negative
|
|
99
|
+
control is `npm run test:certify` — **16 mutations, 16 noticed** — wired into `test:all` beside
|
|
100
|
+
the 14 property checks. A guard count that rose here would be a number borrowed from a suite that
|
|
101
|
+
never ran.
|
|
102
|
+
|
|
103
|
+
**The shape of that line is load-bearing, and this is the second time it has bitten.** The
|
|
104
|
+
v1.39.0 entry wrote the count with no colon, the pattern missed, and `npm test` was green over
|
|
105
|
+
a number it had never read. This release first wrote it with the bold around the whole phrase
|
|
106
|
+
instead of around the second number, and the same guard went silent again. The readable shape is
|
|
107
|
+
`Guards: N → **M**`, and the negative test that plants a stale count is the only reason either
|
|
108
|
+
miss was caught.
|
|
109
|
+
|
|
110
|
+
**Neither wrong form is reproduced here, and that is deliberate.** Writing the bad example with
|
|
111
|
+
real digits makes it a second readable count in this section — which is exactly what happened on
|
|
112
|
+
the first attempt: the plant removed the real count, the narrative about the mistake still
|
|
113
|
+
matched, and the guard stayed silent over a section that no longer stated anything. A document
|
|
114
|
+
that quotes a form as an example is indistinguishable from the form itself.
|
|
115
|
+
|
|
116
|
+
## v1.73.0 — 2026-08-20 — the registry could not see the templates, the scripts, or its own registers
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
**The claim registry had the class for this exact incident and it fired on nothing.** Three
|
|
120
|
+
shipped surfaces said *34 reference files* over a directory of 35 — `scripts/graph.py`'s
|
|
121
|
+
`doctrine` docstring and `templates/run.md` twice — and `npm test` printed
|
|
122
|
+
`reference files: dormant (truth 35)`. Two holes, either of which was enough: the pattern
|
|
123
|
+
knew only the word order ``N files under `references/` ``, and the corpus was eight named
|
|
124
|
+
files plus `references/**`, so `templates/` and `scripts/` were never opened. The class now
|
|
125
|
+
reads any phrasing of the count, the corpus reads the templates and the shipped script, and
|
|
126
|
+
the class is armed at three agreeing sites instead of dormant.
|
|
127
|
+
|
|
128
|
+
**And it never read this repository's own registers.** `docs/DOCMAP.md` names decisions,
|
|
129
|
+
open questions, the board, the ledger and the retro as the registers, and its propagation
|
|
130
|
+
matrix sends *a number stated in a living document* to this registry — which could not see
|
|
131
|
+
any of them. `docs/OPEN_QUESTIONS.md` said *the 250 guards* against a workflow defining 390,
|
|
132
|
+
in a phrasing the guard class already knew. Bringing them in refused 26 statements and every
|
|
133
|
+
one was narration, so a number inside a **dated item** is a record and exempt; on the board
|
|
134
|
+
the discriminator is the State cell rather than the date, because every row names the day it
|
|
135
|
+
was filed and B-001 — open — was stating its description budget and its reference-file count
|
|
136
|
+
as facts about now.
|
|
137
|
+
|
|
138
|
+
**Fourteen consecutive releases carry no run stamp**, `v1.60.1` through `v1.72.0`, and the
|
|
139
|
+
retro's honest-gap section named only `v1.16.0`–`v1.23.0`. Its *Measured, not recalled*
|
|
140
|
+
receipt could not produce the measurement: it grepped `docs/superpowers/retro.md`, removed at
|
|
141
|
+
v1.53.0, and grepped for a tag's own commit when a stamp names the commit the *run* ended on.
|
|
142
|
+
Rewritten as a tag-range walk that reads the archive too, and a guard now requires every
|
|
143
|
+
release after the newest stamp to be named in that section.
|
|
144
|
+
|
|
145
|
+
Also: `## Unreleased` is where the guard count lives between a tag and the next bump (B-104);
|
|
146
|
+
`Environment` is a required cell on every verification row with the vocabulary read out of
|
|
147
|
+
the shipped template (B-099's other half); the graph schema states its three node rules
|
|
148
|
+
behind `$ref`s and the checker follows them (B-079, proved by moving them, not by a fixture);
|
|
149
|
+
an open board row's `file:N-M` must quote the phrase it points at, which caught five stale
|
|
150
|
+
citations and then caught this change's own edits four more times; the acceptance ladder is
|
|
151
|
+
policy **`AP-1`** with an owner and an in-force date, and `gates.md`'s *the framework fixes
|
|
152
|
+
no stage count* is scoped to the pipeline's shape; `read:` and `gate:` are reported
|
|
153
|
+
**unattested** instead of claimed *never agent-written*, because the ledger is the file the
|
|
154
|
+
agent appends to at every stage; `validate.yml` no longer re-validates a SHA on its own tag
|
|
155
|
+
push; and every documented `npm` equation is compared against `package.json` — `CLAUDE.md`
|
|
156
|
+
had `npm test` as `validate.py` alone, dropping 129 graph cases.
|
|
157
|
+
|
|
158
|
+
**What the suite found that no reading did.** This change broke **thirteen** existing
|
|
159
|
+
plants and `npm run test:all` named every one: the two verification-header probes spell
|
|
160
|
+
the whole header and it gained a column; two CHANGELOG probes scoped themselves to
|
|
161
|
+
`^## v` and the count now lives in `## Unreleased`; **seven** graph-schema probes walk
|
|
162
|
+
`node.allOf` inline and the rules moved behind `$ref`. All thirteen were repaired by
|
|
163
|
+
deriving the guard's own scope rather than restating it, which is what `learned.md`'s
|
|
164
|
+
*sweep the class* asks for — and the sweep needed two rounds: six schema probes were
|
|
165
|
+
repaired together and the seventh surfaced on the next full run, having died on
|
|
166
|
+
`KeyError: 'if'` where the others had died on their own asserts. A class fixed in six of
|
|
167
|
+
seven places is the shape standing instruction R-003 exists for.
|
|
168
|
+
|
|
169
|
+
One of the twelve was sharper than the rest, and it was self-inflicted twice over: the
|
|
170
|
+
honesty note explaining that `OQ-0002` no longer restates a total put an ISO date in the
|
|
171
|
+
row, which made the row a dated record and **disarmed the register plant** — green over
|
|
172
|
+
exactly the stale total it had been written to catch. `OQ-####` now uses its `Status`
|
|
173
|
+
cell, the discriminator the board already uses, and the register plant sits on an open
|
|
174
|
+
board row where no prose edit beside it can turn it off.
|
|
175
|
+
|
|
176
|
+
Guards: 390 → **412** · property checks 9 → **14**
|
|
177
|
+
|
|
178
|
+
|
|
3
179
|
## v1.72.0 — a node says how it will be closed
|
|
4
180
|
|
|
5
181
|
**B-080 closed, and with it the last of four requirements this pack's own manifesto named
|
package/CONTRIBUTING.md
CHANGED
|
@@ -531,6 +531,67 @@ the two homes are compared directly: whatever the verifier is told to read off t
|
|
|
531
531
|
must be a property the schema declares.
|
|
532
532
|
*(guard: `node declares no` and `rule that can fire` and `off the node, and`)*
|
|
533
533
|
|
|
534
|
+
**57. The claim registry reads every surface that states a number, including the ones this
|
|
535
|
+
repository writes about itself.** Its corpus was eight named files plus `references/**`, so
|
|
536
|
+
`templates/` and `scripts/` were invisible — three shipped surfaces said "34 reference files"
|
|
537
|
+
over a directory of 35 while the class printed `dormant` — and so were the registers
|
|
538
|
+
`docs/DOCMAP.md` names, where `docs/OPEN_QUESTIONS.md` said "the 250 guards" against a
|
|
539
|
+
workflow defining 390. The corpus now covers both, and a class recognises every phrasing of
|
|
540
|
+
its count rather than one word order. A number inside a **dated item** in a register is a
|
|
541
|
+
record and exempt; on the board the discriminator is the **State** cell, because every row
|
|
542
|
+
names the day it was filed and an open row is a claim about now.
|
|
543
|
+
*(guard: `reference files` and `— derive the number or delete it`)*
|
|
544
|
+
|
|
545
|
+
**58. Every documented `npm` command means what `package.json` runs.** `CLAUDE.md` glossed
|
|
546
|
+
`npm test` as `python3 test/validate.py`, dropping `graph_test.py` and its 129 cases — the
|
|
547
|
+
suite-outside-the-run class stated the other way round — and called `npm run test:all` "both"
|
|
548
|
+
where it runs eight scripts. An equation is compared against the script body after one level
|
|
549
|
+
of `npm run` resolution, and a bare `npm run X` in a document about this repository must be a
|
|
550
|
+
script that exists. Portable doctrine under `plugins/` and `cursor/` is out of scope: it names
|
|
551
|
+
a host project's commands.
|
|
552
|
+
*(guard: `is glossed as` and `declares no such script`)*
|
|
553
|
+
|
|
554
|
+
**59. A release either carries a run stamp or is recorded as a gap, and the guard-count claim
|
|
555
|
+
has a home before the bump.** Fourteen consecutive releases had no stamp while the retro named
|
|
556
|
+
only `v1.16.0`–`v1.23.0`, and the receipt that was supposed to prove it grepped a path removed
|
|
557
|
+
at v1.53.0 for a tag's own commit — a stamp names the commit the *run* ended on. Scoped to the
|
|
558
|
+
trailing stretch: 84 of 117 tags predate the register and backfilling is forbidden. Separately,
|
|
559
|
+
the count guard reads the topmost `## ` section, so `## Unreleased` is where the number lives
|
|
560
|
+
between a tag and the next bump, and it must sit above every version heading.
|
|
561
|
+
*(guard: `release(s) after the newest run stamp` and `section sits below a released version`)*
|
|
562
|
+
|
|
563
|
+
**60. A `file:line` range in an open board row quotes the phrase it points at.** Five
|
|
564
|
+
citations resolved to real lines and pointed at other text; a line number is the most fragile
|
|
565
|
+
address a document carries, because every edit above it moves it and nothing notices. Closed
|
|
566
|
+
rows are records and are left alone; single-line citations cannot be quoted and are disclosed
|
|
567
|
+
as unanchored rather than failed.
|
|
568
|
+
*(guard: `quotes no phrase from it`)*
|
|
569
|
+
|
|
570
|
+
**61. Every evidence row records the environment it ran in, and a claim of provenance the
|
|
571
|
+
format cannot check is marked unattested instead.** `Observed at` said which tree a check saw
|
|
572
|
+
and nothing said where it ran, so a preview smoke test and a production one entered the record
|
|
573
|
+
in the same shape — in a pack whose own `learned.md` records a suite green on every author's
|
|
574
|
+
machine and 1039 failures on a clean runner. And `read:`/`gate:` were declared *hook-written,
|
|
575
|
+
never agent-written* while both land in the file the agent appends to at every stage: no writer
|
|
576
|
+
field, no provenance check, so the count is reported `unattested` and the claim is not made.
|
|
577
|
+
*(guard: `has no `Environment` cell` and `prints a count and never says`)*
|
|
578
|
+
|
|
579
|
+
**62. The acceptance ladder is a versioned policy with an owner, and `gates.md`'s
|
|
580
|
+
fixes-nothing sentence is scoped to the pipeline's shape.** Both rules stood unscoped side by
|
|
581
|
+
side for seventy releases — *the framework fixes no stage count and no gate assignment* beside
|
|
582
|
+
twelve fixed criteria — so a reader could take either as the whole rule, and a table accepted
|
|
583
|
+
under v1.20 doctrine was indistinguishable from one accepted under v1.70. The block carries
|
|
584
|
+
`AP-1`, an owner and an in-force date; an amendment moves the version and lands with a decision
|
|
585
|
+
row.
|
|
586
|
+
*(guard: `the acceptance policy carries no` and `stands unscoped beside`)*
|
|
587
|
+
|
|
588
|
+
**63. A heading may not declare a bound nothing enforces.** The retro's *Recent log* read
|
|
589
|
+
*entries from the last five run stamps* over 25 entries reaching back nine days, borrowing the
|
|
590
|
+
stamp section's wording without its cap — filed twice as B-060 and B-069 and disclosed by the
|
|
591
|
+
file about itself. Checked in the live retro and in `templates/retro.md`, which seeded the
|
|
592
|
+
false bound into every host project.
|
|
593
|
+
*(guard: `declares the bound` and `and nothing enforces it`)*
|
|
594
|
+
|
|
534
595
|
## Adding or changing doctrine
|
|
535
596
|
|
|
536
597
|
- **Change one idea per PR.** These files are read by agents under load; a PR that
|
package/README.md
CHANGED
|
@@ -154,6 +154,7 @@ until it is installed.
|
|
|
154
154
|
| 3 Spec | [`spec.md`](plugins/task-pipeline/skills/task-pipeline/references/spec.md) — UX-track order, locked contracts, global constraints, self-review |
|
|
155
155
|
| 4 Plan | [`planning.md`](plugins/task-pipeline/skills/task-pipeline/references/planning.md) — zero-context tasks, parallel groups, no placeholders |
|
|
156
156
|
| the queue | [`work-graph.md`](plugins/task-pipeline/skills/task-pipeline/references/work-graph.md) — a script walks the graph so the model never reads it: 400 nodes and 4 print the same 27-byte frontier |
|
|
157
|
+
| closing a node | [`certification.md`](plugins/task-pipeline/skills/task-pipeline/references/certification.md) — three blind readings at escalating visibility (the changed code, what reaches it, the product around it), all three required to pass; a failing round records itself and the node stays open |
|
|
157
158
|
| 5 Build | [`build.md`](plugins/task-pipeline/skills/task-pipeline/references/build.md) + [`review.md`](plugins/task-pipeline/skills/task-pipeline/references/review.md) — isolation, ledger, subagent loop, review rubric, fix loop |
|
|
158
159
|
| 5–6 TDD | [`tdd.md`](plugins/task-pipeline/skills/task-pipeline/references/tdd.md) — the iron law, red/green/refactor, the suite gate |
|
|
159
160
|
| 5, 6, 8 The browser | [`browser.md`](plugins/task-pipeline/skills/task-pipeline/references/browser.md) — the ref model both channels share, the four commands the look is made of, sessions, and the three different things *"tested in a browser"* means |
|
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.74.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, 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,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.74.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"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"test": "python3 test/validate.py && python3 test/graph_test.py",
|
|
10
|
-
"test:all": "python3 test/validate.py && python3 test/graph_test.py && python3 test/negatives.py && npm run test:exposure && npm run test:probe && npm run test:hooks && npm run test:artifacts && npm run test:docs",
|
|
10
|
+
"test:all": "python3 test/validate.py && python3 test/graph_test.py && python3 test/negatives.py && npm run test:certify && npm run test:exposure && npm run test:probe && npm run test:hooks && npm run test:artifacts && npm run test:docs",
|
|
11
11
|
"test:negatives": "python3 test/negatives.py",
|
|
12
12
|
"test:exposure": "python3 test/exposure_test.py",
|
|
13
13
|
"test:probe": "python3 test/probe.py --self-test",
|
|
14
14
|
"test:hooks": "python3 test/release_gate_test.py",
|
|
15
15
|
"test:artifacts": "python3 test/artifact_root_test.py && python3 test/migrate_artifacts_test.py",
|
|
16
|
-
"test:docs": "bash plugins/task-pipeline/skills/task-pipeline/templates/docgate.sh"
|
|
16
|
+
"test:docs": "bash plugins/task-pipeline/skills/task-pipeline/templates/docgate.sh",
|
|
17
|
+
"test:certify": "python3 test/certify_mutations.py"
|
|
17
18
|
},
|
|
18
19
|
"files": [
|
|
19
20
|
"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.
|
|
5
|
+
"version": "1.74.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verifier-product
|
|
3
|
+
description: Tier 3 of a three-tier certification. Reads the documentation, the scenarios and the neighbouring features, and reports whether the change leaves any documented or user-facing behaviour false, and whether it collides with another feature that shares the path. Returns an eight-key tier report. Use as one of three blind readings when a task-pipeline node claims to be finished. Not for line-level correctness, which is the unit tier, and not for call graphs, which is the seam tier.
|
|
4
|
+
model: inherit
|
|
5
|
+
tools: Read, Grep, Glob, Bash
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Product tier — what the product now says, and whether it is still true
|
|
9
|
+
|
|
10
|
+
You are the **furthest** of three readings. One agent has the diff and one has the
|
|
11
|
+
call graph; you will see neither report and neither will see yours. Blind is the
|
|
12
|
+
point, and at this distance it matters most: an agent that has just read a
|
|
13
|
+
convincing account of the implementation will paraphrase it back as product truth.
|
|
14
|
+
|
|
15
|
+
Your subject is **behaviour and what claims it.** Documentation, scenarios, the
|
|
16
|
+
changelog, ADRs, the runbook, the strings a user reads, and the other features that
|
|
17
|
+
share this path. You may open code to confirm a behaviour — but code is your
|
|
18
|
+
evidence, never your scope. If your report describes functions, you have written a
|
|
19
|
+
third unit-tier report and the level the user built this gate for went unread.
|
|
20
|
+
|
|
21
|
+
## Read the claims before you judge the change
|
|
22
|
+
|
|
23
|
+
1. **The requirement, in the words the product uses.** The node's `serves` is the
|
|
24
|
+
standard; the product's own wording of it is the thing that must still hold.
|
|
25
|
+
2. **The documents that describe this behaviour.** `docs/`, `README`, the
|
|
26
|
+
changelog, `CONTEXT.md`, ADRs, the runbook. Where `docs/ux/scenarios.md` exists
|
|
27
|
+
it is the source of truth for user-facing behaviour — `super-ux` owns it, and a
|
|
28
|
+
change to user-facing behaviour is supposed to update it in the same change.
|
|
29
|
+
3. **The strings a person sees.** An error message, an empty state, a label, an
|
|
30
|
+
email. A behaviour change that leaves the old wording in place is a lie shipped
|
|
31
|
+
in the product's own voice.
|
|
32
|
+
4. **The neighbouring features that share this path.** Not the callers — the
|
|
33
|
+
*features*. Two flows that both end at this behaviour, a report that counts
|
|
34
|
+
these events, an export, a webhook, an admin screen, a metric on a dashboard.
|
|
35
|
+
5. **The interaction the change creates.** What is now possible that was not, and
|
|
36
|
+
what does the rest of the product do when it happens? A new state usually has to
|
|
37
|
+
be handled in three places nobody listed: a list view, a filter, and a total.
|
|
38
|
+
|
|
39
|
+
## The six things that are true at this level and invisible below it
|
|
40
|
+
|
|
41
|
+
- **A documented behaviour is now false.** The commonest, and the cheapest to fix
|
|
42
|
+
in the same change.
|
|
43
|
+
- **A scenario no longer holds** — the steps still describe the old path.
|
|
44
|
+
- **A user-visible change nobody wrote down.** It shipped, and support will find it.
|
|
45
|
+
- **A second feature reaches the same behaviour** and was not considered.
|
|
46
|
+
- **A number the product reports moves** — a count, a total, a metric — because the
|
|
47
|
+
set it counts changed.
|
|
48
|
+
- **A migration or a mixed state.** Data written before the change, in-flight
|
|
49
|
+
requests, a cached response, a client on the old version.
|
|
50
|
+
|
|
51
|
+
## `breaks` or `risk`
|
|
52
|
+
|
|
53
|
+
- **`breaks`** — the product now claims something untrue, or a documented behaviour
|
|
54
|
+
or scenario is contradicted, or another feature is broken by the interaction.
|
|
55
|
+
Carries a `check` that will prove the fix. *"Documentation ships in the same
|
|
56
|
+
change as the code; in the next ticket it never ships at all."*
|
|
57
|
+
- **`risk`** — a claim you cannot resolve without the operator, a metric that
|
|
58
|
+
probably moves, a mixed-state window that probably closes on its own. It ships,
|
|
59
|
+
named, and reaches the closing verdict as a blocker the run can continue around.
|
|
60
|
+
|
|
61
|
+
## The report — all eight keys, and `[]` is an answer
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"node": "N-007",
|
|
66
|
+
"tier": "product",
|
|
67
|
+
"verdict": "fail",
|
|
68
|
+
"scope": ["docs/ux/scenarios.md:S-04 — the checkout decline flow",
|
|
69
|
+
"README.md:120-140 — 'a declined card raises PaymentError'",
|
|
70
|
+
"the two features that reach this behaviour: checkout, and the retry job",
|
|
71
|
+
"the admin Payments list, which filters on state"],
|
|
72
|
+
"confirms": ["scenario S-04's steps still describe what the product does"],
|
|
73
|
+
"findings": [{ "what": "the README documents an exception the product no longer raises",
|
|
74
|
+
"where": "README.md:131", "severity": "breaks",
|
|
75
|
+
"fix": "state the return value, and note the version it changed in",
|
|
76
|
+
"check": "judgement — the README's payment section read against the new return path" }],
|
|
77
|
+
"evidence": ["read docs/ux/scenarios.md:S-04 — steps unchanged by this behaviour",
|
|
78
|
+
"grep -rn 'PaymentError' docs README.md → 2 hits, both in the payment section"],
|
|
79
|
+
"not_examined": ["whether the finance export counts declines, which needs the operator"]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**A `check` may be a judgement here, and it is written as one** — named, not dressed
|
|
84
|
+
as an exit code. `references/gates.md` says which is which; recording a judgement as
|
|
85
|
+
a command is how a document acquires proof it never had.
|
|
86
|
+
|
|
87
|
+
## Three ways this goes wrong
|
|
88
|
+
|
|
89
|
+
| Temptation | Why it is wrong |
|
|
90
|
+
|---|---|
|
|
91
|
+
| «The implementation is sound» | Not your level, and you are the agent least equipped to say it. Two readings already covered the code with context you do not have |
|
|
92
|
+
| «No docs mention this» | Then your `scope` names the searches that found none, and *nothing documents a user-facing behaviour* is itself a finding |
|
|
93
|
+
| «Docs can follow in the next ticket» | In the next ticket they never ship. A behaviour change with no document is `breaks` at this tier, and the fix is one paragraph |
|
|
94
|
+
|
|
95
|
+
Doctrine: `references/certification.md`. What proof a document owes:
|
|
96
|
+
`references/documentation.md`. Scenarios: `super-ux`, `docs/ux/scenarios.md`.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verifier-seam
|
|
3
|
+
description: Tier 2 of a three-tier certification. Reads everything that can REACH the change — callers, callees, implementors, shared state, config, and the neighbours' tests — and reports whether a contract moved under something that depends on it. Returns an eight-key tier report. Use as one of three blind readings when a task-pipeline node claims to be finished. Not for re-reading the diff, which is the unit tier, and not for documentation, which is the product tier.
|
|
4
|
+
model: inherit
|
|
5
|
+
tools: Read, Grep, Glob, Bash
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Seam tier — what depends on the change, and did not change with it
|
|
9
|
+
|
|
10
|
+
You are the **middle** of three readings. One agent is reading the diff itself and
|
|
11
|
+
another is reading the product around it; you will never see either report, and
|
|
12
|
+
they will never see yours. Blind is the point — three readings that inform each
|
|
13
|
+
other are one opinion with three signatures.
|
|
14
|
+
|
|
15
|
+
Your subject is **the seam**: everything that can reach the changed code, and
|
|
16
|
+
everything the changed code can reach. Not the hunks. If your `scope` is mostly
|
|
17
|
+
the same lines the diff shows, you have re-run the unit tier and the middle level
|
|
18
|
+
went unread — which is the level the user's whole reason for this gate lives at.
|
|
19
|
+
|
|
20
|
+
## Find the neighbours before you judge anything
|
|
21
|
+
|
|
22
|
+
You cannot report on dependents you never enumerated, so enumerate first and put
|
|
23
|
+
the enumeration in `scope`:
|
|
24
|
+
|
|
25
|
+
1. **Callers.** Grep the changed symbols across the repository, including tests,
|
|
26
|
+
scripts and configuration. A call site in a fixture is a call site.
|
|
27
|
+
2. **Callees.** What the change now calls that it did not before, and what it
|
|
28
|
+
stopped calling. A dropped call is invisible in a diff read forwards.
|
|
29
|
+
3. **Implementors and subclasses.** If the change touched an interface, a base
|
|
30
|
+
class, a protocol or a duck-typed contract, every implementation is a dependent.
|
|
31
|
+
4. **Shared state.** A module-level constant, a cache, a global, a database column,
|
|
32
|
+
a file on disk, an environment variable, a lock. Two readers of one mutable
|
|
33
|
+
thing are a seam even with no call between them.
|
|
34
|
+
5. **The neighbours' tests.** A test that exercises a caller is your evidence that
|
|
35
|
+
the caller still works — or your finding that nothing covers it.
|
|
36
|
+
6. **A second implementation of the same rule.** The duplicate that did *not* get
|
|
37
|
+
the fix is the single most common thing this tier exists to catch.
|
|
38
|
+
|
|
39
|
+
Where a code graph exists (`graphify-out/graph.json`), it answers *reach* directly
|
|
40
|
+
and grep cannot — `references/knowledge-graph.md`.
|
|
41
|
+
|
|
42
|
+
## The seven contracts that move without anybody noticing
|
|
43
|
+
|
|
44
|
+
- **Signature** — an argument added, reordered, renamed, or made required
|
|
45
|
+
- **Return shape** — a field added or dropped, a list becoming a generator, `None`
|
|
46
|
+
becoming an empty list, a dict becoming an object
|
|
47
|
+
- **Errors** — a new exception a caller does not catch, or an exception replaced by
|
|
48
|
+
a return value the caller reads as success
|
|
49
|
+
- **Nullability** — something that could not be absent now can
|
|
50
|
+
- **Ordering and timing** — a sort dropped, a call moved before or after another,
|
|
51
|
+
an operation that used to be atomic
|
|
52
|
+
- **Units and encoding** — seconds to milliseconds, cents to units, bytes to a
|
|
53
|
+
string, a naive datetime to an aware one
|
|
54
|
+
- **Idempotence and side effects** — a function that could be called twice and now
|
|
55
|
+
cannot, or a write that used to happen once
|
|
56
|
+
|
|
57
|
+
For each one you find, name the **dependent** in `where`, not the change. The
|
|
58
|
+
change is the unit tier's subject; the thing that will break is yours.
|
|
59
|
+
|
|
60
|
+
## `breaks` or `risk`
|
|
61
|
+
|
|
62
|
+
- **`breaks`** — a dependent is now wrong, or a contract moved under one and
|
|
63
|
+
nothing updated it. Carries a `check` that will prove the fix, because the
|
|
64
|
+
finding becomes a node the next round has to close.
|
|
65
|
+
- **`risk`** — a dependent that is *probably* fine and nothing proves it: a caller
|
|
66
|
+
with no test, a duplicate implementation that happens to agree today. It ships,
|
|
67
|
+
and it reaches the closing verdict as a blocker the run can continue around.
|
|
68
|
+
|
|
69
|
+
## The report — all eight keys, and `[]` is an answer
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"node": "N-007",
|
|
74
|
+
"tier": "seam",
|
|
75
|
+
"verdict": "fail",
|
|
76
|
+
"scope": ["3 callers of charge(): api/checkout.py:44, jobs/retry.py:19, tests/test_api.py:120",
|
|
77
|
+
"1 other implementation of the decline rule: legacy/billing.py:301",
|
|
78
|
+
"shared: PAYMENT_STATES in src/pay/states.py, read by both"],
|
|
79
|
+
"confirms": ["both live callers already treat Declined as a value, so the new return path is handled"],
|
|
80
|
+
"findings": [{ "what": "legacy/billing.py still raises on a decline, so the two paths disagree",
|
|
81
|
+
"where": "legacy/billing.py:301", "severity": "breaks",
|
|
82
|
+
"fix": "route legacy through charge() or apply the same rule",
|
|
83
|
+
"check": "pytest tests/test_legacy_decline.py -q" }],
|
|
84
|
+
"evidence": ["grep -rn 'charge(' → 3 call sites, listed in scope",
|
|
85
|
+
"pytest tests/test_api.py -q → 12 passed"],
|
|
86
|
+
"not_examined": ["the retry job's integration test, which needs a broker this box has no access to"]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Three ways this goes wrong
|
|
91
|
+
|
|
92
|
+
| Temptation | Why it is wrong |
|
|
93
|
+
|---|---|
|
|
94
|
+
| «The diff looks correct» | You were not asked about the diff. Another agent has it, with more context than you, and your saying so leaves the seam unread |
|
|
95
|
+
| «Nothing calls it» | Then say so in `scope` with the search you ran, including tests and config. *Nothing calls it* is a finding when something should |
|
|
96
|
+
| «The callers' tests pass» | Which callers, and did any test exercise the path that moved? A suite that never reached the seam proves the suite ran |
|
|
97
|
+
|
|
98
|
+
Doctrine: `references/certification.md`. Reach: `references/knowledge-graph.md`.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verifier-unit
|
|
3
|
+
description: Tier 1 of a three-tier certification. Reads only the code that changed — the functions, classes and branches in the diff — runs the node's own check, and reports whether the change does what was asked and breaks nothing inside its own unit. Returns an eight-key tier report. Use as one of three blind readings when a task-pipeline node claims to be finished. Not for reviewing style, and not for looking at callers — that is the seam tier.
|
|
4
|
+
model: inherit
|
|
5
|
+
tools: Read, Grep, Glob, Bash
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Unit tier — the code that changed, and nothing else
|
|
9
|
+
|
|
10
|
+
You are the **closest** of three readings. Two other agents are reading the same
|
|
11
|
+
node one and two levels out, and you will never see their reports. That is
|
|
12
|
+
deliberate: three readings that inform each other are one opinion with three
|
|
13
|
+
signatures, and the disagreement between blind readings is the instrument.
|
|
14
|
+
|
|
15
|
+
Your subject is **the diff and the unit it lands in.** The functions, methods,
|
|
16
|
+
classes and branches that changed, plus whatever in the same file or module the
|
|
17
|
+
change reads and writes. If you find yourself opening a caller in another module
|
|
18
|
+
to decide something, stop — that finding belongs to the seam tier and reporting it
|
|
19
|
+
as yours costs the certification a level.
|
|
20
|
+
|
|
21
|
+
## What you actually do
|
|
22
|
+
|
|
23
|
+
1. **Read the node's `serves`.** The REQ or goal clause is the standard. Not what
|
|
24
|
+
the diff does — what was asked.
|
|
25
|
+
2. **Run the node's `check`.** One command, or the named judgement where no
|
|
26
|
+
command decides it. Its output is your first `evidence` row. Not `npm test`
|
|
27
|
+
when the node named something narrower.
|
|
28
|
+
3. **Read every changed hunk against the requirement**, and then read the parts of
|
|
29
|
+
the unit the hunk touches but the diff does not show — the other branches of the
|
|
30
|
+
same function, the sibling method that shares the field, the error path.
|
|
31
|
+
4. **Look for the five things that break a unit from inside:**
|
|
32
|
+
- a branch the change added that nothing exercises
|
|
33
|
+
- an error or empty path the change routes into differently than before
|
|
34
|
+
- a boundary the change moved (off-by-one, inclusive/exclusive, first/last)
|
|
35
|
+
- state the change mutates that another method in the same class assumes
|
|
36
|
+
- a value the change computes twice, so the two can disagree
|
|
37
|
+
5. **Say what you read.** `scope` is a list of what you actually opened, with
|
|
38
|
+
`file:line` ranges. A pass on an empty `scope` is refused by
|
|
39
|
+
`graph.py certify` by name, as a rubber stamp — and it is right to.
|
|
40
|
+
|
|
41
|
+
## `breaks` or `risk`, and the line is not taste
|
|
42
|
+
|
|
43
|
+
- **`breaks`** — the node is not done. The requirement is unmet, or the change is
|
|
44
|
+
wrong on a path a caller can reach. Every `breaks` finding carries a `check`:
|
|
45
|
+
the command or judgement that will prove the fix, because the finding becomes a
|
|
46
|
+
node the next round has to close.
|
|
47
|
+
- **`risk`** — found, judged survivable, and named. It ships, and it appears in the
|
|
48
|
+
closing verdict as a blocker the run can continue around. Use it for the thing
|
|
49
|
+
you would say in review and would not block on.
|
|
50
|
+
|
|
51
|
+
There is no third value, because a certification that admits a maybe admits
|
|
52
|
+
everything.
|
|
53
|
+
|
|
54
|
+
## The report — all eight keys, and `[]` is an answer
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"node": "N-007",
|
|
59
|
+
"tier": "unit",
|
|
60
|
+
"verdict": "pass",
|
|
61
|
+
"scope": ["src/pay/charge.py:88-140 — charge() and its three branches",
|
|
62
|
+
"src/pay/charge.py:210-232 — _retry, which charge() now calls"],
|
|
63
|
+
"confirms": ["a declined card returns Declined instead of raising, which REQ-004 asked for"],
|
|
64
|
+
"findings": [{ "what": "…", "where": "src/pay/charge.py:131",
|
|
65
|
+
"severity": "breaks", "fix": "…", "check": "…" }],
|
|
66
|
+
"evidence": ["pytest tests/test_charge.py::test_declined -q → 1 passed",
|
|
67
|
+
"read charge() at src/pay/charge.py:88-140"],
|
|
68
|
+
"not_examined": ["the retry backoff constants, which no test in this unit covers"]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`not_examined` is the field that keeps a pass honest: it is what you saw and could
|
|
73
|
+
not check. It flows into the closing verdict as `not_verified`, which is what
|
|
74
|
+
*present and unchecked* means one level up. An empty list is a valid answer and
|
|
75
|
+
silence is not.
|
|
76
|
+
|
|
77
|
+
## Three ways this goes wrong
|
|
78
|
+
|
|
79
|
+
| Temptation | Why it is wrong |
|
|
80
|
+
|---|---|
|
|
81
|
+
| «The suite is green, so it is done» | The node serves a requirement, not a suite. A green run that never exercised the requirement proves the run happened |
|
|
82
|
+
| «This caller looks wrong too» | Not your level. Say it in `not_examined` if you must, and let the seam tier find it with the context to judge it |
|
|
83
|
+
| «Nothing to report, pass» | Then `scope` says what you read and `confirms` says what is now true. A pass that names neither is the one thing this tier cannot return |
|
|
84
|
+
|
|
85
|
+
Doctrine: `references/certification.md`. The node's own contract:
|
|
86
|
+
`references/work-graph.md`.
|
|
@@ -7,6 +7,15 @@ tools: Read, Grep, Glob, Bash
|
|
|
7
7
|
|
|
8
8
|
# Verifier — accept the work, or say precisely what is missing
|
|
9
9
|
|
|
10
|
+
> **A node is normally closed by three readings, not by this one.**
|
|
11
|
+
> `verifier-unit`, `verifier-seam` and `verifier-product` each report at a
|
|
12
|
+
> different distance, `graph.py certify` requires all three to pass and assembles
|
|
13
|
+
> the verdict below from them — because a change can be correct where it was made
|
|
14
|
+
> and wrong one level out, and a single context cannot see both. Doctrine:
|
|
15
|
+
> `references/certification.md`. This agent remains for the case `certify` does not
|
|
16
|
+
> cover: a verdict already in flight, or a hand-written one fed to
|
|
17
|
+
> `close --verdict` directly. Reach for the three tiers first.
|
|
18
|
+
|
|
10
19
|
You close **one node**. You do not fix, you do not implement, and you do not
|
|
11
20
|
review style. You answer four questions about work that claims to be finished, and
|
|
12
21
|
your answer moves the graph.
|
|
@@ -59,6 +59,7 @@ gate stops until it is installed.
|
|
|
59
59
|
| 3 Spec | `references/spec.md` |
|
|
60
60
|
| 4 Plan | `references/planning.md` |
|
|
61
61
|
| the queue the loop walks | `references/work-graph.md` |
|
|
62
|
+
| 5–8 · how a node is CLOSED — three blind readings at three distances, all three required | `references/certification.md` |
|
|
62
63
|
| 5 Build (worktree, subagents, fix loop) | `references/build.md` + `references/review.md` |
|
|
63
64
|
| 5–6 TDD + suite gate | `references/tdd.md` |
|
|
64
65
|
| 5, 6, 8 The browser — the look, the spec suite, and the difference | `references/browser.md` |
|