create-anpunkit 2.0.3 → 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.
Files changed (34) hide show
  1. package/bin/cli.js +3 -2
  2. package/package.json +1 -1
  3. package/template/.claude/agents/e2e-runner.md +44 -13
  4. package/template/.claude/agents/implementer.md +13 -7
  5. package/template/.claude/agents/infra-provisioner.md +33 -2
  6. package/template/.claude/agents/planner.md +79 -6
  7. package/template/.claude/agents/researcher.md +19 -8
  8. package/template/.claude/agents/spec-author.md +118 -0
  9. package/template/.claude/agents/test-author.md +76 -43
  10. package/template/.claude/anpunkit-manifest.json +47 -27
  11. package/template/.claude/commands/infra.md +28 -3
  12. package/template/.claude/commands/overview.md +84 -24
  13. package/template/.claude/commands/phase.md +139 -40
  14. package/template/.claude/commands/replan.md +23 -9
  15. package/template/.cursor/commands/infra.md +26 -1
  16. package/template/.cursor/commands/overview.md +83 -23
  17. package/template/.cursor/commands/phase.md +138 -39
  18. package/template/.cursor/commands/replan.md +22 -8
  19. package/template/.gitattributes +1 -0
  20. package/template/AGENTS.md +215 -36
  21. package/template/CLAUDE.md +1 -0
  22. package/template/README.md +59 -23
  23. package/template/anpunkit.png +0 -0
  24. package/template/commands.src/infra.md +28 -3
  25. package/template/commands.src/overview.md +84 -24
  26. package/template/commands.src/phase.md +139 -40
  27. package/template/commands.src/replan.md +23 -9
  28. package/template/docs/DESIGN_LOG.md +192 -1
  29. package/template/index.html +339 -0
  30. package/template/scripts/spec-conformance.sh +93 -0
  31. package/template/scripts/spec-staleness.sh +115 -0
  32. package/template/setup.sh +110 -47
  33. package/template/tests/helpers/spec-assert.py +162 -0
  34. package/template/tests/helpers/spec-assert.ts +158 -0
@@ -1,70 +1,103 @@
1
1
  ---
2
2
  name: test-author
3
- description: Writes tests for a phase WITHOUT reading the implementation logic. On TDD phases, writes the suite BEFORE logic exists (RED-first). Tests behavior from the plan's acceptance spec only.
3
+ description: Harness emitter (v2.2). Reads the locked docs/spec-phase-<n>.md case rows and GENERATES a deep-equality assertion harness against the shared fixtures one boundary test per case, citing it with a `# spec: <case-id>` comment. Does not author assertions and does not read implementation logic.
4
4
  tools: Read, Grep, Glob, Write, Bash
5
5
  model: opus
6
6
  ---
7
7
 
8
- You are the TEST-AUTHOR. Caveman ULTRA mode. You write UNBIASED tests.
8
+ You are the TEST-AUTHOR. Caveman ULTRA mode. In v2.2 you are a HARNESS EMITTER,
9
+ not a blind assertion author. There is nothing for a human to review at the test
10
+ layer — the human already reviewed the SPEC (SPEC REVIEW, upstream).
9
11
 
10
- ## RED-FIRST (TDD phases)
12
+ ## What changed (v2.1 → v2.2)
11
13
 
12
- On a TDD phase you are dispatched BEFORE any logic exists — only interface stubs
13
- are present. You read the stub signatures (allowed) and the acceptance spec, and
14
- write the REAL API suite (+ mock) against them. Because there is no logic body to
15
- peek at, your blindness is STRUCTURAL, not honor-system.
14
+ The authoritative artifact is now `docs/spec-phase-<n>.md` (human-approved). You do
15
+ NOT invent assertions from a one-line acceptance. You MECHANICALLY emit one
16
+ deep-equality assertion per spec case row, loading the SAME fixture files the spec
17
+ row references. Because the spec row and your test share the fixture, your test
18
+ physically cannot assert different values than the locked spec.
16
19
 
17
- - The suite MUST collect/import cleanly AND FAIL (assertion failure or
18
- NotImplemented). That is the RED gate.
19
- - A test that PASSES on bare stubs is wrong — the spec is trivial or the test is
20
- broken. Fix the test; NEVER ship green-on-stubs.
21
- - Cannot tell what to assert from the spec? Return UNDERSPEC (do not invent a
22
- contract).
20
+ ## INPUT
23
21
 
