create-anpunkit 2.1.0 → 2.2.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.
@@ -52,7 +52,7 @@ cd my-project && bash setup.sh
52
52
  |-----------------|------------------------------------------------------------------------------|
53
53
  |`/overview` |design-research → RESEARCH REVIEW → grill (×2, incl. data/state flow) → OVERVIEW + DATAFLOW → PLAN (Phase 0 first) → STATE|
54
54
  |`/infra` |provision Azure infra: Bicep → what-if → review → apply → INFRA.md + .env.test → AUTH PROOF|
55
- |`/phase [n]` |run one phase: research → SCAFFOLD → RED → TEST REVIEW → GREEN → E2E, with circuit breaker|
55
+ |`/phase [n]` |run one phase: research → SPEC fill → SPEC REVIEW → SCAFFOLD → RED → conformance → GREEN → boundary/E2E, with circuit breaker|
56
56
  |`/quick [change]`|small obvious change, direct, no agent chain |
57
57
  |`/unstuck` |deep re-research after a circuit breaker (you trigger it) |
58
58
  |`/synthesize` |compress STATE.md, dedup ISSUES.md, prune snapshots |
@@ -63,23 +63,31 @@ cd my-project && bash setup.sh
63
63
 
64
64
  ## Subagents
65
65
 
66
- `researcher` (Haiku, two modes: design + impl) · `planner` (Opus) · `infra-provisioner` (Opus) ·
67
- `implementer` (Opus, SCAFFOLD/FILL modes) · `test-author` (Opus, blind, RED-first) · `debugger` (Opus, isolated) ·
68
- `e2e-runner` (Opus, blind, Playwright) · `synthesizer` (Haiku)
66
+ `researcher` (Haiku, two modes: design + impl) · `planner` (Opus, also writes skeleton specs) ·
67
+ `infra-provisioner` (Opus) · `spec-author` (Opus, fills per-phase spec + fixtures) ·
68
+ `implementer` (Opus, SCAFFOLD/FILL modes) · `test-author` (Opus, harness emitter) · `debugger` (Opus, isolated) ·
69
+ `e2e-runner` (Opus, Playwright emitter) · `synthesizer` (Haiku)
69
70
 
70
71
  The main session is the orchestrator — it routes, it does not implement.
71
72
 
72
- ## The loop (v2.1: TDD-first + human gates + coverage guards)
73
-
74
- Phases that add a public callable surface run test-first:
75
- `RESEARCH -> SCAFFOLD -> RED -> TEST REVIEW -> GREEN -> E2E -> FIX -> CLOSE`. The
76
- implementer writes interface stubs only; the `test-author` writes the suite blind
77
- against those stubs (it must collect cleanly and FAIL — the RED gate) and emits a
78
- `docs/test-plan-phase-<n>.md` with a mandatory "NOT covered / assumptions"
79
- section. **TEST REVIEW** is a human gate: you approve the test plan before the
80
- implementer fills to green so "all tests passed but the core was broken" can't
81
- slip through silently. Pure infra/config/doc phases keep the direct
82
- `RESEARCH -> IMPLEMENT -> TEST` order (no TEST REVIEW no public surface).
73
+ ## The loop (v2.2: spec-driven contract + upstream human gate + generated tests)
74
+
75
+ Phases that add a public callable surface run spec-first:
76
+ `RESEARCH -> SPEC fill -> spec-staleness -> SPEC REVIEW -> SCAFFOLD -> RED -> spec-conformance -> GREEN -> boundary/E2E -> FIX -> CLOSE`.
77
+ The reviewable, authoritative artifact is the **spec**, not the test. At `/overview`
78
+ the planner enumerates the case *names* per phase (skeleton `docs/spec-phase-<n>.md`).
79
+ At phase start the new `spec-author` fills them with concrete cases real inputs,
80
+ real expected outputs, matcher tokens for volatile fields written to shared
81
+ `fixtures/` files. **SPEC REVIEW** is a human gate that sits *upstream* (before any
82
+ code): you confirm falsifiable claims in plain language ("empty order → 422
83
+ EMPTY_ORDER"). Tests are then GENERATED from the locked spec rows (deep-equality +
84
+ matcher tokens for `data`; Playwright from the descriptor for `ui`) loading the
85
+ *same* fixtures — so a test physically cannot assert different values than the spec.
86
+ `spec-conformance.sh` blocks GREEN until no `TBD` remains and every case-id is cited
87
+ by a boundary test. This is the v2.2 fix for "both agents independently fabricated
88
+ the same wrong contract from a one-line acceptance and the suite went green on a
89
+ broken core." Pure infra/config/doc phases keep the direct
90
+ `RESEARCH -> IMPLEMENT -> TEST` order (no spec, no SPEC REVIEW — no public surface).
83
91
 
84
92
  Frontend phases are detected by a **deterministic path match** (`has_frontend` +
85
93
  the frontend root, both set in `docs/OVERVIEW.md`): if a phase changes a file
@@ -164,6 +172,9 @@ home-dir custom-prompts with a divergent UX).
164
172
  - `docs/HISTORY.md` — one line per finished phase
165
173
  - `docs/OVERVIEW.md` — project scope, written after double-grill
166
174
  - `docs/DATAFLOW.md` — state-transition table per key object (grilled at /overview; drives CLOSE coverage gate)
175
+ - `docs/spec-phase-<n>.md` — per-phase behavioral contract (skeleton at /overview, filled by spec-author; human-reviewed at SPEC REVIEW)
176
+ - `fixtures/<case-id>-{input,expected,ui}.json` — shared by the spec row and the generated test harness (committed; part of the contract)
177
+ - `tests/helpers/spec-assert.{py,ts}` — kit-versioned matcher-aware comparator (honors `<UUID>`, `<ISO8601>`, … tokens)
167
178
  - `docs/INFRA.md` — Azure resource manifest + cost estimates (written by infra-provisioner)
