@ikon85/agent-workflow-kit 0.27.1 → 0.29.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 (79) hide show
  1. package/.agents/skills/ask-matt/SKILL.md +2 -2
  2. package/.agents/skills/board-to-waves/SKILL.md +13 -3
  3. package/.agents/skills/grill-me/SKILL.md +1 -1
  4. package/.agents/skills/grill-with-docs/SKILL.md +1 -1
  5. package/.agents/skills/kit-update/SKILL.md +12 -0
  6. package/.agents/skills/orchestrate-wave/SKILL.md +68 -21
  7. package/.agents/skills/orchestrate-wave/references/builder-contract.md +6 -4
  8. package/.agents/skills/retro/SKILL.md +24 -1
  9. package/.agents/skills/scale-check/SKILL.md +2 -2
  10. package/.agents/skills/setup-workflow/SKILL.md +44 -1
  11. package/.agents/skills/setup-workflow/workflow-overview.md +5 -5
  12. package/.agents/skills/tdd/SKILL.md +68 -14
  13. package/.agents/skills/to-issues/SKILL.md +104 -29
  14. package/.agents/skills/to-prd/SKILL.md +13 -3
  15. package/.agents/skills/to-waves/SKILL.md +16 -4
  16. package/.agents/skills/verify-spike/SKILL.md +1 -1
  17. package/.agents/skills/wrapup/SKILL.md +14 -3
  18. package/.claude/hooks/drift-guard.py +5 -2
  19. package/.claude/hooks/kit-origin-edit-hint.py +64 -0
  20. package/.claude/skills/ask-matt/SKILL.md +2 -2
  21. package/.claude/skills/board-to-waves/SKILL.md +13 -3
  22. package/.claude/skills/codex-build/SKILL.md +69 -23
  23. package/.claude/skills/codex-review/SKILL.md +47 -37
  24. package/.claude/skills/grill-me/SKILL.md +1 -1
  25. package/.claude/skills/grill-me-codex/SKILL.md +45 -34
  26. package/.claude/skills/grill-with-docs/SKILL.md +1 -1
  27. package/.claude/skills/grill-with-docs-codex/SKILL.md +46 -34
  28. package/.claude/skills/kit-update/SKILL.md +12 -0
  29. package/.claude/skills/orchestrate-wave/SKILL.md +68 -21
  30. package/.claude/skills/orchestrate-wave/references/builder-contract.md +6 -4
  31. package/.claude/skills/retro/SKILL.md +23 -0
  32. package/.claude/skills/scale-check/SKILL.md +2 -2
  33. package/.claude/skills/setup-workflow/SKILL.md +44 -1
  34. package/.claude/skills/setup-workflow/workflow-overview.md +5 -5
  35. package/.claude/skills/skill-manifest.json +1 -1
  36. package/.claude/skills/tdd/SKILL.md +68 -14
  37. package/.claude/skills/to-issues/SKILL.md +104 -29
  38. package/.claude/skills/to-prd/SKILL.md +13 -3
  39. package/.claude/skills/to-waves/SKILL.md +16 -4
  40. package/.claude/skills/verify-spike/SKILL.md +1 -1
  41. package/.claude/skills/wrapup/SKILL.md +14 -3
  42. package/README.md +70 -7
  43. package/agent-workflow-kit.package.json +99 -43
  44. package/docs/adr/0001-consumer-divergence-policy.md +49 -0
  45. package/docs/agents/wave-anchor-template.md +1 -1
  46. package/docs/research/wave-152-consumer-acceptance.md +98 -0
  47. package/package.json +1 -1
  48. package/scripts/board-sync.py +187 -12
  49. package/scripts/build-kit.test.mjs +42 -1
  50. package/scripts/codex-exec-scenarios/fake-codex.mjs +152 -0
  51. package/scripts/codex-exec.sh +566 -0
  52. package/scripts/codex-exec.test.mjs +815 -0
  53. package/scripts/codex_proc.py +602 -0
  54. package/scripts/find-by-marker.py +68 -0
  55. package/scripts/marker_lib.py +88 -0
  56. package/scripts/pr-body-check.py +34 -6
  57. package/scripts/pr_body_e2e.py +83 -0
  58. package/scripts/render-anchor.py +111 -0
  59. package/scripts/test_board_sync.py +208 -0
  60. package/scripts/test_census_backstop.py +56 -3
  61. package/scripts/test_marker_lib.py +154 -0
  62. package/scripts/test_orchestrate_wave_contract.py +116 -0
  63. package/scripts/test_pr_body_check.py +245 -0
  64. package/scripts/test_render_anchor.py +267 -0
  65. package/scripts/test_retro_wrapup_contract.py +117 -0
  66. package/scripts/test_skill_codex_exec_lifecycle.py +123 -0
  67. package/scripts/test_tdd_contract.py +78 -0
  68. package/src/cli.mjs +44 -8
  69. package/src/commands/diff.mjs +5 -2
  70. package/src/commands/init.mjs +12 -0
  71. package/src/commands/own.mjs +16 -0
  72. package/src/commands/uninstall.mjs +8 -1
  73. package/src/commands/update.mjs +37 -9
  74. package/src/lib/bundle.mjs +14 -0
  75. package/src/lib/consumerPath.mjs +30 -0
  76. package/src/lib/manifest.mjs +18 -0
  77. package/src/lib/ownedDiff.mjs +88 -0
  78. package/src/lib/updateCandidate.mjs +14 -0
  79. package/src/lib/updateReconcile.mjs +45 -6
@@ -51,12 +51,14 @@ invocation for each in this prompt so the builder cannot guess a wrong one.
51
51
  2. Commit your ONE commit on the slice branch FIRST — before any longer verify