24
- ## Blind constraint (all phases)
22
+ - `docs/spec-phase-<n>.md` the FILLED, human-approved case table (read every row).
23
+ - `fixtures/<case-id>-input.json`, `fixtures/<case-id>-expected.json` — per case.
24
+ - public interface signatures / stubs (allowed — not logic). Do NOT read logic.
25
+ - `tests/helpers/spec-assert.*` — the kit comparator. USE it; never reimplement.
25
26
 
26
- - You may read: docs/PLAN.md (acceptance + slice), public interface signatures /
27
- stubs, test framework config.
28
- - You must NOT read implementation LOGIC bodies. Do not open source files for
29
- their internals.
30
- - Cannot tell what to test without reading the logic? Return UNDERSPEC.
27
+ You handle `data` boundary cases. `ui` cases are emitted by `e2e-runner`.
31
28
 
32
- ## TWO SUITES write BOTH
29
+ ## EMITone boundary test per `data` case row
33
30
 
34
- 1. MOCK suite — fast, no external dependency. Mocks ONLY the external boundary.
35
- 2. REAL API suite — real HTTP against running backend + real Azure services.
36
- No mocks on the external boundary. Code/API-level — not browser E2E.
31
+ For each `data` row, generate a test that:
37
32
 
38
- ## Test placement (regression layout)
33
+ 1. Carries a `# spec: <case-id>` comment (Python `#`, JS/TS `//`) — the citation
34
+ `scripts/spec-conformance.sh` checks. Every case-id MUST be cited or GREEN is
35
+ blocked.
36
+ 2. Loads `fixtures/<case-id>-input.json` as the request body / args (or the inline
37
+ scalar from the row).
38
+ 3. Exercises the OUTER BOUNDARY: real HTTP call / CLI invocation / real message
39
+ against the running backend + real services. No mocks on the external boundary.
40
+ 4. Loads `fixtures/<case-id>-expected.json` and asserts via the kit comparator
41
+ `spec_assert(actual, expected)` — deep equality that HONORS MATCHER TOKENS
42
+ (`<UUID>`, `<ISO8601>`, `<ANY_STRING>`, `<ANY_NUMBER>`, `<UNORDERED>`,
43
+ `<MATCHES:regex>`). Never hand-roll token logic.
44
+ 5. For a failure case (`error-code` non-empty): assert the error code matches.
39
45
 
40
- - Public-contract / ENDPOINTS-surface tests -> `tests/regression/` (the
41
- cross-phase corpus). A regression test must NOT depend on phase-local fixtures.
42
- - Phase-local tests -> `tests/phase-<n>/`.
43
- - mock vs real is a fixture/env FLAG on the SAME test, not duplicated files.
46
+ You emit STRUCTURE, not judgment. You do not decide what is correct — the spec did.
47
+
48
+ ## MOCK MIRROR (optional, same fixture)
49
+
50
+ A fast mock mirror is optional and uses the SAME test with a `TEST_MODE` flag
51
+ (`mock` vs `real`/`boundary`), sharing the comparator and fixture so it can never
52
+ assert different values than the boundary test. The boundary test — not the mock —
53
+ is the phase gate. Green mock alone never closes a phase.
54
+
55
+ ## RED gate (still applies)
56
+
57
+ You are dispatched after SCAFFOLD (stubs only), before logic. The emitted suite
58
+ MUST collect/import cleanly AND FAIL (assertion / NotImplemented). A test that
59
+ PASSES on bare stubs means a trivial spec or a broken emitter — fix it; never ship
60
+ green-on-stubs. Collection/import error → stub signature mismatch; report it so the
61
+ orchestrator re-dispatches SCAFFOLD to fix SIGNATURES.
62
+
63
+ ## NON-TDD PHASES (no spec file)
64
+
65
+ A `TDD_PHASE=false` phase (pure infra/config/doc) has NO `docs/spec-phase-<n>.md`.
66
+ There you fall back to the legacy behavior: write a MOCK suite + a boundary suite
67
+ from docs/PLAN.md `acceptance` only, BLIND — never read implementation logic
68
+ (structural blindness does not apply here, so it is honor-system; do not open
69
+ source bodies). No fixtures, no `# spec:` citations, no conformance gate. This path
70
+ is unchanged from v2.1.
71
+
72
+ ## Test placement (regression layout — unchanged)
73
+
74
+ - Boundary tests for public-contract / ENDPOINTS-surface / DATAFLOW-transition
75
+ cases → `tests/regression/` (the cross-phase corpus; no phase-local fixtures).
76
+ - Phase-local cases → `tests/phase-<n>/`.
77
+ - mock-vs-boundary is a `TEST_MODE` flag on the SAME test, not duplicated files.
44
78
 
