@anhth2/spec-driven-dev-plugin 0.6.0 → 0.7.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 (73) hide show
  1. package/bin/index.js +180 -11
  2. package/commands/debug.md +196 -10
  3. package/commands/debug.tmpl +170 -6
  4. package/commands/define-product.md +31 -5
  5. package/commands/define-product.tmpl +5 -1
  6. package/commands/fix-bug.md +74 -10
  7. package/commands/fix-bug.tmpl +48 -6
  8. package/commands/generate-bdd.md +49 -8
  9. package/commands/generate-bdd.tmpl +23 -4
  10. package/commands/generate-code.md +109 -18
  11. package/commands/generate-code.tmpl +83 -14
  12. package/commands/generate-prd.md +33 -6
  13. package/commands/generate-prd.tmpl +7 -2
  14. package/commands/generate-tech-docs.md +85 -8
  15. package/commands/generate-tech-docs.tmpl +59 -4
  16. package/commands/generate-tests.md +454 -36
  17. package/commands/generate-tests.tmpl +428 -32
  18. package/commands/refine-prd.md +39 -7
  19. package/commands/refine-prd.tmpl +13 -3
  20. package/commands/review-code.md +57 -5
  21. package/commands/review-code.tmpl +31 -1
  22. package/commands/review-context.md +41 -11
  23. package/commands/review-context.tmpl +15 -7
  24. package/commands/review-tech-docs.md +39 -8
  25. package/commands/review-tech-docs.tmpl +13 -4
  26. package/commands/run-tests.md +159 -17
  27. package/commands/run-tests.tmpl +133 -13
  28. package/commands/setup-ai-first.md +61 -3
  29. package/commands/setup-ai-first.tmpl +6 -2
  30. package/commands/smoke-test.md +191 -21
  31. package/commands/smoke-test.tmpl +165 -17
  32. package/commands/validate-traces.md +40 -7
  33. package/commands/validate-traces.tmpl +14 -3
  34. package/core/FRAMEWORK_VERSION +1 -1
  35. package/core/commands/debug.md +196 -10
  36. package/core/commands/define-product.md +31 -5
  37. package/core/commands/fix-bug.md +74 -10
  38. package/core/commands/generate-bdd.md +49 -8
  39. package/core/commands/generate-code.md +109 -18
  40. package/core/commands/generate-prd.md +33 -6
  41. package/core/commands/generate-tech-docs.md +85 -8
  42. package/core/commands/generate-tests.md +454 -36
  43. package/core/commands/refine-prd.md +39 -7
  44. package/core/commands/review-code.md +57 -5
  45. package/core/commands/review-context.md +41 -11
  46. package/core/commands/review-tech-docs.md +39 -8
  47. package/core/commands/run-tests.md +159 -17
  48. package/core/commands/setup-ai-first.md +61 -3
  49. package/core/commands/smoke-test.md +191 -21
  50. package/core/commands/validate-traces.md +40 -7
  51. package/core/skills/code/SKILL.md +29 -6
  52. package/core/skills/debug/SKILL.md +31 -7
  53. package/core/skills/discovery/SKILL.md +25 -3
  54. package/core/skills/prd/SKILL.md +8 -6
  55. package/core/skills/setup-ai-first/SKILL.md +3 -2
  56. package/core/skills/spec/SKILL.md +7 -5
  57. package/core/skills/test/SKILL.md +54 -9
  58. package/core/steps/context-loader.md +22 -1
  59. package/core/steps/gate.md +1 -1
  60. package/core/steps/report-footer.md +3 -2
  61. package/core/steps/spawn-agent.md +3 -1
  62. package/package.json +1 -1
  63. package/skills/code/SKILL.md +29 -6
  64. package/skills/debug/SKILL.md +31 -7
  65. package/skills/discovery/SKILL.md +25 -3
  66. package/skills/prd/SKILL.md +8 -6
  67. package/skills/setup-ai-first/SKILL.md +3 -2
  68. package/skills/spec/SKILL.md +7 -5
  69. package/skills/test/SKILL.md +54 -9
  70. package/steps/context-loader.md +22 -1
  71. package/steps/gate.md +1 -1
  72. package/steps/report-footer.md +3 -2
  73. package/steps/spawn-agent.md +3 -1
@@ -3,55 +3,451 @@
3
3
  ## Gate
