@ikon85/agent-workflow-kit 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/.agents/skills/ask-matt/SKILL.md +139 -0
  2. package/.agents/skills/ask-matt/THIRD-PARTY-NOTICES.md +29 -0
  3. package/.agents/skills/audit-skills/SKILL.md +145 -0
  4. package/.agents/skills/board-to-waves/SKILL.md +135 -0
  5. package/.agents/skills/code-review/SKILL.md +64 -0
  6. package/.agents/skills/codebase-design/DEEPENING.md +37 -0
  7. package/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  8. package/.agents/skills/codebase-design/SKILL.md +114 -0
  9. package/.agents/skills/codebase-design/THIRD-PARTY-NOTICES.md +29 -0
  10. package/.agents/skills/codex-adapter-sync/SKILL.md +151 -0
  11. package/.agents/skills/decision-gate/SKILL.md +67 -0
  12. package/.agents/skills/diagnose/SKILL.md +136 -0
  13. package/.agents/skills/diagnose/THIRD-PARTY-NOTICES.md +29 -0
  14. package/.agents/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
  15. package/.agents/skills/domain-modeling/ADR-FORMAT.md +47 -0
  16. package/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  17. package/.agents/skills/domain-modeling/SKILL.md +76 -0
  18. package/.agents/skills/domain-modeling/THIRD-PARTY-NOTICES.md +29 -0
  19. package/.agents/skills/git-worktree-recover/SKILL.md +176 -0
  20. package/.agents/skills/grill-me/SKILL.md +54 -0
  21. package/.agents/skills/grill-me/THIRD-PARTY-NOTICES.md +29 -0
  22. package/.agents/skills/grill-with-docs/ADR-FORMAT.md +47 -0
  23. package/.agents/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
  24. package/.agents/skills/grill-with-docs/SKILL.md +137 -0
  25. package/.agents/skills/grill-with-docs/THIRD-PARTY-NOTICES.md +29 -0
  26. package/.agents/skills/implement/SKILL.md +15 -0
  27. package/.agents/skills/implement/THIRD-PARTY-NOTICES.md +29 -0
  28. package/.agents/skills/improve-codebase-architecture/ADR-FORMAT.md +47 -0
  29. package/.agents/skills/improve-codebase-architecture/CONTEXT-FORMAT.md +60 -0
  30. package/.agents/skills/improve-codebase-architecture/DEEPENING.md +37 -0
  31. package/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  32. package/.agents/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +46 -0
  33. package/.agents/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
  34. package/.agents/skills/improve-codebase-architecture/SKILL.md +88 -0
  35. package/.agents/skills/improve-codebase-architecture/THIRD-PARTY-NOTICES.md +29 -0
  36. package/.agents/skills/kit-release/SKILL.md +56 -0
  37. package/.agents/skills/local-ci/SKILL.md +94 -0
  38. package/.agents/skills/orchestrate-wave/SKILL.md +261 -0
  39. package/.agents/skills/orchestrate-wave/references/builder-contract.md +67 -0
  40. package/.agents/skills/prototype/LOGIC.md +79 -0
  41. package/.agents/skills/prototype/SKILL.md +30 -0
  42. package/.agents/skills/prototype/THIRD-PARTY-NOTICES.md +29 -0
  43. package/.agents/skills/prototype/UI.md +112 -0
  44. package/.agents/skills/research/SKILL.md +12 -0
  45. package/.agents/skills/research/THIRD-PARTY-NOTICES.md +29 -0
  46. package/.agents/skills/resolving-merge-conflicts/SKILL.md +14 -0
  47. package/.agents/skills/resolving-merge-conflicts/THIRD-PARTY-NOTICES.md +29 -0
  48. package/.agents/skills/retro/SKILL.md +209 -0
  49. package/.agents/skills/scale-check/SKILL.md +141 -0
  50. package/.agents/skills/security-audit/SKILL.md +67 -0
  51. package/.agents/skills/setup-workflow/SKILL.md +187 -0
  52. package/.agents/skills/setup-workflow/THIRD-PARTY-NOTICES.md +29 -0
  53. package/.agents/skills/setup-workflow/board-sync.md +111 -0
  54. package/.agents/skills/setup-workflow/code-review.md +26 -0
  55. package/.agents/skills/setup-workflow/domain.md +51 -0
  56. package/.agents/skills/setup-workflow/issue-tracker-github.md +35 -0
  57. package/.agents/skills/setup-workflow/issue-tracker-gitlab.md +34 -0
  58. package/.agents/skills/setup-workflow/issue-tracker-local.md +30 -0
  59. package/.agents/skills/setup-workflow/orchestrate-wave-seed.md +44 -0
  60. package/.agents/skills/setup-workflow/spec-completeness-seed.md +44 -0
  61. package/.agents/skills/setup-workflow/spec-self-critique-seed.md +43 -0
  62. package/.agents/skills/setup-workflow/triage-labels.md +18 -0
  63. package/.agents/skills/setup-workflow/workflow-overview.md +33 -0
  64. package/.agents/skills/spec-self-critique/SKILL.md +152 -0
  65. package/.agents/skills/spec-self-critique/scenarios.md +82 -0
  66. package/.agents/skills/tdd/SKILL.md +120 -0
  67. package/.agents/skills/tdd/THIRD-PARTY-NOTICES.md +29 -0
  68. package/.agents/skills/tdd/deep-modules.md +33 -0
  69. package/.agents/skills/tdd/interface-design.md +31 -0
  70. package/.agents/skills/tdd/mocking.md +59 -0
  71. package/.agents/skills/tdd/refactoring.md +10 -0
  72. package/.agents/skills/tdd/tests.md +61 -0
  73. package/.agents/skills/to-issues/SKILL.md +325 -0
  74. package/.agents/skills/to-issues/THIRD-PARTY-NOTICES.md +29 -0
  75. package/.agents/skills/to-prd/PROGRAM-PRD-FORMAT.md +162 -0
  76. package/.agents/skills/to-prd/SKILL.md +180 -0
  77. package/.agents/skills/to-prd/THIRD-PARTY-NOTICES.md +29 -0
  78. package/.agents/skills/to-waves/SKILL.md +260 -0
  79. package/.agents/skills/to-waves/SLICE-METADATA-FORMAT.md +74 -0
  80. package/.agents/skills/triage/AGENT-BRIEF.md +168 -0
  81. package/.agents/skills/triage/OUT-OF-SCOPE.md +101 -0
  82. package/.agents/skills/triage/SKILL.md +122 -0
  83. package/.agents/skills/triage/THIRD-PARTY-NOTICES.md +29 -0
  84. package/.agents/skills/verify-spike/SKILL.md +39 -0
  85. package/.agents/skills/wayfinder/SKILL.md +127 -0
  86. package/.agents/skills/wayfinder/THIRD-PARTY-NOTICES.md +29 -0
  87. package/.agents/skills/wrapup/SKILL.md +71 -0
  88. package/.agents/skills/wrapup/SOURCES.txt +6 -0
  89. package/.agents/skills/zoom-out/SKILL.md +7 -0
  90. package/.agents/skills/zoom-out/THIRD-PARTY-NOTICES.md +29 -0
  91. package/.claude/hooks/_hook_utils.py +184 -0
  92. package/.claude/hooks/drift-guard.py +176 -0
  93. package/.claude/hooks/skill-drift-hint.py +122 -0
  94. package/.claude/hooks/sync-board-status.py +191 -0
  95. package/.claude/skills/ask-matt/SKILL.md +139 -0
  96. package/.claude/skills/ask-matt/THIRD-PARTY-NOTICES.md +29 -0
  97. package/.claude/skills/audit-skills/SKILL.md +145 -0
  98. package/.claude/skills/board-to-waves/SKILL.md +148 -0
  99. package/.claude/skills/code-review/SKILL.md +64 -0
  100. package/.claude/skills/codebase-design/DEEPENING.md +37 -0
  101. package/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  102. package/.claude/skills/codebase-design/SKILL.md +114 -0
  103. package/.claude/skills/codebase-design/THIRD-PARTY-NOTICES.md +29 -0
  104. package/.claude/skills/codex-build/SKILL.md +126 -0
  105. package/.claude/skills/codex-build/THIRD-PARTY-NOTICES.md +35 -0
  106. package/.claude/skills/codex-review/SKILL.md +145 -0
  107. package/.claude/skills/codex-review/THIRD-PARTY-NOTICES.md +31 -0
  108. package/.claude/skills/decision-gate/SKILL.md +67 -0
  109. package/.claude/skills/diagnose/SKILL.md +136 -0
  110. package/.claude/skills/diagnose/THIRD-PARTY-NOTICES.md +29 -0
  111. package/.claude/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
  112. package/.claude/skills/domain-modeling/ADR-FORMAT.md +47 -0
  113. package/.claude/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  114. package/.claude/skills/domain-modeling/SKILL.md +76 -0
  115. package/.claude/skills/domain-modeling/THIRD-PARTY-NOTICES.md +29 -0
  116. package/.claude/skills/git-guardrails-claude-code/SKILL.md +96 -0
  117. package/.claude/skills/git-guardrails-claude-code/THIRD-PARTY-NOTICES.md +29 -0
  118. package/.claude/skills/git-guardrails-claude-code/scripts/block-dangerous-git.sh +28 -0
  119. package/.claude/skills/git-worktree-recover/SKILL.md +182 -0
  120. package/.claude/skills/grill-me/SKILL.md +54 -0
  121. package/.claude/skills/grill-me/THIRD-PARTY-NOTICES.md +29 -0
  122. package/.claude/skills/grill-me-codex/SKILL.md +158 -0
  123. package/.claude/skills/grill-me-codex/THIRD-PARTY-NOTICES.md +32 -0
  124. package/.claude/skills/grill-with-docs/ADR-FORMAT.md +47 -0
  125. package/.claude/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
  126. package/.claude/skills/grill-with-docs/SKILL.md +137 -0
  127. package/.claude/skills/grill-with-docs/THIRD-PARTY-NOTICES.md +29 -0
  128. package/.claude/skills/grill-with-docs-codex/ADR-FORMAT.md +47 -0
  129. package/.claude/skills/grill-with-docs-codex/CONTEXT-FORMAT.md +60 -0
  130. package/.claude/skills/grill-with-docs-codex/SKILL.md +233 -0
  131. package/.claude/skills/grill-with-docs-codex/THIRD-PARTY-NOTICES.md +33 -0
  132. package/.claude/skills/implement/SKILL.md +15 -0
  133. package/.claude/skills/implement/THIRD-PARTY-NOTICES.md +29 -0
  134. package/.claude/skills/improve-codebase-architecture/ADR-FORMAT.md +47 -0
  135. package/.claude/skills/improve-codebase-architecture/CONTEXT-FORMAT.md +60 -0
  136. package/.claude/skills/improve-codebase-architecture/DEEPENING.md +37 -0
  137. package/.claude/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  138. package/.claude/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +46 -0
  139. package/.claude/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
  140. package/.claude/skills/improve-codebase-architecture/SKILL.md +88 -0
  141. package/.claude/skills/improve-codebase-architecture/THIRD-PARTY-NOTICES.md +29 -0
  142. package/.claude/skills/kit-release/SKILL.md +56 -0
  143. package/.claude/skills/local-ci/SKILL.md +94 -0
  144. package/.claude/skills/orchestrate-wave/SKILL.md +269 -0
  145. package/.claude/skills/orchestrate-wave/references/builder-contract.md +67 -0
  146. package/.claude/skills/prototype/LOGIC.md +79 -0
  147. package/.claude/skills/prototype/SKILL.md +30 -0
  148. package/.claude/skills/prototype/THIRD-PARTY-NOTICES.md +29 -0
  149. package/.claude/skills/prototype/UI.md +112 -0
  150. package/.claude/skills/research/SKILL.md +12 -0
  151. package/.claude/skills/research/THIRD-PARTY-NOTICES.md +29 -0
  152. package/.claude/skills/resolving-merge-conflicts/SKILL.md +14 -0
  153. package/.claude/skills/resolving-merge-conflicts/THIRD-PARTY-NOTICES.md +29 -0
  154. package/.claude/skills/retro/SKILL.md +209 -0
  155. package/.claude/skills/scale-check/SKILL.md +141 -0
  156. package/.claude/skills/security-audit/SKILL.md +67 -0
  157. package/.claude/skills/setup-pre-commit/SKILL.md +104 -0
  158. package/.claude/skills/setup-pre-commit/scripts/pre-commit.template.sh +35 -0
  159. package/.claude/skills/setup-workflow/SKILL.md +187 -0
  160. package/.claude/skills/setup-workflow/THIRD-PARTY-NOTICES.md +29 -0
  161. package/.claude/skills/setup-workflow/board-sync.md +111 -0
  162. package/.claude/skills/setup-workflow/code-review.md +26 -0
  163. package/.claude/skills/setup-workflow/domain.md +51 -0
  164. package/.claude/skills/setup-workflow/issue-tracker-github.md +35 -0
  165. package/.claude/skills/setup-workflow/issue-tracker-gitlab.md +34 -0
  166. package/.claude/skills/setup-workflow/issue-tracker-local.md +30 -0
  167. package/.claude/skills/setup-workflow/orchestrate-wave-seed.md +44 -0
  168. package/.claude/skills/setup-workflow/spec-completeness-seed.md +44 -0
  169. package/.claude/skills/setup-workflow/spec-self-critique-seed.md +43 -0
  170. package/.claude/skills/setup-workflow/triage-labels.md +18 -0
  171. package/.claude/skills/setup-workflow/workflow-overview.md +33 -0
  172. package/.claude/skills/skill-manifest.json +389 -0
  173. package/.claude/skills/spec-self-critique/SKILL.md +152 -0
  174. package/.claude/skills/spec-self-critique/scenarios.md +82 -0
  175. package/.claude/skills/tdd/SKILL.md +120 -0
  176. package/.claude/skills/tdd/THIRD-PARTY-NOTICES.md +29 -0
  177. package/.claude/skills/tdd/deep-modules.md +33 -0
  178. package/.claude/skills/tdd/interface-design.md +31 -0
  179. package/.claude/skills/tdd/mocking.md +59 -0
  180. package/.claude/skills/tdd/refactoring.md +10 -0
  181. package/.claude/skills/tdd/tests.md +61 -0
  182. package/.claude/skills/to-issues/SKILL.md +325 -0
  183. package/.claude/skills/to-issues/THIRD-PARTY-NOTICES.md +29 -0
  184. package/.claude/skills/to-prd/PROGRAM-PRD-FORMAT.md +162 -0
  185. package/.claude/skills/to-prd/SKILL.md +180 -0
  186. package/.claude/skills/to-prd/THIRD-PARTY-NOTICES.md +29 -0
  187. package/.claude/skills/to-waves/SKILL.md +260 -0
  188. package/.claude/skills/to-waves/SLICE-METADATA-FORMAT.md +74 -0
  189. package/.claude/skills/triage/AGENT-BRIEF.md +168 -0
  190. package/.claude/skills/triage/OUT-OF-SCOPE.md +101 -0
  191. package/.claude/skills/triage/SKILL.md +122 -0
  192. package/.claude/skills/triage/THIRD-PARTY-NOTICES.md +29 -0
  193. package/.claude/skills/verify-spike/SKILL.md +39 -0
  194. package/.claude/skills/wayfinder/SKILL.md +127 -0
  195. package/.claude/skills/wayfinder/THIRD-PARTY-NOTICES.md +29 -0
  196. package/.claude/skills/wrapup/SKILL.md +81 -0
  197. package/.claude/skills/wrapup/SOURCES.txt +6 -0
  198. package/.claude/skills/write-a-skill/GLOSSARY.md +201 -0
  199. package/.claude/skills/write-a-skill/SKILL.md +88 -0
  200. package/.claude/skills/write-a-skill/THIRD-PARTY-NOTICES.md +29 -0
  201. package/.claude/skills/zoom-out/SKILL.md +7 -0
  202. package/.claude/skills/zoom-out/THIRD-PARTY-NOTICES.md +29 -0
  203. package/LICENSE +28 -0
  204. package/PROVENANCE.md +39 -0
  205. package/README.md +619 -0
  206. package/agent-workflow-kit.package.json +1939 -0
  207. package/docs/agents/board-sync.md +71 -0
  208. package/docs/agents/code-review.md +14 -0
  209. package/docs/agents/domain.md +7 -0
  210. package/docs/agents/issue-tracker.md +12 -0
  211. package/docs/agents/security-audit-runbook-template.md +205 -0
  212. package/docs/agents/skills/orchestrate-wave.md +13 -0
  213. package/docs/agents/skills/spec-self-critique.md +18 -0
  214. package/docs/agents/triage-labels.md +10 -0
  215. package/docs/agents/wave-anchor-template.md +88 -0
  216. package/docs/conventions/spec-completeness.md +23 -0
  217. package/docs/index.html +56 -0
  218. package/docs/methodology.html +488 -0
  219. package/docs/methodology.svg +93 -0
  220. package/docs/workflow.png +0 -0
  221. package/package.json +40 -0
  222. package/scripts/anchor_table.py +343 -0
  223. package/scripts/board-sync.py +1232 -0
  224. package/scripts/board_config.py +147 -0
  225. package/scripts/board_fields.py +192 -0
  226. package/scripts/build-kit.mjs +116 -0
  227. package/scripts/build-kit.test.mjs +59 -0
  228. package/scripts/check-kit-staleness.mjs +45 -0
  229. package/scripts/check-kit-staleness.test.mjs +19 -0
  230. package/scripts/execute-ready-check.py +516 -0
  231. package/scripts/issue_deps.py +79 -0
  232. package/scripts/kit-release.mjs +100 -0
  233. package/scripts/kit-release.test.mjs +67 -0
  234. package/scripts/lib/audit-refs.mjs +146 -0
  235. package/scripts/lib/scrub.mjs +113 -0
  236. package/scripts/lib/scrub.test.mjs +187 -0
  237. package/scripts/loc_offender_core.py +196 -0
  238. package/scripts/loc_offender_gate.py +182 -0
  239. package/scripts/node_kind.py +68 -0
  240. package/scripts/portability_profile_scan.py +53 -0
  241. package/scripts/pr-body-check.py +263 -0
  242. package/scripts/program_graph.py +125 -0
  243. package/scripts/program_graph_parse.py +275 -0
  244. package/scripts/program_graph_validate.py +256 -0
  245. package/scripts/program_sync.py +160 -0
  246. package/scripts/release-delta-guard.mjs +96 -0
  247. package/scripts/release-delta-guard.test.mjs +53 -0
  248. package/scripts/test_board_sync_create_idempotency.py +104 -0
  249. package/scripts/test_dist_kit_smoke.py +199 -0
  250. package/scripts/test_kit_docs_language_census.py +178 -0
  251. package/scripts/test_skill_code_review_seed.py +89 -0
  252. package/scripts/test_skill_frontmatter_lint.py +226 -0
  253. package/scripts/test_skill_gh_lint.py +124 -0
  254. package/scripts/test_skill_language_census.py +254 -0
  255. package/scripts/test_skill_portability_lint.py +773 -0
  256. package/scripts/test_skill_publish_audit.py +300 -0
  257. package/scripts/test_skill_selfcontainment_lint.py +255 -0
  258. package/scripts/test_skill_setup_workflow_seeds.py +200 -0
  259. package/scripts/test_skill_stale_name_lint.py +126 -0
  260. package/scripts/test_skill_surface_refs.py +300 -0
  261. package/scripts/test_skill_trailing_artifact_lint.py +71 -0
  262. package/scripts/wrapup-land.py +573 -0
  263. package/src/cli.mjs +70 -0
  264. package/src/commands/diff.mjs +6 -0
  265. package/src/commands/init.mjs +59 -0
  266. package/src/commands/uninstall.mjs +43 -0
  267. package/src/commands/update.mjs +95 -0
  268. package/src/lib/atomicWrite.mjs +49 -0
  269. package/src/lib/bundle.mjs +133 -0
  270. package/src/lib/hash.mjs +13 -0
  271. package/src/lib/manifest.mjs +58 -0
  272. package/src/lib/sentinel.mjs +20 -0
  273. package/src/lib/settings.mjs +23 -0
