task-pipeline-skill 1.66.0 → 1.68.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 CHANGED
@@ -1,5 +1,96 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.68.0 — the worst body in the family, and the rule that was wrong about it
4
+
5
+ **6685 tokens against a 5000 budget → 4735**, under the 4750 working limit, by
6
+ splitting rather than trimming. This was the largest `SKILL.md` body in the
7
+ ssheleg family and the furthest over — 34% — and the body loads on every turn of
8
+ every session that resolves the skill.
9
+
10
+ Most of the overrun sat in the **stage table's Gate column**, which restated
11
+ `references/stages.md` under a heading that literally says *(detail in
12
+ `references/stages.md`)*. The table is the index and the run order now; the
13
+ reference is what you read while standing in the stage. Nothing was deleted:
14
+
15
+ | Moved | To | Why there |
16
+ |---|---|---|
17
+ | Stage 10 in a project of several repositories | `references/acceptance.md` | it owns stage-10 close-out |
18
+ | Step 5's cross-cutting rules | `references/gates.md` | they fire at any stage, not inside step 5 |
19
+
20
+ and five *Prerequisites* paragraphs that restated a reference in full were cut to
21
+ the rule plus the failure it prevents — which is what a body is for — with the
22
+ procedure left in the file that owns it.
23
+
24
+ **All 38 routed trigger phrases across both skills survive verbatim**
25
+ (`node test/advertised_check.js`), and the stage list still matches across the
26
+ three surfaces the validator compares mechanically.
27
+
28
+ ### The description rule was wrong, and this repository was already right
29
+
30
+ The family's shared auditor demands a description **start** with `Use when …`.
31
+ This repository's own validator refuses exactly that, and its comment says why:
32
+ Anthropic's guidance asks for **both** halves — what the skill does and when to
33
+ use it — and their own example leads with the capability (*"Extracts text and
34
+ tables from PDF files… Use when working with PDF files."*). Demanding `Use when`
35
+ at position 0 enforces the WHEN half and leaves the WHAT half optional.
36
+
37
+ So the 2026-08-16 audit's finding that this description *"does not open with Use
38
+ when, against the house rule its sibling obeys"* is **withdrawn — the house rule
39
+ is the one that is wrong**, and this repository had corrected its own copy of it
40
+ already. Applying the corrected rule to the family measures **22 of 24 skills**
41
+ opening with the trigger, so flipping it rewrites 22 descriptions that carry live
42
+ routing phrases. That is a family decision rather than a member's, and it is
43
+ filed as umbrella `B-76` rather than taken here.
44
+
45
+ ### Fixed
46
+
47
+ - A negative self-test was pinned to a literal containing a **line break**, so it
48
+ stopped landing the moment the paragraph reflowed — the guard then read green
49
+ while proving nothing. Matched by regex now. Same class as the two that refused
50
+ `seo-aeo-audit`'s release earlier the same day, and the reason the local gate
51
+ there learned to catch it before the tag.
52
+
53
+ Guards: 351 → **351**. No guard was added or removed — one plant was repaired, and
54
+ the suite that reports `all 351 guards provably reject their planted defect` was
55
+ red until it was, which is the whole point of counting them.
56
+
57
+ Found by the nine-repository audit of 2026-08-16 (umbrella `B-66`;
58
+ `F-task-pipeline-01`, and `F-task-pipeline-02` withdrawn).
59
+
60
+ ## v1.67.0 — a ledger records two different things, and most record only one
61
+
62
+ **A ledger records two different things, and most record only one.** *What confirmed it*
63
+ is evidence — a command, a CI run id, a fixture name. *Whether a person looked* is the
64
+ `Human` axis, and it is the only one the exposure line is defined over.
65
+
66
+ Measured across this family: nine repositories, **ten** header shapes, **815** rows.
67
+
68
+ | what the state column can say | rows | repositories |
69
+ |---|---|---|
70
+ | whether a **person** looked (`Human`) | **126** | 1 |
71
+ | a date and what was watched (`Last verified`) | 180 | 1 |
72
+ | `verified` — by a person **or** a command, indistinguishable | 391 | 4 |
73
+ | nothing: evidence recorded, no state column at all | 118 | 3 |
74
+
75
+ So `never` is measurable in **one repository of nine, over 15% of the rows**, and the
76
+ number this doctrine is written around is undefined in the rest. That is not a defect in
77
+ those ledgers — recording what confirmed something is the Auto job done properly. **The
78
+ defect is doctrine that speaks as though the column were there**, so `references/verification.md`
79
+ now states the split, and three rules follow from it: where there is no state column the
80
+ line says so and prints no number; a `verified` that cannot separate a person from a
81
+ command may not be reported as human confirmation; and adding the column later never
82
+ reaches backwards, because a back-filled ledger answers the question wrongly instead of not
83
+ at all.
84
+
85
+ `exposure.sh` also stops calling a self-explaining status unreadable. `**observed** — the
86
+ row exists because the miss happened in this run` is an ordinary way to write a state, and
87
+ four rows in this family were reported unparseable for explaining themselves. The
88
+ vocabulary now matches the **leading word**, with the empty cell tested before the word is
89
+ taken so a blank still counts as unconfirmed.
90
+
91
+ Guards: 351 → **351**. Fixtures 20 → **20**; these are behaviours the existing cases
92
+ exercise by running the script, and all nine family ledgers were run through it by hand.
93
+
3
94
  ## v1.66.0 — the shape is not fixed, so nothing may assume it
4
95
 
5
96
  **The check-list printed the size of the work labelled as who it hurts, in every seeded
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.66.0 |
15
+ | **Version** | 1.68.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,6 +1,6 @@
1
1
  {
2
2
  "name": "task-pipeline-skill",
3
- "version": "1.66.0",
3
+ "version": "1.68.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"
@@ -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.66.0",
5
+ "version": "1.68.0",
6
6
  "author": {
7
7
  "name": "ssheleg",
8
8
  "url": "https://x.com/sshlg93"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: task-pipeline
3
- description: "Runs a substantial task through a full delivery pipeline: an intake grill that locks the request into a brief, then docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy check, docs/wiki sync and acceptance. Use when work changes the repository — a feature, fix, refactor, migration, integration, rewrite, adoption or hardening; фича, фикс, рефактор, миграция, интеграция, доработать, починить, внедрить, перевести — or when the output is a finding that lands in it: audit/аудит, bug hunt/проверь ошибки, production check/проверь прод, PR review/ревью PR — or on 'run this through the pipeline' / 'прогони по конвейеру', 'the full cycle' / 'полный цикл', /task-pipeline. Two modes need no task at all: 'checkup' / 'чекап' reports what shipped unconfirmed and what to look at first; 'setup' audits existing documentation. Not for: answering a question, explaining code, a typo or a one-line edit — say 'без пайплайна' / 'quick' to opt out."
3
+ description: "Runs a substantial task through a full delivery pipeline: an intake grill that locks the request into a brief, then docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki sync and acceptance. Use when work changes the repository — a feature, fix, refactor, migration, integration, rewrite, adoption or hardening; фича, фикс, рефактор, миграция, интеграция, доработать, починить, внедрить, перевести — or when the output is a finding that lands in it: audit/аудит, bug hunt/проверь ошибки, production check/проверь прод, PR review/ревью PR — or on 'run this through the pipeline' / 'прогони по конвейеру', 'the full cycle' / 'полный цикл', /task-pipeline. Two modes need no task at all: 'checkup' / 'чекап' reports what shipped unconfirmed and what to look at first; 'setup' audits existing documentation. Not for: answering a question, explaining code, a typo or a one-line edit — say 'без пайплайна' / 'quick' to opt out."
4
4
  license: MIT
5
5
  ---
6
6
 
@@ -79,76 +79,60 @@ gate stops until it is installed.
79
79
  | 6–10 · How the host project's CLAUDE.md is read | `references/conventions.md` |
80
80
  | preflight · Model map, ids and the override | `references/model-tiering.md` |
81
81
 
82
- **Optional bridge.** An equivalent skill set the operator already runs (e.g.
83
- `superpowers:brainstorming` / `writing-plans` / `subagent-driven-development` /
84
- `using-git-worktrees` / `test-driven-development`) can be mapped onto stages 2/4/5/6
85
- in `pipeline.json` `skills[]`. That is a **substitution, never a requirement**: the
86
- built-in doctrine is normative, the gates in `references/stages.md` still govern, and
87
- nothing detects, recommends or waits for an external provider.
82
+ **Optional bridge.** An equivalent skill set the operator already runs can be mapped
83
+ onto stages 2/4/5/6 in `pipeline.json` `skills[]`. That is a **substitution, never a
84
+ requirement**: the built-in doctrine is normative, the gates in `references/stages.md`
85
+ still govern, and nothing detects, recommends or waits for an external provider.
88
86
 
89
87
  **super-ux — recommended for ANY user-facing task**, and the one thing that can stop a
90
- gate. The moment a task implies an interface (web / mobile / CLI / TUI the stage-0
91
- grill detects it early), the WHY→UI→scenario chain runs through `/ux`,
92
- `ux-foundation`, `ux-flows`, `ux-scenarios` and the `/ux-lint` linter, which belongs in
93
- the host's CI so UX drift cannot merge. **Not installed on a UI task? The stage-3 spec
94
- gate stops** — offer `/plugin marketplace add ssheleg/super-ux` and
95
- `/plugin install super-ux@super-ux` (or `npx skills add ssheleg/super-ux`) and wait.
96
- Details: `references/companion-skills.md`.
88
+ gate. The moment a task implies an interface (web / mobile / CLI / TUI), the
89
+ WHY→UI→scenario chain runs through `/ux` and its linter, which belongs in the host's
90
+ CI so UX drift cannot merge. **Not installed on a UI task? The stage-3 spec gate
91
+ stops** offer the install and wait (`references/companion-skills.md`).
97
92
 
98
93
  **The grill is built in and mandatory** (`references/grill.md`). No "clear enough task"
99
- exemption, no stage 1 without a committed, operator-confirmed brief; the one sanctioned
100
- bypass is the entry-from-super-ux short-circuit, and even that demands a scope
101
- confirmation. It produces the **REQ spine** the request as an addressable list, each
102
- row naming how it is verified. Stages 3–5 trace to those ids, stage 4's gate is a
103
- mechanical set-comparison against them, and **stage 10 accounts for every one**, which
104
- is what turns the pipeline from a funnel into a circle.
94
+ exemption and no stage 1 without a committed, operator-confirmed brief. It produces the
95
+ **REQ spine** the request as an addressable list, each row naming how it is verified —
96
+ which stages 3–5 trace to, stage 4 set-compares against, and **stage 10 accounts for
97
+ every one of**, turning the pipeline from a funnel into a circle.
105
98
 
106
99
  **Harvest before you ask** (`references/knowledge-sources.md`). Stage 0 opens by
107
- pulling what the project already knows about *this* task the code and its graph,
108
- `CLAUDE.md`, `CONTEXT.md`/ADRs, the decision register, `docs/` and `docs/ux/`, past
109
- briefs, the wiki, and whatever else the project names as its docs. **The retro is read
110
- two ways and the difference matters:** its standing instructions and run stamps are
111
- read **in full** because they bind this run and are bounded by construction; its recent
112
- log and archive are **queried** by the task's nouns, because nothing caps them
113
- (`references/retrospective.md`). Write the source ledger into the brief and interview
114
- *against* it: every answer touching a source is checked against it, and the operator
115
- outranks any document — **but only out loud**, so an override is a recorded decision
116
- rather than an undetected divergence. That ledger is also stage 9's work list.
100
+ pulling what the project already knows about *this* task, writes the source ledger
101
+ into the brief, and then interviews **against** it so the operator outranks any
102
+ document, **but only out loud**, and an override is a recorded decision rather than
103
+ an undetected divergence. That ledger is also stage 9's work list. Which sources,
104
+ and the two ways the retro is read standing instructions in full because they
105
+ bind this run, the log queried because nothing caps it — are in
106
+ `references/knowledge-sources.md` and `references/retrospective.md`.
117
107
 
118
108
  **Three artifacts close a run, not two — and they are a convergence, not a sequence.**
119
- Stage 9 syncs the docs, the wiki **and the code graph** (`/graphify . --update`). None of
120
- the three consumes another; all three consume the same change, and the **graph↔docs
121
- divergence check is the gate over their convergence** rather than an extra nicety. That is
122
- why it is not optional where a graph exists: it is the only thing that compares two of the
123
- three outputs against each other. The graph is what the next run's harvest queries
124
- first, so a stale one is a false premise **carrying the authority of a machine** —
125
- a wrong doc gets argued with, a wrong graph gets believed. Refreshing it buys the
126
- graph↔docs divergence check; doc-side findings are fixed at stage 9, absences become
127
- REQ rows at stage 10 (`references/knowledge-graph.md`, `references/audit.md`).
109
+ Stage 9 syncs the docs, the wiki **and the code graph**. None consumes another; all three
110
+ consume the same change, and the **graph↔docs divergence check is the gate over their
111
+ convergence** the only thing that compares two of the three against each other, which
112
+ is why it is not optional where a graph exists. A stale graph is a false premise
113
+ **carrying the authority of a machine**: a wrong doc gets argued with, a wrong graph gets
114
+ believed (`references/knowledge-graph.md`, `references/audit.md`).
128
115
 
129
116
  **Documentation is a deliverable, and it has a gate** (`references/documentation.md`).
130
- A second stage-0 phase asks the four questions that make docs a *system* where
131
- settled things live, each fact's single home, what a change of type X obliges, what
132
- proves it and writes them to `docs/DOCMAP.md`. From then the **Doc Loop** fires
133
- whenever anything is settled, at **any** stage rather than only at stage 9; the stage-9
134
- sweep walks the **propagation matrix** (the harvest ledger names what you *read*, the
135
- matrix names what you *owe*); and *"docs in sync"* becomes a command with an exit code.
117
+ Stage 0 answers the four questions that make docs a *system* into `docs/DOCMAP.md`;
118
+ from then the **Doc Loop** fires whenever anything is settled, at **any** stage rather
119
+ than only at stage 9, the stage-9 sweep walks the **propagation matrix** — the harvest
120
+ ledger names what you *read*, the matrix names what you *owe* and *"docs in sync"*
121
+ becomes a command with an exit code.
136
122
 
137
123
  **The run teaches the next run, and the list stays short**
138
124
  (`references/retrospective.md`). Every gate is good at *this* run and blind across
139
125
  runs, so one class of failure can be caught, fixed and forgotten five times with
140
- nothing noticing it is the same one. Stage 10's last act: **stamp the run first** the
141
- only thing that makes the next step computable — **then prune** every standing
142
- instruction against its retirement triggers, hold the list to a hard cap of **ten**,
143
- log every deletion, and write an entry **only if the run diverged** (symptom, the stage
144
- that *owned* it, root cause, fix, and the check that catches it next time).
145
-
146
- Stage 0 reads those standing instructions in full, which is exactly why the prune is
147
- a gate criterion and not a good intention: a rule nobody reads to the end is worse
148
- than no rule, because everyone believes it is covered. **The order is load-bearing,
149
- not stylistic** one retirement trigger counts firings across the last five run
150
- stamps, so a prune placed ahead of the stamp reads a counter its own stage writes
151
- afterwards and can never run on real data (`references/learned.md` rule 21).
126
+ nothing noticing it is the same one. Stage 10's last act, **in this order and the
127
+ order is load-bearing**: stamp the run, then prune, then write the entry — a
128
+ retirement trigger counts firings across the last five stamps, so a prune placed
129
+ ahead of the stamp reads a counter its own stage has not written yet. The cap, the
130
+ triggers and what an entry must carry are in `references/retrospective.md`; why
131
+ the order cannot be swapped is `references/learned.md` rule 21.
132
+
133
+ Stage 0 reads those standing instructions in full, which is why the prune is a gate
134
+ criterion and not a good intention: a rule nobody reads to the end is worse than no
135
+ rule, because everyone believes it is covered.
152
136
 
153
137
  Three things the grill does beyond clarifying the request:
154
138
  - **Domain awareness.** It reads the project's own `CONTEXT.md` / `docs/adr/` and
@@ -210,40 +194,13 @@ Three things the grill does beyond clarifying the request:
210
194
  stop/return on fail; for `manual`, present the result and **wait for the
211
195
  operator's explicit "continue"/go** — an auto gate never substitutes for a
212
196
  required manual approval.
213
- 5. Cross-cutting, every stage: **when anything is settled scope, a contract, a
214
- name, a policy, a vocabulary run the Doc Loop
215
- (`references/documentation.md`) before the run moves on**: reserve the id,
216
- record it, resolve the question it answers, propagate by the matrix, commit
217
- with the ids. A decision that lives only in the spec dies with the spec, and one
218
- that lives only in the conversation was never made;
219
- **answer from the brief's autonomy section rather
220
- than asking again** — it was grilled precisely so you wouldn't have to;
221
- **anything deferred, dropped or left half-done goes into the carry-over ledger
222
- the moment it's said** — deferred out loud is forgotten; **never narrow the task
223
- silently** — the REQ list is frozen, adding is free, removing needs the
224
- operator's explicit agreement; **when a loop starts undoing an earlier pass —
225
- the same file edited twice for the same reason, a closed finding coming back, a
226
- third entry into one stage — stop and run the loop guard**
227
- (`references/loop-guard.md`): name the two shapes, escalate to the layer that
228
- owns the conflict, re-plan the check as an ordered list, then go through it one
229
- item at a time; **when a pass is *searching* rather than editing and starts
230
- finding mostly what the previous pass's own fixes broke, the axis is exhausted —
231
- rotate it, don't look harder** (`references/audit.md`); **every gate
232
- prints `holds: N` — what this run left running** across the eight classes
233
- (background shells, monitors, scheduled loops, coordination leases, worktrees,
234
- containers, scratch files, remote state), enumerated **by class and never by a
235
- single tool**, and stage 10 does not close while this run's residue is live and
236
- unaccounted (`references/residue.md`); and remember that a
237
- green from a check nobody has watched fail is not evidence; task
238
- tracker + conventional commits per host conventions; worktree isolation for the
239
- build, integrated back per the brief's branch policy before stage 7; honest
240
- degradation (never claim a failed/skipped step succeeded);
241
- outward/irreversible actions (deploy, publish, repo create, opening a PR,
242
- **editing a shared design file — frames are read by designers and stakeholders,
243
- so drawing in one is publishing — and above all *creating* one, which needs a
244
- named team and never happens while a recorded file resolves**) need explicit
245
- operator go — or a **specific** standing authorization recorded in the brief
246
- (named target + preconditions; a vague "do everything" is not one).
197
+ 5. **The cross-cutting rules fire at any stage**, not only herethe Doc Loop, the
198
+ loop guard, the audit's exit, the frozen REQ list, the carry-over ledger, and
199
+ what counts as evidence, and **every gate prints `holds: N`** — what this run left
200
+ running, across all eight classes, enumerated by class and never by a single
201
+ tool and stage 10 does not close while this run's residue is live and
202
+ unaccounted (`references/residue.md`). The rest are in
203
+ [`references/gates.md`](references/gates.md) *Cross-cutting, at every stage*.
247
204
 
248
205
  ## Stages (detail in `references/stages.md`)
249
206
 
@@ -252,44 +209,36 @@ capable available — see `references/model-tiering.md`).
252
209
 
253
210
  | # | Stage | Gate | Type |
254
211
  |---|---|---|---|
255
- | 0 | Intake grill — **mandatory** | source ledger written **with its `Contradictions:` line** — the harvest converges on one brief and nothing else compares the sources with each other; **the documentation inventory answered into `docs/DOCMAP.md`** registers, single homes, the propagation matrix, the gate command — and **intent reconciled against as-built**, every divergence resolved ([`references/documentation.md`](references/documentation.md)); the retro read in full and its archive queried; shared understanding reached; autonomy sweep covered; brief locked + confirmed | manual |
212
+ | 0 | Intake grill — **mandatory** | source ledger written with its `Contradictions:` line; `docs/DOCMAP.md` answered and intent reconciled against as-built; the retro read in full; autonomy sweep covered; brief locked and confirmed | manual |
256
213
  | 1 | Docs study | contracts grounded on fetched docs | auto |
257
214
  | 2 | Brainstorm + decompose | design approved; UI verdict recorded; every REQ answered; platform: module map approved | manual |
258
- | 3 | Spec | committed + reviewed; UI: chain validated, linter green, scenarios/`SCR-` traced; **COPY and VISUAL are a parallel layer after UX, and where both ran their convergence check is recorded** — a label the layout has no room for is right in each track and wrong on the screen ([`references/stages.md`](references/stages.md)) | manual |
259
- | 4 | Plan | parallel-ready, DoD per task; **every edge names what it carries** — the fake-edge test run, its `Edges:` count computed, and no arrow left whose payload nobody can name ([`references/planning.md`](references/planning.md)) | auto |
260
- | 5 | Dev | tasks DONE, TDD green per task, branch integrated per the brief; **a fanned-out group gets one convergence check over all its diffs together before the first worktree lands** — a per-task review cannot see a contradiction that exists only between two of them ([`references/build.md`](references/build.md) §4.2a); **anything generated passes its own checks, and local infrastructure does not publish the host's default ports** ([`references/learned.md`](references/learned.md)) | auto |
261
- | 6 | Tests | full suite green; new/changed code covered; **every new check probed both ways and asserted on its exit code**, and the suite run once against a cold environment ; **on a web front end the surface is checked in a browser, not in the diff** — a green suite cannot see a component that renders under a fixed header, a request that 404s past its mock, or a console error — and a browser **test suite** is the other half of the pair, never a substitute for the look (`playwright` or `chrome-devtools`, either one — **how**: [`references/browser.md`](references/browser.md), which channel: [`references/companion-skills.md`](references/companion-skills.md); absent → say *verified by reading the diff* and record it as the weaker claim it is) | auto |
262
- | 7 | Lint + deploy | lint clean + suite green before deploy; deploy needs a go (or the brief's specific standing authorization) | manual |
263
- | 8 | Post-deploy | clean boot or honest degradation report; **a deployed web target is opened, not curled** — a `200` proves the server answered and says nothing about a 404'd bundle or a console full of errors on load (`playwright` or `chrome-devtools`, either one, [`references/browser.md`](references/browser.md); absent → call it an HTTP response, which is its honest name) | auto |
264
- | 9 | Docs + wiki | every stale row of the stage-0 source ledger updated; **the propagation matrix walked for every change type this run produced** the ledger names what you read, the matrix names what you owe — every settled thing recorded with an id, every answered question resolved, and **the documentation gate green with its ratchet counts printed**; docs synced; wiki synced; **the code graph refreshed where one exists** and checked against the docs (a hub no doc names, a doc naming a node the graph lost); **every number computed rather than restated, every named command or file resolvable** ([`references/learned.md`](references/learned.md)); the carry-over count printed beside the verdict | auto |
265
- | 10 | **Acceptance** | ladder walk ran, its absences became REQ rows; every REQ accounted for with evidence from a check seen failing once; ledger has no unresolved row; **axis rotation recorded** (new findings vs self-inflicted, rule 1 of [`references/learned.md`](references/learned.md)), **every closure verified against the artefact rather than the document describing it**, **each correction swept across its class**, **every deferral a printed ratchet rather than a TODO**; **in a multi-repository project, every repository is clean, pushed and pointed at** (below); **the hand-back is written** — the request quoted as given, progress against it, what was solved, what surfaced unasked, waiting decisions asked here, and the ambiguity count computed ([`references/progress.md`](references/progress.md)); **the environment is given back** — all eight classes enumerated, what this run started ended and verified by re-enumerating rather than by the teardown's reply, an earlier run of this project ended only when **provably spent**, anything this project does not own reported rather than ended, written as a `holds:` line (`references/residue.md`); operator signs off; **every check this close-out leans on — the documentation gate included — has been seen failing once against a planted defect, and its ratchet counts are printed beside the verdict**; **the retrospective written last, and in order — the run stamped with its commit FIRST (the cold-retirement trigger reads that stamp), then the prune with the list at or under its cap and every deletion logged, then the entry; every deletion and every entry carrying its commit, entries older than five stamps rotated into the archive, counts printed** ; **every disclosure printed beside the verdict** — `abstained` (what the run declined to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither with a floor, neither ever a target ([`references/gates.md`](references/gates.md) → *Disclosures*) | manual |
266
-
267
-
268
- ### Stage 10 in a project of several repositories
269
-
270
- **A submodule is finished when its parent says so.** A parent repository records each submodule as
271
- a pointer to one commit, and moving the submodule does not move the pointer. So the work is
272
- committed, pushed, its CI is green and its own roadmap says done and anyone who clones the parent
273
- gets the commit **before** the change. Nothing looks wrong in either repository on its own; the
274
- disagreement exists only between them, which is why it survives every check that runs inside one.
275
-
276
- Stage 10 does not close until:
277
-
278
- ```bash
279
- git submodule status # no line begins with '+' (a '+' is the missing bump)
280
- git -C <each repo> status --porcelain && git -C <each repo> log @{u}..HEAD --oneline
281
- ```
282
-
283
- report nothing for the parent as well as every submodule. Where
284
- [agent-sync](https://github.com/ssheleg/agent-sync) is installed, `/agent-sync finish` runs
285
- exactly this plus *no lease left held*, and `--gates` adds the project's own gate commands.
286
-
287
- The fix, when it fails, is two commands and the second is the one that gets forgotten:
288
-
289
- ```bash
290
- git -C <submodule> push
291
- git add <submodule> && git commit -m "chore: bump <name> submodule — <why>"
292
- ```
215
+ | 3 | Spec | committed + reviewed; UI: chain validated, linter green, scenarios and `SCR-` traced; COPY and VISUAL are a parallel layer after UX, and where both ran their convergence check is recorded | manual |
216
+ | 4 | Plan | parallel-ready, DoD per task; **every edge names what it carries** — the fake-edge test run and its `Edges:` count computed | auto |
217
+ | 5 | Dev | tasks DONE, TDD green per task, branch integrated per the brief; a fanned-out group gets **one convergence check over all its diffs together** before the first worktree lands | auto |
218
+ | 6 | Tests | full suite green, new and changed code covered, every new check probed both ways and asserted on its exit code; **a web surface is checked in a browser, not in the diff** | auto |
219
+ | 7 | Lint + deploy | lint clean and suite green before deploy; deploy needs a go, or the brief's specific standing authorization | manual |
220
+ | 8 | Post-deploy | clean boot or an honest degradation report; **a deployed web target is opened, not curled** — a `200` proves the server answered and nothing else | auto |
221
+ | 9 | Docs + wiki | every stale row of the stage-0 source ledger updated; the propagation matrix walked for every change type this run produced; the documentation gate green with its ratchets printed; docs, wiki and the code graph synced and checked against each other | auto |
222
+ | 10 | **Acceptance** | the ladder walk ran and its absences became REQ rows; every REQ accounted for with evidence from a check seen failing once; no unresolved ledger row; **every repository clean, pushed and pointed at**; the hand-back written and the environment given back; the retrospective written **last**, and in order | manual |
223
+
224
+ **Every gate above is the short form**, and the long form is the point of
225
+ [`references/stages.md`](references/stages.md) one section per stage. What the
226
+ ladder walk is, which eight environment classes stage 10 enumerates, what makes an
227
+ edge fake, why a `200` is not a working page: all there, none here.
228
+
229
+ That split is the budget rule this pack states for everyone else, applied to
230
+ itself: the body was **6685 tokens against a 5000 budget**, the worst in the
231
+ family, and most of the overrun sat in this table's Gate column restating files
232
+ that already load on demand.
233
+
234
+
235
+
236
+ **Several repositories?** A submodule is finished when its parent says so the
237
+ work can be committed, pushed and green while a clone of the parent still gets the
238
+ commit before it, and neither repository looks wrong alone. The two commands that
239
+ prove it, and the two-command fix whose second half gets forgotten, are in
240
+ [`references/acceptance.md`](references/acceptance.md) *A project of several
241
+ repositories*.
293
242
 
294
243
  ## Model — ask once, at preflight
295
244
 
@@ -309,14 +258,12 @@ pinned to the confirmed model automatically. Detail: `references/model-tiering.m
309
258
 
310
259
  ## Bring your own skills
311
260
 
312
- The stages above (stage 0 intake + 1→10) are the **example** flow (this skill's
313
- built-in doctrine + a super-ux UX track for user-facing tasks + host conventions). A
314
- host project owns its pipeline: copy `pipeline.example.json` `pipeline.json`,
315
- then define its **own** stages (any count), point each stage's `skills[]` at the
316
- skills/agents its environment resolves, set each `gate.type` (`auto`/`manual`) to
317
- fit its process, and configure/toggle its own `release` block. The framework ships
318
- no fixed stage count and no opinion on which gates are manual or whether release
319
- automation is on — `pipeline.schema.json` is the only contract.
261
+ The stages above are the **example** flow. A host project owns its pipeline: copy
262
+ `pipeline.example.json` `pipeline.json`, define its **own** stages (any count),
263
+ point each `skills[]` at what its environment resolves, set each `gate.type`
264
+ (`auto`/`manual`) to fit its process, and toggle its own `release` block. The
265
+ framework ships no fixed stage count and no opinion on which gates are manual
266
+ `pipeline.schema.json` is the only contract.
320
267
 
321
268
  ## References
322
269
 
@@ -22,6 +22,7 @@ requirement.** It is what turns the pipeline from a funnel into a circle.
22
22
  - A seam is not a deliverable, and REQ rows are written against deliverables
23
23
  - GATE (manual)
24
24
  - When the answer is "something's missing"
25
+ - A project of several repositories
25
26
 
26
27
  ## Why a stage and not a gate
27
28
 
@@ -361,3 +362,35 @@ or a tracked follow-up. Both are legitimate outcomes of this stage. Closing the
361
362
  run with a known gap is fine **if the gap is written down** — closing it with the
362
363
  gap only in someone's memory is the failure mode this whole spine exists to
363
364
  prevent.
365
+
366
+ ---
367
+
368
+ ## A project of several repositories
369
+
370
+ **A submodule is finished when its parent says so.** A parent repository records each submodule as
371
+ a pointer to one commit, and moving the submodule does not move the pointer. So the work is
372
+ committed, pushed, its CI is green and its own roadmap says done — and anyone who clones the parent
373
+ gets the commit **before** the change. Nothing looks wrong in either repository on its own; the
374
+ disagreement exists only between them, which is why it survives every check that runs inside one.
375
+
376
+ Stage 10 does not close until:
377
+
378
+ ```bash
379
+ git submodule status # no line begins with '+' (a '+' is the missing bump)
380
+ git -C <each repo> status --porcelain && git -C <each repo> log @{u}..HEAD --oneline
381
+ ```
382
+
383
+ report nothing — for the parent as well as every submodule. Where
384
+ [agent-sync](https://github.com/ssheleg/agent-sync) is installed, `/agent-sync finish` runs
385
+ exactly this plus *no lease left held*, and `--gates` adds the project's own gate commands.
386
+
387
+ The fix, when it fails, is two commands and the second is the one that gets forgotten:
388
+
389
+ ```bash
390
+ git -C <submodule> push
391
+ git add <submodule> && git commit -m "chore: bump <name> submodule — <why>"
392
+ ```
393
+
394
+ Moved out of `SKILL.md` on 2026-08-16: the body was 6685 tokens against a
395
+ < 5000 budget, and stage-10 close-out is what this file is for.
396
+
@@ -40,6 +40,7 @@ elsewhere and is not restated here:
40
40
  - Where a gate runs
41
41
  - Adding a check to an existing gate
42
42
  - Rationalizations
43
+ - Cross-cutting, at every stage
43
44
 
44
45
  ## Axis A — the stage gate type
45
46
 
@@ -589,3 +590,47 @@ of is deleted in the next refactor by someone who assumed it was dead.
589
590
  | "The gate would be red on day one, so I'll add it later" | Make the section dormant instead. Dormant is visible and green; "later" is neither. |
590
591
  | "I raised the floor to get the build green" | Then say so in the log, in the same commit. A floor raised silently is a ratchet running backwards. |
591
592
  | "A hook is overkill, CI catches it" | CI catches it after the edit, the commit and the push. If the point is to stop the edit, CI is the wrong rung — and if it is not, do not pay the latency. |
593
+
594
+ ---
595
+
596
+ ## Cross-cutting, at every stage
597
+
598
+ 5. Cross-cutting, every stage: **when anything is settled — scope, a contract, a
599
+ name, a policy, a vocabulary — run the Doc Loop
600
+ (`references/documentation.md`) before the run moves on**: reserve the id,
601
+ record it, resolve the question it answers, propagate by the matrix, commit
602
+ with the ids. A decision that lives only in the spec dies with the spec, and one
603
+ that lives only in the conversation was never made;
604
+ **answer from the brief's autonomy section rather
605
+ than asking again** — it was grilled precisely so you wouldn't have to;
606
+ **anything deferred, dropped or left half-done goes into the carry-over ledger
607
+ the moment it's said** — deferred out loud is forgotten; **never narrow the task
608
+ silently** — the REQ list is frozen, adding is free, removing needs the
609
+ operator's explicit agreement; **when a loop starts undoing an earlier pass —
610
+ the same file edited twice for the same reason, a closed finding coming back, a
611
+ third entry into one stage — stop and run the loop guard**
612
+ (`references/loop-guard.md`): name the two shapes, escalate to the layer that
613
+ owns the conflict, re-plan the check as an ordered list, then go through it one
614
+ item at a time; **when a pass is *searching* rather than editing and starts
615
+ finding mostly what the previous pass's own fixes broke, the axis is exhausted —
616
+ rotate it, don't look harder** (`references/audit.md`); **every gate
617
+ prints `holds: N` — what this run left running** across the eight classes
618
+ (background shells, monitors, scheduled loops, coordination leases, worktrees,
619
+ containers, scratch files, remote state), enumerated **by class and never by a
620
+ single tool**, and stage 10 does not close while this run's residue is live and
621
+ unaccounted (`references/residue.md`); and remember that a
622
+ green from a check nobody has watched fail is not evidence; task
623
+ tracker + conventional commits per host conventions; worktree isolation for the
624
+ build, integrated back per the brief's branch policy before stage 7; honest
625
+ degradation (never claim a failed/skipped step succeeded);
626
+ outward/irreversible actions (deploy, publish, repo create, opening a PR,
627
+ **editing a shared design file — frames are read by designers and stakeholders,
628
+ so drawing in one is publishing — and above all *creating* one, which needs a
629
+ named team and never happens while a recorded file resolves**) need explicit
630
+ operator go — or a **specific** standing authorization recorded in the brief
631
+ (named target + preconditions; a vague "do everything" is not one).
632
+
633
+ Moved out of `SKILL.md` on 2026-08-16 for the same budget reason as the
634
+ multi-repository block: these fire at any stage, so they belong with the gate
635
+ doctrine rather than inside step 5 of the run order.
636
+
@@ -22,6 +22,7 @@ the run*. Three things it does not say, and each is why this file exists:
22
22
 
23
23
  - Why it keys to the brief, not to the coverage table
24
24
  - `never` is a fact
25
+ - A ledger records two different things, and most record only one
25
26
  - What stage 8 writes and what stage 10 refuses
26
27
  - Rationalizations
27
28
 
@@ -53,6 +54,39 @@ So the count has **no floor, no direction, and may never be given a target**, ex
53
54
  like the disclosures in [`gates.md`](gates.md). A project with forty `never` rows is not
54
55
  failing; it is a project that now knows something it could not previously ask.
55
56
 
57
+ ## A ledger records two different things, and most record only one
58
+
59
+ **What confirmed it** and **whether a person looked** are separate facts. The first is
60
+ evidence: a command, a CI run id, a fixture name. The second is the `Human` axis, and it is
61
+ the one the exposure line is defined over.
62
+
63
+ A ledger may carry either or both, and most carry only the first. Measured across this
64
+ family on 2026-08-16 — nine repositories, **ten** header shapes, **815** rows:
65
+
66
+ | what the state column can say | rows | repositories |
67
+ |---|---|---|
68
+ | whether a **person** looked (`Human`) | **126** | 1 |
69
+ | a date and what was watched (`Last verified`) | 180 | 1 |
70
+ | `verified` — by a person **or** a command, indistinguishable | 391 | 4 |
71
+ | nothing: the ledger records evidence and carries no state column | 118 | 3 |
72
+
73
+ So **`never` is measurable in one repository of nine, over 15% of the rows**, and the exposure line — which this
74
+ doctrine defines over it — is undefined in the rest. That is not a defect in those
75
+ ledgers. Recording *what confirmed it* is the Auto job done properly, and a project that
76
+ never asks the human question is making a choice.
77
+
78
+ What is a defect is **doctrine that speaks as though the column were there**. So:
79
+
80
+ - **Where there is no state column, the exposure line says so** and prints no number.
81
+ `templates/exposure.sh` reports `dormant` and names the column headings it looked for.
82
+ A zero would be the reassuring answer to a question nobody asked.
83
+ - **A `verified` that cannot separate a person from a command may not be reported as
84
+ human confirmation.** The script names the column it read, for exactly this reason.
85
+ - **Adding the column later never reaches backwards.** New rows start at `never`;
86
+ retrospective statuses for work nobody actually checked are the failure the
87
+ `evidence-docs` router exists to name, and a back-filled ledger is worse than an absent
88
+ one because it answers the question wrongly instead of not at all.
89
+
56
90
  ## What stage 8 writes and what stage 10 refuses
57
91
 
58
92
  **A coverage verdict of `review` becomes `none`.** *No check can decide this* is not
@@ -123,9 +123,15 @@ fi
123
123
  # file's purpose.
124
124
  # NORMALISED first: these ledgers write `**never**`, not `never`. Bold hid three real
125
125
  # unverified rows in one member and seven in another, and both reported zero.
126
+ # THE LEADING WORD, not the whole cell. `**observed** — the row exists because …` is a
127
+ # normal way to write a status, and four rows in this family were reported unreadable for
128
+ # explaining themselves. An empty cell still counts, which is why the emptiness test comes
129
+ # before the word is taken.
126
130
  awk -F'\t' '{ s=tolower($2); gsub(/[*`]/, "", s); gsub(/^[ \t]+|[ \t]+$/, "", s);
127
- if (s=="never" || s=="" || s=="-" || s=="no" || s=="unverified" ||
128
- s=="pending" || s=="none") print }' \
131
+ if (s=="") { print; next }
132
+ w=s; sub(/[ \t].*$/, "", w); sub(/[.,;:—-]+$/, "", w);
133
+ if (w=="never" || w=="-" || w=="no" || w=="unverified" ||
134
+ w=="pending" || w=="none") print }' \
129
135
  "$TMP/rows" > "$TMP/unverified"