4
4
  {{include:steps/gate.md}}
5
5
 
6
- *Note: For this command, the target in Step 1 is a UC-ID or class path. Find files to test: controllers with `@trace.implements={UC-ID}`, service/facade implementations, and the `.feature` file at `{paths.specs_dir}/{domain}/{UC-ID}.feature`.*
6
+ *Note: For this command, the target in Step 1 is a UC-ID or `.feature` file path. Find the feature file at `{paths.specs_dir}/{domain}/{UC-ID}-*.feature` (glob match — filename includes slug suffix) and the implementation files tagged `@trace.implements={UC-ID}`.*
7
7
 
8
8
  ## Context
9
9
  {{include:steps/context-loader.md}}
10
10
 
11
11
  ---
12
12
 
13
+ ## Service Detection
14
+
15
+ Read `@trace.service` and `@trace.module` from the feature file header.
16
+
17
+ | Condition | Action |
18
+ |---|---|
19
+ | `@trace.module` present | Use as `active_module` |
20
+ | `@trace.module` absent | Use `tech_stack.module` from project-context.yaml |
21
+ | `@trace.service` present | Store as `active_service` |
22
+ | `@trace.service` absent | Use `{UC-ID}` domain as fallback |
23
+
24
+ **Platform type classification:**
25
+
26
+ | Platform | Modules |
27
+ |---|---|
28
+ | `backend` | `java-spring`, `golang`, `dotnet`, `php-laravel`, `context-engineering` |
29
+ | `web-frontend` | `react`, `nextjs`, `vue`, `nuxt`, `angular` |
30
+ | `mobile` | `flutter`, `react-native`, `ios-swiftui`, `android-compose` |
31
+
32
+ ---
33
+
13
34
  ## CHECKPOINT — Test Plan
35
+
36
+ Before generating, scan the feature file for scenarios and the implementation files for classes/functions. Display:
37
+
14
38
  ```
15
- Test Plan — {UC-ID}:
16
- Unit Tests:
17
- - {Service}ImplTest: {method} {scenario} {expected}
18
- Integration Tests:
19
- - {Controller}Test: {endpoint} {scenario} HTTP {status}
20
- Total: {N} classes, ~{M} test cases. Proceed? (Y/N)
39
+ Test Plan — {UC-ID} ({active_module})
40
+ ──────────────────────────────────────
41
+ Platform : {backend | web-frontend | mobile}
42
+ Scenarios : {N} scenarios from .feature file
43
+ Impl files : {list of files tagged @trace.implements={UC-ID}}
44
+
45
+ Tests to generate:
46
+ {platform-specific list — see templates below}
47
+
48
+ Proceed? (Y/N)
21
49
  ```
22
50
 
51
+ Wait for explicit "Y" before generating.
52
+
53
+ ---
54
+
23
55
  ## Generate
24
56
 
25
- ### Unit Test Template
26
- ```
57
+ ### If `platform_type = backend`
58
+
59
+ #### java-spring
60
+
61
+ ```java
27
62
  // @trace.verifies={UC-ID}
63
+ // @trace.service={active_service}
28
64
  // @trace.test_type=unit
29
65
  class {Resource}ServiceImplTest {
30
- // Mock dependencies
31
- // Test: methodName_whenValid_shouldReturnExpected()
32
- // Given — set up mocks | When — call method | Then — assert
33
- // Test: methodName_whenNotFound_shouldThrowException()
34
- // Given — mock returns empty | When & Then — assert exception
66
+ @Mock {Repository} {repository};
67
+ @InjectMocks {Resource}ServiceImpl service;
68
+
69
+ // methodName_whenValid_shouldReturnExpected()
70
+ // Given — mock repository returns data
71
+ // When — call service method
72
+ // Then — assert result matches expected
73
+
74
+ // methodName_whenNotFound_shouldThrowException()
75
+ // Given — mock returns Optional.empty()
76
+ // When & Then — assertThrows({NotFoundException}.class, ...)
77
+ }
78
+
79
+ // @trace.verifies={UC-ID}
80
+ // @trace.service={active_service}
81
+ // @trace.test_type=integration
82
+ @WebMvcTest({Resource}Controller.class)
83
+ class {Resource}ControllerTest {
84
+ @MockBean {Facade | Service} facade;
85
+
86
+ // endpoint_shouldReturn200WhenValid()
87
+ // endpoint_shouldReturn400WhenInvalid()
88
+ // endpoint_shouldReturn404WhenNotFound()
89
+ // endpoint_shouldReturn401WhenUnauthenticated()
35
90
  }
