task-pipeline-skill 1.91.2 → 1.93.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/CONTRIBUTING.md +12 -6
  3. package/HOW-IT-WORKS.md +9 -4
  4. package/README.md +32 -4
  5. package/SKILL-CARD.md +1 -1
  6. package/cursor/rules/task-pipeline.mdc +11 -2
  7. package/evals/RESULTS.md +1 -1
  8. package/evals/task-pipeline.evals.json +16 -1
  9. package/package.json +3 -3
  10. package/plugins/task-pipeline/.claude-plugin/plugin.json +2 -2
  11. package/plugins/task-pipeline/commands/task-pipeline.md +23 -8
  12. package/plugins/task-pipeline/hooks/hooks.json +11 -0
  13. package/plugins/task-pipeline/hooks/memory-nudge.sh +49 -0
  14. package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +3 -1
  15. package/plugins/task-pipeline/skills/project-audit/SKILL.md +2 -1
  16. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +10 -20
  17. package/plugins/task-pipeline/skills/task-pipeline/execution-packet.example.json +1 -1
  18. package/plugins/task-pipeline/skills/task-pipeline/execution-packet.schema.json +2 -2
  19. package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +8 -2
  20. package/plugins/task-pipeline/skills/task-pipeline/pipeline.example.json +2 -1
  21. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +7 -0
  22. package/plugins/task-pipeline/skills/task-pipeline/references/artifacts.md +4 -0
  23. package/plugins/task-pipeline/skills/task-pipeline/references/brainstorm.md +6 -3
  24. package/plugins/task-pipeline/skills/task-pipeline/references/build.md +2 -2
  25. package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +20 -2
  26. package/plugins/task-pipeline/skills/task-pipeline/references/decomposition.md +4 -0
  27. package/plugins/task-pipeline/skills/task-pipeline/references/deploy-targets.md +31 -0
  28. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -0
  29. package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +14 -5
  30. package/plugins/task-pipeline/skills/task-pipeline/references/hooks.md +3 -1
  31. package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +1 -0
  32. package/plugins/task-pipeline/skills/task-pipeline/references/planning.md +8 -0
  33. package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
  34. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +15 -7
  35. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +233 -0
  36. package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +3 -1
  37. package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +8 -2
  38. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +89 -5
  39. package/plugins/task-pipeline/skills/task-pipeline/scripts/packet.py +4 -2
  40. package/plugins/task-pipeline/skills/task-pipeline/scripts/plan_audit.py +1 -1
  41. package/plugins/task-pipeline/skills/task-pipeline/scripts/stage_checkpoint.py +68 -1
  42. package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +2 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: task-pipeline
3
- description: "Use when work changes the repository — feature, fix, bug, 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. Runs a substantial task through an intake grill, docs study, brainstorm, spec, plan, build, tests, deploy, post-deploy, docs/wiki sync and acceptance with explicit gates. 'checkup' / 'чекап' reports unconfirmed releases; 'setup' audits existing docs. Not for: answering a question, explaining code, a typo or a one-line edit, a mechanical rename, reconnaissance that lands nothing — say 'no pipeline' / 'без пайплайна' to opt out."
3
+ description: "Use when work changes the repository — feature, fix, bug, refactor, migration, integration, rewrite, adoption or hardening; фича, фикс, баг, рефактор, миграция, интеграция, доработать, починить, внедрить, перевести — or 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. Runs a substantial task through gated stages: intake grill, docs, brainstorm, spec, plan, build, tests, deploy, post-deploy, docs/wiki, acceptance. 'waves' / 'волнами' closes the whole board; 'checkup' / 'чекап' lists unconfirmed releases; 'setup' audits docs. Not for: answering a question, explaining code, a typo, a one-line edit, a mechanical rename, reconnaissance that lands nothing — say 'no pipeline' / 'без пайплайна' to opt out."
4
4
  license: MIT
5
5
  compatibility: "Doctrine runs on any agent. The bundled scripts need python3; the run needs git. Missing either degrades, never blocks — the graph verbs and seeded gates go unused, and the run says so."
6
6
  ---
@@ -17,8 +17,8 @@ GAP CHECK before it is an interview: the brief is built from the request, the
17
17
  files and the harvest first, and a question is asked only for a **material
18
18
  unknown** the sources cannot answer. A complete brief yields ZERO intake
19
19
  questions; what the request or the project already decided is recorded, never
20
- re-negotiated. The interview, where gaps remain, is one-question-at-a-time and
21
- sweeps stages 1→10 for anything that would stop the run later — then locks the
20
+ re-negotiated. The interview, where gaps remain, is ONE batch ordered by dependency
21
+ and sweeps stages 1→10 for anything that would stop the run later — then locks the
22
22
  answers into a brief. Autonomy is bought there or not at all; every MATERIAL
23
23
  question skipped at stage 0 comes back as an interruption at stage 6.
24
24
 
@@ -66,16 +66,7 @@ gate stops until it is installed.
66
66
  Which reference owns which stage — all forty-odd of them, by stage number:
67
67
  [`references/doctrine-map.md`](./references/doctrine-map.md).
68
68
 