168
179
  - `docs/ENDPOINTS.md` — API/service endpoint catalogue (maintained by implementer)
169
180
  - `docs/.snapshots/` — pre-compact recovery markers (auto-pruned, gitignored)
@@ -119,6 +119,18 @@ Store the round-1 answers as working context — do NOT write OVERVIEW.md yet.
119
119
  interactive element the phase introduces (not "page renders 200").
120
120
  - Map each phase to the DATAFLOW transitions it is expected to make reachable.
121
121
 
122
+ The planner ALSO writes the up-front SKELETON spec files (v2.2, §5.44/§5.51):
123
+ one `docs/spec-phase-<n>.md` per public-surface phase (skip Phase 0 + pure
124
+ infra/config/doc phases), enumerating the case NAMES — happy path, each named
125
+ edge, each named failure + error code — for every `dataflow:` transition and
126
+ every `acceptance` criterion, with `TBD` values. The generated header transcludes
127
+ that phase's `acceptance:` line + in-scope `DATAFLOW.md` transition rows verbatim.
128
+
129
+ 8b. STAMP each skeleton's staleness hash: for every `docs/spec-phase-<n>.md` the
130
+ planner wrote, run `bash scripts/spec-staleness.sh stamp <n>`. This embeds the
131
+ hash of the transcluded acceptance line + transition rows so phase-time
132
+ `/phase` can detect upstream drift. (Values are filled per phase by `spec-author`.)
133
+
122
134
  9. Create docs/STATE.md:
123
135
  ```
124
136
 
@@ -144,6 +156,11 @@ blocker: none
144
156
  ```
145
157
 
146
158
  Then stop and show me PLAN.md + DATAFLOW.md for approval before any phase starts.
159
+ EXTEND the approval surface (v2.2, §5.51 — one confirmation, no new gate): for each
160
+ public-surface phase, list the transition/acceptance ids it covers and the enumerated
161
+ case NAMES (no values). I confirm the case-name set is COMPLETE here — these names
162
+ are the up-front behavioral contract; values get filled + reviewed per phase at
163
+ `/phase` SPEC REVIEW.
147
164
 
148
165
  Remind me: "Run `/infra` next to provision the Azure environment (Phase 0) and
149
166
  run the one-time AUTH PROOF before starting Phase 1."
@@ -1,10 +1,10 @@
1
1
  ---
2
- description: Run one phase end-to-end. TDD phases run SCAFFOLD -> RED -> TEST REVIEW -> GREEN; non-TDD phases run IMPLEMENT -> TEST. Both with the debug circuit breaker and the regression + dataflow + evidence guards at CLOSE.
2
+ description: Run one phase end-to-end. TDD phases run SPEC fill -> SPEC REVIEW -> SCAFFOLD -> RED -> conformance -> GREEN -> boundary/E2E; non-TDD phases run IMPLEMENT -> TEST. Both with the debug circuit breaker and the regression + dataflow + evidence guards at CLOSE.
3
3
  argument-hint: [phase number]
4
4
  ---
5
5
 
6
6
  Caveman ULTRA mode. You are the ORCHESTRATOR. Route work to subagents —
7
- you do NOT implement or debug yourself.
7
+ you do NOT implement, fill specs, or debug yourself.
8
8
 
9
9
  Note: subagents cannot talk to the user. Only YOU can.
10
10
 
@@ -29,20 +29,21 @@ b. PHASE STATE CHECK: Read docs/STATE.md and docs/PLAN.md.
29
29
  c. FINAL PHASE CHECK: Read docs/PLAN.md. Is this the last phase (no further
30
30
  pending phases after this one)? Record this as IS_FINAL_PHASE=true/false.
31
31
 
32
- d. AUTH LIVENESS GATE (hard rule 16 replaces the old soft nudge): if this phase
33
- will run a real/E2E suite, confirm every credential it needs is live NOW.
32
+ d. AUTH LIVENESS GATE (hard rule 16): if this phase will run a boundary/E2E suite,
33
+ confirm every credential it needs is live NOW.
34
34
  - If INFRA.md has no `AUTH PROOF: PASS` marker -> STOP: "Auth never proven
35
35
  reusable. Run `/infra` first."
36
36
  - Run `scripts/auth-setup.sh --check` (Entra token obtainable + not expired)
37
37
  and, for each external system this phase touches (docs/DATAFLOW.md external
38
38
  rows + docs/ENDPOINTS.md auth column), confirm its credential is obtainable
39
- headlessly. Any failure -> real/E2E is BLOCKED; tell me what to run; the
39
+ headlessly. Any failure -> boundary/E2E is BLOCKED; tell me what to run; the
40
40
  MOCK suite may still proceed.
41
41
 
42
42
  e. FRONTEND TRIGGER (hard rule 13): read docs/OVERVIEW.md `has_frontend` + the
43
43
  frontend root. Set FRONTEND_PHASE=true iff `has_frontend: true` AND this
44
44
  phase's `changes` (docs/PLAN.md) include any path under the frontend root.
45
- This is a PATH MATCH, not a judgment call. Record FRONTEND_PHASE for the GATE.
45
+ This is a PATH MATCH, not a judgment call. Record FRONTEND_PHASE it gates the
46
+ `ui` boundary run + evidence at CLOSE.
46
47
 
47
48
  ---
48
49
 
@@ -57,8 +58,9 @@ datasource, compare what it touches to the confirmed BASELINE in
57
58
  docs/research/datasource-<name>.md. If it touches a NEW table/column beyond the
58
59
  baseline -> surface my understanding of just that delta as a falsifiable claim;
59
60
  WAIT for confirm; append it to datasource-<name>.md. If it touches only confirmed