36
91
  ```
37
92
 
38
- ### Integration Test Template (HTTP layer)
93
+ Rules:
94
+ - Unit tests: mock at Repository layer, test Service logic
95
+ - Integration tests: mock at Facade/Service layer, test HTTP contract only
96
+ - Never mock the class under test
97
+ - Follow naming: `methodName_whenCondition_shouldOutcome` (from CLAUDE.md §6)
98
+
99
+ #### golang
100
+
101
+ ```go
102
+ // @trace.verifies={UC-ID}
103
+ // Unit: table-driven tests for service layer
104
+ func Test{Resource}Service_{Method}(t *testing.T) {
105
+ tests := []struct {
106
+ name string
107
+ input {InputType}
108
+ want {OutputType}
109
+ wantErr bool
110
+ }{
111
+ {"valid input", ..., ..., false},
112
+ {"not found", ..., nil, true},
113
+ }
114
+ for _, tt := range tests {
115
+ t.Run(tt.name, func(t *testing.T) { ... })
116
+ }
117
+ }
118
+
119
+ // @trace.verifies={UC-ID}
120
+ // Integration: HTTP handler tests using httptest
121
+ func Test{Resource}Handler_{Endpoint}(t *testing.T) {
122
+ // setup router, mock service, fire request
123
+ // assert status code and response body
124
+ }
39
125
  ```
126
+
127
+ #### dotnet
128
+
129
+ ```csharp
130
+ // @trace.verifies={UC-ID}
131
+ // Unit: xUnit + Moq
132
+ public class {Resource}ServiceTests {
133
+ private readonly Mock<I{Repository}> _repoMock = new();
134
+ private readonly {Resource}Service _sut;
135
+
136
+ [Fact]
137
+ public async Task {Method}_WhenValid_Returns{Expected}() { }
138
+
139
+ [Fact]
140
+ public async Task {Method}_WhenNotFound_ThrowsNotFoundException() { }
141
+ }
142
+
143
+ // @trace.verifies={UC-ID}
144
+ // Integration: WebApplicationFactory
145
+ public class {Resource}ControllerTests : IClassFixture<WebApplicationFactory<Program>> {
146
+ [Fact]
147
+ public async Task {Endpoint}_Returns200_WhenValid() { }
148
+
149
+ [Fact]
150
+ public async Task {Endpoint}_Returns400_WhenInvalid() { }
151
+ }
152
+ ```
153
+
154
+ #### php-laravel
155
+
156
+ ```php
157
+ // @trace.verifies={UC-ID}
158
+ // Unit: PHPUnit
159
+ class {Resource}ServiceTest extends TestCase {
160
+ public function test_{method}_when_valid_should_return_expected(): void { }
161
+ public function test_{method}_when_not_found_should_throw(): void { }
162
+ }
163
+
164
+ // @trace.verifies={UC-ID}
165
+ // Feature: Laravel HTTP tests
166
+ class {Resource}ControllerTest extends TestCase {
167
+ use RefreshDatabase;
168
+ public function test_{endpoint}_returns_200_when_valid(): void {
169
+ $response = $this->getJson('/api/{resource}');
170
+ $response->assertStatus(200)->assertJsonStructure([...]);
171
+ }
172
+ }
173
+ ```
174
+
175
+ #### context-engineering
176
+
177
+ Check `tech_stack.language` from project-context.yaml to select the correct test syntax:
178
+
179
+ **If language = Python** (default):
180
+
181
+ ```python
182
+ # @trace.verifies={UC-ID}
183
+ # @trace.test_type=unit
184
+ # Unit: test prompt orchestration functions
185
+
186
+ import pytest
187
+ from unittest.mock import patch, MagicMock
188
+
189
+ class Test{Resource}Prompt:
190
+ # test_{function}_when_valid_input_should_return_expected_output()
191
+ # Given — mock LLM client returns controlled response
192
+ # When — call prompt function with valid input
193
+ # Then — assert output matches expected structure/content
194
+
195
+ # test_{function}_when_llm_unavailable_should_raise()
196
+ # Given — mock LLM client raises connection error
197
+ # When & Then — assert specific exception is raised
198
+
199
+ # test_{function}_trace_assertions()
200
+ # Given — run function with trace capture enabled
201
+ # Then — assert @trace.implements tag present in function definition
202
+ # assert output conforms to expected schema
203
+
204
+ def test_{function}_when_valid_should_return_expected(self, mock_llm):
205
+ # Arrange
206
+ mock_llm.complete.return_value = "{expected response}"
207
+ # Act
208
+ result = {function}(input={test_input})
209
+ # Assert
210
+ assert result == {expected_output}
211
+ mock_llm.complete.assert_called_once_with(...)
212
+
213
+ def test_{function}_when_invalid_input_should_raise(self):
214
+ with pytest.raises({ExpectedError}):
215
+ {function}(input=None)
216
+ ```
217
+
218
+ **If language = TypeScript / JavaScript** (Node.js LangChain.js, etc.):
219
+
220
+ ```typescript
221
+ // @trace.verifies={UC-ID}
222
+ // @trace.test_type=unit
223
+ import { jest } from '@jest/globals'
224
+
225
+ describe('{Resource}Prompt', () => {
226
+ const mockLlm = { complete: jest.fn() }
227
+
228
+ it('{scenario description}', async () => {
229
+ mockLlm.complete.mockResolvedValue('{expected response}')
230
+ const result = await {function}({ input: '{test_input}', llm: mockLlm })
231
+ expect(result).toEqual({expected_output})
232
+ expect(mockLlm.complete).toHaveBeenCalledWith(expect.objectContaining({ ... }))
233
+ })
234
+
235
+ it('throws when input is invalid', async () => {
236
+ await expect({function}({ input: null, llm: mockLlm })).rejects.toThrow('{ExpectedError}')
237
+ })
238
+ })
239
+ ```
240
+
241
+ **If language = Java** (LangChain4j, etc.): use JUnit 5 + Mockito, same patterns as java-spring unit tests above — mock the `ChatLanguageModel` interface.
242
+
243
+ Rules:
244
+ - Mock the LLM client at the boundary — never call real LLM in unit tests
245
+ - Validate input schema and output schema separately
246
+ - Each scenario in `.feature` maps to one test function
247
+ - Use parameterized tests for multiple input variants
248
+
249
+ ---
250
+
251
+ ### If `platform_type = web-frontend`
252
+
253
+ #### react / nextjs / vue / nuxt / angular
254
+
255
+ ```typescript
256
+ // @trace.verifies={UC-ID}
257
+ // @trace.service={active_service}
258
+ // @trace.test_type=component
259
+
260
+ // Component tests (Vitest + Testing Library)
261
+ describe('{ComponentName}', () => {
262
+ it('renders correctly when data is loaded', () => {
263
+ render(<{ComponentName} {...props} />)
264
+ expect(screen.getByText('...')).toBeInTheDocument()
265
+ })
266
+
267
+ it('shows loading state while fetching', () => { })
268
+
269
+ it('shows error message on API failure', () => { })
270
+
271
+ it('calls handler when user interacts', async () => {
272
+ await userEvent.click(screen.getByRole('button', { name: '...' }))
273
+ expect(mockHandler).toHaveBeenCalledWith(...)
274
+ })
275
+ })
276
+
277
+ // @trace.verifies={UC-ID}
278
+ // @trace.test_type=e2e
279
+
280
+ // E2E tests (Playwright or Cypress — use whichever is in project)
281
+ test('{scenario from .feature}', async ({ page }) => {
282
+ await page.goto('/{route}')
283
+ await page.getByRole('button', { name: '...' }).click()
284
+ await expect(page.getByText('...')).toBeVisible()
285
+ })
286
+ ```
287
+
288
+ Rules:
289
+ - One component test file per component involved in the UC
290
+ - One E2E test file per UC covering happy path + key error scenarios
291
+ - Mock API calls at the network layer (MSW or cy.intercept), not at component props
292
+ - Use accessible queries (`getByRole`, `getByLabelText`) — avoid `getByTestId` unless necessary
293
+ - Each test maps to exactly one scenario in the `.feature` file
294
+
295
+ ---
296
+
297
+ ### If `platform_type = mobile`
298
+
299
+ #### flutter
300
+
301
+ ```dart
302
+ // @trace.verifies={UC-ID}
303
+ // @trace.service={active_service}
304
+ // @trace.test_type=widget
305
+
306
+ // Widget tests
307
+ group('{FeatureName} widget tests', () {
308
+ testWidgets('renders correctly when state is loaded', (tester) async {
309
+ await tester.pumpWidget(MaterialApp(home: {Widget}()));
310
+ await tester.pumpAndSettle();
311
+ expect(find.text('...'), findsOneWidget);
312
+ });
313
+
314
+ testWidgets('shows loading indicator while fetching', (tester) async { });
315
+ testWidgets('shows error widget on failure', (tester) async { });
316
+ testWidgets('calls handler on tap', (tester) async {
317
+ await tester.tap(find.byType(ElevatedButton));
318
+ await tester.pumpAndSettle();
319
+ verify(() => mockBloc.add({Event}())).called(1);
320
+ });
321
+ });
322
+
40
323
  // @trace.verifies={UC-ID}