52
52
  (verify-then-forget-to-commit leaves the orchestrator hand-committing your
53
53
  worktree). Do NOT push. Do NOT `--no-verify` (pre-commit hooks must pass).
54
- 3. Run the commands above. Never end your turn with a background command still
55
- running.
54
+ 3. Run the commands above IN THE FOREGROUND never background a test/gate
55
+ command. Use a generous foreground timeout for a long suite and wait for every
56
+ completed command result. Never end your turn while a command is still running.
56
57
 
57
58
  ## Report back (concise)
58
- Files touched · decisions taken · test results (exact output) · commit SHA ·
59
- STOP items · what the orchestrator should visually verify.
59
+ Files touched · decisions taken · test results (exact completed command results
60
+ and exit status) · commit SHA · STOP items · what the orchestrator should visually
61
+ verify.
60
62
  ```
61
63
 
62
64
  Orchestrator notes:
@@ -114,6 +114,25 @@ For **every** friction point (user-reported AND self-found), the agent analyzes:
114
114
 
115
115
  If the user's description in step 2a is ambiguous, the agent may ask **ONE** clarifying outcome question — e.g. "where was it most annoying — during setup, mid-work, or during cleanup?". Never multiple-choice with memory names, hook paths, or config classes.
116
116
 
117
+ ### 3a. Mechanical enforcement check (before target + weight)
118
+
119
+ Before placing a finding on the target/weight ladder, ask for every finding:
120
+
121
+ > **"Could a machine decide this — with a grep, parser, test, hook, or CI gate?"**
122
+
123
+ - **Yes, within the current patch:** implement the enforcement. Supporting prose
124
+ may explain the rule, but prose alone does not resolve a machine-checkable
125
+ finding.
126
+ - **Yes, but enforcement is too expensive for the current patch:** propose the
127
+ prose change **plus a tracked enforcement issue** and state the **explicit
128
+ trade-off** (why enforcement is deferred, what failure remains possible, and
129
+ when the issue should fire). Do not present the prose-only half as complete.
130
+ - **No:** record why judgment is required, then continue to the target/weight
131
+ ladder.
132
+
133
+ This check prevents detection without enforcement: a rule that a machine can
134
+ decide should not depend on a future reader remembering a sentence.
135
+
117
136
  ### 3b. Determine target + weight (threshold ladder)
118
137
 
119
138
  Before formulating a patch in step 4, place **every** friction point on the threshold ladder. **Weight** = how durable/far-reaching the rule is (drives the visible patch line in step 4 + the user's approval depth). **Target** = where the patch physically goes.
@@ -137,6 +156,10 @@ Before formulating a patch in step 4, place **every** friction point on the thre
137
156
 
138
157
  **A GitHub issue is NOT a weight tier.** A real follow-up = work to track → `python3 scripts/board-sync.py create` (step-4 table), **orthogonal** to the ladder; its "weight" follows the follow-up scope. The ladder classifies **config patches**, not "turn it into a ticket".
139
158
 
159
+ **Kit-repo routing target (always ask; never automatic).** When a finding lands on a kit-shipped file (a consumer-manifest entry with kit origin), ask whether the improvement is generic or project-specific. For a generic improvement, offer to file a lightweight issue against the public kit repo: a title plus a short body that states the finding, affected file, and why it is generic. For a project-specific improvement, recommend `own` (keep it consumer-owned). The consumer user does not need to be the kit maintainer.
160
+
161
+ Before any `gh issue create --repo <owner>/agent-workflow-kit` runs, show the user a **sanitized preview** of the exact title and body with consumer identifiers and secrets stripped. Create the issue only after the user explicitly approves that exact text; if the title or body changes, show the revised preview and ask again. This approval is additional to the per-patch approval in step 5.
162
+
140
163
  **Target missing in the project — separate two cases cleanly:**
141
164
  - **(a) Tier skill missing entirely** (e.g. a foreign project without `spec-self-critique`): no durable spec-time gate exists. **Memory is NOT a substitute** — passive recall doesn't catch a recurring spec defect before building. Report honestly: *"this project has no durable target for this tier"* + propose a `/setup-workflow` follow-up. **No fake guard via memory.**
142
165
  - **(b) Skill exists, project-layer file missing** (`docs/agents/skills/<skill>.md`): **create / append** — that is the normal retro-sink behavior that `spec-self-critique` step 0 expects anyway. **No** downgrade.
@@ -119,7 +119,7 @@ One behavior, already clear enough to build — no PRD, no slicing.
119
119
 
120
120
  ```
121
121
  Small change: <one-sentence behavior>.
122
- `tdd` — one behavior at a time, red → green → refactor. No PRD, no decomposition.
122
+ `implement` — build directly, one behavior at a time (red → green → refactor). No PRD, no decomposition.
123
123
  ```
124
124
 
125
125
  ### Bug (something that used to work)
@@ -134,7 +134,7 @@ Bug: <what's broken — expected vs. actual>.
134
134
  ```
135
135
  scale-check: verdict=<Program | Feature | Direct-Slice | Bug>
136
136
  criteria tripped=<C1,C2,… | none | n/a (bug/direct)>
137
- route=<program grill → to-prd → to-waves (all waves execute-ready by default) | grill-with-docs → to-prd → to-issues | tdd | diagnose>
137
+ route=<program grill → to-prd → to-waves (all waves execute-ready by default) | grill-with-docs → to-prd → to-issues | implement | diagnose>
138
138
  start-prompt: <the paste-ready block above, filled in>