60
- data -> proceed with a one-line note, no stop. Real/E2E against an UNCONFIRMED
61
- datasource is HARD-BLOCKED (mock still runs).
61
+ data -> proceed with a one-line note, no stop. Boundary/E2E against an UNCONFIRMED
62
+ datasource is HARD-BLOCKED (mock still runs). The confirmed baseline is what
63
+ `spec-author` grounds fixtures in.
62
64
 
63
65
  Then classify the phase:
64
66
 
@@ -66,63 +68,105 @@ Then classify the phase:
66
68
  exported function/class, CLI command, message contract) assertable from the
67
69
  acceptance spec. Size is NOT the criterion.
68
70
 
69
- - Clear public surface -> `TDD_PHASE=true` -> run the TDD path (§2 → §3a → §3r → §3b).
71
+ - Clear public surface -> `TDD_PHASE=true` -> run the TDD path (§2 → §3 → §4 → §5 → §6 → §7).
70
72
  - Pure infra/config/doc, no public surface -> `TDD_PHASE=false` -> run the
71
73
  non-TDD path (§2N → §3N).
72
74
  - AMBIGUOUS -> default `TDD_PHASE=true`, but STATE the classification + the reason
73
- to me, so I can override to non-TDD BEFORE SCAFFOLD fires. (Hard rule 11: never
74
- downgrade a TDD phase just to dodge the RED gate.)
75
+ to me, so I can override to non-TDD BEFORE SPEC fill fires. (Hard rule 11: never
76
+ downgrade a TDD phase just to dodge the gates.)
75
77
 
76
78
  =====================================================================
77
79
  ## TDD PATH (TDD_PHASE=true)
78
80
  =====================================================================
79
81
 
80
- ## 2. SCAFFOLD
82
+ ## 2. SPEC FILL + STALENESS
83
+
84
+ a. SKELETON CHECK: confirm docs/spec-phase-<n>.md exists (planner generated it at
85
+ /overview). If MISSING (planner classified it non-TDD, or it's a new phase from
86
+ /replan): generate the skeleton NOW from this phase's PLAN.md `acceptance` +
87
+ `dataflow:` transitions in the planner skeleton format (generated header + named
88
+ `TBD` rows), then `bash scripts/spec-staleness.sh stamp <n>` to stamp its hash.
89
+
90
+ b. Dispatch `spec-author`. It fills each case row with a real input payload
91
+ (`fixtures/<case-id>-input.json`), concrete expected output
92
+ (`fixtures/<case-id>-expected.json`), matcher tokens for volatile fields,
93
+ `error-code` for failures, and `selector/assert/value` `ui` descriptors —
94
+ grounded in the RESEARCH findings + the confirmed datasource baseline.
95
+
96
+ c. CASE-SET-DIVERGENCE (hard re-entry, hard rule 12 / §5.52): if `spec-author`
97
+ returns `CASE-SET-DIVERGENCE` (a required case can't be filled from real facts,
98
+ or research revealed an unlisted/contradicted case) -> STOP. Surface the finding.
99
+ I amend the up-front case-name contract in the skeleton; you re-stamp
100
+ (`bash scripts/spec-staleness.sh stamp <n>`); then re-dispatch `spec-author` to
101
+ re-fill from scratch. AI never amends the case-name set — I own the contract.
102
+
103
+ d. STALENESS (hard rule 17): run `bash scripts/spec-staleness.sh <n>`. Nonzero
104
+ (upstream PLAN acceptance line / DATAFLOW rows drifted since the skeleton was
105
+ stamped, e.g. via /replan) -> regenerate the skeleton header from current
106
+ PLAN/DATAFLOW, re-stamp, re-dispatch `spec-author`. Do NOT hand-edit the hash.
107
+
108
+ ## 3. SPEC REVIEW — human gate (hard rule 12)
109
+
110
+ STOP. Surface the FILLED cases to me as FALSIFIABLE CLAIMS in plain language, e.g.:
111
+ - "POST /orders/submit with an empty line-item list → 422 EMPTY_ORDER."
112
+ - "Successful submit of a 3-line order → 201; order.id is a UUID; order.status is
113
+ 'submitted'."
114
+ Re-run `bash scripts/spec-staleness.sh <n>` at entry (nonzero -> back to §2d).
115
+ SCAFFOLD cannot begin until I confirm. Classify any rejection WITH me (§5.50):
116
+ - WRONG EXPECTED -> fix the case row + `fixtures/<case-id>-expected.json`; no
117
+ re-research. (You may patch the fixture directly per my correction.)
118
+ - WRONG INPUT SHAPE -> re-dispatch `spec-author` with the correction.
119
+ - NEW CASE or CONTRADICTED CASE -> hard re-entry (§2c): I amend the skeleton, you
120
+ re-stamp, re-confirm the amended case(s) + any case sharing their `covers` id
121
+ (the staleness hash certifies the unchanged remainder — not re-read), re-fill.
122
+ Loop until I approve. Unskippable on TDD phases.
123
+
124
+ ## 4. SCAFFOLD
81
125
 
82
126
  Dispatch `implementer` in SCAFFOLD mode: interface stubs only (signatures +
83
- types; bodies raise NotImplementedError / return 501); NO logic, NO tests.
84
- Returns the stub files + the interface surface.
127
+ types; bodies raise NotImplementedError / return 501); NO logic, NO tests, NO
128
+ edits to the spec or fixtures. Returns the stub files + the interface surface.
85
129
 
86
- ## 3a. RED
130
+ ## 5. RED
87
131
 