41
324
  // @trace.test_type=integration
42
- class {Resource}ControllerTest {
43
- // Mock Facade/Service
44
- // Test: filter_shouldReturn200()
45
- // Test: create_shouldReturn201()
46
- // Test: create_shouldReturn400WhenInvalid()
325
+ // Integration test (flutter_test / integration_test package)
326
+ void main() {
327
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
328
+ testWidgets('{scenario from .feature}', (tester) async {
329
+ app.main();
330
+ await tester.pumpAndSettle();
331
+ // Navigate, interact, assert
332
+ });
333
+ }
334
+ ```
335
+
336
+ #### react-native
337
+
338
+ ```typescript
339
+ // @trace.verifies={UC-ID}
340
+ // @trace.service={active_service}
341
+ // @trace.test_type=component
342
+
343
+ // Jest + React Native Testing Library
344
+ describe('{ComponentName}', () => {
345
+ it('{scenario description}', () => {
346
+ const { getByText, getByRole } = render(<{ComponentName} {...props} />)
347
+ expect(getByText('...')).toBeTruthy()
348
+ })
349
+
350
+ it('calls navigation on button press', () => {
351
+ const mockNavigate = jest.fn()
352
+ const { getByRole } = render(<{ComponentName} navigation={{ navigate: mockNavigate }} />)
353
+ fireEvent.press(getByRole('button'))
354
+ expect(mockNavigate).toHaveBeenCalledWith('...')
355
+ })
356
+ })
357
+ ```
358
+
359
+ #### ios-swiftui
360
+
361
+ ```swift
362
+ // @trace.verifies={UC-ID}
363
+ // @trace.service={active_service}
364
+ // @trace.test_type=unit
365
+
366
+ // XCTest — ViewModel unit tests
367
+ @MainActor
368
+ final class {Feature}ViewModelTests: XCTestCase {
369
+ var sut: {Feature}ViewModel!
370
+ var mockRepo: Mock{Repository}!
371
+
372
+ override func setUp() async throws {
373
+ mockRepo = Mock{Repository}()
374
+ sut = {Feature}ViewModel(repository: mockRepo)
375
+ }
376
+
377
+ func test_{method}_whenValid_shouldUpdate{State}() async throws {
378
+ // Given
379
+ mockRepo.stub{Method}Result = {expected}
380
+ // When
381
+ await sut.{method}()
382
+ // Then
383
+ XCTAssertEqual(sut.{state}, {expected})
384
+ }
385
+
386
+ func test_{method}_whenError_shouldSetErrorState() async throws { }
387
+ }
388
+ ```
389
+
390
+ #### android-compose
391
+
392
+ ```kotlin
393
+ // @trace.verifies={UC-ID}
394
+ // @trace.service={active_service}
395
+ // @trace.test_type=unit
396
+
397
+ // Unit test — ViewModel
398
+ class {Feature}ViewModelTest {
399
+ @get:Rule val mainDispatcherRule = MainDispatcherRule()
400
+ private val mockRepo: {Repository} = mockk()
401
+ private lateinit var sut: {Feature}ViewModel
402
+
403
+ @Before fun setup() { sut = {Feature}ViewModel(mockRepo) }
404
+
405
+ @Test fun `{method} when valid should emit success state`() = runTest {
406
+ coEvery { mockRepo.{method}(any()) } returns Result.success({data})
407
+ sut.{method}({input})
408
+ assertEquals(UiState.Success({data}), sut.uiState.value)
409
+ }
410
+ }
411
+
412
+ // @trace.verifies={UC-ID}
413
+ // @trace.test_type=ui
414
+
415
+ // UI test — Compose
416
+ @HiltAndroidTest
417
+ class {Feature}ScreenTest {
418
+ @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this)
419
+ @get:Rule(order = 1) val composeRule = createAndroidComposeRule<MainActivity>()
420
+
421
+ @Test fun {scenario}_displaysExpectedUi() {
422
+ composeRule.onNodeWithText("...").assertIsDisplayed()
423
+ composeRule.onNodeWithContentDescription("...").performClick()
424
+ composeRule.onNodeWithText("...").assertIsDisplayed()
425
+ }
47
426
  }