@@ -0,0 +1,325 @@
1
+ ---
2
+ name: to-issues
3
+ description: "Break a plan, spec, or PRD into independently-grabbable issues on the project issue tracker using tracer-bullet vertical slices. Use when user wants to convert a plan into issues, create implementation tickets, or break down work into issues."
4
+ ---
5
+
6
+ # To Issues
7
+
8
+ > **Skill identity (don't get confused):** the folder `to-issues` + invocation `/to-issues` map to Matt Pocock's upstream skill **`to-tickets`**. Upstream merged `to-issues` + the short-lived `to-plan` into `to-tickets` (v1.1.0); we deliberately keep the folder name `to-issues` (invocation stability, and issues are this workflow's vocabulary). Content remains our fork, compared against upstream `to-tickets` @ `d574778`. Provenance/rename ledger: `docs/agents/provenance.md` (§Re-Sync-Log), at the project root.
9
+
10
+ Break a plan into independently-grabbable issues using vertical slices (tracer bullets).
11
+
12
+ The issue tracker and triage label vocabulary should have been provided to you — run `/setup-workflow` if not.
13
+
14
+ ## Process
15
+
16
+ ### 1. Gather context
17
+
18
+ Work from whatever is already in the conversation context. If the user passes an issue reference (issue number, URL, or path) as an argument, fetch it from the issue tracker and read its full body and comments.
19
+
20
+ ### 2. Explore the codebase (optional)
21
+
22
+ If you have not already explored the codebase, do so to understand the current state of the code. Issue titles and descriptions should use the project's domain glossary vocabulary, and respect ADRs in the area you're touching.
23
+
24
+ ### 3. Draft vertical slices
25
+
26
+ Break the plan into **tracer bullet** issues. Each issue is a thin vertical slice that cuts through ALL integration layers end-to-end, NOT a horizontal slice of one layer.
27
+
28
+ Slices may be 'HITL' or 'AFK'. HITL slices require human interaction, such as an architectural decision or a design review. AFK slices can be implemented and merged without human interaction. Prefer AFK over HITL where possible.
29
+
30
+ <vertical-slice-rules>
31
+ - Each slice delivers a narrow but COMPLETE path through every layer (schema, API, UI, tests)
32
+ - A completed slice is demoable or verifiable on its own
33
+ - Prefer many thin slices over few thick ones
34
+ - Title each user-facing slice as an OUTCOME ("<user action> → <visible result>"), never as a layer ("Config UI", "Backend resolver"). A layer-only title hides whether the full vertical is covered.
35
+ - A slice MAY be a deliberate PREP / byte-neutral slice (refactor, infra, schema seed) that is NOT end-to-end — but then it MUST name which user-facing half it defers AND which later slice closes it. A deferred half with no named closing slice is a gap: the connective path becomes owned by no slice.
36
+ - **Seam ownership (Fix A):** a PRD decision that **replaces / unifies / retires a central mechanism** ("replaces the X special-path", "unifies Y", "retires Z") MUST become its **own slice**, marked 🧊 **grill-needed** (HITL) — **never** folded implicitly into a behavior-preserving naming/tweak leaf. A behavior-preserving slice (byte-neutral, seed-preserving) does **NOT** discharge a seam replacement. Sister rule to "new architecture layer = first-class slice" (CLAUDE.md ## Workflow). *(Incident: a central seam hid inside a "naming" leaf of a broadly-grilled epic → a full re-plan at a leaf.)*
37
+ </vertical-slice-rules>
38
+
39
+ **Wide refactors are the exception to vertical slicing.** A **wide refactor** is one mechanical change — rename a DB column, retype a shared symbol, move a helper — whose **blast radius** fans across the whole tree, so a single edit breaks call sites everywhere at once and no vertical slice can land green. Don't force it into a tracer bullet; sequence it as **expand → contract**. An expand→contract sequence is inherently **≥2 slices → PROMOTE to a wave anchor** (§5), never one atomic leaf:
40
+
41
+ - **Expand** (first slice, blocks all the rest) — add the new form beside the old so nothing breaks yet; both coexist.
42
+ - **Migrate** (one slice per batch, sized by blast radius — per package, per directory) — move the call sites onto the new form, each batch **blocked by** the expand slice. CI stays green batch to batch because the old form still exists. Each migrate-batch PR says **`Part of #<anchor>`, never `closes`** (Backlog-Workflow) — a `closes` would shut the anchor before the sequence finished.
43
+ - **Contract** (final slice, **blocked by every migrate batch**) — delete the old form once no caller remains.
44
+
45
+ When even a single batch can't stay green on its own, keep the sequence but let the batches share an **integration branch** that they all block, feeding a final **integrate-and-verify** slice — green is promised only there, and that final slice's PR is the one that merges the branch. The migrate batches are precisely how a wide refactor answers the §3b **blast-radius threshold**: the batch boundaries ARE the split. A batch that still lands deliberately large records its "why indivisible" one-liner in the issue body per §3b — a mechanical migrate batch stays AFK (`ready-for-agent`), it is not made HITL just for its file count.
46
+
47
+ ### 3b. Verify slice completeness (gate — do NOT skip on a pre-cut table)
48
+
49
+ Even when the slices were already cut upstream (a grill/PRD slice table), do NOT rubber-stamp them — re-derive and verify. Check each slice against your project's spec conventions — from the project root, `docs/conventions/spec-completeness.md` §Vertical-Slice-Completeness (if absent → `/setup-workflow`):
50
+
51
+ - Every user-facing slice is a tracer-bullet outcome sentence, not a layer name.
52
+ - Every byte-neutral/prep slice names its deferred half + the slice that closes it.
53
+ - For the FIRST outcome slice after any prep slices, trace one concrete value through ALL layers against the code (`grep`/Read) — do not trust an abstraction like "config-driven resolver replaces the FIELD_MAPs". A missing layer = carve a new slice BEFORE publishing.
54
+ - **Seam ownership check (Fix A):** does any slice **replace/unify/retire a central mechanism**? If yes, it MUST be its own 🧊 grill-needed slice — NOT hidden in a behavior-preserving naming/tweak leaf. A byte-neutral slice does not discharge the seam.
55
+ - **Blast-radius threshold:** for each slice, estimate the blast radius (~N files, from recon/grep — not a guess; workflow slices count SKILL.md + adapter mirrors + tests). **≥ 10 estimated files OR not estimable → check for a split.** If the slice stays deliberately large, it MUST be 🧊 **grill-needed** (HITL) with a "why indivisible" justification **in the issue body** — a guideline, not a hard block, but the deviation lives in the body, not in the agent's head. (Incident: a slice cut too coarse ballooned to 34 prod files at execute-recon, an emergency in-build split — no gate at the cut existed.) (Terminology note: this blast radius is a **slice estimate** — ~N files for this one cut — not a project-owned rollout-completeness census (e.g. an-style, code-derived "X of Y" census over all surfaces of a cross-cutting concept, if your repo runs one).)
56
+ <!-- mirror-xform:start codex-escalation -->
57
+ - **Gate type + sequencing (Retro):** every slice that is **not** a clean AFK build gets a gate tag — 🧭 **Design Grill** (a decision with alternatives, hard-to-reverse, ADR-worthy → `grill-with-docs`), 🔬 **Verify Spike** (a pure fact question, read-only), 📐 **Trade-off/Research** (a concrete trade-off choice OR "needs more research", **below** the grill threshold — read-only research + a documented trade-off in the issue), 📝 **Review Note** (a finding, **not** a build slice). A gate slice (🧭/🔬/📐) is cut as its **own slice**, sequenced **before** its dependent build slice, and blocks it (gate-before-build — published as a **native blocking edge** (§5a step 5), visible in the mirrored "Blocked by" section + table order). "Needs a decision / open call / research gap" while cutting → gate slice, **never** a blind AFK `/tdd`. (🔬 **Verify Spike** runs via the `verify-spike` skill — read-only fact question, throwaway harness, verdict as ADR/comment, the throwaway deleted. 📐 **Trade-off/Research** runs via the `decision-gate` skill — options + criteria, read-only research/measurement, a documented trade-off table, a reasoned decision as ADR/comment; throwaway measurement code deleted.)
58
+ <!-- mirror-xform:end -->
59
+ - **🧭-vs.-📐 discriminator:** if the decision replaces/unifies/retires a **central seam**, is a **one-way door** (hard/costly to reverse), or a **schema migration** → 🧭 Design Grill (ADR-worthy, see Seam Ownership above). Otherwise — a **bounded choice between concrete options**, easily revised → 📐 Trade-off/Research.
60
+ - **Absence-before-build (Retro):** a slice cut as "build feature/page/endpoint/flow X" (or a gate "X gap unclear") MUST cite an **existence grep** — *absent* (`grep <pattern> = 0` across route **and** UI **and** repo) OR *partial* (`exists @<file>, gap = <Y>`). A hedge ("current state unclear → verify during build") is **not** a valid slice state: the check is cheap (minutes), so it happens **at the cut**, not deferred into a gate. (Incident: a gate was cut for a feature that greps already showed built — the gap was deferred instead of resolved.)
61
+ - **Gate discipline:** a 🔬/📐 gate is only legitimate **after** the cheap read-only check fails to resolve it — the gate slice states one line "why the check wasn't enough". A gate is not a parking lot for recon that never ran.
62
+
63
+ - **`## Offene Punkte` from the source → downstream HITL:** if the source artefact (e.g. a `to-prd` PRD with non-derivable sections) carries a non-empty **`## Offene Punkte`** section, `to-issues` **must** either **stop + ask** OR publish the affected slice(s)/leaf as **HITL** with the `headings.vorBau` heading (§5c) — the open questions never disappear silently (a Draft-PRD itself has no bucket; that only lives on the child/leaf, §5c).
64
+
65
+ The table is only "done" when every user-facing row passes the trace. **Incident:** a custom-field read-path fell between a byte-neutral resolver slice and a "UI" slice — owned by neither, caught a slice too late.
66
+
67
+ #### 3b variant for workflow/skill-doc slices (no schema/API/UI)
68
+
69
+ When the slices change **workflow markdown** (skills, hooks, conventions) instead of app code, the schema→API→UI layers don't exist — but the gate does NOT get weaker. Map the trace onto the four layers a workflow behavior actually has:
70
+
71
+ 1. **Contract prose** — the `SKILL.md`/convention rule that prescribes the behavior.
72
+ 2. **Mechanism** — the command/hook/helper that *enforces* it (e.g. `scripts/board-sync.py`, a lint fixture, a hook). If a behavior genuinely has no machinery, write the explicit notation **`Mechanism: n/a because <reason>`** — never silently omit it.
73
+ 3. **Test/fixture** — *if your repo runs a test layer for workflow scripts* (e.g. `scripts/test_*.py`): the test that proves it. Otherwise the explicit notation **`Test: n/a because <reason>`** (e.g. no script-test harness in the consumer repo) — never silently omit it.
74
+ 4. **Adapter mirror** — *if your skill is dual-surface* (Claude + Codex): the `.agents/skills/…` copy, kept via `codex-adapter-sync`. Otherwise the explicit notation **`Mirror: n/a because project-private / single-surface`**.
75
+
76
+ Trace ONE concrete behavior (e.g. "a HITL child never carries `ready-for-agent`") through all four: prose says it → helper guard rejects it → test asserts the rejection → mirror carries the same prose. A missing layer = carve a slice before publishing; an `n/a` layer (3/4) is a deliberate, named exemption, not a gap. *(This trace is checklist discipline in prose; mechanically enforced are only the Test/Mirror **existence** via lint — not the full four-layer trace, and never for a layer marked `n/a`.)*
77
+
78
+ ### 4. Quiz the user
79
+
80
+ Present the proposed breakdown as a numbered list. For each slice, show:
81
+
82
+ - **Title**: short descriptive name
83
+ - **Type**: HITL / AFK
84
+ <!-- mirror-xform:start codex-escalation -->
85
+ - **Gate**: `—` (clean AFK build) · 🧭 Design Grill (`grill-with-docs`, ADR-worthy) · 🔬 Verify Spike (read-only fact question) · 📐 Trade-off/Research (trade-off choice OR research below the grill threshold, read-only + documented trade-off) · 📝 Review Note (not a build slice). A gate slice (🧭/🔬/📐) is placed **before** its dependent build slice (gate-before-build) + blocks it.
86
+ <!-- mirror-xform:end -->
87
+ - **🧭-vs.-📐:** central seam / one-way door / schema migration → 🧭; a bounded choice between concrete options → 📐 (criterion: §3b).
88
+ - **Blast-Radius**: ~N estimated files (from recon/grep, not a guess — workflow slices count SKILL.md + adapter mirrors + tests). Flags the §3b threshold at the cut.
89
+ - **Blocked by**: which other slices (if any) must complete first
90
+ - **User stories covered**: which user stories this addresses (if the source material has them)
91
+
92
+ Ask the user:
93
+
94
+ - Does the granularity feel right? (too coarse / too fine)
95
+ - Are the dependency relationships correct?
96
+ - Should any slices be merged or split further?
97
+ - Are the correct slices marked as HITL and AFK?
98
+
99
+ Iterate until the user approves the breakdown.
100
+
101
+ ### 5. Publish — promote-or-atomic (contract)
102
+
103
+ **Cluster/Wave discriminator (identical wording — `to-prd` §2 / `to-issues` §5):** `type:cluster` (label) always stops. A Wave number also stops, **unless** the target carries the `wave-stub` label — a Wave-stamped `wave-stub` issue is a **Stufe-1p Program-stub** (`to-waves`-published, native parent = a Program-PRD) and remains a **valid target**. A Wave-stamped issue **without** `wave-stub` (an already-assigned leaf, or a drifted item) is still a hard stop.
104
+
105
+ The canonical source is a **Draft-PRD** issue from `to-prd` (carries `plan_revision`, `<!-- prd: awaiting-decomposition -->`, exactly one `type:*` + one `priority:*`, **no** `type:cluster`, and no Wave **unless** the discriminator's `wave-stub` exception applies — a Program-stub's per-wave-start content pass writes this same shape into an already Wave-stamped stub, `to-prd` §2). But `to-issues` is **provenance-independent**: it re-derives readiness from the **artefact** (§3b), never from which tool produced it.
106
+
107
+ **Cold entry on an already-existing issue.** The source can also be a **raw issue**, an **external PRD embedded in an issue**, or a **mechanical file bundle** — without the `to-prd` markers. Then a **cold-entry preflight applies before anything is mutated:**
108
+ - **Hard-stop per the discriminator above** — `type:cluster` always; Wave only when the issue is **not** a `wave-stub` (the exception is already an intended promote target — `promote` reuses its pre-stamped Wave number, §5a below).
109
+ - **Normalize labels** (mirroring `to-prd`'s normalization): exactly **one `type:*` + one `priority:*`**; `needs-info`/`ready-for-agent` **stripped** until the final bucket assignment (§5c).
110
+ - **Synthesize missing `to-prd` markers in place** (never assume them): `plan_revision r1` at the body head, render the Tier-2 anchor body from the template. Surface `source`/`synthesized` in the §7 audit.
111
+ - **§4 user approval also applies here** — the synthesized slice table is shown + iterated, **never** published silently (see §4).
112
+
113
+ How it is published depends on the decomposition test (applies to **every** source):
114
+
115
+ - **≥2 independently mergeable slices → PROMOTE.** The source issue *becomes the anchor*.
116
+ - **exactly 1 slice → ATOMIC.** The source issue *stays a leaf*; the single PR `closes` it. *(A mechanical bundle with only one sensible slice does **not** become an anchor.)*
117
+
118
+ **`wave-stub` strip is automatic — no manual edit.** If the source was a `board-to-waves` candidate stub (`label:wave-stub`), **both** publish mechanics remove the label idempotently: `promote` (§5a) **and** `add --bucket` (§5b atomic). This takes it off the "awaiting planning" list (`is:open label:wave-stub`), regardless of whether it becomes a wave or an atomic leaf. Never help it along with a bare `gh issue edit --remove-label wave-stub` — the helper is the only label writer (see box below).
119
+
120
+ **Lane D — mechanical bundle (file list/refactor).** It may **skip** the domain grill — **only** if: blast radius is *estimable* **and** `<10 files` **and** *no* seam is replaced (§3b Seam Ownership/Blast Radius still apply). Otherwise → **HITL** with the `headings.vorBau` heading (structural questions / why-indivisible), as §3b/§5c require. No `headings.vorBau` heading needed if nothing is open.
121
+
122
+ **All board writes go through `scripts/board-sync.py` only** — never a bare `gh issue create`/`project item-add`/`item-edit`/`addSubIssue`, and never a workflow-state label edit (`gh issue edit --add-label ready-for-agent|needs-info|type:cluster`). The helper owns the one-parent-check, preview header, field IDs, and the HITL guard.
123
+
124
+ #### 5a. PROMOTE (≥2 slices)
125
+
126
+ ```bash
127
+ # 1. allocate the Wave number — needed for BOTH title + body render. An ordinary
128
+ # board-to-waves stub (Stufe 1, cluster/Wave-less) gets a FRESH one; a Stufe-1p
129
+ # Program-stub was already stamped with one by to-waves at publish — reuse
130
+ # it, never re-allocate (promote's mismatch guard refuses a DIFFERENT number):
131
+ CURRENT=$(python3 scripts/board-sync.py field-value --issue <prd#> --field wave)
132
+ if [ "$CURRENT" = "unset" ]; then
133
+ WAVE=$(python3 scripts/board-sync.py next-wave) # Stufe-1 stub — allocate fresh
134
+ else
135
+ WAVE="$CURRENT" # Stufe-1p Program-stub — reuse
136
+ fi
137
+
138
+ # 2. render the LEAN Tier-2 anchor body from docs/agents/wave-anchor-template.md into /tmp/anchor.md:
139
+ # body header `**Welle $WAVE — <Thema>**`, **plan_revision:** r<N> at top (before the first
140
+ # heading), the FILLED Slices table (you know the cut), the To-Do checklist collapsed to its
141
+ # one-line summary. The full grilled PRD does NOT go into the body (: every slice
142
+ # session's `--json body` read loads the whole body — a <details> block collapses only in
143
+ # the browser). Save it to /tmp/prd-archive.md instead — **with ALL embedded PRD markers
144
+ # stripped** (`plan_revision`, `prd-source-id`, `prd-content-fp`,
145
+ # `<!-- prd: awaiting-decomposition -->`; a stray second `plan_revision` on the issue is
146
+ # exactly the Retro confusion) — posted as ISSUE COMMENT #1 in step 2b.
147
+ # The anchor carries its own markers at the head. The issue TITLE is rewritten to
148
+ # `Welle N — <Thema>` by the promote step below (step 3) — do NOT set it here; promote
149
+ # prepends the wave prefix (and strips any `fix:`/`feat:` prefix) idempotently.
150
+ # Rewrite the PRD body via skill-prose gh (body-fill is issue CONTENT, NOT a board write — the
151
+ # helper owns board state only; cf. test_plan_body_fill_is_not_a_board_sync_op; gh-lint allows a
152
+ # non-workflow-label `gh issue edit`). Content-edit FIRST so a failure stops before board mutation:
153
+ gh issue edit <prd#> --body-file /tmp/anchor.md
154
+
155
+ # 2b. archive the full PRD as comment #1 on the anchor: one click away for a human,
156
+ # loaded only on demand by an agent (`--json body` never fetches comments). First line:
157
+ # `📄 Full PRD (archive, r<N>) — the body carries navigation/decisions only`.
158
+ # Idempotent re-run: a comment already starting with `📄 Full PRD (archive` → skip, never duplicate:
159
+ gh issue comment <prd#> --body-file /tmp/prd-archive.md
160
+
161
+ # 3. set the board state (type:cluster + Wave). If THIS fails AFTER the body edit, the title/body are
162
+ # already rewritten → STOP, report "board state incomplete (body/title already changed)", and
163
+ # re-run the idempotent promote (do not leave a silent partial state):
164
+ python3 scripts/board-sync.py promote --issue <prd#> --wave "$WAVE" # sets type:cluster + Wave + title `Welle N — …`
165
+
166
+ # 4. create each child (dependency order), then link it under the anchor — BEFORE the §7 exit audit,
167
+ # so the checker sees the anchor's children (a childless type:cluster anchor mis-reads as a leaf)
168
+ python3 scripts/board-sync.py create --title "Welle $WAVE / Slice 1a — <outcome>" \
169
+ --body-file /tmp/slice-1a.md --label type:feature --label priority:medium \
170
+ --status-role spec --wave "$WAVE" # AFK: append --label ready-for-agent
171
+ # HITL: pass --hitl, never ready-for-agent
172
+ python3 scripts/board-sync.py link --parent <prd#> --child <new#>
173
+
174
+ # 5. set every blocking edge NATIVELY — one `dep-add` per "Blocked by" relation in
175
+ # the slice table (gate-before-build edges from §3b/§5c included). Native issue
176
+ # dependencies are the blocking SSOT where the tracker supports them; the helper
177
+ # also writes the `## Blocked by` body section as the machine mirror (on a
178
+ # tracker without native dependencies the body section is the primary record):
179
+ python3 scripts/board-sync.py dep-add --issue <blocked#> --blocked-by <blocker#>
180
+ # → the promoted anchor graph is audited at exit (§7, execute-ready --mode audit, non-blocking)
181
+ ```
182
+
183
+ - The anchor body comes from **`docs/agents/wave-anchor-template.md` (Tier 2)** — lean: filled Slices table (`# | Status | Slice | Sub-Issue | Gate | closes/refs`), NO embedded PRD, NO per-slice handoff blocks. The full PRD (markers stripped: `plan_revision`/`prd-source-id`/`prd-content-fp`/`awaiting-decomposition`) is **issue comment #1**; each slice's paste-ready handoff is **self-contained in its leaf** (§5d).
184
+ - Promoted children carry the title prefix **`Welle N / Slice X — <outcome>`**.
185
+ - Fresh children each have exactly one parent → the one-parent constraint is never violated. `link` refuses a foreign-parent re-parent (exits non-zero — drift, never silent).
186
+ - **Member reconcile when promoting a stub (mandatory — Retro, corrected by; extended to the top-down origin).** The pipeline never runs directly `board-to-waves → to-issues` — it always goes through the intermediate step `board-to-waves` (stub) → [optional grill] → `to-prd` (Draft-PRD) → `to-issues` (publish); the top-down origin is `scale-check → grill → to-prd (program mode) → to-waves` (stub) → `to-issues` (publish). **The reconcile input is the union of the member issues listed in the stub-body `#…` list AND `children-of <stub#>`** (read the body, e.g. `gh issue view <anchor#> --json body`, plus `python3 scripts/board-sync.py children-of <stub#>`) — covering both origins: a bottom-up `board-to-waves` stub sets **no** native sub-issue link at clustering time, so `children-of` finds nothing before this promotion and only the body list matters; a top-down Stufe-1p Program-stub **already** has native children — the slice leaves `to-waves` pre-created at publish (`to-waves` SKILL.md §4) — which `children-of` returns even before this promotion, on top of any body-listed **adopted** references (`to-waves`'s Adopt Path). These members MUST be reconciled during the publish pass, or they end up sitting next to the fresh slices → **duplicates + execute-ready `DENY`** (the anchor's child set must equal the slice set; a legacy member without `plan_revision`/bucket denies the §7 audit). Rule per member:
187
+ - **1:1 mapping (member ⇒ exactly one slice)** → **reuse the member issue as the slice** (lift its body to the slice contract, **then** set `link` if it doesn't exist yet — a Stufe-1p member's `link` already exists from `to-waves`'s publish, so this is a no-op there, not a fresh `link` call), **not** create-fresh + close-old. **Reuse finalization — three things in the SAME publish pass, not a follow-up:** (1) stamp the `**Part of:** Welle <N> · Anchor #<prd#>` line into its body (§5d template); (2) apply the Wave field stamp if not already set (a bottom-up member has none yet; a Stufe-1p member already carries it from `to-waves`'s publish — idempotent no-op there); (3) finalize its bucket (`add --bucket afk|hitl`, §5c).
188
+ - **Split/merge (member ⇒ multiple slices, or multiple members ⇒ one slice) OR a fresh slice with no member** → close the superseded member(s) as **"superseded by Slice #<n>"** (mapping comment); if a member exceptionally already carries a native link (e.g. from an earlier partial run of the same promotion), first `unlink` it via `python3 scripts/board-sync.py unlink --parent <anchor#> --child <member#>` (parent-checked + idempotent; **never** bare `gh api removeSubIssue`), then `gh issue close <member#> -c "…"`.
189
+ - **Before publishing**, read the member issues listed in the stub body and decide the reuse-vs-close branch per member — not reactively at the §7 audit DENY. (Incident Retro: 12 slices were created fresh before 8 members with 1:1/1:N mappings were reconciled after the fact; `board-sync unlink` didn't exist yet then, it does now.)
190
+ - **Program-PRD status flip (first promotion only).** If the promoted stub's native parent is a Program-PRD (`<!-- prd: program -->` marker or the `labels.programType` label, distinct from `<prd#>` above — call its issue number `<program-prd#>`) still at the spec-role status, this is the program's **first** wave promotion — flip the Program-PRD's Status to the in-progress role alongside the stub's own promote (`python3 scripts/board-sync.py add --issue <program-prd#> --status-role inProgress`). A Program-PRD already at the in-progress status (a later wave's promotion) needs no further flip — check-then-set, idempotent, monotone forward only (mirrors the Wellenplan `Status` column's own monotone regeneration in `program-sync`).
191
+
192
+ #### 5b. ATOMIC (1 slice)
193
+
194
+ The Draft-PRD stays the executable leaf. Edit its body: **remove** `<!-- prd: awaiting-decomposition -->`, keep `type:*`+`priority:*` (**no** `type:cluster`/Wave, **no** `Welle N` title prefix), stamp the leaf `plan_revision`, add the `## Handoff Start Command`. The single PR `closes #<prd#>`.
195
+
196
+ Then set the bucket via the helper — the leaf already exists, so the workflow-label write goes through `board-sync.py add --bucket` (§5a forbids a bare `gh issue edit --add-label ready-for-agent`):
197
+
198
+ ```bash
199
+ # AFK (buildable now): set ready-for-agent
200
+ python3 scripts/board-sync.py add --issue <prd#> --bucket afk
201
+ # HITL (grill first): strip ready-for-agent + the body carries the `headings.vorBau` heading (§5c)
202
+ python3 scripts/board-sync.py add --issue <prd#> --bucket hitl
203
+ ```
204
+
205
+ `--bucket hitl` strips the label mechanically (a HITL leaf is never buildable — same invariant `create --hitl` enforces by rejecting). Bucket semantics + the `headings.vorBau` heading requirement → §5c (the authority is `execute-ready-check.py`).
206
+
207
+ #### 5c. HITL/AFK — label + body (`ready-for-agent` is the discriminator)
208
+
209
+ Every child **and** the atomic leaf sits in **exactly one** bucket:
210
+
211
+ | Bucket | `ready-for-agent` | Status | Body |
212
+ |---|---|---|---|
213
+ | **AFK** (buildable now) | **present** | `Spec` | complete What + AC |
214
+ | **HITL** (grill first) | **absent** | `Spec` | mandatory `headings.vorBau` heading (board profile `docs/agents/board-sync.md`; <project> currently `## Vor Bau zu klären`) with the open questions known from the macro-grill |
215
+
216
+ Status alone cannot discriminate (both are `Spec`) — the **label** does. The helper's `--hitl` flag rejects a `ready-for-agent` label mechanically. Authority = `scripts/execute-ready-check.py` (`parse_bucket`) — the checker wins on a mismatch.
217
+
218
+ **Gate slices (🔬/📐) are AFK.** A `🔬` Verify-Spike or `📐` Trade-off/Research gate slice is **read-only** (a fact question, or a bounded trade-off + read-only research) — an agent can run it solo, so it carries `ready-for-agent` like any other AFK slice; the **native blocked-by edge** on its dependent build slice (set at publish, §5a step 5) is what protects the gate-before-build ordering (§3b/§4), not the HITL bucket. Only a `🧭` Design-Grill gate slice is HITL (it needs the human in the grill). A gate slice's **placement** — which altitude/layer it lands on — follows `decision-gate`'s placement rule (owned there, referenced here).
219
+
220
+ #### 5d. Issue body template (each child / atomic leaf)
221
+
222
+ <issue-template>
223
+ <!-- slice-id: <stable-kebab-id> -->
224
+ <!-- parent-prd: #<prd#> --> <!-- omit for an atomic leaf -->
225
+ **plan_revision:** r<N> <!-- child mirrors the anchor's revision; atomic leaf carries its own -->
226
+
227
+ **Part of:** Welle <N> · Anchor #<prd#> <!-- visible child→anchor link (bare #N, not a /issues/ URL); omit for an atomic leaf -->
228
+
229
+ ## Blast-Radius
230
+ **Primary:** <files this slice directly rebuilds — comma-separated>
231
+ **Transitive:** <indirectly touched/read files, "—" if none>
232
+ <!-- structured (Primary/Transitive), NOT a scalar "~N files": board-sync intersects Primary∪Transitive
233
+ with the known LoC-offender baseline → loc-offender marker (Phase 1, early warning). An optional
234
+ pre-push LoC gate (`scripts/loc_offender_gate.py`, opt-in) is the enforcing authority (Phase 2).
235
+ Recon estimate at the cut: the build session checks the stamped estimate against its own finding,
236
+ real >2× → STOP, re-cut at the anchor. -->
237
+
238
+ ## What to build
239
+ End-to-end behavior of this vertical slice (not layer-by-layer). Avoid file paths/snippets (stale fast).
240
+
241
+ ## Acceptance criteria
242
+ - [ ] Criterion 1
243
+ - [ ] Criterion 2
244
+
245
+ ## Blocked by
246
+ Reference the blocking ticket(s), or "None - can start immediately".
247
+ <!-- machine-written MIRROR since: publish sets the edges natively (dep-add,
248
+ §5a step 5) and the helper maintains this section — never hand-edit it; on
249
+ conflict the native dependency API is the truth. Tracker without native
250
+ dependencies → this section is the primary record (kit fallback). -->
251
+
252
+ ## Vor Bau zu klären <!-- heading = board profile `headings.vorBau` (docs/agents/board-sync.md); HITL only — the open decisions; omit for AFK -->
253
+ - <open question 1>
254
+
255
+ ## Verification Question <!-- 🔬 Verify Spike only — omit otherwise -->
256
+ **Question (Yes/No):** <exactly one falsifiable question>
257
+ **Scope/Version:** <Lib@version / Runtime / DB / platform context>
258
+ **YES looks like:** <concrete output/evidence>
259
+ **NO looks like:** <concrete output/evidence>
260
+ **Verdict sink:** <ADR / this body / follow-up slice #N>
261
+
262
+ ## Trade-off <!-- 📐 Trade-off/Research only — omit otherwise -->
263
+ **Options:** <competing approaches>
264
+ **Criteria:** <decision axes, e.g. complexity / blast radius / reversibility / fit>
265
+ **Trade-offs:** <table of options × criteria, each cell backed by evidence (`file:line` / measurement / doc) — no adjectives>
266
+ **Decision:** <chosen option + why it wins on the criteria that matter + what was consciously traded off>
267
+ **Verdict sink:** <ADR / this body / follow-up slice #N>
268
+
269
+ ## Handoff Start Command
270
+ <!-- SELF-CONTAINED: scope + live-verify live HERE, never as a "see anchor
271
+ handoff" pointer — the anchor carries no per-slice handoff blocks anymore, and a
272
+ leaf→anchor→leaf reference loop made every build session read both. -->
273
+ <!-- mirror-xform:start codex-escalation -->
274
+ ```
275
+ Welle <N> · Slice <X> (<closes #x | refs #<prd#>, Parent #<prd#>>). Read #<prd#> for decisions.
276
+ Start skill: 🧭 Design Grill → /grill-with-docs · 🔬 Verify Spike → /verify-spike · 📐 Trade-off/Research → /decision-gate · AFK → /tdd · HITL → /grill-me → /tdd. Recommended model: <Model [Effort]>.
277
+ Worktree: your project's worktree helper, or `git worktree add`
278
+ Scope (<N> files) — REQUIRED FIELD, blast-radius estimate at cut time; the build session checks it against its own recon findings, >2x deviation → STOP:
279
+ - <concrete file + change>
280
+ Live-verify: <user outcome, DB/UI value with comparison>
281
+ PR: <closes #x | Part of #<prd#> — NEVER closes on the anchor>.
282
+ ```
283
+ <!-- mirror-xform:end -->
284
+ </issue-template>
285
+
286
+ **Blast-radius reconciliation (build session):** the stamped `**Blast-Radius:**` is the estimate *at the cut* — the build session compares it against its own recon finding. A real finding **> 2× the estimate → STOP + report** (re-cut at the anchor), do NOT keep building silently.
287
+
288
+ ### 6. Idempotent reconcile (re-run)
289
+
290
+ A re-run (or a re-grill that re-enters the pipeline) must leave the affected sub-graph coherent. **Mutation is one top-down pass rooted at the resolved anchor:**
291
+
292
+ ```bash
293
+ # entered from a child? lift to its anchor, then enumerate all siblings
294
+ PARENT=$(python3 scripts/board-sync.py parent-of <child#>) # FREE = atomic leaf
295
+ python3 scripts/board-sync.py children-of "$PARENT" # the full child set to reconcile
296
+ ```
297
+
298
+ - Diff each child against the anchor; update bodies; stamp `plan_revision` on **every** child (mirrors the anchor's revision — coherence = `child.rev == parent.rev`) and on the atomic leaf (its own fingerprint, like `to-prd`). Missing/malformed `plan_revision` → treat as `r1` + warn.
299
+ - **Never silently mutate across a boundary:** a foreign-parent child (`link` conflict), a cross-anchor dependency, or an **atomic↔promoted flip** is **reported as drift and stopped**, not auto-restructured. On a flip (a 1-slice PRD that now needs ≥2, or vice-versa), stop with an instruction — confirm the promote/demote, then spin the old scope into a child — because auto-demoting a PRD that may already have an open `closes` PR is exactly the silent structural mutation that closes anchors prematurely.
300
+
301
+ ### 7. Execute-ready exit assertion + audit (non-blocking)
302
+
303
+ After publishing/reconciling, run the shared checker (the same logic the **blocking** Drift-Guard uses at handoff):
304
+
305
+ ```bash
306
+ python3 scripts/execute-ready-check.py --issue <anchor-or-leaf#> --mode audit
307
+ ```
308
+
309
+ It asserts, for the rooted local graph:
310
+ - every child + the atomic leaf is in **exactly one** bucket (AFK: `ready-for-agent` + complete · HITL: no `ready-for-agent` + the `headings.vorBau` heading, §5c);
311
+ - `plan_revision` stamped and coherent (child == anchor, leaf own); no stale in-between;
312
+ - Parent↔Child consistent (anchor carries no bucket / no `ready-for-agent`);
313
+ - ** Anchor shape** (`## Origin`/`## Decisions`/`## Slices` + body header line — legacy German anchors' `## Herkunft`/`## Entscheidungen`/`**Welle N —**` satisfy it too) — as **`shape_warnings`** (purely non-blocking, **never** flows into `deny_recommended`).
314
+
315
+ If the source was a `wave-stub` stub, briefly confirm the label is gone (the publish mechanic strips it automatically — see §5): `gh issue view <anchor-or-leaf#> --json labels -q '.labels[].name'` shows **no** `wave-stub`. (Not part of `execute-ready-check.py` — its own quick check.)
316
+
317
+ `--mode audit` is **non-blocking** — a mismatch is a **loud warning** here; the **hard block** is `.claude/hooks/drift-guard.py` at handoff-creation. Emit a visible audit two-liner:
318
+
319
+ ```
320
+ to-issues: anchor=#<X> mode=<promote|atomic> slices=<n> rev <old>→<new>
321
+ source=<draft-prd|raw-issue|external-prd|bundle> synthesized=<marker-list | none>
322
+ AFK=[#a #b] HITL=[#c] · drift=<none | …> shape=<ok | warn:…>
323
+ ```
324
+
325
+ Do NOT close or modify any parent issue beyond the promote stamp.
@@ -0,0 +1,29 @@
1
+ # Third-Party Notices
2
+
3
+ This skill is adapted from **Matt Pocock's skills**
4
+ (https://github.com/mattpocock/skills), `skills/engineering/to-tickets` @ d574778, Copyright (c) 2026 Matt Pocock,
5
+ used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
6
+
7
+ ```
8
+ MIT License
9
+
10
+ Copyright (c) 2026 Matt Pocock
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ ```
@@ -0,0 +1,162 @@
1
+ # PROGRAM-PRD-FORMAT — the Program-PRD body grammar
2
+
3
+ The machine-parsable body grammar for a **Program-PRD** — the native Sub-Issue
4
+ Anchor sitting above a multi-Wave program (Programm → Phase → Welle → Slice,
5
+ per the program-altitude design, §2). Written by `to-prd`'s `mode=program`
6
+ auto-detection or by hand for an early program draft; parsed by
7
+ `scripts/program_graph.py` (`board-sync.py validate-graph`) for the counted
8
+ Vorschau-Gate report that `to-waves` shows before any Board write.
9
+
10
+ A regular feature-PRD (`.claude/skills/to-prd/SKILL.md`'s `<prd-template>`) stays
11
+ unchanged — this is a **parallel** grammar for the program altitude, not a
12
+ replacement.
13
+
14
+ ## Top-of-body markers
15
+
16
+ ```
17
+ <!-- prd: program -->
18
+ **plan_revision:** r1
19
+ ```
20
+
21
+ `<!-- prd: program -->` is the durable, board-discoverable distinguishability
22
+ marker (the program-altitude counterpart of a feature-PRD's
23
+ `<!-- prd: awaiting-decomposition -->`). `**plan_revision:** rN` is the existing
24
+ convention (`execute-ready-check.py`'s `parse_plan_revision`) — it must sit before
25
+ the first Markdown heading.
26
+
27
+ ## `## Scope` — stable Scope-Item IDs
28
+
29
+ A flat list of Scope-Items, each with a **stable ID** (`S1`, `S2`, …) that never
30
+ changes across revisions — the Wellenplan table's `covers` column references
31
+ these IDs, which is what makes Scope-Abdeckung ("X von Y") countable instead of
32
+ prose-only:
33
+
34
+ ```
35
+ ## Scope
36
+ - **S1:** <one-line capability or outcome>
37
+ - **S2:** <one-line capability or outcome>
38
+ ```
39
+
40
+ IDs are assigned once, in order, and never reused or renumbered — a later
41
+ revision that drops S2 leaves a gap rather than shifting S3 down (identity ≠
42
+ position, same spirit as `to-prd`'s `prd-source-id`).
43
+
44
+ ## `## Wellenplan` — the machine-parsable wave plan table
45
+
46
+ Wrapped in explicit markers (parser locates the block by marker, not by
47
+ heuristic column-sniffing — a fresh grammar gets a fresh, unambiguous anchor):
48
+
49
+ ```
50
+ ## Wellenplan
51
+ <!-- wellenplan:start -->
52
+ | Welle | Status | Issue | Name | Phase | Slices | Gate | covers |
53
+ |---|---|---|---|---|---|---|---|
54
+ | 1 | ⬜ | — | Fundament | P1 | 1a, 1b | — | S1,S2 |
55
+ | 2 | ⬜ | — | Helper | P1 | 2a | 📐 | S3 |
56
+ | 3 | ⬜ | — | Cleanup | | 3a | — | enabler |
57
+ <!-- wellenplan:end -->
58
+ ```
59
+
60
+ Columns:
61
+
62
+ - **Welle** — the wave number (monotone within the program; stable once
63
+ published, per the ex-ante-stempel decision).
64
+ - **Status** — volatile, `⬜` at authoring; regenerated monotonically by
65
+ `program-sync` from the wave's board status (⬜ not-started → 🔄 In
66
+ Arbeit/Review → ✅ Done), never regresses. Not authored by hand and not a
67
+ `validate-graph` input.
68
+ - **Issue** — the navigation link `#<n>` down to the wave's own issue (its
69
+ stub / promoted Wave-Anchor); author it as `—`. Machine-written:
70
+ `program-sync` fills it from the board child whose title carries the
71
+ matching `Welle <N> —` prefix (`to-waves` runs a sync right after publish,
72
+ `wrapup`'s upward propagation keeps it fresh); once set it is identity —
73
+ never overwritten. Tolerant-optional on parse like Status; not a
74
+ `validate-graph` input.
75
+ - **Name** — the wave's short title (becomes `Welle <N> — <Name>` on promotion,
76
+ same `wave_title()` convention as the bottom-up route). Hand-owned prose —
77
+ `program-sync` never touches this cell.
78
+ - **Phase** — optional. **Omit the whole column** if the program doesn't use
79
+ phases at all (phases are optional per the program-altitude design, §2). If used, every wave row
80
+ needs a Phase value (checked by `validate-graph`'s Rollup-Kette axis).
81
+ - **Slices** — comma-separated local-ids (see SLICE-METADATA-FORMAT.md)
82
+ referencing the `## Slices` chapter below — **not** issue numbers (none exist
83
+ pre-publish; `to-waves` mints the real Sub-Issues at publish time).
84
+ - **Gate** — this wave's Gate tag, same legend as `wave-anchor-template.md`:
85
+ `—` AFK-Bau · 🧭 Design-Grill · 🔬 Verify-Spike · 📐 Abwägung/Research ·
86
+ 📝 Review-Notiz. Always filled (`—` is a valid, explicit "no gate").
87
+ - **covers** — comma-separated Scope-Item IDs this wave carries forward
88
+ (`S1,S2`), or the literal token **`enabler`** for a wave that intentionally
89
+ serves no Scope-Item directly (pure infrastructure/groundwork — declared, not
90
+ silently absent).
91
+
92
+ The table is the **single source of truth** for the vertical Rollup-Kette
93
+ (Programm → Phase → Welle → Slice must close with no gaps) and the horizontal
94
+ Scope-Abdeckung (every `S<n>` must be covered by ≥1 wave; every wave must cover
95
+ ≥1 Scope-Item or be an explicit `enabler`) — both counted, not eyeballed, at the
96
+ Vorschau-Gate.
97
+
98
+ ## `## Phasen-Gates` — the phase-gate checklist
99
+
100
+ Only present when the program uses phases (Wellenplan `Phase` column filled):
101
+
102
+ ```
103
+ ## Phasen-Gates
104
+ - [ ] P1: <the acceptance criterion that closes this phase>
105
+ - [ ] P2: <…>
106
+ ```
107
+
108
+ Every Phase referenced by a Wellenplan row needs a matching entry here (checked
109
+ by `validate-graph`); an entry naming a Phase no wave uses is a "Checklisten-Waise"
110
+ gap, also surfaced.
111
+
112
+ **Auto-checkoff:** when every Wellenplan wave carrying a phase reaches
113
+ `✅`, `program-sync` checks that phase's box mechanically (appending
114
+ `— alle Wellen ✅ (<date>)`, monotone — a checked box is never touched again).
115
+ Word each criterion so wave completion IS the criterion; an acceptance judgment
116
+ beyond "all waves merged" belongs in the waves' own gates, not here — the
117
+ checkoff cannot judge prose.
118
+
119
+ ## `## Slices` — per-slice detail sections
120
+
121
+ One `####`-level section per planned slice, referenced by its local-id from the
122
+ Wellenplan's `Slices` column. Grammar (metadata block + body skeleton) is owned
123
+ by `.claude/skills/to-waves/SLICE-METADATA-FORMAT.md` — read that file for the
124
+ exact field set. Example:
125
+
126
+ ```
127
+ ## Slices
128
+ #### 1a — Formate + Graph-Modul
129
+ <!-- wave: 1 -->
130
+ <!-- phase: P1 -->
131
+ <!-- area: scripts -->
132
+ <!-- gate: — -->
133
+ <!-- blocked_by: none -->
134
+
135
+ Outcome: `validate-graph` reports a counted Programm-Graph preflight.
136
+
137
+ What to build: …
138
+ AC: …
139
+ ```
140
+
141
+ `blocked_by` references other **local-ids** (`blocked_by: 1a` or
142
+ `blocked_by: 1a,2c`) — never issue numbers, since none exist yet pre-publish.
143
+ A local-id referencing a slice in a **later** wave is a blocking
144
+ Rückwärts-Ref-über-Wellengrenze finding; a Gate-Slice (🧭/🔬/📐/📝) with
145
+ dependents outside its own wave is a non-blocking "Struktur-Verdacht" warning
146
+ (Gate-Slices are meant to be wave-local/AFK-safe).
147
+
148
+ ## Abbruch-Konvention (program abort)
149
+
150
+ If a program is abandoned before completion, close in this order — never leave
151
+ Board zombies:
152
+
153
+ 1. **Leaves** first — every unbuilt Slice sub-issue closes with the comment
154
+ `superseded by program abort`.
155
+ 2. **Stubs** (Welle-Anchors) next — same closing comment, once all their leaves
156
+ are closed.
157
+ 3. **The Program-PRD** last, closed manually by the maintainer — a Program-PRD
158
+ is **never** auto-closed by a PR (`closes` never targets it, same rule as any
159
+ other Wellen-Anchor).
160
+
161
+ Document the abort in the Program-PRD body itself (a short "Abgebrochen am
162
+ <Datum>: <Grund>" note) before closing it, so the history stays legible.