88
- Dispatch `test-author` to write the REAL API suite (+ mock) BLIND against the
89
- stubs + acceptance, AND emit docs/test-plan-phase-<n>.md (acceptance criteria →
90
- test names, plus a mandatory "NOT covered / assumptions" section). Place
91
- contract/ENDPOINTS/DATAFLOW-transition tests in `tests/regression/`, phase-local
92
- tests in `tests/phase-<n>/`. Run the suite.
132
+ Dispatch `test-author` to EMIT the boundary harness from the locked spec `data`
133
+ rows: one deep-equality assertion per case against `fixtures/<case-id>-expected.json`
134
+ via the kit comparator `tests/helpers/spec-assert.*`, each citing its case with a
135
+ `# spec: <case-id>` comment. It does NOT author assertions — it generates them from
136
+ the spec. Place contract/ENDPOINTS/transition tests in `tests/regression/`,
137
+ phase-local in `tests/phase-<n>/`.
93
138
 
94
- RED GATE = every acceptance test COLLECTS cleanly AND FAILS (assertion /
95
- NotImplemented).
96
- - Any test PASSES on stubs -> STOP (spec trivial or test wrong); show me.
139
+ If FRONTEND_PHASE (and the phase has `ui` cases): also dispatch `e2e-runner` to EMIT
140
+ Playwright assertions from each `ui` case's `fixtures/<case-id>-ui.json` descriptor,
141
+ each citing `// spec: <case-id>`. Run the suites.
142
+
143
+ RED GATE = every case test COLLECTS cleanly AND FAILS (assertion / NotImplemented).
144
+ - Any test PASSES on stubs -> STOP (spec trivial or emitter wrong); show me.
97
145
  - Collection / import / syntax error -> stub mismatch; re-dispatch SCAFFOLD to
98
146
  fix SIGNATURES (not logic); re-run.
99
- - UNDERSPEC -> STOP; ask me to sharpen the acceptance spec.
100
147
 
101
- ## 3r. TEST REVIEWhuman gate (hard rule 12)
148
+ ## 6. CONFORMANCE GATE (hard rule 18) replaces the v2.1 human TEST REVIEW
102
149
 
103
- STOP. Surface docs/test-plan-phase-<n>.md to me: what each acceptance criterion
104
- maps to, and the "NOT covered / assumptions" section. GREEN cannot begin until I
105
- approve. On rejection, classify with me:
106
- - MISREAD of an adequate spec -> re-dispatch `test-author` with my feedback as
107
- added constraint; re-run RED; re-present the test plan.
108
- - UNDERSPEC (the acceptance spec itself is too vague) -> sharpen the acceptance
109
- spec in docs/PLAN.md, then re-dispatch `test-author` fresh.
110
- Loop until I approve. This gate is unskippable on TDD phases.
150
+ Run `bash scripts/spec-conformance.sh <n>`. It loud-fails (and BLOCKS GREEN) if:
151
+ - any `TBD` marker remains in docs/spec-phase-<n>.md or a referenced fixture, OR
152
+ - any case-id in the spec table has no boundary test citing it (`# spec: <case-id>`).
153
+ Nonzero -> fix the gap (re-dispatch `spec-author` for a stray TBD, or `test-author`/
154
+ `e2e-runner` for a missing citation) and re-run. GREEN cannot start until it passes.
111
155
 
112
- ## 3b. GREEN
156
+ ## 7. GREEN + BOUNDARY/E2E
113
157
 
114
- Dispatch `implementer` in FILL mode with the phase spec + research + the test
115
- file paths (it MAY read the tests — frozen before logic, no overfit — but must
116
- NOT edit them). Fill to green. Budget 3, WARN@2, STUCK@3.
158
+ Dispatch `implementer` in FILL mode with the FILLED docs/spec-phase-<n>.md + its
159
+ fixtures + research + the generated test file paths (it MAY read the tests — frozen
160
+ before logic, no overfit but must NOT edit tests, spec, or fixtures). Fill to
161
+ green against the spec. Budget 3, WARN@2, STUCK@3.
117
162
 
118
- If FRONTEND_PHASE (from PRE-FLIGHT e): dispatch `e2e-runner` MANDATORY, not
119
- optional (hard rule 13). It reads INFRA.md target, runs `scripts/e2e-stack.sh up`
120
- / Playwright / `down`, and captures a screenshot at EACH UI-existence assertion
121
- regardless of pass/fail to docs/evidence/e2e-phase-<n>/, with a summary in
122
- docs/research/e2e-<slug>.md. Acceptance spec has no UI-existence criterion ->
123
- e2e-runner returns UNDERSPEC -> STOP, sharpen the spec.
163
+ Run the BOUNDARY suite (real HTTP/CLI/message; `TEST_MODE=real`). If FRONTEND_PHASE,
164
+ `e2e-runner` runs its emitted `ui` specs — MANDATORY (hard rule 13) reads INFRA.md
165
+ target, runs `scripts/e2e-stack.sh up` / Playwright / `down`, and captures a
166
+ screenshot at EACH UI-existence assertion regardless of pass/fail to
167
+ docs/evidence/e2e-phase-<n>/, with a summary in docs/research/e2e-<slug>.md.
124
168
 
125
- PHASE GATE (rule 5) -> go to §456 (see GATE below).
169
+ PHASE GATE (rule 5) -> go to §8910 (see GATE below).
126
170
 
127
171
  =====================================================================
128
172
  ## NON-TDD PATH (TDD_PHASE=false)
@@ -137,18 +181,19 @@ includes "deployed URL" before proceeding.
137
181
 
138
182
  ## 3N. TEST (blind)
139
183
 
140
- Dispatch `test-author`. It writes MOCK + REAL API suites from the acceptance
141
- spec — never reads the logic. (No TEST REVIEW gate on the non-TDD path — no
142
- public surface to mis-test. e2e-runner only if FRONTEND_PHASE.)
184
+ Dispatch `test-author`. It writes MOCK + boundary suites from the acceptance
185
+ spec — never reads the logic. (No spec file, SPEC REVIEW, or conformance gate on
186
+ the non-TDD path — no public surface to contract. e2e-runner only if FRONTEND_PHASE.)
143
187
 