48
427
  ```
49
428
 
429
+ ---
430
+
50
431
  ## Checklist
51
- - [ ] `@trace.verifies` on every test class
52
- - [ ] Every .feature scenario has a test
53
- - [ ] Correct layer mocked (no repo mocks in controller tests)
54
- - [ ] Test names follow pattern from CLAUDE.md §6 (e.g., `methodName_whenCondition_shouldOutcome`)
432
+
433
+ **All platforms:**
434
+ - [ ] `@trace.verifies` on every test class / test group
435
+ - [ ] `@trace.service` on every test class / test group
436
+ - [ ] Every scenario in `.feature` file has ≥ 1 corresponding test
437
+ - [ ] Happy path covered
438
+ - [ ] Key error / edge case scenarios covered
439
+
440
+ **Backend only:**
441
+ - [ ] Correct layer mocked (Repository in unit tests, Facade/Service in controller tests)
442
+ - [ ] No real DB calls in unit tests
443
+ - [ ] Test naming follows `methodName_whenCondition_shouldOutcome` (CLAUDE.md §6)
444
+
445
+ **Frontend / Mobile only:**
446
+ - [ ] No hardcoded delays (`sleep`, `setTimeout`) in tests — use `waitFor` / `pumpAndSettle`
447
+ - [ ] Accessible queries used (role, label) not implementation-specific selectors
448
+ - [ ] API calls mocked at network layer, not at component level
449
+
450
+ ---
55
451
 
56
452
  ## Write Trace State
57
453
 
@@ -59,22 +455,22 @@ After generating all test files, update `{paths.trace_dir}/{UC-ID}.tsv` — for
59
455
 
60
456
  | Column | Value |
61
457
  |--------|-------|
62
- | `test_count` | number of test methods covering this SC across all generated test classes |
63
- | `test_classes` | comma-separated list of test class names (e.g., `OrderServiceImplTest,OrderControllerTest`) |
458
+ | `test_count` | number of test methods covering this SC |
459
+ | `test_classes` | comma-separated test class / describe-block names |
64
460
  | `last_updated` | today `YYYY-MM-DD` |
65
461
 
66
- Count `test_count` by scanning generated test files for methods that correspond to this SC (methods whose name or comment references the SC-ID, or all methods in a test class dedicated to this UC).
67
-
68
462
  Leave all other columns unchanged.
69
463
 
464
+ ---
465
+
70
466
  ## Output
71
467
 
72
468
  {{include:steps/report-footer.md}}
73
469
 
74
470
  ```