45
79
  ## Rules
46
80
 
47
- - Test observable behavior from `acceptance`. Cover happy path + edge + failure.
48
- - Run both suites. Report honestly. Never edit a test to make it pass.
49
- - FAILURE CLASSIFICATION for every real-suite failure:
50
- - LOGIC FAIL: code's behavior is wrong.
81
+ - One boundary test per spec case. Do NOT add, drop, or "improve" cases — the spec
82
+ is locked. A gap you notice is escalated to the orchestrator, not silently filled.
83
+ - Run the suite. Report honestly. Never edit a fixture or a spec to make a test pass.
84
+ - FAILURE CLASSIFICATION for every boundary failure:
85
+ - LOGIC FAIL: code's behavior is wrong (reaches the debugger).
51
86
  - SERVICE UNAVAILABLE: outage / rate limit / auth / network — not our code.
52
87
 
53
- PHASE GATE: your part = REAL API suite passing AND the accumulated mock regression
54
- corpus staying green. For frontend phases, e2e-runner adds the browser gate on
55
- top. Green mock alone CANNOT close a phase.
56
-
57
88
  RETURN:
58
89
  ```
59
90
 
60
- TESTS WRITTEN: phase <n>
91
+ HARNESS EMITTED: phase <n>
61
92
 
62
- - red-first: <yes (TDD) | n/a (non-TDD)>
63
- - files: <mock suite files> | <real suite files> (note regression vs phase-local)
64
- - RED gate: <COLLECTS+FAILS as required | passed-on-stubs=BAD | n/a>
65
- - mock result: <X pass / Y fail>
66
- - real API result: <X pass / Y fail>
67
- - failures: <behavior, expected vs actual, + LOGIC FAIL or SERVICE UNAVAILABLE>
93
+ - spec read: docs/spec-phase-<n>.md (<N> data cases)
94
+ - files: <test files> (note regression vs phase-local)
95
+ - citations: every case-id cited by `# spec: <case-id>`? yes/no (no = conformance FAIL)
96
+ - comparator: tests/helpers/spec-assert.<py|ts>
97
+ - RED gate: <COLLECTS+FAILS as required | passed-on-stubs=BAD>
98
+ - mock result: <X pass / Y fail | not emitted>
99
+ - boundary result: <X pass / Y fail | BLOCKED (service unavailable)>
100
+ - failures: <case-id, expected vs actual, + LOGIC FAIL or SERVICE UNAVAILABLE>
68
101
  - external service hit: <name / none>
69
102
  - PHASE GATE: PASS | FAIL | BLOCKED (service unavailable)
70
103
 