69
- **Optional bridge.** An equivalent skill set the operator already runs can be mapped
70
- onto stages 2/4/5/6 in `pipeline.json` → `skills[]`. That is a **substitution, never a
71
- requirement**. And the precedence is explicit, because two layers could seem to
72
- disagree: on a CUSTOM profile the **kernel wins** — scope, evidence, deps and
73
- resume are owed by every unit of work — while `references/stages.md` is the
74
- **default profile's** normative gate set, governing the stages that profile
75
- actually selects, not imposing its stage numbers on a profile that dropped
76
- them. The built-in doctrine is normative for the default profile; the kernel is
77
- normative for all. Nothing detects, recommends or waits for an external
78
- provider.
69
+ **Precedence:** on a CUSTOM profile the **kernel wins** — scope, evidence, deps and resume are owed by every unit of work; `references/stages.md` is the **default profile's** normative gate set; the kernel is normative for all. Another skill set on stages 2/4/5/6: `references/companion-skills.md`.
79
70
 
80
71
  **super-ux — the preferred provider for ANY user-facing task.** The moment a task
81
72
  implies an interface (web / mobile / CLI / TUI), the WHY→UI→scenario chain runs
@@ -176,15 +167,16 @@ Three things the grill does beyond clarifying the request, each in full in
176
167
  stages and gates run** (FIX-TP-03.02): the numbers "1→10" name the DEFAULT
177
168
  profile, and a custom profile with three stages runs three — no hidden stage
178
169
  0, 7 or 10 is injected because the default profile has one. What a custom
179
- profile does NOT escape is the KERNEL (03.01): scope, evidence, deps and
180
- resume are owed by every stage of every profile, so dropping stages never
181
- drops the evidence gate. And an unknown MANDATORY capability blocks the
170
+ profile does NOT escape is the KERNEL (03.01): dropping stages never drops
171
+ the evidence gate. And an unknown MANDATORY capability blocks the
182
172
  compile — a profile whose `must_understand` names a capability this runtime
183
173
  does not have is refused, never run with the capability silently absent.
184
174
  **Is the brief a platform rather than a change?** Then stage 2 also cuts it into
185
175
  modules (`references/decomposition.md`) and stages 3→10 run **per module** in
186
176
  build order, one brick at a time — stages 0–2 run once, and the module map's
187
177
  status column is the resume point (`references/stages.md` → *The program loop*).
178
+ **The whole board?** `/task-pipeline waves` (`references/waves.md`): stages
179
+ 0–4 once, 5–8 per wave, 9–10 to close.
188
180
  4. Do **not** advance until the stage **gate** passes (`references/stages.md`).
189
181
  Honor the gate **type**: for `auto`, verify the gate's `check` yourself and
190
182
  stop/return on fail; for `judgment`, record the named judge's ruling as
@@ -272,7 +264,5 @@ substitute for, and a ResultEnvelope whose stale candidate (older revision, or
272
264
  a superseded fence) re-plans instead of landing as current
273
265
  (`scripts/packet.py validate-result`). The compiler's first stage maps an
274
266
  audit report onto parent tasks (`scripts/context_packets.py compile|verify`):
275
- ids derived from finding ids — never positional, so a shuffled report compiles
276
- byte-identically — evidence/limits/priority in their own fields separate from
277
- status, and any row it cannot map blocks the whole compile rather than being
278
- dropped silently.
267
+ ids derived from finding ids, never positional; evidence, limits and priority
268
+ kept apart from status; and any row it cannot map blocks the compile.
@@ -1,5 +1,5 @@
1
1
  {
2
- "schema_version": "execution-packet/1",
2
+ "schema_version": "task-pipeline/execution-packet/1",
3
3
  "id": "FIX-EX-01.01",
4
4
  "parent_id": "FIX-EX-01",
5
5
  "module": "example-module",
@@ -18,8 +18,8 @@
18
18
  "properties": {
19
19
  "schema_version": {
20
20
  "type": "string",
21
- "pattern": "^execution-packet/[0-9]+$",
22
- "description": "Contract version, `execution-packet/<major>`. A consumer that does not know the major REJECTS the packet — an unknown mandatory version is not a warning."
21
+ "pattern": "^(task-pipeline/)?execution-packet/[0-9]+$",
22
+ "description": "Contract version, `task-pipeline/execution-packet/<major>` (namespaced since 1.93.0 so Fabric's former packet id cannot be mistaken for it; the bare `execution-packet/<major>` is still read until live packets are migrated, backlog B-135). A consumer that does not know the major REJECTS the packet — an unknown mandatory version is not a warning."
23
23
  },
24
24
  "id": {
25
25
  "type": "string",
@@ -205,6 +205,11 @@
205
205
  ],
206
206
  "description": "The class of the user-facing surface this node builds, copied from the brief's `surface_class` (stage 0). It selects the gate profile, and `graph.py certify` reads it: on `flagship` or `product` the fourth, `visual` tier report is REQUIRED, because none of unit, seam or product opens the contact sheet; on any other class a `visual` report is accepted when given. Absent on a node that builds no user-facing surface. `references/certification.md` → *The fourth reading*."
207
207
  },
208
+ "wave": {
209
+ "type": "integer",
210
+ "minimum": 1,
211
+ "description": "Wave mode only (`references/waves.md`): the pass of stages 5–8 that closes this node, from 1, where wave 1 is the walking skeleton. `graph.py validate` refuses an edge from a later wave's node into an earlier wave's node, because an earlier wave waiting on a later one cannot close in its own pass; `graph.py next --wave N` prints that wave's frontier only; `graph.py wave` moves a node and records the re-cut as a revision. Absent outside wave mode."
212
+ },
208
213
  "certification": {
209
214
  "type": "object",
210
215
  "description": "What the tiered certification recorded for this node. Written by `graph.py certify` on every round, pass or fail: a failing round that wrote nothing would erase the only evidence that a node is churning, which is the number the loop-guard ceiling reads.",
@@ -444,9 +449,10 @@
444
449
  "park",
445
450
  "close",
446
451
  "invalidate",
447
- "waive"
452
+ "waive",
453
+ "wave"
448
454
  ],
449
- "description": "Which mutation made this entry. `close` joined the two on 2026-08-17 with T-5 — and it was caught by a probe rather than by the fixture asserting *the graph after a close still validates*, because `violations()` never reaches an enum. The same disagreement B-084 records, one field over. `invalidate` joined with PF-02.02: a REQ/interface/brief change supersedes a node and resets its downstream proofs."
455
+ "description": "Which mutation made this entry. `close` joined the two on 2026-08-17 with T-5 — and it was caught by a probe rather than by the fixture asserting *the graph after a close still validates*, because `violations()` never reaches an enum. The same disagreement B-084 records, one field over. `invalidate` joined with PF-02.02: a REQ/interface/brief change supersedes a node and resets its downstream proofs. `wave` joined with wave mode: the re-cut after every wave moves nodes between waves, and a move nobody recorded is the quiet re-plan `references/planning.md` refuses."
450
456
  },