75
- /generate-tests Complete — {UC-ID}
76
- ✅ {Service}Test ({M} tests)
77
- ✅ {Controller}Test ({M} tests)
78
- Trace: {paths.trace_dir}/{UC-ID}.tsv updated (test_count, test_classes)
471
+ /generate-tests Complete — {UC-ID} ({active_module})
472
+ ✅ {TestClass1} ({N} tests)
473
+ ✅ {TestClass2} ({N} tests)
474
+ Trace: {paths.trace_dir}/{UC-ID}.tsv updated
79
475
  Next: /run-tests {UC-ID}
80
476
  ```
@@ -31,7 +31,7 @@ Display and wait for response:
31
31
  ```
32
32
  ⚙️ MODEL CHECK
33
33
  ──────────────────────────────────────────────────────────────────
34
- Recommended : claude-opus-4-5 (or claude-opus-4)
34
+ Recommended : claude-opus-4 (or latest Opus model)
35
35
  Why needed : Spec analysis, architecture review, code generation
36
36
  require deep reasoning. Smaller models miss edge cases.
37
37
 
@@ -140,7 +140,7 @@ If `paths` section is absent, use these defaults:
140
140
  - `domain_knowledge_dir` = `specs/domain-knowledge`
141
141
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
142
142
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
143
- - `tech_docs_dir` = `tech-docs`
143
+ - `tech_docs_dir` = `specs/tech-docs`
144
144
  - `trace_dir` = `.trace`