144
188
  =====================================================================
145
189
 
146
190
  ## GATE (both paths)
147
191
 
148
- PHASE GATE = current-phase REAL API suite passes AND (FRONTEND_PHASE) E2E passes
149
- WITH evidence captured AND the accumulated mock regression corpus stays green AND
150
- every docs/ENDPOINTS.md entry has a regression test AND every REACHABLE
151
- docs/DATAFLOW.md transition has a regression test (all checked at CLOSE).
192
+ PHASE GATE = current-phase BOUNDARY suite passes AND (FRONTEND_PHASE) the `ui`
193
+ boundary passes WITH evidence captured AND the accumulated mock regression corpus
194
+ stays green AND every docs/ENDPOINTS.md entry has a regression test AND (TDD)
195
+ `spec-conformance.sh` passed AND every REACHABLE docs/DATAFLOW.md transition has a
196
+ filled case in the phase spec (all checked at CLOSE).
152
197
  - GATE PASS -> go to CLOSE.
153
198
  - GATE BLOCKED (SERVICE UNAVAILABLE, STACK NOT READY, AZURE UNAVAILABLE, FLAKE)
154
199
  -> tell me, wait. Not a code bug. For AZURE UNAVAILABLE: suggest `/infra verify`.
@@ -156,17 +201,17 @@ docs/DATAFLOW.md transition has a regression test (all checked at CLOSE).
156
201
 
157
202
  ---
158
203
 
159
- ## 4. FIX
204
+ ## 8. FIX
160
205
 
161
206
  Dispatch `debugger` (isolated context) on the specific failure.
162
- - FIXED -> re-run TEST (and the regression corpus).
207
+ - FIXED -> re-run the boundary suite (and the regression corpus).
163
208
  - SERVICE UNAVAILABLE -> tell me, wait. Suggest `/infra verify` if Azure.
164
209
  - WARN (2 attempts failed) -> relay immediately, then let debugger finish attempt 3.
165
210
  - STUCK -> go to ESCALATE.
166
211
 
167
212
  ---
168
213
 
169
- ## 5. ESCALATE — circuit breaker. Mode B.
214
+ ## 9. ESCALATE — circuit breaker. Mode B.
170
215
 
171
216
  FIRST STUCK: STOP. Present to me: the problem, 3 failed hypotheses, the
172
217
  debugger's recommendation, the debug file path. Ask what to do. Wait. Options:
@@ -179,20 +224,22 @@ what to try next. Hand control to me.
179
224
 
180
225
  ---
181
226
 
182
- ## 6. CLOSE
227
+ ## 10. CLOSE
183
228
 
184
229
  REGRESSION + COVERAGE GATES (before closing — all FAIL HARD, do not close):
185
- - Run `scripts/regression.sh` (mock corpus). A failure BLOCKS close -> route to FIX.
230
+ - Run `bash scripts/regression.sh` (mock corpus). A failure BLOCKS close -> route to FIX.
186
231
  - ENDPOINTS COVERAGE: every `docs/ENDPOINTS.md` entry MUST have >=1 test in
187
232
  `tests/regression/`. Zero coverage -> FAIL HARD.
188
- - DATAFLOW COVERAGE (hard rule 14): every `docs/DATAFLOW.md` transition whose
189
- trigger is REACHABLE in the code shipped so far MUST have >=1 test in
190
- `tests/regression/`. Zero coverage on a reachable transition -> FAIL HARD.
191
- Unreachable transitions list as PENDING (not failed). IF IS_FINAL_PHASE: any
192
- transition still PENDING -> FAIL HARD (everything must be live by the last phase).
233
+ - DATAFLOW COVERAGE (hard rule 14, re-seamed v2.2): every `docs/DATAFLOW.md`
234
+ transition whose trigger is REACHABLE in the code shipped so far MUST have >=1
235
+ FILLED CASE in docs/spec-phase-<n>.md. Zero coverage on a reachable transition ->
236
+ FAIL HARD. Unreachable transitions list as PENDING (not failed). IF
237
+ IS_FINAL_PHASE: any transition still PENDING -> FAIL HARD. (The case→test half is
238
+ already enforced by `spec-conformance.sh` at §6 — every case-id is cited by a
239
+ boundary test, which by placement lands in tests/regression/.)
193
240
  - EVIDENCE (FRONTEND_PHASE only, hard rule 13): docs/evidence/e2e-phase-<n>/ must
194
241
  contain at least the per-UI-existence-assertion screenshots. Empty -> FAIL HARD.