130
136
  UNVERIFIED=$(grep -c '' "$TMP/unverified" 2>/dev/null) || UNVERIFIED=0
131
137
 
@@ -134,11 +140,13 @@ UNVERIFIED=$(grep -c '' "$TMP/unverified" 2>/dev/null) || UNVERIFIED=0
134
140
  # it as confirmed is how a shrug becomes a clean bill, which the fixture for this line
135
141
  # caught the moment it was written.
136
142
  awk -F'\t' '{ s=tolower($2); gsub(/[*`]/, "", s); gsub(/^[ \t]+|[ \t]+$/, "", s);
137
- if (s=="never" || s=="" || s=="-" || s=="no" || s=="unverified" ||
138
- s=="pending" || s=="none") next;
143
+ if (s=="") next;
144
+ w=s; sub(/[ \t].*$/, "", w); sub(/[.,;:—-]+$/, "", w);
145
+ if (w=="never" || w=="-" || w=="no" || w=="unverified" ||
146
+ w=="pending" || w=="none") next;
139
147
  if ($2 ~ /[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/) next;
140
- if (s=="pass" || s=="yes" || s=="verified" || s=="ok" || s=="observed" ||
141
- s=="confirmed" || s=="green") next;
148
+ if (w=="pass" || w=="yes" || w=="verified" || w=="ok" || w=="observed" ||
149
+ w=="confirmed" || w=="green" || w=="planted") next;
142
150
  print }' "$TMP/rows" > "$TMP/unreadable"
143
151
  UNREADABLE=$(grep -c '' "$TMP/unreadable" 2>/dev/null) || UNREADABLE=0
144
152