451
457
  "node": {
452
458
  "type": "string",
@@ -18,7 +18,7 @@
18
18
  ],
19
19
  "gate": {
20
20
  "type": "manual",
21
- "check": "MANDATORY stage — never skipped (only sanctioned bypass: the entry-from-super-ux short-circuit). PHASE 1, before the first question: harvest the knowledge sources (references/knowledge-sources.md) — code, THE CODE GRAPH when one is built (references/knowledge-graph.md: graphify query/affected/god-nodes answer reach, which grep cannot; detect graphify-out/graph.json — recommended, never required), CLAUDE.md/AGENTS.md, CONTEXT.md + docs/adr, docs/ + docs/ux, past pipeline briefs and carry-over ledgers, THE RETRO'S STANDING INSTRUCTIONS (docs/evidence/retro.md — read IN FULL, not queried: they are capped at ten and they BIND this run; stamp each one the moment it fires, since that date is the only evidence behind stage 10's cold-retirement rule — references/retrospective.md), the knowledge wiki when installed (obsidian-wiki — recommended, never required; detect ~/.obsidian-wiki/config), and any other repo or hosted doc system the project names as its docs — queried by this task's own terms, with the SOURCE LEDGER written into the brief (a row per source consulted, or an explicit 'none found'; THE GRAPH'S ROW CARRIES ITS MEASURED LAG — commits and days behind HEAD, the signal it was measured with (built_at_commit exact / mtime approximate / unresolvable), and the marker '⚠ not trusted for reach until refreshed' — that exact string, so one marker is greppable across every ledger — on anything but current. A bare build date does NOT satisfy this: it is the graph's own reply about itself, true and self-reported and silent about whether the graph describes the tree this run is about to change — references/knowledge-graph.md -> Measure the lag, and references/gates.md -> False success for the class). PHASE 2, the grill, built into the skill (references/grill.md) — no companion to install. Per its contract: one question at a time, a recommended answer with each, explore the codebase/docs before asking, depth-first, contradictions reconciled; EVERY answer that touches a harvested source is validated against that source — the operator outranks any document, but only out loud, and the losing side is logged for the stage-9 doc update; domain awareness applied (terms challenged against CONTEXT.md, ADRs recorded for hard-to-reverse calls). The autonomy sweep is covered — every stage 1-10 has its blockers pre-resolved (docs sources, branch/tracker policy, test + lint commands, deploy target and authorization, log/health locations, docs+wiki targets, and for UI tasks the design surface: Figma on or text-only, is the Figma MCP connected, and if it is not — ship text-only or stop and connect it, since the UX chain degrades on its own and never blocks; plus, with Figma on, the DESIGN DESTINATION — which team/org by name and which file per surface, App / Web / ASO (the recorded one, a URL the operator gives, or creation in that named team with the creation explicitly authorized), written into the project's canonical record before the first frame, and never created while a recorded file resolves — an unreachable recorded file means stop and ask, never make a replacement) or is explicitly marked 'stop and ask here'. UI verdict recorded (arms super-ux), and for a user-facing task its SURFACE CLASS — surface_class: flagship | product | internal | ad — which selects the visual gate profile for stages 3, 6 and 10 (references/stages.md -> The surface class); model decision recorded. All of it locked into a committed task brief the operator confirms before stage 1. The REQ table is written — one row per independently verifiable deliverable, each naming how it is verified — and frozen: adding later is free, removing or narrowing needs the operator's explicit agreement. The carry-over ledger is seeded. PHASE 1b, THE DOCUMENTATION INVENTORY (references/documentation.md): four questions answered into docs/DOCMAP.md before the interview — where settled things live (the DECISION HOME, and there is exactly one per project: an existing docs/adr/ IS the register and is recorded as such, never duplicated), what each fact's single home is, what a change of type X obliges (THE PROPAGATION MATRIX, non-empty, every row naming the check that enforces it or the word 'review' with a one-line reason), and what proves it (the gate command). A project with no answers gets them seeded — registers, matrix and scripts/check-docs.sh from the skill's templates — and the seeding is recorded as the register's first entry; the seeded gate must exit 0 on its own seeds, because a project that starts red teaches everyone on day one that the gate is noise. The regime is recorded. PHASE 1c, RECONCILE: git says how it should be, the run record says how it turned out — read both for the area about to be touched and resolve every divergence (the document is stale, the record is wrong, or they genuinely disagree and that is a decision), because starting on an unresolved divergence means building against a system that does not exist. The retro's in-force sections are read IN FULL and its archive is QUERIED by the task's nouns."
21
+ "check": "MANDATORY stage — never skipped (only sanctioned bypass: the entry-from-super-ux short-circuit). PHASE 1, before the first question: harvest the knowledge sources (references/knowledge-sources.md) — code, THE CODE GRAPH when one is built (references/knowledge-graph.md: graphify query/affected/god-nodes answer reach, which grep cannot; detect graphify-out/graph.json — recommended, never required), CLAUDE.md/AGENTS.md, CONTEXT.md + docs/adr, docs/ + docs/ux, past pipeline briefs and carry-over ledgers, THE RETRO'S STANDING INSTRUCTIONS (docs/evidence/retro.md — read IN FULL, not queried: they are capped at ten and they BIND this run; stamp each one the moment it fires, since that date is the only evidence behind stage 10's cold-retirement rule — references/retrospective.md), the knowledge wiki when installed (obsidian-wiki — recommended, never required; detect ~/.obsidian-wiki/config), and any other repo or hosted doc system the project names as its docs — queried by this task's own terms, with the SOURCE LEDGER written into the brief (a row per source consulted, or an explicit 'none found'; THE GRAPH'S ROW CARRIES ITS MEASURED LAG — commits and days behind HEAD, the signal it was measured with (built_at_commit exact / mtime approximate / unresolvable), and the marker '⚠ not trusted for reach until refreshed' — that exact string, so one marker is greppable across every ledger — on anything but current. A bare build date does NOT satisfy this: it is the graph's own reply about itself, true and self-reported and silent about whether the graph describes the tree this run is about to change — references/knowledge-graph.md -> Measure the lag, and references/gates.md -> False success for the class). PHASE 2, the grill, built into the skill (references/grill.md) — no companion to install. Per its contract: close what the code/docs answer first, then ONE batch of the material unknowns ordered by dependency, a recommended answer with each (one at a time only where answers depend on each other or the operator asks), contradictions reconciled; EVERY answer that touches a harvested source is validated against that source — the operator outranks any document, but only out loud, and the losing side is logged for the stage-9 doc update; domain awareness applied (terms challenged against CONTEXT.md, ADRs recorded for hard-to-reverse calls). The autonomy sweep is covered — every stage 1-10 has its blockers pre-resolved (docs sources, branch/tracker policy, test + lint commands, deploy target and authorization, log/health locations, docs+wiki targets, and for UI tasks the design surface: Figma on or text-only, is the Figma MCP connected, and if it is not — ship text-only or stop and connect it, since the UX chain degrades on its own and never blocks; plus, with Figma on, the DESIGN DESTINATION — which team/org by name and which file per surface, App / Web / ASO (the recorded one, a URL the operator gives, or creation in that named team with the creation explicitly authorized), written into the project's canonical record before the first frame, and never created while a recorded file resolves — an unreachable recorded file means stop and ask, never make a replacement) or is explicitly marked 'stop and ask here'. UI verdict recorded (arms super-ux), and for a user-facing task its SURFACE CLASS — surface_class: flagship | product | internal | ad — which selects the visual gate profile for stages 3, 6 and 10 (references/stages.md -> The surface class); model decision recorded. All of it locked into a committed task brief the operator confirms before stage 1. The REQ table is written — one row per independently verifiable deliverable, each naming how it is verified — and frozen: adding later is free, removing or narrowing needs the operator's explicit agreement. The carry-over ledger is seeded. PHASE 1b, THE DOCUMENTATION INVENTORY (references/documentation.md): four questions answered into docs/DOCMAP.md before the interview — where settled things live (the DECISION HOME, and there is exactly one per project: an existing docs/adr/ IS the register and is recorded as such, never duplicated), what each fact's single home is, what a change of type X obliges (THE PROPAGATION MATRIX, non-empty, every row naming the check that enforces it or the word 'review' with a one-line reason), and what proves it (the gate command). A project with no answers gets them seeded — registers, matrix and scripts/check-docs.sh from the skill's templates — and the seeding is recorded as the register's first entry; the seeded gate must exit 0 on its own seeds, because a project that starts red teaches everyone on day one that the gate is noise. The regime is recorded. PHASE 1c, RECONCILE: git says how it should be, the run record says how it turned out — read both for the area about to be touched and resolve every divergence (the document is stale, the record is wrong, or they genuinely disagree and that is a decision), because starting on an unresolved divergence means building against a system that does not exist. The retro's in-force sections are read IN FULL and its archive is QUERIED by the task's nouns."
22
22
  }