195
- - IF IS_FINAL_PHASE: additionally run `scripts/regression.sh --real` (full real
242
+ - IF IS_FINAL_PHASE: additionally run `bash scripts/regression.sh --real` (full real
196
243
  corpus). A failure blocks close.
197
244
 
198
245
  Mark phase `done` in docs/PLAN.md.
@@ -202,7 +249,7 @@ ARCHITECTURE / DATAFLOW SELF-CHECK:
202
249
  workflow rule? YES -> run `/log-decision`. NO -> state why not.
203
250
  - Did this phase add/change an object's STATE LIFECYCLE? YES -> update
204
251
  docs/DATAFLOW.md (hard rule 9) in this CLOSE, and confirm new reachable
205
- transitions are covered. NO -> state why not.
252
+ transitions are covered by a filled case. NO -> state why not.
206
253
 
207
254
  IF IS_FINAL_PHASE — FINAL CLOSE sequence:
208
255
 
@@ -17,6 +17,31 @@
17
17
 
18
18
  Newest first. One entry per architectural change. Appended by `/log-decision`.
19
19
 
20
+ - **(v2.2)** — **Spec-driven behavioral contract.** Closes the v2.1 residual:
21
+ fabrication under a thin acceptance surface. In v2.1 a phase's whole contract was
22
+ a single `acceptance:` line; `implementer` and `test-author` each independently
23
+ elaborated it, and when both filled the same gap the same plausible-but-wrong way
24
+ the suite went green on a broken core — TEST REVIEW (review of *coverage*, after
25
+ RED) could not catch a faithful mapping to a *fabricated* criterion. The reframe:
26
+ the reviewable, authoritative artifact is the SPEC, not the test. New mechanism —
27
+ skeleton case-NAMES locked at `/overview` (planner) → per-phase concrete filling by
28
+ a new **`spec-author`** (real inputs/expecteds in shared `fixtures/`) → **SPEC
29
+ REVIEW** human gate UPSTREAM of code → tests GENERATED from the locked rows
30
+ (deep-equality + matcher tokens for `data`, Playwright-from-descriptor for `ui`),
31
+ sharing the same fixtures so a test cannot assert different values than the spec.
32
+ Two new orchestrator-procedure scripts (`spec-staleness.sh`, `spec-conformance.sh`)
33
+ replace the human TEST REVIEW gate. `test-author`/`e2e-runner` become harness
34
+ EMITTERS; `implementer` reads the filled spec as its contract (author ≠ implementer).
35
+ New decision entries §5.43–§5.56. New files: `.claude/agents/spec-author.md`,
36
+ `scripts/spec-staleness.sh`, `scripts/spec-conformance.sh`, `tests/helpers/
37
+ spec-assert.{py,ts}`, plus per-project `docs/spec-phase-<n>.md` + `fixtures/`.
38
+ REMOVED: the v2.1 human TEST REVIEW gate (humans no longer review tests).
39
+ NOTE: the v2.1 entries §5.33–§5.42 (TEST REVIEW gate, mandatory frontend E2E +
40
+ evidence, DATAFLOW coverage, datasource understanding, auth proof/liveness,
41
+ installer tool-selection) live in the v2.1 release bundle and the on-disk AGENTS.md
42
+ hard rules; they were never merged into this on-disk log (a hybrid file). The v2.2
43
+ decision numbers continue at §5.43 for continuity with the requirements doc.
44
+
20
45
  - **(v2.0.2)** — KB setup stays PATH-FIRST: the user clones the KB repo
21
46
  themselves (`git clone ... ~/anpunkit-kb`) and passes `--kb-path` (or the
22
47
  interactive prompt). New: the remote URL is auto-recorded from the clone's
@@ -452,6 +477,150 @@ native wiring).
452
477
 
453
478
  ---
454
479
 