139
139
  ```
140
140
 
@@ -27,6 +27,7 @@ This is a prompt-driven skill, not a deterministic script. Explore, present what
27
27
  | `.github/workflows/agent-workflow-kit-update.yml` | optional tested Kit update pull request for GitHub consumers (Section A2) |
28
28
  | `docs/agents/census.md` | optional-census choice, paths, state, and safe disable contract seeded from [census.md](./census.md) (Section A3) |
29
29
  | `docs/agents/workflow-capabilities.json` + capability assets | consumer-owned Worktree Lifecycle, Memory Lifecycle, Workflow Advisories, and Safety Guardrails choices (Sections A4–A7) |
30
+ | `.claude/settings.json` | additive activation of the advisory kit-origin Edit/Write hint (Section A8) |
30
31
 
31
32
  ## Idempotency contract — read before writing anything
32
33
 
@@ -57,7 +58,7 @@ Read the current state; don't assume. For every target file, read its first line
57
58
  - `CONTEXT.md`, `CONTEXT-MAP.md`, `docs/adr/` — domain-doc layout.
58
59
  - `docs/agents/`, `docs/agents/skills/`, `docs/conventions/` — prior output of this skill.
59
60
  - `docs/agents/census.md`, `.census/profile.json`, `.census/active.json` — an existing census choice or consumer-owned census to adopt.
60
- - `docs/agents/workflow-capabilities.json`, `.claude/settings.json`, `git config --get core.hooksPath` — existing capability choices/profile plus Worktree Lifecycle, Workflow Advisories, and Safety Guardrails wiring to adopt.
61
+ - `docs/agents/workflow-capabilities.json`, `.claude/settings.json`, `git config --get core.hooksPath` — existing capability choices/profile plus Worktree Lifecycle, Workflow Advisories, Safety Guardrails, and kit-origin hint wiring to adopt.
61
62
  - `.memory/active/`, `.memory/archive/`, and `.memory/receipts/` — consumer-owned Memory Lifecycle policies or recovery evidence to adopt without normalization.
62
63
  - `gh auth status` (if GitHub) — is `gh` authenticated, and with which scopes?
63
64
 
@@ -243,6 +244,42 @@ The seed's reference consumer uses the parity-on profile. Other consumers are
243
244
  opt-in/manual: never copy its package-manager, path, shim, surface, or outage
244
245
  decisions without repository evidence and user confirmation.
245
246
 
247
+ ### 2g. Section A8 — Advisory kit-origin edit hint (non-interactive)
248
+
249
+ > The shipped kit-origin hook asks the upstream-or-own question before an agent
250
+ > Edit/Write changes a file recorded with `origin: "kit"` in the consumer
251
+ > manifest. It is advisory only: it never blocks, reads the manifest once, uses
252
+ > no network, and silently fails open when the manifest cannot be read. Shell
253
+ > redirection, formatters, and IDE edits are knowingly outside its coverage; the
254
+ > skills remain the rule's primary carrier.
255
+
256
+ Activate the shipped hook by reconciling this exact entry into
257
+ `.claude/settings.json`:
258
+
259
+ ```json kit-origin-edit-hook-settings
260
+ {
261
+ "matcher": "Edit|Write",
262
+ "hooks": [
263
+ {
264
+ "type": "command",
265
+ "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/kit-origin-edit-hint.py\""
266
+ }
267
+ ]
268
+ }
269
+ ```
270
+
271
+ This is an additive, idempotent settings edit, not a settings rewrite:
272
+
273
+ 1. Missing settings → create `{ "hooks": { "PreToolUse": [<entry>] } }`.
274
+ 2. Existing valid settings → preserve every consumer key, matcher, command,
275
+ hook event, ordering, and formatting byte-for-byte; append only `<entry>` to
276
+ `hooks.PreToolUse`.
277
+ 3. If any existing hook already contains the exact command above, do nothing,
278
+ regardless of its surrounding matcher. A rerun must be byte-identical.
279
+ 4. Unreadable/invalid settings, or a non-object `hooks` / non-array
280
+ `PreToolUse`, are consumer-owned conflicts: leave the file untouched and
281
+ report the skipped activation. Never replace or normalize them.
282
+
246
283
  ### 3. Section B — Triage labels
247
284
 
248
285
  > When `triage` processes an incoming issue it applies labels (or your tracker's equivalent). It needs strings you've actually configured, or it creates duplicates.
@@ -341,6 +378,12 @@ Do not copy templates with shell commands or edit the capability profile by
341
378
  hand. Report `seeded · adopted · skipped`; do not print memory contents or
342
379
  receipt contents.
343
380
 
381
+ For `.claude/settings.json`, run the Section A8 reconciliation on fresh and
382
+ already-initialized consumers. Report `activated · already active · skipped
383
+ (consumer-owned conflict)`. Do not make the hook conditional on an optional
384
+ capability choice: its self-filtering, fail-open behavior keeps it inert except
385
+ for matching kit-origin Edit/Write events.
386
+
344
387
  For the **`## Workflow`**, **`## Agent skills`**, and **`## Prod`** blocks, reconcile per section in **both** CLAUDE.md and AGENTS.md that exist:
345
388
 
346
389
  - If **both** files exist → write/update the block in **both** (keep them coherent — Codex is a first-class surface).
@@ -11,12 +11,12 @@ Use this section as the entry-point map for agent-assisted work. The individual
11
11
  - **Existing plan, PRD, or ready issue:** use `to-issues` to split it into independently buildable tracer-bullet slices.
12
12
  - **A Program-PRD with a wave plan:** use `to-waves` to unfold it into named wave stubs + slice leaves on the board, after a chat preview gate that shows the whole plan before any write.
13
13
  - **A backlog of open issues needs clustering into themed waves:** use `board-to-waves`.