23
23
  },
24
24
  {
@@ -183,6 +183,7 @@
183
183
  "release": {
184
184
  "enabled": true,
185
185
  "trigger": "tag",
186
+ "approval": "checks",
186
187
  "steps": [
187
188
  "create a GitHub release from the matching CHANGELOG section",
188
189
  "npm publish (task-pipeline-skill) — a second job in the same workflow, armed per repository by the PUBLISH_NPMJS variable (NPM_TOKEN granular automation token, or trusted publishing via OIDC); unarmed it falls back to a human 2FA step"
@@ -204,6 +204,13 @@
204
204
  "_goal_note": {
205
205
  "type": "string",
206
206
  "description": "Free prose beside `goal`."
207
+ },
208
+ "approval": {
209
+ "enum": [
210
+ "checks",
211
+ "reviewers"
212
+ ],
213
+ "description": "Who admits a release: `checks` — a guard (tag on main, CI green on that commit) and no reviewers, so the run tags, watches and reports; `reviewers` — an environment with required reviewers, so the run reports the direct link to the run that is actually `waiting`. Absent: read the organisation's declaration or the environment's protection rules; never assume `checks` (references/deploy-targets.md)."
207
214
  }
208
215
  }
209
216
  },
@@ -33,6 +33,8 @@ docs/
33
33
  YYYY-MM-DD-<topic>-brief.md # stage 0 — locked intake brief (grill output)
34
34
  YYYY-MM-DD-<topic>-carryover.md # stage 0 seeds it; EVERY stage appends; stage 10 reads it
35
35
  YYYY-MM-DD-<topic>-modules.md # stage 2 — module map + build order (platforms only)
36
+ YYYY-MM-DD-<topic>-inventory.json # wave mode, stage 0 — every open item by id, verified
37
+ YYYY-MM-DD-<topic>-canvas.md # wave mode, stages 2–3 — the target state over the current logic
36
38
  YYYY-MM-DD-<topic>-design.md # stage 3 — the spec / module dossier (locks shared contracts)
37
39
  YYYY-MM-DD-<topic>-acceptance.md # stage 10 — REQ coverage table + evidence
38
40
  plans/
@@ -170,6 +172,8 @@ them is a finding, not a tie-break ([`knowledge-sources.md`](knowledge-sources.m
170
172
  | 10 Board resolution | `<artifacts>/backlog.md` — every unresolved ledger row — homed `backlog` or still `open` — arrives with a real id, and the ledger row is updated to name it; priority re-derived ([`backlog.md`](backlog.md)) | the next run's harvest, and every loop iteration |
171
173
  | 10 Retro rotation | `<artifacts>/retro/YYYY-QN.md` — entries older than five stamps, plus every retirement, each with its commit | queried by a later run's harvest |
172
174
  | 2 Decompose | `specs/<topic>-modules.md` — module map, build order, contracts, per-module status (platforms only) | stages 3–10, every module's run |
175
+ | 0 Wave mode | `specs/<topic>-inventory.json` — every open item: id, source, status, area, node, wave, release ([`waves.md`](waves.md)) | stages 2–10, every wave's re-measure |
176
+ | 2–3 Wave mode | `specs/<topic>-canvas.md` — as-is → to-be per module and contract, the seams, REQ → module → wave, what is deleted | every wave, and each re-cut |
173
177
  | 3 Spec | `specs/<topic>-design.md` — module dossier for a decomposed platform (+ links `docs/ux/*` for UI) | stage 4 |
174
178
  | 4 Plan | `plans/<topic>.md` | stage 5 |
175
179
  | 3 UX track | `docs/ux/{foundation,flows,screens,scenarios}.md` | stages 4–9 + `/ux-lint` |
@@ -56,9 +56,12 @@ not a question to re-open from scratch.
56
56
  the platform's shape — the pieces, how they relate, what order they land in —
57
57
  not the details of one corner; those belong to each module's own stage-3
58
58
  dossier. Don't refine something that needs splitting first.
59
- 3. **Questions one at a time.** Never bundle. Multiple choice where it fits, open
60
- where it doesn't. Purpose, constraints, success criteria — anything the brief
61
- left at design level.
59
+ 3. **Questions in one batch, after the sources.** What the brief, the code and the
60
+ recorded decisions cannot answer goes in one message, ordered by dependency, each
61
+ with a recommendation; one at a time only where an answer reshapes the next
62
+ question or the operator asks ([`grill.md`](grill.md)). Multiple choice where it
63
+ fits, open where it doesn't. Purpose, constraints, success criteria — anything the
64
+ brief left at design level.
62
65
  4. **Propose 2–3 approaches with trade-offs**, lead with your recommendation and
63
66
  the reason for it. **YAGNI ruthlessly** — strip anything the task doesn't need
64
67
  from every option before presenting.
@@ -610,9 +610,9 @@ merge.
610
610
 
611
611
  If it returns findings, dispatch **ONE** fix subagent with the complete list — not
612
612
  one fixer per finding; per-finding fixers each rebuild context and re-run suites.
613
- Then exactly **one** scoped re-review of the fix wave. Adjudicate residuals as in
613
+ Then exactly **one** scoped re-review of the fix round. Adjudicate residuals as in
614
614
  the breaker: park with rulings, or stop on load-bearing ones. There is no second
615
- fix wave.
615
+ fix round.
616
616
 
617
617
  ## 6. Integrate, then finish
618
618
 
@@ -47,13 +47,21 @@ This spans the whole run, not one stage:
47
47
 
48
48
  - the plan's tasks at stage 5;
49
49
  - the boundary between stages whose gate is `auto`;
50
- - the per-module program loop when the brief was a platform;
50
+ - the per-module program loop when the brief was a platform, and the waves when
51
+ the request was the whole board ([`waves.md`](waves.md));
51
52
  - the acceptance → retro tail, which is where runs most often stall one step from
52
53
  finished.
53
54
 
54
55
  It stops for exactly four things: a `manual` gate, a block it cannot resolve, a
55
56
  genuine ambiguity the brief does not answer, and completion.
56
57
 
58
+ **A block or an ambiguity stops its node, not the run.** The node is parked with the
59
+ question as its reason, marked `needs-operator` and answerable without context
60
+ ([`prioritisation.md`](prioritisation.md) → *5. Where the human goes*), and the run
61
+ continues on every node it does not block. The run itself stops only when the whole
62
+ frontier is blocked — `graph.py next` exits `4` — and the questions are then asked
63
+ together. **When the board is empty, say so once**, and do not invent work to fill it.
64
+
57
65
  **This extends [`build.md`](build.md); it does not replace it.** That file's
58
66
  *Continuous execution* rule governs the inside of a stage-5 execution — do not
59
67
  check in between the tasks of a plan you were told to execute. It is unconditional
@@ -122,7 +130,9 @@ So at the bottom of an iteration, beside the re-derived `prio`:
122
130
  2. state whether the next item still serves it;
123
131
  3. if it does not, **re-order or re-scope the queue and say what moved and why.** A row
124
132
  that stops serving the goal leaves for the board with its reason
125
- ([`backlog.md`](backlog.md)), it does not get worked because it was next.
133
+ ([`backlog.md`](backlog.md)), it does not get worked because it was next. On a work
134
+ graph the move is a committed `revisions` entry — `park`, `add`, or `wave` between
135
+ waves — never an untracked edit.
126
136
 
127
137
  A queue re-derived only by `age` and `sev` is a queue that is honest about priority and
128
138
  silent about purpose. Both numbers can be right while the run is finishing something the
@@ -308,6 +318,12 @@ right costs nothing extra and pays twice.
308
318
 
309
319
  ## Part 3 — workflow memory at the stage boundary
310
320
 
321
+ Which of the five handoff mechanisms carries what — the Git record, Observatory's lease
322
+ and checkpoint, a host's launch context, the inbound queue — and the order a successor
323
+ reads them in, has one home:
324
+ [sshlg-skills `docs/working-rules/handoff-layers.md`](https://github.com/ssheleg/sshlg-skills/blob/main/docs/working-rules/handoff-layers.md).
325
+ This part is the checkpoint and lease half of it.
326
+
311
327
  The ledger survives a compaction. It does not survive a quota that ran out on another
312
328
  account, or a run picked up by a different agent on another machine. When the host has
313
329
  Project Observatory's memory tools, **every gate that returns also writes a workflow
@@ -318,6 +334,8 @@ checkpoint**, and the next executor continues from the last finished stage.
318
334
  - **The constraints.** Give the brief's restrictive rules once, as `--constraint`. They are carried to every later boundary, and a successor reads them first.
319
335
  - **Keys.** Pass keys by name, as `--credential PROJECT/ENV/NAME`, never as a value.
320
336
  - **Without the tools.** `stage_checkpoint.py record --unavailable "<why>"` appends one `event: memory — unavailable` line, and the run continues exactly as before. Missing memory is a state the ledger names, not a failure.
337
+ - **A planned change of executor** — a quota running out, a route moving the work to another model or account. `stage_checkpoint.py handoff --to-provider <p> [--to-model <m>] --reason limit|plan_route|operator` prints `observatory_handoff_create`'s arguments; `record --answer -` keeps the offer as one ledger line, and the lease stays with this run until the successor accepts. The successor runs `stage_checkpoint.py accept --handoff-id <id>` → `observatory_handoff_accept` → `record --answer -` **before its first write**, and obeys the constraints the answer carries first. `LeaseLost` is then left for the race nobody planned.
338
+ - **The reminder.** `hooks/memory-nudge.sh` (PostToolUse) reads the ledger after each tool call and, once per `stage:` line with no `event: memory` line after it, puts one sentence in front of the model naming the two commands above. It decides nothing and blocks nothing; adoption measured before it was one write in 293 sessions.
321
339
  - **A refusal.** `LeaseLost` means another executor holds the workflow now. The script drops the token. Read the workflow (`observatory_checkpoint_latest` with `stage_checkpoint.py state`'s id) before doing anything else. A stale writer stops after one refusal.
322
340
  - **The lease token.** It lives in `.task-pipeline/memory.json` (mode 0600, git-ignored) and never in the ledger, a reply or a commit.
323
341
  - **What this is not.** Not a second ledger and not the narrative. The checkpoint is the work's state for the next executor. The wiki and the ledger keep everything else.
@@ -137,6 +137,10 @@ Rules for the loop:
137
137
  lands, or build several and deploy once. Record it; don't decide it per module.
138
138
  - **Update the map's status column as each module closes**, in the same commit as
139
139
  that module's acceptance. The map is the resume point after a lost context.
140
+ - **The whole board is waves, not bricks** ([`waves.md`](waves.md)). When the request
141
+ is every open item rather than one platform, stages 0–2 still run once, the map
142
+ becomes the canvas, and the loop runs **one wave at a time**. A wave may hold several
143
+ bricks or nodes, provided they close together in one pass.
140
144
  - **Loop discipline:** a module re-entering the same stage a third time trips the
141
145
  loop guard ([`loop-guard.md`](loop-guard.md)) — stop, name the oscillation, and
142
146
  fix the layer that owns it instead of iterating.
@@ -163,6 +163,37 @@ gh run view <run-id> --log-failed # only the failed step's log
163
163
  or failed deploy is the most common way a run reports success while nothing
164
164
  shipped — and it is exactly what the stage-8 gate is for.
165
165
 
166
+ ### When the release waits for an approval
167
+
168
+ **Read the project's approval mode before tagging, and do not guess it.** It is one of
169
+ two, and each owes the operator something different.
170
+
171
+ - **`checks`** — a guard admits the release, with no person on the path. For example,
172
+ `release-guard` checks that the tag is on main and that CI on that commit is green,
173
+ and the `release` environment has no reviewers. PassionCode products declare this in
174
+ `passioncode-ai/.github` `release-signing/products.json` (`"approval": "checks"`).
175
+ Push the tag, watch the run selected **by the tag you pushed**, and report what was
176
+ published, or the guard's refusal and its cause. A refusal is fixed at its cause,
177
+ never worked around. Send no approval request: there is nobody to send it to.
178
+ - **`reviewers`** — the run stops at an environment with required reviewers. Find that
179
+ run by the tag, and confirm its status is `waiting` before saying anything:
180
+
181
+ ```bash
182
+ gh run list -w release.yml --json url,status,headBranch -L 5
183
+ ```
184
+
185
+ Then hand the operator the **direct link** to that run, where they press *Review
186
+ deployments*, together with the tag and the jobs that are waiting. A request without
187
+ the link is incomplete, and so is a link to a run that is not waiting.
188
+
189
+ The mode comes from, in order:
190
+ 1. `pipeline.json` → `release.approval`;
191
+ 2. an organisation declaration such as the file above;
192
+ 3. the environment's own protection rules
193
+ (`gh api repos/<owner>/<repo>/environments/release`).
194
+
195
+ A run that cannot establish the mode says so. It does not assume `checks`.
196
+
166
197
  ## Other platforms, quick verbs
167
198
 
168
199
  | Platform | Deploy | Verify |
@@ -27,6 +27,7 @@ UX track on a user-facing task.
27
27
  | 0 Intake grill | `references/grill.md` |
28
28
  | 2 Brainstorm | `references/brainstorm.md` |
29
29
  | 2 Decompose (platforms only) | `references/decomposition.md` |
30
+ | 0–10 · **wave mode** — the whole board: 0–4 once, 5–8 per wave, 9–10 to close | `references/waves.md` |
30
31
  | 3 Spec | `references/spec.md` |
31
32
  | 4 Plan | `references/planning.md` |
32
33
  | the queue the loop walks | `references/work-graph.md` |
@@ -63,16 +63,25 @@ not depend on it.
63
63
 
64
64
  Where material unknowns remain, interview the operator about THOSE until you
65
65
  reach a **shared understanding**. Walk down each unresolved branch of the
66
- decision tree, resolving dependencies between decisions one by one.
67
-
68
- 1. **One question per turn.** Never bundle. Wait for the answer before the next.
66
+ decision tree, resolving dependencies between decisions in order.
67
+
68
+ 1. **Close from the sources first, then ask ONE batch.** Every material unknown
69
+ the harvest, the code and the recorded decisions leave open goes into one
70
+ message, ordered by dependency, each with a recommended answer and what each
71
+ answer changes. **One question at a time only when the answers depend on each
72
+ other** — the next question cannot be written until this one is answered, and
73
+ then you go depth-first — **or when the operator asks for it.** Decided by the
74
+ operator on 2026-10-11: a question asked alone costs a human round, and a batch
75
+ costs one. [`prioritisation.md`](prioritisation.md) → *5. Where the human goes*
76
+ says the same about the rest of the run.
69
77
  2. **Recommend an answer with every question** (+ a one-line rationale). "What do
70
78
  you think?" is lazy — you have the codebase in front of you, they don't.
71
79
  3. **If the codebase can answer it, go read the codebase.** Spending the
72
80
  operator's turn on something `grep`/`Read`/context7 would have told you is the
73
81
  most common way to waste a grill.
74
- 4. **Depth-first.** Finish a branch before opening another; ask prerequisite
75
- decisions first, so later answers don't invalidate earlier ones.
82
+ 4. **Prerequisites first.** Order the batch so prerequisite decisions come before
83
+ the ones they shape; where an answer can invalidate a later question, ask the
84
+ prerequisite alone and go depth-first.
76
85
  5. **Reconcile contradictions immediately**, and chase dodges: "we'll decide
77
86
  later" → "what's the latest you can decide and still ship?"
78
87
  6. **Cover the autonomy sweep** (below). An unasked MATERIAL question is not
@@ -218,7 +218,9 @@ Since v1.50.0 the plugin carries hooks of its own. `hooks/release-gate.sh`
218
218
  (`PreToolUse` on `Bash`) refuses an **outward, irreversible act** — `git tag`, a
219
219
  tag push, `gh release create`, `npm publish` — while the run says the suite has not
220
220
  passed. `hooks/gate-observer.sh` (`PostToolUse` and `PostToolUseFailure`) records
221
- what the declared gate command actually did.
221
+ what the declared gate command actually did. `hooks/memory-nudge.sh` (`PostToolUse` on `Bash|Edit|Write|MultiEdit`) reminds,
222
+ once per returned gate, that no workflow-memory line follows it
223
+ ([`continuity.md`](continuity.md), Part 3).
222
224
 
223
225
  **Two lessons from v1.50.0, both shipped as defects and both fixed in v1.51.0.**
224
226
 
@@ -42,6 +42,7 @@ makes the grill's answers *checkable* instead of merely confident.
42
42
 
43
43
  | # | Source | How to find it | What it's good for |
44
44
  |---|---|---|---|
45
+ | 0 | **A host's launch context** | a session started by Fabric or Fabric Dashboards (`session-handoff/1`): the brief arrives appended to the system prompt, the task as the first prompt, and `context.md` is the cited context pack | the request in the words the operator gave the host — taken as the request, not re-asked; the context pack is a harvest source like any other and is cited by its section |
45
46
  | 1 | **The code** | the repo you're in | what actually runs — the tiebreaker |
46
47
  | 2 | **The code graph** | `graphify-out/graph.json` — see below | *reach*: what calls this, what breaks if it moves, what every change passes through |
47
48
  | 3 | **Host agent docs** | `CLAUDE.md`, `AGENTS.md`, `.cursor/rules/` | conventions, commands, deploy path, house rules |
@@ -112,6 +112,14 @@ which grows but never reorders a stage. Discovery that lands in a committed
112
112
  artifact is not a dynamic graph; discovery that changes what runs next, silently,
113
113
  is.
114
114
 
115
+ **Wave mode's re-cut is the same kind of discovery** ([`waves.md`](waves.md)). After
116
+ each wave the remaining waves are re-cut from the re-measured inventory, and every move
117
+ lands twice in committed form: a `revisions` entry in the work graph (`graph.py wave`,
118
+ which refuses a move that breaks the wave order) and the canvas edit that says why. The
119
+ stage list does not change and no stage is invented; what changes is which nodes the
120
+ next pass of stages 5–8 takes, and that is written down before the pass begins. So the
121
+ static-graph decision holds.
122
+
115
123
  ## Task right-sizing
116
124
 
117
125
  A task is the smallest unit that carries its own test cycle and is worth a fresh
@@ -71,6 +71,7 @@ a row pointing outside the bundle is the defect this file exists to catch.
71
71
  | What a stage reads, and which host files bind it | `references/artifacts.md` |
72
72
  | The design conversation, its hard gate, UI detection, user paths | `references/brainstorm.md` |
73
73
  | Cutting a platform into modules, brick criteria, build order | `references/decomposition.md` |
74
+ | **Wave mode** — the whole board: the inventory, the canvas, the one question batch, the wave cut and the close pass | `references/waves.md` |
74
75
  | What a spec must lock, the UX-track order, the module dossier | `references/spec.md` |
75
76
  | The zero-context plan format, parallel groups, set equality | `references/planning.md` |
76
77
  | The work graph: its fields, the verbs and their exit codes, and the three invariants a schema cannot state | `references/work-graph.md`, `scripts/graph.py`, `graph.schema.json` |
@@ -166,9 +166,10 @@ never that the work was skipped quietly.
166
166
  ([`progress.md`](progress.md)), and a skip nobody can see is indistinguishable from a
167
167
  stage that was never entered.
168
168
  - **How it runs: [`grill.md`](grill.md)** — the full doctrine, built into this
169
- skill (nothing to install). In short: one question per turn, a recommended
170
- answer with each, explore the codebase before asking, depth-first through the
171
- decision tree, contradictions reconciled on the spot; **every answer that touches
169
+ skill (nothing to install). In short: close what the sources can, then ONE batch
170
+ of the material unknowns, ordered by dependency, a recommended answer with each —
171
+ one at a time only where answers depend on each other or the operator asks;
172
+ contradictions reconciled on the spot; **every answer that touches
172
173
  a harvested source is checked against it** — the operator outranks any document,
173
174
  but only out loud, and the losing side is logged for the stage-9 doc update; plus
174
175
  **domain awareness**
@@ -267,9 +268,9 @@ never that the work was skipped quietly.
267
268
  - **Freedom: high** — many designs are valid — this is the open field, and the only fixed thing is the gate ([`gates.md`](gates.md) → *Axis C*).
268
269
  - **How it runs: [`brainstorm.md`](brainstorm.md)** — built into this skill. Read
269
270
  the brief first (stage 0 already answered scope/constraints/done-criteria), then
270
- explore the codebase, scope-check for decomposition, one question at a time, 2–3
271
- approaches with a recommendation, design presented in sections and approved
272
- section by section. **Hard gate:** no code, no scaffolding, no implementation
271
+ explore the codebase, scope-check for decomposition, the open questions in one
272
+ batch, 2–3 approaches with a recommendation, design presented in sections and
273
+ approved section by section. **Hard gate:** no code, no scaffolding, no implementation
273
274
  skill before the operator approves the design — including on "obviously simple"
274
275
  tasks.
275
276
  - **UI detection (mandatory check):** decide whether the task touches any
@@ -588,7 +589,11 @@ never that the work was skipped quietly.
588
589
  `partial` ships only with the operator's explicit acceptance. A gap is cheapest to
589
590
  close before it ships, and the operator is already present at this gate. **The
590
591
  carry-over count is printed beside this verdict.** Deploy is outward → explicit
591
- operator go. Respect deploy-from-main rules if the project mandates them. **Before
592
+ operator go — unless the operator already authorised releases. **Before the tag, read
593
+ the release's approval mode** (`pipeline.json` → `release.approval`; then
594
+ [`deploy-targets.md`](deploy-targets.md) → *When the release waits for an approval*):
595
+ `checks` — push the tag, watch the run selected by the tag, report; `reviewers` — the
596
+ direct link to the run that is actually `waiting`, never a request without it. Respect deploy-from-main rules if the project mandates them. **Before
592
597
  tagging, the CI verdict for what was just pushed is READ, not assumed**
593
598
  ([`conventions.md`](conventions.md) → *The CI verdict*) — a tag on a commit whose
594
599
  run nobody read is how a red `main` ships.
@@ -859,6 +864,9 @@ module N → 3 spec (dossier) → 4 plan → 5 build → 6 tests → 7 lint+depl
859
864
  - **Program done** when every row is `done` or `deferred` with an agreed home, the
860
865
  cross-module contracts are covered by tests that cross the seam, and a final
861
866
  acceptance covers the platform's whole REQ table — not module by module.
867
+ - **The whole board, rather than one platform, is wave mode**
868
+ ([`waves.md`](waves.md)): stages 0–4 once over every open item, 5–8 per wave with a
869
+ close pass after each, 9–10 to close the release.
862
870
 
863
871
  ## Cross-cutting — the Doc Loop
864
872