480
+ > **Numbering note (v2.2).** §5.33–§5.42 are the v2.1 decisions (TEST REVIEW gate,
481
+ > mandatory frontend E2E + evidence, DATAFLOW transition coverage, datasource
482
+ > understanding, auth proof/liveness, installer tool-selection). They were recorded
483
+ > in the v2.1 release bundle and are reflected in AGENTS.md's hard rules, but were
484
+ > never merged into this on-disk log. v2.2 continues at §5.43 for continuity with the
485
+ > v2.2 requirements doc rather than renumbering.
486
+
487
+ ### 5.43 Spec file is a per-phase artifact, not inline in PLAN.md (v2.2)
488
+ **Problem:** a phase's whole behavioral contract was one `acceptance:` line; two
489
+ agents independently elaborated it and could agree on the same wrong contract.
490
+ **Decision:** `docs/spec-phase-<n>.md` is a new per-phase artifact; `PLAN.md`'s
491
+ `acceptance:` stays a one-line summary, the spec is its concrete expansion. The spec
492
+ is self-correlating: a GENERATED header transcludes that phase's `acceptance:` line +
493
+ the in-scope `DATAFLOW.md` transition rows and embeds a staleness hash; only the
494
+ example-case table is human-authored. **Rejected:** expanding `acceptance:` inline in
495
+ PLAN.md — couples the contract to `/replan` churn, bloats PLAN, mixes phase-ordering
496
+ review with concrete-behavior review.
497
+
498
+ ### 5.44 Two-layer baseline/delta — case-names up front, values per phase (v2.2)
499
+ **Decision:** lock behavior in two passes. (1) Up-front case-NAME contract at
500
+ `/overview`: for every DATAFLOW transition + every acceptance criterion, enumerate
501
+ the case names (happy / each edge / each failure + error code), no values yet —
502
+ skeleton spec files. (2) Per-phase concrete filling at `/phase` start (after
503
+ RESEARCH, before SCAFFOLD): `spec-author` fills real payloads/outputs grounded in
504
+ fresh research + the confirmed datasource baseline. **Rationale:** the only design
505
+ that gives BOTH "complete requirements locked before implementation" (names up front)
506
+ and "values grounded in real facts, not plan-time guesses" (per-phase fill). Mirrors
507
+ the established baseline/delta shape (datasource understanding, DATAFLOW coverage).
508
+
509
+ ### 5.45 Skeleton→filled single file; "no unfilled stub" is the conformance invariant (v2.2)
510
+ **Decision:** skeletons are generated at `/overview` (names + `TBD`); `spec-author`
511
+ fills in-place. Invariant: no `TBD` may remain when `spec-conformance.sh` runs
512
+ (between RED and GREEN). **Consequence:** a case that cannot be filled from research
513
+ is escalated as UNDERSPEC / `CASE-SET-DIVERGENCE` BEFORE SCAFFOLD, not discovered at
514
+ GREEN.
515
+
516
+ ### 5.46 Case structure: table row + boundary-typed fixture-ref (v2.2)
517
+ **Decision:** each case is one row — `case-id | covers | boundary | input-ref |
518
+ expected-ref | error-code | volatile`. `covers` = a DATAFLOW transition-id
519
+ (convention `Object:from->to`, no new DATAFLOW column) or acceptance criterion-id
520
+ (`ACC-<k>`). `boundary` ∈ {`data`,`ui`}. Refs point to `fixtures/<case-id>-*.json`
521
+ (scalars may inline). **Key property:** the harness loads the SAME fixture files the
522
+ spec row references — transcription from spec to test is STRUCTURAL, not honor-system;
523
+ a test physically cannot assert different values than the spec.
524
+
525
+ ### 5.47 Boundary test is system-of-record per case; optional mock mirror (v2.2)
526
+ **Decision:** every case has exactly one BOUNDARY test — `data`: real
527
+ HTTP/CLI/message vs the running backend + real services (v2.1's "real API suite");
528
+ `ui`: Playwright vs the deployed/local-docker target (v2.1's E2E). The boundary test
529
+ is the phase gate; green mock alone never closes (rule 5 / §5.38 preserved). A mock
530
+ mirror is optional, shares the fixture + comparator via `TEST_MODE`. "E2E" is
531
+ generalized to *outer-boundary*, not browser-specific: on `has_frontend: false` all
532
+ cases are `data` and `ui` rows are invalid.
533
+
534
+ ### 5.48 Human TEST REVIEW removed; assertion is generated deep-equality (v2.2)
535
+ **Decision:** remove the v2.1 human TEST REVIEW gate. Humans never review tests.
536
+ Tests are not authored — a harness generator emits a deep-equality assertion against
537
+ `fixtures/<case-id>-expected.json` per case row. SPEC REVIEW (§5.50) is the
538
+ human gate; it sits upstream (before SCAFFOLD), reviews concrete behavior in plain
539
+ language, and is the correctness-bearing moment TEST REVIEW was not (wrong thing,
540
+ wrong layer: TEST REVIEW reviewed coverage and asked humans to read assertions).
541
+
542
+ ### 5.49 Volatile fields use matcher tokens in the fixture (v2.2)
543
+ **Decision:** volatile fields (generated IDs, timestamps, order, cursors) are matched
544
+ by TYPE, not excluded. The expected fixture carries sentinels — `<UUID>`, `<ISO8601>`,
545
+ `<ANY_STRING>`, `<ANY_NUMBER>`, `<UNORDERED>`, `<MATCHES:regex>`. The per-language
546
+ comparator `tests/helpers/spec-assert.*` honors them. A token asserts PRESENCE +
547
+ SHAPE, never "ignore this field" (a missing volatile field still fails). The
548
+ comparator is bounded + kit-versioned (one impl per supported language); no
549
+ per-project comparator code.
550
+
551
+ ### 5.50 SPEC REVIEW — per-phase human gate on concrete fillings (v2.2)
552
+ **Decision:** after `spec-author` fills + `spec-staleness.sh` passes, the orchestrator
553
+ surfaces filled cases as FALSIFIABLE CLAIMS; the human confirms/corrects. Rejection
554
+ classification: wrong expected → fix row + fixture (no re-research); wrong input shape
555
+ → re-dispatch `spec-author`; new case OR contradicted case → hard re-entry (§5.52).
556
+ Unskippable on TDD phases; absent on non-TDD. Replaces v2.1 human TEST REVIEW.
557
+
558
+ ### 5.51 Up-front case-name completeness folded into existing /overview approval (v2.2)
559
+ **Decision:** the existing end-of-`/overview` approval (PLAN.md + DATAFLOW.md) is
560
+ EXTENDED to confirm the cross-phase skeleton case-name set (per phase: covered
561
+ transition/acceptance ids + enumerated case names, no values). One confirmation, one
562
+ surface, no new gate — the names derive from the same PLAN + DATAFLOW being approved.
563
+
564
+ ### 5.52 Any case-set divergence at phase time → hard re-entry (v2.2)
565
+ **Decision:** if phase-time RESEARCH reveals a case not enumerated up front, or one
566
+ that contradicts an enumerated case (locked contract impossible), the phase STOPS.
567
+ `spec-author` returns `CASE-SET-DIVERGENCE`; the human amends the up-front skeleton;
568
+ re-confirms the amended case(s) + any case sharing their `covers` id (the staleness
569
+ hash certifies the unchanged remainder — not re-read); `spec-author` re-fills from
570
+ scratch. **Rationale:** AI writes code; the human owns the contract. No fold-forward,
571
+ no AI amendment of the case-name set.
572
+
573
+ ### 5.53 Dedicated spec-author agent; author ≠ implementer invariant (v2.2)
574
+ **Decision:** a new `spec-author` (Opus) fills the per-phase spec + fixtures after
575
+ RESEARCH, before SPEC REVIEW; returns `CASE-SET-DIVERGENCE` when a case can't be
576
+ filled from real facts or research reveals an unlisted branch. It is NOT
577
+ `implementer`. The **author ≠ implementer** invariant replaces v2.1's test-author
578
+ blindness invariant: `implementer` reads the filled spec as its contract (normal
579
+ spec-driven development), `test-author` becomes a harness emitter (reads spec rows,
580
+ generates the assertion harness, authors no assertions).
581
+
582
+ ### 5.54 UI boundary cases use generated Playwright; e2e-runner is an emitter (v2.2)
583
+ **Decision:** for `ui` cases, `e2e-runner` stops authoring blind and EMITS a
584
+ Playwright assertion from the case's `fixtures/<case-id>-ui.json` descriptor. The
585
+ descriptor vocabulary is closed + kit-versioned: `visible`, `text-equals`, `enabled`,
586
+ `count`. Screenshot-on-each-UI-existence-assertion (v2.1 §5.35) is retained as the
587
+ visual backstop. `ui` cases have no mock mirror (the browser is the boundary). On
588
+ `has_frontend: false`, `ui` rows are invalid.
589
+
590
+ ### 5.55 spec-staleness.sh + spec-conformance.sh as orchestrator-procedure scripts (v2.2)
591
+ **Decision:** two new scripts, same idiom as `regression.sh` (`set -euo pipefail`,
592
+ nonzero = loud fail). `spec-staleness.sh` re-hashes the current PLAN acceptance line +
593
+ in-scope DATAFLOW rows and compares to the spec's embedded header hash (`stamp`
594
+ subcommand embeds it at `/overview`/regenerate; default `check` compares); runs after
595
+ SPEC fill + at SPEC REVIEW entry. `spec-conformance.sh` asserts no `TBD` remains and
596
+ every case-id is cited by a boundary test (`# spec: <case-id>`); runs between RED and
597
+ GREEN, replacing the human TEST REVIEW gate. Both port to Cursor for free (same
598
+ `/phase` body, same bash scripts — no new hook wiring). **Design choice (impl):**
599
+ hashing lives ONLY in the script (a `stamp` subcommand), not duplicated in agent
600
+ prompts; transition-ids are derived (`Object:from->to`) so DATAFLOW needs no new column.
601
+
602
+ ### 5.56 Rule 14 re-seamed: transition→case reachability; conformance owns case→test (v2.2)
603
+ **Decision:** v2.1 rule 14 (DATAFLOW transition coverage) is re-seamed. New
604
+ responsibility: every reachable DATAFLOW transition must have ≥1 FILLED CASE in
605
+ `docs/spec-phase-<n>.md` (was: ≥1 test in `tests/regression/`). Reachability judgment
606
+ unchanged (orchestrator decides at CLOSE; unreachable list PENDING; all live by final
607
+ phase or FAIL HARD). The case→test half moves to `spec-conformance.sh` (every case-id
608
+ cited by a boundary test, which by placement convention lands in `tests/regression/`).
609
+ The full guarantee is preserved by the chain: reachable transition → filled case
610
+ (rule 14) → cited boundary test (conformance) → regression corpus (placement). The
611
+ ENDPOINTS coverage gate is unchanged and orthogonal (endpoint-keyed vs behavior-keyed).
612
+
613
+ **Numbering reconciliation (v2.2).** The requirements doc's hard-rule table labeled
614
+ new rules 12–16, but its own "Non-changes" section retains the frontend-E2E (old 13),
615
+ datasource (old 15) and auth (old 16) rules — so the table is illustrative, not literal.
616
+ AGENTS.md realizes a coherent set: rule **12** = SPEC REVIEW (reuses the slot freed by
617
+ the removed TEST REVIEW); rule **14** = re-seamed DATAFLOW (kept in place); rules
618
+ **13/15/16** keep their v2.1 meanings (frontend E2E / datasource / auth); the remaining
619
+ new rules append as **17** (spec staleness), **18** (spec conformance), **19** (author ≠
620
+ implementer). This preserves every existing `hard rule N` cross-reference except 12.
621
+
622
+ ---
623
+
455
624
  ## 6. Current file inventory
456
625
  ```
457
626
 
@@ -542,6 +711,24 @@ create-anpunkit/ npx package (package.json, bin/cli.js, build.
542
711
  ownership taxonomy, adapter generation, idempotent JSON hook merge, VERIFY,
543
712
  backup, `--dry-run`).
544
713
 
714
+ ### v2.2 additions to the inventory
715
+
716
+ ```
717
+ .claude/agents/spec-author.md NEW — fills per-phase spec + fixtures (Opus); author ≠ implementer
718
+ scripts/spec-staleness.sh NEW — stamp/check the spec header hash vs PLAN+DATAFLOW (rule 17)
719
+ scripts/spec-conformance.sh NEW — no-TBD + every case-id cited by a boundary test (rule 18)
720
+ tests/helpers/spec-assert.py NEW — kit comparator (matcher tokens), Python
721
+ tests/helpers/spec-assert.ts NEW — kit comparator (matcher tokens), TS/JS
722
+ docs/spec-phase-<n>.md NEW per-project — skeleton at /overview, filled per phase (committed)
723
+ fixtures/<case-id>-*.json NEW per-project — shared by spec row + generated harness (committed)
724
+ ```
725
+
726
+ Role deltas: `planner` also writes skeleton specs; `test-author` + `e2e-runner`
727
+ become harness EMITTERS (generate from spec rows, author no assertions);
728
+ `implementer` FILL reads the filled spec as its contract. `.gitattributes` gains
729
+ `*.py text eol=lf` (the kit now ships a Python comparator). REMOVED: the v2.1 human
730
+ TEST REVIEW gate + the `docs/test-plan-phase-<n>.md` artifact.
731
+
545
732
  ## 7. How each original problem maps to its fix
546
733
 
547
734
  | Problem | Fix |
@@ -587,7 +774,11 @@ backup, `--dry-run`).
587
774
  4. The phase gate is a REAL test. A mock suite never closes a phase.
588
775
  5. Noisy work writes full output to `docs/research/` and returns only
589
776
  terse summary + path — keeps the orchestrator context clean.
590
- 6. Tests are written blind — this is the unbiased-test guarantee.
777
+ 6. The behavioral contract is the human-approved SPEC; tests are GENERATED from its
778
+ case rows against shared fixtures (author ≠ implementer). This is the v2.2
779
+ unbiased-test guarantee — it replaces v2.1's "tests written blind" (the spec
780
+ fixtures are authored before code, so the contract can't be shaped to an impl).
781
+ (Non-TDD phases keep blind-from-acceptance tests — no spec to drive them.)
591
782
  7. Never script the Microsoft login UI.
592
783
  8. Fail loud, never silent — especially hook wiring.
593
784
  9. Honest failure classification — environment issues never burn the debug budget.