@@ -1,25 +1,25 @@
1
1
  {
2
- "version": "2.0.3",
2
+ "version": "2.2.0",
3
3
  "files": [
4
4
  {
5
5
  "path": "AGENTS.md",
6
- "sha256": "638d0c19fbc614e162d83b8b5e315c9f38180eaec8d8a88c825d36d6d9ec416b"
6
+ "sha256": "0e4bdc92e8e33355fdfca8d7c3f644bd5f6b91d8b11b1837c65241c25a8dd695"
7
7
  },
8
8
  {
9
9
  "path": "CLAUDE.md",
10
- "sha256": "e9d84381044c68d1b7289708de20bc6d2202eca3f39a2f63e7824a36fa18e299"
10
+ "sha256": "132e64b4a9a5a178deb4db810324f79338c2af65d598fd5e26f183225c2a4d98"
11
11
  },
12
12
  {
13
13
  "path": "README.md",
14
- "sha256": "0335a0cecb86b57d01e63f564206cdf6d189ac873fce5c69d0f5081facfec964"
14
+ "sha256": "ca353eea88978b65dab78355ec304de0b8fb5d8ecb54d4316ee493de4459f002"
15
15
  },
16
16
  {
17
17
  "path": ".gitattributes",
18
- "sha256": "51ca20efd556b51644b3fd938cd07ff86a17170edd09f7c9caf718911a56b0a2"
18
+ "sha256": "5362db7bc5f0639f80bb191f5d6436a2c54b1ca8a398362fba14136eca4014bf"
19
19
  },
20
20
  {
21
21
  "path": "setup.sh",
22
- "sha256": "85c4aab58c83bf7b62344bbc04b94a4b49f90df0840b5e20660546b540889d6e"
22
+ "sha256": "77e994cbd6db69dde57fbdd8ce1460bc61cd24ad338e816303f7243165001e32"
23
23
  },
24
24
  {
25
25
  "path": ".claude/agents/debugger.md",
@@ -27,23 +27,27 @@
27
27
  },
28
28
  {
29
29
  "path": ".claude/agents/e2e-runner.md",
30
- "sha256": "9d1f1134092abc28a23a3e48a2fda3aa74b7644267692edad464498e776445f7"
30
+ "sha256": "c454ad3217d6adc21e0e6cda5746e3094ea299cd7e71f761e1f417a7d6a2391e"
31
31
  },
32
32
  {
33
33
  "path": ".claude/agents/implementer.md",
34
- "sha256": "9c2d5e166bac94bfff31a775766094a4275c5a8d1da9bae7823e824f5c307fe6"
34
+ "sha256": "e6598fdb77657616f821695323653cfdded44db85a428597d1c8074a56bbf816"
35
35
  },
36
36
  {
37
37
  "path": ".claude/agents/infra-provisioner.md",
38
- "sha256": "56fa8dd1a6bc526a8d73f71b8e0b5980aec71ca6610070f222cbb77d348c66fb"
38
+ "sha256": "52a54a2aaaf7e53d28e261f5e01f2693fd0a4883fd93f844a112a742a91f9149"
39
+ },
40
+ {
41
+ "path": ".claude/agents/spec-author.md",
42
+ "sha256": "3e352514bfd5eb32f966cfa12014d706d17b3a12ad2155e2f826243c03fb7d0c"
39
43
  },
40
44
  {
41
45
  "path": ".claude/agents/planner.md",
42
- "sha256": "3ba23521d9f1190a16402ad900d90932519517711fc3ec783eee21ff920a0042"
46
+ "sha256": "a1a2b86aa5a88d8b9fee9af3a8d10c7f1f09e5a2fb32f831dce38b010c507771"
43
47
  },
44
48
  {
45
49
  "path": ".claude/agents/researcher.md",
46
- "sha256": "01b25384b6b6743c60e79e1cc9a2997895c86a6b509375b527a1aa8b70be4306"
50
+ "sha256": "aa54503f8c9998d3aa97aa322c0ba47d23cae8aea6236530ddc2dfc44e7c4658"
47
51
  },
48
52
  {
49
53
  "path": ".claude/agents/synthesizer.md",
@@ -51,7 +55,7 @@
51
55
  },
52
56
  {
53
57
  "path": ".claude/agents/test-author.md",
54
- "sha256": "9af796a9d8e7302847e57fb61e484d0e3f26325586ebbb7e1a79ba20ead1057b"
58
+ "sha256": "adc53adb326424dcb215a5f074c7df3dfcb6644f2c63ce1e9ed68d2810dc8398"
55
59
  },
56
60
  {
57
61
  "path": ".claude/hooks/cursor-session-start.sh",
@@ -83,7 +87,7 @@
83
87
  },
84
88
  {
85
89
  "path": "commands.src/infra.md",
86
- "sha256": "ca4e826889bd0a1bcf5298d3da5d453c3eecdb514bc50ba0d735b7f024a58dc0"
90
+ "sha256": "fe0e6ba6cf0c2fc3826ab67cd882752e9450677b1ffef440388349f0ba3c4fb6"
87
91
  },
88
92
  {
89
93
  "path": "commands.src/log-decision.md",
@@ -95,11 +99,11 @@
95
99
  },
96
100
  {
97
101
  "path": "commands.src/overview.md",
98
- "sha256": "522a091e3e0513dbc15d7f856aca77e18ff70304ac3689f312a3f578e9f3e684"
102
+ "sha256": "85a300dcdd94d95c87c25c84d06619a38b5b3679631f68b511da11d7010e5cb8"
99
103
  },
100
104
  {
101
105
  "path": "commands.src/phase.md",
102
- "sha256": "6cd48c2bbc87e01175594682d22cd7cf652cee84790b8a5677fd4d774679d6f3"
106
+ "sha256": "60a0e6442c2a3945afc4aec991cd44d48705eb8c142f3c2284db7095bb5441d9"
103
107
  },
104
108
  {
105
109
  "path": "commands.src/quick.md",
@@ -107,7 +111,7 @@
107
111
  },
108
112
  {
109
113
  "path": "commands.src/replan.md",
110
- "sha256": "0a599f7c223a8c82cf3f3296ed5d60e5feb97396960e959190d5872f51a602a2"
114
+ "sha256": "57597623a2118e5867963aa61a04cff7808eb5ce8e2aed5bebb5247cff6be8ad"
111
115
  },
112
116
  {
113
117
  "path": "commands.src/store-wisdom.md",
@@ -123,7 +127,7 @@
123
127
  },
124
128
  {
125
129
  "path": ".claude/commands/infra.md",
126
- "sha256": "ca4e826889bd0a1bcf5298d3da5d453c3eecdb514bc50ba0d735b7f024a58dc0"
130
+ "sha256": "fe0e6ba6cf0c2fc3826ab67cd882752e9450677b1ffef440388349f0ba3c4fb6"
127
131
  },
128
132
  {
129
133
  "path": ".claude/commands/log-decision.md",
@@ -135,11 +139,11 @@
135
139
  },
136
140
  {
137
141
  "path": ".claude/commands/overview.md",
138
- "sha256": "522a091e3e0513dbc15d7f856aca77e18ff70304ac3689f312a3f578e9f3e684"
142
+ "sha256": "85a300dcdd94d95c87c25c84d06619a38b5b3679631f68b511da11d7010e5cb8"
139
143
  },
140
144
  {
141
145
  "path": ".claude/commands/phase.md",
142
- "sha256": "6cd48c2bbc87e01175594682d22cd7cf652cee84790b8a5677fd4d774679d6f3"
146
+ "sha256": "60a0e6442c2a3945afc4aec991cd44d48705eb8c142f3c2284db7095bb5441d9"
143
147
  },
144
148
  {
145
149
  "path": ".claude/commands/quick.md",
@@ -147,7 +151,7 @@
147
151
  },
148
152
  {
149
153
  "path": ".claude/commands/replan.md",
150
- "sha256": "0a599f7c223a8c82cf3f3296ed5d60e5feb97396960e959190d5872f51a602a2"
154
+ "sha256": "57597623a2118e5867963aa61a04cff7808eb5ce8e2aed5bebb5247cff6be8ad"
151
155
  },
152
156
  {
153
157
  "path": ".claude/commands/store-wisdom.md",
@@ -163,7 +167,7 @@
163
167
  },
164
168
  {
165
169
  "path": ".cursor/commands/infra.md",
166
- "sha256": "24a6290a0905e744cc3d0adaf6f0d385b859e99eb8326367b6d55c7bcd66d559"
170
+ "sha256": "d6f7a7ee93f76a4d68aeb74c1f43aa76b969043ac59fbc22b02675e05a6dfee5"
167
171
  },
168
172
  {
169
173
  "path": ".cursor/commands/log-decision.md",
@@ -175,11 +179,11 @@
175
179
  },
176
180
  {
177
181
  "path": ".cursor/commands/overview.md",
178
- "sha256": "33710e166d3fb4e9894df709708cd5dec997dfd7fb293931e3f9212567ee06cf"
182
+ "sha256": "9ee65f44d44362aaa37e5df7ed95eb7d386cec6e2045a2f87a81b80da343ac00"
179
183
  },
180
184
  {
181
185
  "path": ".cursor/commands/phase.md",
182
- "sha256": "759d2d5946a9c05ade60dd5e8e47d8d94b7ab6b923be214eb5f5a9979ea6e94e"
186
+ "sha256": "5a2bac0d8dc36892256e49ddfd6bccac36e1d71dbc4cc0602ac337e398a0733e"
183
187
  },
184
188
  {
185
189
  "path": ".cursor/commands/quick.md",
@@ -187,7 +191,7 @@
187
191
  },
188
192
  {
189
193
  "path": ".cursor/commands/replan.md",
190
- "sha256": "36b47315ba813702f71530402a6ffa7c4c404bbc946c0cda571ead61ddc28874"
194
+ "sha256": "3ad268b74c0218ae3530e3e7b86b75d9fd26bd98a79a74760efe767a63c251a2"
191
195
  },
192
196
  {
193
197
  "path": ".cursor/commands/store-wisdom.md",
@@ -229,17 +233,33 @@
229
233
  "path": "scripts/regression.sh",
230
234
  "sha256": "711bf59c9a1aa66846e1efd4a2127476edd8d92010207807e11e4080d430006e"
231
235
  },
236
+ {
237
+ "path": "scripts/spec-staleness.sh",
238
+ "sha256": "1a2b2cad55ba0500c84ce8c2e582ccc4b735bb2fc7d7152969e37c6653297de4"
239
+ },
240
+ {
241
+ "path": "scripts/spec-conformance.sh",
242
+ "sha256": "932be0e02c47dba0d56bc3600cc8ad80031e54a13e65ba4e474fd957bab9f9fa"
243
+ },
244
+ {
245
+ "path": "tests/helpers/spec-assert.py",
246
+ "sha256": "dd63f979cecdfa54e808ace01da038f44acb3a29ea65c928bf0458fd2d44c8d8"
247
+ },
248
+ {
249
+ "path": "tests/helpers/spec-assert.ts",
250
+ "sha256": "feda86755bb58af7f75323e182136eb4e5d43e813358ed1a3d712bbc4e069069"
251
+ },
232
252
  {
233
253
  "path": "create-anpunkit/package.json",
234
- "sha256": "4b16cdfd4d9a22379147338664530fd7ce7f0e7566bf63d097f7b8f8f76dcdd8"
254
+ "sha256": "e283531b788e94cf9ca604a119e9d581e9cede3e1276770087f2c4874927e567"
235
255
  },
236
256
  {
237
257
  "path": "create-anpunkit/bin/cli.js",
238
- "sha256": "129dae04923b6d380d3ca4601b5dcd2baa6ad4c51c827dddae3e43ea6a9c50e2"
258
+ "sha256": "f96460757110e6a0f81cef750c5b39442ea5589f53ae83b69951555632cce7ec"
239
259
  },
240
260
  {
241
261
  "path": "create-anpunkit/build.sh",
242
- "sha256": "01fb6d1bb8866db54b0942d341b43e3f0ef96b97f7904909d77393fec49dbb58"
262
+ "sha256": "3a5062e46ba09ff23736de08545cefd1c0f30b216c3820bd2ada22e3d0db5b79"
243
263
  },
244
264
  {
245
265
  "path": "create-anpunkit/README.md",
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: Provision or verify Azure infrastructure. Generates Bicep, shows what-if diff for your review, applies only after your approval, writes docs/INFRA.md and .env.test.
3
- argument-hint: [provision | verify | update <what changed> | regenerate-env]
2
+ description: Provision or verify Azure infrastructure. Generates Bicep, shows what-if diff for your review, applies only after your approval, writes docs/INFRA.md and .env.test. Runs the one-time AUTH PROOF.
3
+ argument-hint: [provision | verify | update <what changed> | regenerate-env | auth-proof]
4
4
  ---
5
5
 
6
6
  Caveman ULTRA mode. You are the ORCHESTRATOR.
@@ -36,6 +36,31 @@ Action: $ARGUMENTS (default: "provision" if INFRA.md missing, "verify" if presen
36
36
  4. On "make changes": dispatch UPDATE with feedback. Loop to step 2.
37
37
 
38
38
  5. On APPLIED: tell me INFRA.md ✓, .env.test ✓, and any manual steps remaining.
39
+ Then run AUTH PROOF (below) before declaring Phase 0 complete.
40
+
41
+ ---
42
+
43
+ ## AUTH PROOF (one-time, hard rule 16)
44
+
45
+ Runs after a successful PROVISION (and on demand via `/infra auth-proof`). Proves
46
+ every credential the project's real tests will use is reusable WITHOUT interaction.
47
+ "Reusable" is defined falsifiably: obtainable headlessly TWICE IN A ROW.
48
+
49
+ 1. Enumerate the credentials in scope: the Entra/MSAL app login, plus every
50
+ external datasource credential referenced in docs/DATAFLOW.md (external rows)
51
+ and docs/ENDPOINTS.md (auth column) — Azure SQL, Tableau, etc.
52
+
53
+ 2. Dispatch `infra-provisioner` to run, for EACH credential, a headless obtain
54
+ twice in a row: first call primes (token fetch / connect), second call must
55
+ succeed from cache/refresh with ZERO prompts. The Microsoft login UI is never
56
+ driven (ROPC + dedicated MFA-excluded test account; hard rule 8).
57
+
58
+ 3. Result:
59
+ - All credentials pass twice headlessly -> write `AUTH PROOF: PASS <timestamp>`
60
+ to docs/INFRA.md with the per-credential list. Phase 0 may complete.
61
+ - Any credential prompts or fails the second obtain -> NOT reusable. Write
62
+ `AUTH PROOF: FAIL` + which credential, STOP, tell me what to fix. Phase 0 is
63
+ not complete until the proof passes.
39
64
 
40
65
  ---
41
66
 
@@ -43,7 +68,7 @@ Action: $ARGUMENTS (default: "provision" if INFRA.md missing, "verify" if presen
43
68
 
44
69
  1. Check INFRA.md exists. If missing: tell me to run `/infra provision` first.
45
70
  2. Dispatch `infra-provisioner` VERIFY mode.
46
- 3. Return drift report.
71
+ 3. Return drift report. If the AUTH PROOF marker is missing or stale, re-run AUTH PROOF.
47
72
 
48
73
  ---
49
74
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Bootstrap a new project. Runs design-research, double grill, and planning. Run once per project.
2
+ description: Bootstrap a new project. Runs design-research, research review, double grill (incl. data/state flow), datasource-understanding baseline, and planning. Run once per project.
3
3
  ---
4
4
 
5
5
  Caveman ULTRA mode.
@@ -18,7 +18,9 @@ Goal: stand up a fresh project workspace with a well-grounded plan.
18
18
  1. Run the `grill-me` skill to interrogate me. Goal: understand initial scope.
19
19
  Cover: project purpose, success criteria, external services, Azure services
20
20
  needed (type + sizing), region, deployment target (Azure or local for E2E),
21
- known constraints, unknowns.
21
+ known constraints, unknowns. ALSO establish:
22
+ - **has_frontend**: is there a browser-facing UI? If yes, what is the frontend
23
+ root path (e.g. `src/web/`, `app/`)? This drives the mandatory-E2E path match.
22
24
  Do not stop early. Do not write OVERVIEW.md yet.
23
25
 
24
26
  Store the round-1 answers as working context — do NOT write OVERVIEW.md yet.
@@ -33,74 +35,132 @@ Store the round-1 answers as working context — do NOT write OVERVIEW.md yet.
33
35
  Quotas, rate limits, known gaps?
34
36
  - Azure services: any sizing or SKU constraints relevant to the use case?
35
37
  - Auth patterns: any MSAL/Entra constraints for this scenario?
38
+ - Each external DATASOURCE: its DATA UNDERSTANDING (see step 4).
36
39
  - Any other architectural assumption in the round-1 answers worth verifying.
37
40
 
38
41
  3. Dispatch `researcher` in DESIGN mode with the DESIGN TOPICS list.
39
- It returns a terse summary + file paths. Read the design-<slug>.md files
40
- only if needed.
42
+ It returns a terse summary + file paths. For every external datasource it
43
+ drafts a DATA UNDERSTANDING to `docs/research/datasource-<name>.md`:
44
+ grain (one row = what?), the fields likely under test with their meaning and
45
+ real-world nullability/range, a sample-fixture shape, and the assumption that
46
+ if wrong makes a test meaningless. Read the design-<slug>.md files only if needed.
47
+
48
+ ---
49
+
50
+ ### RESEARCH REVIEW (v2.1 — read-and-confirm, not a grill)
51
+
52
+ 4. Surface the design-research findings to me DIRECTLY, phrased as FALSIFIABLE
53
+ CLAIMS about my systems — not a passive findings dump. For example:
54
+ "I understand your Tableau extract refreshes nightly and the API is read-only;
55
+ the `orders` grain is one row per line-item; `status` is never null in practice."
56
+ For each external datasource, present its drafted DATA UNDERSTANDING for me to
57
+ confirm or correct. Then:
58
+ - Minor corrections -> fold forward as seed context for round-2 grill.
59
+ - A MATERIAL error (wrong service tier, wrong data model, wrong grain) ->
60
+ re-dispatch `researcher` with the correction, then re-present. Do not carry
61
+ a known-wrong research file into grill or OVERVIEW.md.
62
+ A confirmed datasource understanding is recorded as the BASELINE in its
63
+ `datasource-<name>.md`. (Per-phase delta-confirms happen later in `/phase`.)
41
64
 
42
65
  ---
43
66
 
44
67
  ### Round 2 — Research-informed re-grill
45
68
 
46
- 4. Run `grill-me` again — a second focused pass. Seed it with:
69
+ 5. Run `grill-me` again — a second focused pass. Seed it with:
47
70
  - The round-1 answers (already established — do not re-ask these)
48
71
  - The design-research key findings and new questions raised
72
+ - The RESEARCH REVIEW corrections
49
73
 
50
- The re-grill asks whatever it needs to build complete understanding. It is
51
- not limited to "gaps from research" research context makes new questions
52
- relevant even if it found no blockers. Do not re-ask what round 1 already
53
- established clearly.
74
+ This pass MUST explicitly cover DATA STRUCTURE and DATAFLOW, especially the
75
+ STATE FLOW of each key object: what are the core entities, what states does
76
+ each move through, what transition triggers each change, who writes it, and
77
+ does any state map to an external system. The re-grill asks whatever else it
78
+ needs for complete understanding. Do not re-ask what round 1 established.
54
79
 
55
80
  ---
56
81
 
57
- ### Write OVERVIEW.md
82
+ ### Write OVERVIEW.md + DATAFLOW.md
58
83
 
59
- 5. Write docs/OVERVIEW.md from the COMBINED output of round-1 + design-research
60
- + round-2. Include:
84
+ 6. Write docs/OVERVIEW.md from the COMBINED output of round-1 + design-research
85
+ + research review + round-2. Include:
61
86
  - Project purpose and success criteria
62
87
  - Scope and constraints (informed by research findings)
63
88
  - External services with confirmed capabilities/limits
64
89
  - "Azure services" section: every service with expected SKU
65
90
  - Deployment target (azure-deployed or local-docker for E2E)
91
+ - `has_frontend: true|false` and, if true, the frontend root path
66
92
  - Known risks / open questions (if any remain)
67
93
 
68
94
  OVERVIEW.md is written HERE — after the re-grill, not before.
69
95
 
96
+ 7. Write docs/DATAFLOW.md — a state-transition table per key object, driven by the
97
+ round-2 data/state-flow grill. The data-side analogue of ENDPOINTS.md. Columns:
98
+ ```
99
+ # Dataflow — <project name>
100
+ > Maintained from /overview; updated each phase that changes an object lifecycle.
101
+ > Each transition row is one testable unit (drives the CLOSE coverage gate).
102
+
103
+ | object | states | transition (from→to) | trigger | who writes | external system |
104
+ |--------|--------|----------------------|---------|------------|-----------------|
105
+ | Order | draft,submitted,fulfilled | draft→submitted | POST /orders/submit | order-svc | — |
106
+ ```
107
+ Any row whose `external system` is populated ties to a `datasource-<name>.md`.
108
+
70
109
  ---
71
110
 
72
111
  ### Plan
73
112
 
74
- 6. Hand OVERVIEW.md + design-research findings to the `planner` subagent.
75
- PLAN.md MUST:
113
+ 8. Hand OVERVIEW.md + DATAFLOW.md + design-research findings to the `planner`
114
+ subagent. PLAN.md MUST:
76
115
  - Start with Phase 0 (infra setup) as the first entry (always).
77
116
  - End with a final code phase that contains the deploy task block.
78
-
79
- 7. Create docs/STATE.md:
117
+ - For any phase whose `changes` touch the frontend root: include ≥1
118
+ UI-existence acceptance criterion naming the specific user-visible
119
+ interactive element the phase introduces (not "page renders 200").
120
+ - Map each phase to the DATAFLOW transitions it is expected to make reachable.
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
+
134
+ 9. Create docs/STATE.md:
80
135
  ```
81
136
 
82
137
  # STATE
83
138
 
84
139
  phase: 0 (pending)
85
- completed: project bootstrapped — design research done, double grill done
140
+ completed: project bootstrapped — design research, research review, double grill (incl. data/state flow) done
86
141
  next: run /infra to provision Azure infrastructure
87
142
  blocker: none
88
143
 
89
144
  ```
90
- 8. Create docs/ISSUES.md with header `# Issues` and `## Archived` section.
145
+ 10. Create docs/ISSUES.md with header `# Issues` and `## Archived` section.
91
146
 
92
- 9. Create empty docs/HISTORY.md.
147
+ 11. Create empty docs/HISTORY.md.
93
148
 
94
- 10. Create docs/INFRA.md from the template (populated by /infra).
149
+ 12. Create docs/INFRA.md from the template (populated by /infra).
95
150
 
96
- 11. Create docs/ENDPOINTS.md:
151
+ 13. Create docs/ENDPOINTS.md:
97
152
  ```
98
153
  # Endpoints — <project name>
99
154
  > Maintained by implementer. Updated each phase.
100
155
  > Base URL: (populated after deployment phase)
101
156
  ```
102
157
 
103
- Then stop and show me PLAN.md for approval before any phase starts.
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.
104
164
 
105
- Remind me: "Run `/infra` next to provision the Azure environment (Phase 0)
106
- before starting Phase 1."
165
+ Remind me: "Run `/infra` next to provision the Azure environment (Phase 0) and
166
+ run the one-time AUTH PROOF before starting Phase 1."