14
- - **A whole wave anchor (file-disjoint slices, specs already locked) to build, verify and land end-to-end — often AFK:** use `orchestrate-wave` — it dispatches implementers per slice, integrates serially, verifies centrally, and lands. (A single slice just goes to `tdd`.)
14
+ - **A whole wave anchor (file-disjoint slices, specs already locked) to build, verify and land end-to-end — often AFK:** use `orchestrate-wave` — it dispatches implementers per slice, integrates serially, verifies centrally, and lands. (A single slice just goes to `implement`.)
15
15
  - **Bugs or requests piling up that you didn't create:** use `triage` to move them into agent-ready issues.
16
16
  - **Bug or regression:** use `diagnose` to reproduce, minimize, hypothesize, instrument, fix, and regression-test.
17
17
  - **A design question needs a runnable answer (state, business logic, a UI you have to see):** spike it with `prototype`, then fold what you learned back in.
18
- - **Multi-session build from a PRD or issue:** use `implement` to drive `tdd` end-to-end, one red-green slice at a time.
19
- - **Implementation slice:** use `tdd` for one behavior at a time: RED, GREEN, then refactor.
18
+ - **Multi-session build from a PRD or issue:** use `implement` to drive the build end-to-end, one red-green slice at a time.
19
+ - **Implementation slice:** use `implement` for one behavior at a time: RED, GREEN, then refactor.
20
20
  - **Build or refresh a project-local census:** use `census-update` to scan facts, resolve ambiguous decisions one at a time, and transactionally activate a counted census.
21
21
  - **Preview or restore consumer-owned memories:** use `memory-lifecycle` to classify every configured path without writing, then apply an explicitly approved collision-safe restore with a content-free receipt.
22
22
  - **Finished slice:** use `wrapup` to prepare the branch, PR, and cleanup steps your repo expects.
@@ -27,11 +27,11 @@ Use this section as the entry-point map for agent-assisted work. The individual
27
27
 
28
28
  ## Routing Rule
29
29
 
30
- Prefer the smallest workflow that produces a clear next action. A tiny fix can go straight to `tdd`; a cross-cutting feature should become a PRD and then slices before implementation. When a skill reports missing project context, run `setup-workflow` again and fill only the missing stub.
30
+ Prefer the smallest workflow that produces a clear next action. A tiny fix can go straight to `implement`; a cross-cutting feature should become a PRD and then slices before implementation. When a skill reports missing project context, run `setup-workflow` again and fill only the missing stub.
31
31
 
32
32
  ## Depth Ladder
33
33
 
34
- - **Light:** direct `tdd` for a small, well-understood change.
34
+ - **Light:** direct `implement` for a small, well-understood change.
35
35
  - **Medium:** `to-issues` for a ready artefact that needs slicing.
36
36
  - **Deep:** `grill-with-docs` followed by `to-prd` and `to-issues` when terminology, contracts, rollout order, or ownership are still uncertain.
37
37
  - **Gate:** insert `verify-spike` or `decision-gate` before any depth level when a slice hinges on an unresolved fact or trade-off.