145
145
 
146
146
  If `tech_stack.module` is set, also load `.agent/modules/{module}/stack-profile.yaml` if it exists.
@@ -217,6 +217,26 @@ If the file does not exist → skip silently.
217
217
 
218
218
  ---
219
219
 
220
+ ## Step 6.5 — [PLATFORM] Derive active_module and platform_type
221
+
222
+ Using `tech_stack.module` loaded in Step 1, derive and store two variables for use by all downstream commands:
223
+
224
+ ```
225
+ active_module = tech_stack.module (e.g. "java-spring", "react", "flutter")
226
+ ```
227
+
228
+ | `platform_type` | Modules |
229
+ |---|---|
230
+ | `backend` | `java-spring`, `golang`, `dotnet`, `php-laravel`, `context-engineering` |
231
+ | `web-frontend` | `react`, `nextjs`, `vue`, `nuxt`, `angular` |
232
+ | `mobile` | `flutter`, `react-native`, `ios-swiftui`, `android-compose` |
233
+
234
+ If `tech_stack.module` is blank or not recognized → set `platform_type = "unknown"` and flag as ⚠️ in the Step 7 recap.
235
+
236
+ These two variables (`active_module`, `platform_type`) are the canonical source for all branching logic in commands that need platform-specific behavior (generate-tests, debug, fix-bug, smoke-test).
237
+
238
+ ---
239
+
220
240
  ## Step 7 — [RECAP] Working Memory Recap (anti-lost-in-middle)
221
241
 
222
242
  After loading all context, synthesize and output a compact summary block.
@@ -227,6 +247,7 @@ Output exactly this block:
227
247
  ```
228
248
  [CTX LOADED]
229
249
  Stack : {language} / {framework} / {database}
250
+ Platform : {active_module} ({platform_type})
230
251
  Layers : {layer order from CLAUDE.md §2, e.g., Controller → Facade → Service → Repository}
231
252
  Ticket : {ticket_prefix}-
232
253
  Dict : {loaded — N canonical terms, M banned terms | missing}
@@ -324,6 +345,7 @@ Suggest the logical next command based on workflow phase:
324
345
 
325
346
  | Current command | Suggest next |
326
347
  |-------------------------|-----------------------------------------------|
348
+ | /setup-ai-first | `/define-product` to start your first feature |
327
349
  | /define-product | `/generate-prd {product-definition-file}` |
328
350
  | /generate-prd | `/refine-prd {prd-file}` then `/review-context {prd-file}` |
329
351
  | /refine-prd | Open Review Board → update PRD → `/review-context {prd-file}` |
@@ -332,13 +354,13 @@ Suggest the logical next command based on workflow phase:
332
354
  | /review-context (BDD) | `/generate-tech-docs {UC-ID}` if APPROVED; regenerate if NEEDS_FIX |
333
355
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
334
356
  | /review-tech-docs | `/generate-code {feature-file}` if APPROVED; fix doc if NEEDS_FIX |
335
- | /generate-code | `/generate-tests {UC-ID}` |
357
+ | /generate-code | First gen → `/review-code {UC-ID}`; re-gen → `/generate-tests {UC-ID}` |
336
358
  | /generate-tests | `/run-tests {UC-ID}` |
337
359
  | /run-tests (passing) | `/review-code {UC-ID}` |
338
360
  | /run-tests (failing) | `/fix-bug {ticket-id}` or `/debug {error}` |
339
361
  | /review-code | `/smoke-test {UC-ID}` or create PR |
340
362
  | /smoke-test | Create PR and link to ticket |
341
- | /validate-traces | `/generate-code {UC-ID}` for gaps |
363
+ | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/generate-tests {UC-ID}`; all OK → create PR |
342
364
  | /fix-bug | Create PR and link to ticket |