@@ -150,7 +150,7 @@
150
150
  "tdd": {
151
151
  "class": "vendored",
152
152
  "publish": true,
153
- "entryPoint": true,
153
+ "entryPoint": false,
154
154
  "surfaces": [
155
155
  "claude",
156
156
  "codex"
@@ -60,6 +60,8 @@ Before writing any code:
60
60
 
61
61
  - [ ] Confirm with user what interface changes are needed
62
62
  - [ ] Confirm with user which behaviors to test (prioritize)
63
+ - [ ] Find the nearest existing tests for those behaviors
64
+ - [ ] Assign exactly one test-delta decision per behavior
63
65
  - [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
64
66
  - [ ] Design interfaces for [testability](interface-design.md)
65
67
  - [ ] List the behaviors to test (not implementation steps)
@@ -69,34 +71,81 @@ Ask: "What should the public interface look like? Which behaviors are most impor
69
71
 
70
72
  **You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
71
73
 
72
- ### 2. Tracer Bullet
73
-
74
- Write ONE test that confirms ONE thing about the system:
74
+ ### 2. Existing-Test-First Decision
75
+
76
+ TDD does not imply a new test file or a growing test count. Start at the nearest
77
+ existing behavioral test. For each planned behavior, record exactly one of these
78
+ test-delta decisions:
79
+
80
+ - **REUSE** — the existing public-behavior test already protects the change.
81
+ - **EXTEND** — add the missing boundary to the nearest suite or parameter table.
82
+ - **REPLACE** — establish equivalent protection at a smaller or more stable level,
83
+ then retire the duplicate.
84
+ - **NEW** — only for a distinct, previously unprotected risk; name the plausible
85
+ defect it catches.
86
+ - **RETIRE** — the behavior or contract is intentionally gone or already replaced;
87
+ delete its obsolete test.
88
+ - **NO-NEW-TEST** — a behavior-neutral refactor or removal without a durable
89
+ negative contract.
90
+
91
+ Do not create a new test file until the nearest existing owner has been inspected
92
+ and rejected with a reason. A feature, source file, component, method, or
93
+ acceptance-criterion line is not itself a test boundary.
94
+
95
+ Every executable new behavior and bug fix must begin with a failing assertion.
96
+ REUSE and NO-NEW-TEST never bypass this RED-first invariant. For a `REUSE`
97
+ candidate, run the existing assertion before implementation: if the requested
98
+ behavior is executable and the assertion is already green, an already-green
99
+ assertion does not prove the requested change; choose `EXTEND`, or choose `NEW`
100
+ after rejecting the nearest owner. `NO-NEW-TEST` is limited to behavior-neutral
101
+ work and removals without a durable absence contract.
102
+
103
+ For removals, delete the tests that specified the retired behavior. Add or keep a
104
+ negative assertion (`404`, forbidden, hidden) only when absence itself is a durable
105
+ security, API, or compatibility promise. Permanent skipped executable tests are
106
+ retired or moved to a runbook or issue, not parked in the green suite.
107
+
108
+ ### Worked decision matrix
109
+
110
+ | Behavior situation | Decision | Feedback proof |
111
+ |---|---|---|
112
+ | An existing regression test reproduces the bug | REUSE | Existing assertion is RED, then the minimal fix makes it GREEN |
113
+ | The nearest suite lacks one requested boundary | EXTEND | Added assertion is RED, then the minimal change makes it GREEN |
114
+ | A broad duplicate can become a stable focused check | REPLACE | Equivalent protection is proven before the duplicate is removed |
115
+ | A distinct risk has no suitable owner after documented inspection | NEW | New assertion is RED and names the plausible defect it catches |
116
+ | The specified behavior is intentionally removed | RETIRE | Obsolete test is removed with the obsolete behavior |
117
+ | An internal refactor preserves all observable behavior | NO-NEW-TEST | Relevant existing suite is GREEN before and after the change |
118
+
119
+ ### 3. First Feedback Cycle
120
+
121
+ Pick ONE behavior and use its decision's feedback loop:
75
122
 
76
123
  ```
77
- RED: Write test for first behaviortest fails
78
- GREEN: Write minimal code to passtest passes
124
+ REUSE, executable change: existing assertion REDminimal code → GREEN
125
+ EXTEND/NEW: assertion in nearest suite REDminimal code → GREEN
126
+ REUSE, neutral change: relevant suite GREEN → small refactor → stays GREEN
127
+ REPLACE: prove equivalent protection → remove duplicate → GREEN
128
+ RETIRE: remove obsolete behavior and its obsolete test → GREEN
129
+ NO-NEW-TEST: relevant suite GREEN → behavior-neutral change → stays GREEN
79
130
  ```
80
131
 
81
- This is your tracer bullet - proves the path works end-to-end.
132
+ The RED-to-GREEN cycle is the tracer bullet for each executable new behavior or
133
+ bug fix. It proves the path end to end without automatically creating another
134
+ test file.
82
135
 
83
- ### 3. Incremental Loop
136
+ ### 4. Incremental Loop
84
137
 
85
- For each remaining behavior:
86
-
87
- ```
88
- RED: Write next test → fails
89
- GREEN: Minimal code to pass → passes
90
- ```
138
+ Repeat one behavior at a time, using the matching feedback loop above.
91
139
 
92
140
  Rules:
93
141
 
94
142
  - One test at a time
143
+ - Prefer extending the existing owner or parameter matrix over adding a sibling file
95
144
  - Only enough code to pass current test
96
145
  - Don't anticipate future tests
97
146
  - Keep tests focused on observable behavior
98
147
 
99
- ### 4. Refactor
148
+ ### 5. Refactor
100
149
 
101
150
  After all tests pass, look for [refactor candidates](refactoring.md):
102
151
 
@@ -114,7 +163,12 @@ After all tests pass, look for [refactor candidates](refactoring.md):
114
163
  [ ] Test describes behavior, not implementation
115
164
  [ ] Test uses public interface only
116
165
  [ ] Test would survive internal refactor
166
+ [ ] Exactly one test-delta decision is recorded for this behavior
167
+ [ ] NEW names the distinct plausible defect; a new file has a justified owner boundary
117
168
  [ ] Code is minimal for this test
118
169
  [ ] No speculative features added
119
170
  [ ] Wave slice: a flipped/new assumption affecting an unbuilt sibling issue → log it to ANNAHMEN.md (worktree root; wrapup Step 0c reads it)
120
171
  ```
172
+
173
+ At handoff, list every behavior and its one decision, then report the counted
174
+ test delta: `Reused X · Extended Y · New Z · Replaced/retired W`.
@@ -54,7 +54,7 @@ Even when the slices were already cut upstream (a grill/PRD slice table), do NOT
54
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
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
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-codex`), 🔬 **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.)
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-codex`), 🔬 **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 `/implement`. (🔬 **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
58
  <!-- mirror-xform:end -->
59
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
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.)
@@ -143,33 +143,108 @@ else
143
143
  WAVE="$CURRENT" # Stufe-1p Program-stub — reuse
144
144
  fi
145
145
 
146
- # 2. render the LEAN Tier-2 anchor body from docs/agents/wave-anchor-template.md into /tmp/anchor.md:
147
- # body header `**Welle $WAVE — <Thema>**`, **plan_revision:** r<N> at top (before the first
148
- # heading), the FILLED Slices table (you know the cut), the To-Do checklist collapsed to its
149
- # one-line summary. The full grilled PRD does NOT go into the body (: every slice
150
- # session's `--json body` read loads the whole body a <details> block collapses only in
151
- # the browser). Save it to /tmp/prd-archive.md instead — **with ALL embedded PRD markers
152
- # stripped** (`plan_revision`, `prd-source-id`, `prd-content-fp`,
153
- # `<!-- prd: awaiting-decomposition -->`; a stray second `plan_revision` on the issue is
154
- # exactly the Retro confusion) posted as ISSUE COMMENT #1 in step 2b.
155
- # The anchor carries its own markers at the head. The issue TITLE is rewritten to
156
- # `Welle N — <Thema>` by the promote step below (step 3) — do NOT set it here; promote
157
- # prepends the wave prefix (and strips any `fix:`/`feat:` prefix) idempotently.
158
- # Rewrite the PRD body via skill-prose gh (body-fill is issue CONTENT, NOT a board write — the
159
- # helper owns board state only; cf. test_plan_body_fill_is_not_a_board_sync_op; gh-lint allows a
160
- # non-workflow-label `gh issue edit`). Content-edit FIRST so a failure stops before board mutation:
161
- gh issue edit <prd#> --body-file /tmp/anchor.md
162
-
163
- # 2b. archive the full PRD as comment #1 on the anchor: one click away for a human,
164
- # loaded only on demand by an agent (`--json body` never fetches comments). First line:
165
- # `📄 Full PRD (archive, r<N>) the body carries navigation/decisions only`.
166
- # Idempotent re-run: a comment already starting with `📄 Full PRD (archive` skip, never duplicate:
167
- gh issue comment <prd#> --body-file /tmp/prd-archive.md
168
-
169
- # 3. set the board state (type:cluster + Wave). If THIS fails AFTER the body edit, the title/body are
170
- # already rewritten STOP, report "board state incomplete (body/title already changed)", and
171
- # re-run the idempotent promote (do not leave a silent partial state):
172
- python3 scripts/board-sync.py promote --issue <prd#> --wave "$WAVE" # sets type:cluster + Wave + title `Welle N — …`
146
+ # 2. Fill /tmp/anchor-template.md from docs/agents/wave-anchor-template.md (Tier 2):
147
+ # body header `**Welle $WAVE — <Topic>**`, anchor-owned markers at the head,
148
+ # filled Slices table, and the To-Do checklist collapsed to one line. Save the
149
+ # unchanged source PRD body as /tmp/source-prd.md. The renderer reads only those
150
+ # two files and writes only stdout: no GitHub/network call and no mutation.
151
+ python3 scripts/render-anchor.py --template /tmp/anchor-template.md \
152
+ --prd /tmp/source-prd.md --document anchor > /tmp/anchor.md
153
+ python3 scripts/render-anchor.py --template /tmp/anchor-template.md \
154
+ --prd /tmp/source-prd.md --document archive > /tmp/prd-archive.md
155
+ ```
156
+
157
+ The anchor output is the filled template byte-for-byte. The archive starts with
158
+ the stable `📄 Full PRD` marker and strips every canonical marker line
159
+ (`plan_revision`, `prd-source-id`, `prd-content-fp`, `<!-- prd: -->`) only
160
+ from the source body's head block. Marker-looking text in a quote, fence, or
161
+ later section is content and remains untouched.
162
+
163
+ Promotion uses the remote issue itself as its journal. Classify four
164
+ observations before every resume. Before transition 1, `S=yes|no` compares a
165
+ freshly fetched remote body byte-for-byte with `/tmp/source-prd.md`, the source
166
+ snapshot that produced both rendered outputs. Once `B=yes`, that source
167
+ snapshot is no longer active and `S=n/a`. `B=yes|no` says whether the fetched
168
+ issue body is byte-identical to `/tmp/anchor.md`.
169
+ `C=0|exact-1|wrong-1|duplicates(<ids>)` classifies stable-marker comments:
170
+ none; exactly one whose whole body is byte-identical to
171
+ `/tmp/prd-archive.md`; exactly one with different bytes; or multiple matches
172
+ with every comment ID retained. `P=absent|complete|partial` classifies only
173
+ promotion-owned board state. `P=absent` accepts either an
174
+ ordinary pre-state (no `type:cluster`, Wave unset, no `Welle` title prefix) or a
175
+ valid Stufe-1p pre-state (`wave-stub` present, no `type:cluster`, and the
176
+ pre-stamped Wave/title match `$WAVE`). `P=complete` requires `type:cluster`, the
177
+ expected Wave/title, and no remaining `wave-stub`. Every other combination —
178
+ including a different Wave — is `P=partial`. Fetch comments with the paginated
179
+ API, never the first page alone:
180
+
181
+ ```bash
182
+ gh api --paginate --slurp \
183
+ "repos/<owner>/<repo>/issues/<prd#>/comments?per_page=100"
184
+ ```
185
+
186
+ Flatten every returned page, retain the comment `id`, and exact-match the
187
+ start-of-body marker. The four valid states and their sole resume action are:
188
+
189
+ <!-- promotion-board-observation-table:start -->
190
+ | Scenario | Observable board facts | P classification |
191
+ |---|---|---|
192
+ | `ordinary-prestate` | no cluster; Wave unset; no Wave title | `absent` |
193
+ | `stufe-1p-prestate` | wave-stub; no cluster; expected Wave/title | `absent` |
194
+ | `promoted` | cluster; expected Wave/title; no wave-stub | `complete` |
195
+ | `cluster-only` | cluster; Wave/title missing | `partial` |
196
+ | `wrong-wave` | any different Wave value | `partial` |
197
+ <!-- promotion-board-observation-table:end -->
198
+
199
+ <!-- promotion-state-table:start -->
200
+ | State | Observable predicates | Resume action |
201
+ |---|---|---|
202
+ | `initial` | `S=yes`, `B=no`, `C=0`, `P=absent` | render + write body |
203
+ | `body-written` | `S=n/a`, `B=yes`, `C=0`, `P=absent` | reconcile + write archive comment |
204
+ | `comment-written` | `S=n/a`, `B=yes`, `C=exact-1`, `P=absent` | promote board state |
205
+ | `promoted` | `S=n/a`, `B=yes`, `C=exact-1`, `P=complete` | no-op; continue publish audit |
206
+ <!-- promotion-state-table:end -->
207
+
208
+ Each transition is idempotent and has an explicit contract:
209
+
210
+ 1. **Write body (`initial → body-written`).** Pre: `S=yes`, `B=no`, `C=0`,
211
+ `P=absent`. Fetch the remote body again immediately before the command and
212
+ recompute `S`; a prior fetch is not sufficient.
213
+ Run `gh issue edit <prd#> --body-file /tmp/anchor.md`, refetch the body, and
214
+ require a byte match. Post: `S=n/a`, `B=yes`, `C=0`, `P=absent`.
215
+ 2. **Write archive (`body-written → comment-written`).** Pre: `S=n/a`, `B=yes`,
216
+ `C=0`, `P=absent`. Re-run the pagination-aware lookup immediately before
217
+ create; if it now yields `C=exact-1`, classify as `comment-written` and do
218
+ not create. `C=wrong-1` or `C=duplicates(<ids>)` is drift and enters repair,
219
+ never create. Only `C=0` runs `gh issue comment <prd#> --body-file
220
+ /tmp/prd-archive.md`, then immediately paginate and reconcile again. Post:
221
+ `S=n/a`, `B=yes`, `C=exact-1`, `P=absent`.
222
+ 3. **Promote (`comment-written → promoted`).** Pre: `S=n/a`, `B=yes`,
223
+ `C=exact-1`, `P=absent`. Run `python3 scripts/board-sync.py promote --issue <prd#> --wave
224
+ "$WAVE"`, refetch body, comments, labels, Wave, and title. Post: `S=n/a`,
225
+ `B=yes`, `C=exact-1`, `P=complete`. Re-running `promote` with the same Wave
226
+ is the repair for `P=partial`; a different Wave remains a hard stop.
227
+
228
+ Any other predicate combination is drift, not a fifth state. Repair it
229
+ explicitly, then reclassify. `S=no` before transition 1 means **STOP**: report
230
+ the diff between the fresh remote body and `/tmp/source-prd.md`, never write the
231
+ stale render, re-fetch the remote body into a reviewed source snapshot, and
232
+ rerender both outputs before recomputing `S`. `B=no` outside the valid `initial` tuple
233
+ means **STOP**, report the body diff against `/tmp/anchor.md`, and require
234
+ an explicit operator decision to restore the rendered anchor or adopt the remote
235
+ edit and rerender both outputs; never overwrite remote journal evidence automatically.
236
+ Only transition 1 performs the approved source-to-anchor body write without
237
+ this drift gate. `C=wrong-1` → report its ID and explicitly update it to the
238
+ rendered archive; `P=complete` with `C=0` → create/reconcile the archive without
239
+ demoting. For `P=partial`, a different Wave is a hard stop; otherwise rerun
240
+ same-Wave `promote`. `C=duplicates(<ids>)` always means **STOP and report every
241
+ comment ID**. An operator must choose and explicitly delete/update the
242
+ duplicates, then rerun the paginated lookup; never select the first match or
243
+ silently discard one. No local operation journal is written: these
244
+ observations are the journal.
245
+
246
+ ```bash
247
+ # 3. Continue only from the `promoted` state.
173
248
 
174
249
  # 4. create each child (dependency order), then link it under the anchor — BEFORE the §7 exit audit,
175
250
  # so the checker sees the anchor's children (a childless type:cluster anchor mis-reads as a leaf)
@@ -302,7 +377,7 @@ Reference the blocking ticket(s), or "None - can start immediately".
302
377
  <!-- mirror-xform:start codex-escalation -->
303
378
  ```
304
379
  Welle <N> · Slice <X> (<closes #x | refs #<prd#>, Parent #<prd#>>). Read #<prd#> for decisions.
305
- Start skill: 🧭 Design Grill → /grill-with-docs-codex · 🔬 Verify Spike → /verify-spike · 📐 Trade-off/Research → /decision-gate · AFK → /tdd · HITL → /grill-me → /tdd. Recommended model: <Model [Effort]>.
380
+ Start skill: 🧭 Design Grill → /grill-with-docs-codex · 🔬 Verify Spike → /verify-spike · 📐 Trade-off/Research → /decision-gate · AFK → /implement · HITL → /grill-me → /implement. Recommended model: <Model [Effort]>.
306
381
  Worktree: your project's worktree helper, or `git worktree add`
307
382
  Scope (<N> files) — REQUIRED FIELD, blast-radius estimate at cut time; the build session checks it against its own recon findings, >2x deviation → STOP:
308
383
  - <concrete file + change>
@@ -49,11 +49,21 @@ gh project item-list 1 --owner <owner> --limit 500 --format json # check targe
49
49
  - **Mode A — idempotency via two separate markers in the body:**
50
50
  - **Stable source identity** `<!-- prd-source-id: <id> -->` — **never** changes across plan content edits (otherwise search-before-create misses the changed re-run → duplicate). **Default rule** for `<id>` (identity ≠ content; set on the **first** to-prd run, **never** changed after — the slug then lives in the issue body and is discoverable via search-before-create): kebab-case slug of the plan topic. Priority: **(1)** explicitly passed ID / durable issue number → **(2)** existing slug from a prior run (found via search-before-create) → **(3)** new kebab-case slug from the plan/title topic. The `PLAN.md` path is only a **secondary hint** (not stable across worktrees; external specs have none), **never** the identity itself.
51
51
  - **Separate content fingerprint** `<!-- prd-content-fp: <hash> -->` — only for diff/audit/bump decisions, **not** for identity.
52
- - **search-before-create:** **no** reliance on GitHub Search (doesn't index HTML comments). Bounded, local:
52
+ - **search-before-create:** use the shared all-state exact-marker lookup (it uses
53
+ `gh api --paginate`, discards REST pull-request items, and never relies on
54
+ GitHub Search or a capped issue list):
53
55
  ```bash
54
- gh issue list --repo <owner>/<repo> --state open --limit 500 --json number,body,labels
55
- # filter locally on `prd-source-id: <id>` → 1 match ⇒ update; >1 ⇒ STOP+report; 0 ⇒ create
56
+ python3 scripts/find-by-marker.py --kind prd-source-id --slug "<id>"
56
57
  ```
58
+ Branch on its JSON contract (`count`, `issues[].number`, `issues[].state`,
59
+ `verdict`): `0` / `create` → create; exactly one `open` / `update` → update
60
+ that issue; exactly one `closed` / `user-decision` → ask the user whether to
61
+ reopen, use a new identity, or stop; `>1` / `STOP` → stop and report every
62
+ number/state. Never auto-delete or silently replace a closed/duplicate identity.
63
+ Immediately after a Mode-A create, run the same lookup with
64
+ `--created <new-issue-number>`. Continue only when it returns exactly the
65
+ newly-created open issue; duplicate reconciliation is a loud `STOP` that
66
+ reports both/all numbers for user-decided resolution.
57
67
 
58
68
  ## 4. Write the Draft PRD (deliverable)
59
69
 
@@ -192,10 +192,22 @@ A re-run of to-waves on the same program is **delta-apply** and doubles as
192
192
  bottom-up `wave-stub-source` marker; `<prd-source-id>` is the PRD's own source
193
193
  slug). These never change across revisions — they are the identity for
194
194
  search-before-create.
195
- - **Delta apply.** Filter existing issues locally by their source marker
196
- (`gh issue list --json number,body` + a local filter, no reliance on GitHub search —
197
- it does not index HTML comments). For each planned stub/leaf: **match** → update in
198
- place (never duplicate); **missing** → create; a live issue carrying a
195
+ - **Delta apply.** Resolve every planned identity through the shared all-state,
196
+ exact-marker CLI (it uses `gh api --paginate`, discards REST pull-request
197
+ items, and does not rely on GitHub Search or a capped issue list):
198
+ ```bash
199
+ python3 scripts/find-by-marker.py --kind program-stub-source --slug "<prd-source-id>/w<N>"
200
+ python3 scripts/find-by-marker.py --kind program-leaf-source --slug "<prd-source-id>/<local-id>"
201
+ ```
202
+ Branch on each JSON result (`count`, `issues[].number`, `issues[].state`,
203
+ `verdict`): `0` / `create` → create; exactly one `open` / `update` → update in
204
+ place; exactly one `closed` / `user-decision` → ask the user whether to reopen,
205
+ use a new identity, or stop; `>1` / `STOP` → stop and report every number/state.
206
+ Never auto-delete or silently replace a closed/duplicate identity. Immediately
207
+ after every create, run the same lookup with `--created <new-issue-number>` and
208
+ continue only when exactly the newly-created open issue is returned; a duplicate
209
+ reconciliation stops loudly with both/all numbers for user-decided resolution.
210
+ A live issue carrying a
199
211
  `program-*-source` for this program that the current plan no longer references →
200
212
  report as **orphaned** (do not auto-close — closing is the abort convention, §8).
201
213
  Cross-check the native children (`children-of <prd#>` and each stub) against the
@@ -17,7 +17,7 @@ This is the "Verify First" rule with a runnable harness behind it: when you cann
17
17
  | "Which of these options, given these trade-offs?" / "I need to research this before I can choose." (bounded, sub-grill) | `decision-gate` |
18
18
  | "Does this design / state model / UI feel right?" (open-ended) | `prototype` |
19
19
  | "Why is this broken / slow?" (root-cause of a known defect) | `diagnose` |
20
- | "Build this behaviour, test-first." (new feature/fix) | `tdd` |
20
+ | "Build this behaviour, test-first." (new feature/fix) | `implement` |
21
21
 
22
22
  If the question is really "what should this be", it is not a verify-spike — those are open, not yes/no.
23
23
 
@@ -39,9 +39,21 @@ Hard stop (the only pure precondition): not in a feature worktree / on `main`
39
39
 
40
40
  ### 2 · Retro gate (blocking, optional retro-exit — before anything is committed)
41
41
  One reminder, not a merge confirmation:
42
- > "Already ran a retro? **(a)** yes / continue → landing now. **(b)** you want one first → clean abort here, run `/retro`, then `/wrapup` again — repo-file patches then travel in this PR."
42
+ > "Already ran a retro? **(a)** yes / continue → landing now. **(b)** you want one first → the retro starts now; afterwards, invoke `/wrapup` again — repo-file patches then travel in this PR."
43
43
 
44
- (b) → exit cleanly, touch nothing (a skill can't pause/resume another skill). **Never auto-run `/retro`.** The answer materializes as the mandatory `**Retro:**` PR-body line in step 4 — that's recording, not a second question. Why the gate lives here: in a foreign project this is the only portable retro touchpoint; a project-local "offer retro before PR" convention usually answers it already.
44
+ (b) → **invoke the `retro` skill immediately in this run.** Retro is
45
+ model-invocable and non-deploying, and every mutation still has its own approval
46
+ gate. After retro finishes, **land nothing in this run**. Require a **fresh
47
+ explicit `/wrapup` invocation** because retro may have changed the exact diff
48
+ that the next merge authorization covers.
49
+
50
+ General chaining rule: automatically chain only into a **model-invocable**,
51
+ **non-deploying** workflow. If the named target is user-only, deploys, or
52
+ depends on an external action, **return control to the user** and **state the
53
+ reason**. A forward chain never carries wrapup's merge/deploy authorization
54
+ into another run.
55
+
56
+ The answer materializes as the mandatory `**Retro:**` PR-body line in step 4 — that's recording, not a second question. Why the gate lives here: in a foreign project this is the only portable retro touchpoint; a project-local "offer retro before PR" convention usually answers it already.
45
57
 
46
58
  ### 3 · Commit (only if the tree is dirty)
47
59
  Judgment first, then the guarded commit:
@@ -77,5 +89,4 @@ STOP → diagnose in the main conversation, fix, re-run `land` (an already-merge
77
89
 
78
90
  ## Out of scope
79
91
  - Live-verify / DoD: must happen **before** `/wrapup` — this skill lands, it does not verify.
80
- - `/retro`: offered before landing (step 2), never run by this skill.
81
92
  - Other worktrees / their servers stay untouched.