343
365
  | /debug | `/fix-bug {ticket-id}` if fix needed |
344
366
 
@@ -355,7 +377,9 @@ Next : {suggested command with example arguments}
355
377
  /refine-prd Complete — {PRD name}
356
378
  Findings: {total} | 🔴 Critical: {N} | 🟡 Major: {N} | 🟢 Minor: {N}
357
379
  Review: {paths.refinement_dir}/{prd-slug}-findings.yaml
358
- Next: Open in Review Board (right-click file) → Update PRD → /generate-bdd
380
+ Next: Open in Review Board (right-click file) → Update PRD
381
+ → /review-context {prd-file} ← verify PRD quality before generating BDD
382
+ → /generate-bdd {prd-file}
359
383
  ```
360
384
 
361
385
  ---
@@ -374,9 +398,16 @@ Next: Open in Review Board (right-click file) → Update PRD → /generate-bdd
374
398
 
375
399
  For each accepted finding, in order of severity (critical → major → minor):
376
400
  - Navigate to the PRD section indicated by `finding.section`.
377
- - Apply `finding.suggestion` (or the note from `modified` status if applicable).
401
+ - Apply `finding.suggestion`. For `status: "modified"` findings, the human has already edited `finding.suggestion` in the Review Board — that edited value IS the fix to apply.
378
402
  - Do not alter any sections not referenced by an accepted finding.
379
403
 
404
+ ### Phase 2.5 — Update findings file
405
+
406
+ For each finding that was applied (status was `accepted` or `modified`):
407
+ - Set `status: "applied"` in `{paths.refinement_dir}/{prd-slug}-findings.yaml`.
408
+
409
+ Update `summary.status: "applied"` in the findings file.
410
+
380
411
  ### Phase 3 — Bump version & write changelog entry
381
412
 
382
413
  1. Read current `| **Version** |` value from PRD metadata table.
@@ -404,5 +435,6 @@ Changes :
404
435
  - {change 2}
405
436
 
406
437
  ⚠️ BDD may be outdated. Run:
407
- /generate-bdd {prd-file}
438
+ /review-context {prd-file} ← verify PRD quality first
439
+ → /generate-bdd {prd-file}
408
440
  ```
@@ -58,7 +58,9 @@ summary:
58
58
  /refine-prd Complete — {PRD name}
59
59
  Findings: {total} | 🔴 Critical: {N} | 🟡 Major: {N} | 🟢 Minor: {N}
60
60
  Review: {paths.refinement_dir}/{prd-slug}-findings.yaml
61
- Next: Open in Review Board (right-click file) → Update PRD → /generate-bdd
61
+ Next: Open in Review Board (right-click file) → Update PRD
62
+ → /review-context {prd-file} ← verify PRD quality before generating BDD
63
+ → /generate-bdd {prd-file}
62
64
  ```
63
65
 
64
66
  ---
@@ -77,9 +79,16 @@ Next: Open in Review Board (right-click file) → Update PRD → /generate-bdd
77
79
 
78
80
  For each accepted finding, in order of severity (critical → major → minor):
79
81
  - Navigate to the PRD section indicated by `finding.section`.
80
- - Apply `finding.suggestion` (or the note from `modified` status if applicable).
82
+ - Apply `finding.suggestion`. For `status: "modified"` findings, the human has already edited `finding.suggestion` in the Review Board — that edited value IS the fix to apply.
81
83
  - Do not alter any sections not referenced by an accepted finding.
82
84
 
85
+ ### Phase 2.5 — Update findings file
86
+
87
+ For each finding that was applied (status was `accepted` or `modified`):
88
+ - Set `status: "applied"` in `{paths.refinement_dir}/{prd-slug}-findings.yaml`.
89
+
90
+ Update `summary.status: "applied"` in the findings file.
91
+
83
92
  ### Phase 3 — Bump version & write changelog entry
84
93
 
85
94
  1. Read current `| **Version** |` value from PRD metadata table.
@@ -107,5 +116,6 @@ Changes :
107
116
  - {change 2}
108
117
 
109
118
  ⚠️ BDD may be outdated. Run:
110
- /generate-bdd {prd-file}
119
+ /review-context {prd-file} ← verify PRD quality first
120
+ → /generate-bdd {prd-file}
111
121
  ```