@atlashub/smartstack-cli 2.7.1 → 2.7.3
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.
- package/dist/index.js +50 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/agents/ba-writer.md +180 -11
- package/templates/agents/efcore/squash.md +3 -1
- package/templates/skills/business-analyse/_shared.md +19 -5
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +43 -1
- package/templates/skills/business-analyse/schemas/shared/common-defs.json +96 -3
- package/templates/skills/business-analyse/steps/step-00-init.md +48 -0
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +75 -7
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +21 -10
- package/templates/skills/business-analyse/steps/step-03-specify.md +702 -93
- package/templates/skills/business-analyse/steps/step-04-consolidation.md +169 -4
- package/templates/skills/business-analyse/steps/step-05-handoff.md +24 -0
- package/templates/skills/efcore/steps/squash/step-03-create.md +39 -0
- package/templates/skills/ralph-loop/SKILL.md +35 -3
- package/templates/skills/ralph-loop/steps/step-00-init.md +93 -0
- package/templates/skills/ralph-loop/steps/step-01-task.md +182 -3
- package/templates/skills/ralph-loop/steps/step-03-commit.md +8 -1
- package/templates/skills/ralph-loop/steps/step-04-check.md +77 -13
- package/templates/skills/ralph-loop/steps/step-05-report.md +79 -0
|
@@ -208,6 +208,115 @@ Store results in consolidation.semanticChecks[]:
|
|
|
208
208
|
- ≥1 ERROR → BLOCK (fix before handoff, ask user for each)
|
|
209
209
|
- WARNING only → PASS with user notification
|
|
210
210
|
|
|
211
|
+
### 4-bis. Structural Schema Conformity Check (MANDATORY)
|
|
212
|
+
|
|
213
|
+
> **Post-generation validation.** After semantic checks, verify that ALL module feature.json files conform to the JSON schema structure. This catches field name mismatches, missing sections, and wrong nesting.
|
|
214
|
+
|
|
215
|
+
For EACH module feature.json, run these structural checks:
|
|
216
|
+
|
|
217
|
+
**A. Required Sections Presence**
|
|
218
|
+
|
|
219
|
+
| Section | Required | Check |
|
|
220
|
+
|---------|----------|-------|
|
|
221
|
+
| `metadata` | YES | Must have: app, module, language, featureDescription, featureType |
|
|
222
|
+
| `discovery` | YES | Must exist (even if minimal) |
|
|
223
|
+
| `analysis.entities[]` | YES | Must have ≥1 entity |
|
|
224
|
+
| `analysis.businessRules[]` | YES | Must have ≥1 BR |
|
|
225
|
+
| `analysis.objectives[]` | YES | Must have ≥1 objective |
|
|
226
|
+
| `analysis.processFlow` | YES | Must have entryPoints, mainFlow, decisionPoints |
|
|
227
|
+
| `analysis.dataLifecycle` | YES | Must have retention, archival, deletion, gdprRelevant |
|
|
228
|
+
| `specification.useCases[]` | YES | Must have ≥1 UC |
|
|
229
|
+
| `specification.functionalRequirements[]` | YES | Must have ≥1 FR |
|
|
230
|
+
| `specification.permissionMatrix` | YES | Must be `{permissions[], roleAssignments[]}` (NOT flat array) |
|
|
231
|
+
| `specification.sections[]` | YES | Must have ≥1 section with resources |
|
|
232
|
+
| `specification.uiWireframes[]` | YES | Must have ≥1 wireframe with `layout` object |
|
|
233
|
+
| `specification.lifeCycles[]` | IF entities have status | States must be objects (NOT strings) |
|
|
234
|
+
| `specification.seedDataCore` | YES | Must have 5 arrays: navigationModules, navigationTranslations, permissions, rolePermissions, permissionConstants |
|
|
235
|
+
| `specification.gherkinScenarios` | YES | Must be `{feature, scenarios[]}` (NOT flat array) |
|
|
236
|
+
| `specification.navigation` | YES | Must have entries[] |
|
|
237
|
+
| `specification.i18nKeys[]` | YES | Must have ≥1 key with fr, en, nl, de |
|
|
238
|
+
| `validation` | YES | Must have completenessChecks, consistencyChecks, semanticChecks, decision |
|
|
239
|
+
| `handoff` | Written by step-05 | Checked post-handoff |
|
|
240
|
+
|
|
241
|
+
**B. Field Name Conformity**
|
|
242
|
+
|
|
243
|
+
For each section, verify NO FORBIDDEN field names are used:
|
|
244
|
+
|
|
245
|
+
| Section | FORBIDDEN fields | Correct fields |
|
|
246
|
+
|---------|-----------------|----------------|
|
|
247
|
+
| `entities[].attributes[]` | `type`, `values`, `rules` | `description`, `unique`, `validation` |
|
|
248
|
+
| `businessRules[]` | `rule`, `condition` (singular), `action` | `name`, `statement`, `conditions[]` |
|
|
249
|
+
| `useCases[]` | `actor`, `linkedBRs`, `linkedFRs` | `primaryActor`, `linkedRules` |
|
|
250
|
+
| `functionalRequirements[]` | `name`, `description`, `linkedUCs`, `linkedBRs` | `statement`, `linkedUseCases`, `linkedRules` |
|
|
251
|
+
| `permissionMatrix` | flat array with `resource`/`roles` | `{permissions[], roleAssignments[]}` |
|
|
252
|
+
| `lifeCycles[].states[]` | string values like `"Active"` | objects with `{id, displayName, color, isTerminal}` |
|
|
253
|
+
| `seedDataCore` | flat object, string values | 5 typed arrays |
|
|
254
|
+
| `gherkinScenarios` | flat scenario array | `{feature, scenarios[]}` nested |
|
|
255
|
+
|
|
256
|
+
**C. ID Pattern Conformity**
|
|
257
|
+
|
|
258
|
+
| ID Type | Pattern | Example |
|
|
259
|
+
|---------|---------|---------|
|
|
260
|
+
| BR | `BR-(VAL\|CALC\|WF\|SEC\|DATA)-{PREFIX}-\d{3}` | BR-VAL-RM-001 |
|
|
261
|
+
| UC | `UC-{PREFIX}-\d{3}` | UC-RM-001 |
|
|
262
|
+
| FR | `FR-{PREFIX}-\d{3}` | FR-RM-001 |
|
|
263
|
+
| Permissions | `business.{app}.{module}.{resource}.{action}` | business.freebike.repairs.create |
|
|
264
|
+
|
|
265
|
+
Verify all IDs use the correct module prefix (2-4 uppercase letters).
|
|
266
|
+
|
|
267
|
+
**D. Cross-Module ID Uniqueness**
|
|
268
|
+
|
|
269
|
+
Verify no ID collision across modules:
|
|
270
|
+
```
|
|
271
|
+
SET all_ids = {}
|
|
272
|
+
FOR each module:
|
|
273
|
+
FOR each BR, UC, FR id:
|
|
274
|
+
IF id IN all_ids → ERROR: "Duplicate {id} in {module1} and {module2}"
|
|
275
|
+
ADD id to all_ids
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**E. Wireframe Layout Completeness**
|
|
279
|
+
|
|
280
|
+
For each `uiWireframes[]`:
|
|
281
|
+
```
|
|
282
|
+
IF missing componentMapping[] → ERROR
|
|
283
|
+
IF missing layout object → ERROR
|
|
284
|
+
IF missing layout.regions[] → ERROR
|
|
285
|
+
FOR each region in layout.regions[]:
|
|
286
|
+
IF missing position → ERROR
|
|
287
|
+
IF missing components[] → ERROR
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**F. SeedDataCore Translation Coverage**
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
FOR each navigationModules[].code:
|
|
294
|
+
FOR each language in [fr, en, nl, de]:
|
|
295
|
+
IF NOT EXISTS navigationTranslations[] with moduleCode AND language → ERROR
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Result aggregation:**
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"structuralChecks": [
|
|
302
|
+
{ "check": "required-sections", "module": "...", "status": "PASS|ERROR", "details": "Missing: analysis.objectives" },
|
|
303
|
+
{ "check": "field-names", "module": "...", "status": "PASS|ERROR", "details": "businessRules[0] uses 'rule' instead of 'name'+'statement'" },
|
|
304
|
+
{ "check": "id-patterns", "module": "...", "status": "PASS|ERROR", "details": "BR-001 missing category segment" },
|
|
305
|
+
{ "check": "id-uniqueness", "module": "...", "status": "PASS|ERROR", "details": "UC-RM-003 duplicated in Vehicles and Repairs" },
|
|
306
|
+
{ "check": "wireframe-layout", "module": "...", "status": "PASS|ERROR", "details": "Wireframe repairs-list missing layout object" },
|
|
307
|
+
{ "check": "seeddata-translations", "module": "...", "status": "PASS|ERROR", "details": "Missing nl translation for NavigationModuleRepairs" }
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Blocking rule:**
|
|
313
|
+
- 0 ERROR → PASS (merge structuralChecks into consolidation.semanticChecks[])
|
|
314
|
+
- ≥1 ERROR → BLOCK. For each ERROR:
|
|
315
|
+
1. Attempt AUTO-FIX (rename fields, restructure)
|
|
316
|
+
2. Re-write the module feature.json with fixes
|
|
317
|
+
3. Re-check
|
|
318
|
+
4. If still ERROR → ask user
|
|
319
|
+
|
|
211
320
|
### 5. End-to-End Flows
|
|
212
321
|
|
|
213
322
|
Identify business processes that span multiple modules:
|
|
@@ -308,21 +417,77 @@ IF "Modifier les interactions":
|
|
|
308
417
|
|
|
309
418
|
### 9. Write Consolidation
|
|
310
419
|
|
|
420
|
+
> **STRUCTURE CARD: consolidation** — Must match `application-schema.json`. Follow this structure exactly.
|
|
421
|
+
|
|
311
422
|
```
|
|
312
423
|
ba-writer.enrichSection({
|
|
313
424
|
featureId: {feature_id},
|
|
314
425
|
section: "consolidation",
|
|
315
426
|
data: {
|
|
316
|
-
crossModuleInteractions:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
427
|
+
crossModuleInteractions: [
|
|
428
|
+
{
|
|
429
|
+
"fromModule": "Orders",
|
|
430
|
+
"toModule": "Customers",
|
|
431
|
+
"interactionType": "FK-reference|event-publish|event-subscribe|shared-lookup|cascade-delete|cascade-update",
|
|
432
|
+
"description": "Order references customer via FK",
|
|
433
|
+
"entities": ["Order→Customer"]
|
|
434
|
+
}
|
|
435
|
+
],
|
|
436
|
+
sharedEntities: [
|
|
437
|
+
{
|
|
438
|
+
"entity": "Customer",
|
|
439
|
+
"ownerModule": "Customers",
|
|
440
|
+
"referencedBy": ["Orders", "Invoices"],
|
|
441
|
+
"sharedFields": ["code", "name"]
|
|
442
|
+
}
|
|
443
|
+
],
|
|
444
|
+
permissionCoherence: {
|
|
445
|
+
"rolesConsistent": true,
|
|
446
|
+
"pathFormatConsistent": true,
|
|
447
|
+
"hierarchyRespected": true,
|
|
448
|
+
"conflicts": [],
|
|
449
|
+
"warnings": []
|
|
450
|
+
},
|
|
451
|
+
e2eFlows: [
|
|
452
|
+
{
|
|
453
|
+
"name": "Order to Invoice",
|
|
454
|
+
"modules": ["Customers", "Orders", "Invoices"],
|
|
455
|
+
"steps": [
|
|
456
|
+
{ "module": "Orders", "action": "Create order", "permission": "business.sales.orders.create", "dataFlow": "Customer → Order" }
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
],
|
|
460
|
+
globalRiskAssessment: [
|
|
461
|
+
{
|
|
462
|
+
"risk": "Cross-module coupling complexity",
|
|
463
|
+
"category": "coupling|complexity|dependency-chain|security|scope",
|
|
464
|
+
"severity": "critical|high|medium|low",
|
|
465
|
+
"mitigation": "Event-driven communication instead of direct FK"
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
semanticChecks: [
|
|
469
|
+
{ "check": "permission-orpheline", "status": "PASS|WARNING|ERROR", "details": "..." },
|
|
470
|
+
{ "check": "uc-sans-fr", "status": "PASS|WARNING|ERROR", "details": "..." },
|
|
471
|
+
{ "check": "wireframe-coverage", "status": "PASS|WARNING|ERROR", "details": "..." }
|
|
472
|
+
],
|
|
473
|
+
decision: {
|
|
474
|
+
"approved": true,
|
|
475
|
+
"reason": "All cross-module validations passed",
|
|
476
|
+
"approvedBy": "Client",
|
|
477
|
+
"approvedAt": "{ISO timestamp}"
|
|
478
|
+
}
|
|
320
479
|
}
|
|
321
480
|
})
|
|
322
481
|
|
|
323
482
|
ba-writer.updateStatus({feature_id}, "consolidated")
|
|
324
483
|
```
|
|
325
484
|
|
|
485
|
+
> **STRUCTURE DIFFERENCES FROM OLD FORMAT:**
|
|
486
|
+
> - `crossModuleInteractions` is a FLAT ARRAY (not `{fkReferences, sharedEntities, events}` nested object)
|
|
487
|
+
> - `sharedEntities` is TOP-LEVEL (not nested inside crossModuleInteractions)
|
|
488
|
+
> - `decision` is an OBJECT with `approved`, `reason`, `approvedBy`, `approvedAt` (not `clientApproval` string)
|
|
489
|
+
> - `globalRiskAssessment` is an ARRAY of risk objects (not `{totalEntities: {value, threshold}}`)
|
|
490
|
+
|
|
326
491
|
Add changelog entry:
|
|
327
492
|
```json
|
|
328
493
|
{
|
|
@@ -759,6 +759,30 @@ COLORS:
|
|
|
759
759
|
|
|
760
760
|
#### 9a. Module Handoff Loop (MANDATORY)
|
|
761
761
|
|
|
762
|
+
> **STRUCTURE CARD: handoff** — Field names are EXACT. Include ALL fields below.
|
|
763
|
+
> ```json
|
|
764
|
+
> {
|
|
765
|
+
> "complexity": "simple|medium|complex",
|
|
766
|
+
> "filesToCreate": {
|
|
767
|
+
> "domain": [{"path": "...", "type": "Entity|ValueObject|Enum", "linkedFRs": [], "linkedUCs": [], "module": "..."}],
|
|
768
|
+
> "application": [{"path": "...", "type": "Service|Dto|Validator", "linkedFRs": [], "linkedUCs": [], "module": "..."}],
|
|
769
|
+
> "infrastructure": [{"path": "...", "type": "Repository|DbContext", "linkedFRs": [], "module": "..."}],
|
|
770
|
+
> "api": [{"path": "...", "type": "ApiController", "linkedUCs": [], "linkedFRs": [], "module": "..."}],
|
|
771
|
+
> "frontend": [{"path": "...", "type": "Page|Component|Hook|DashboardPage", "linkedUCs": [], "linkedWireframes": [], "module": "..."}],
|
|
772
|
+
> "seedData": [{"path": "...", "type": "HasData", "category": "core|business", "source": "...", "module": "..."}],
|
|
773
|
+
> "tests": [{"path": "...", "type": "UnitTests|IntegrationTests|SecurityTests", "linkedFRs": [], "linkedUCs": [], "module": "..."}]
|
|
774
|
+
> },
|
|
775
|
+
> "brToCodeMapping": [{"ruleId": "BR-...", "files": ["path1", "path2"], "implementation": "description"}],
|
|
776
|
+
> "apiEndpointSummary": [{"method": "GET|POST|PUT|DELETE", "path": "/api/...", "permission": "business.{app}.{module}.{action}", "linkedUC": "UC-..."}],
|
|
777
|
+
> "prdFile": ".ralph/prd-{module}.json",
|
|
778
|
+
> "totalFiles": 0,
|
|
779
|
+
> "totalTasks": 0,
|
|
780
|
+
> "handedOffAt": "{ISO timestamp}"
|
|
781
|
+
> }
|
|
782
|
+
> ```
|
|
783
|
+
> **MANDATORY fields:** ALL of the above. `filesToCreate` MUST have all 7 categories (even if empty arrays).
|
|
784
|
+
> **FORBIDDEN:** `handoff: {}` (empty object is a CRITICAL BUG). Missing `brToCodeMapping` or `apiEndpointSummary`.
|
|
785
|
+
|
|
762
786
|
**For i = 0; i < modules.length; i++:**
|
|
763
787
|
|
|
764
788
|
```
|
|
@@ -131,6 +131,45 @@ echo " Up methods: $UP_METHODS"
|
|
|
131
131
|
echo " Down methods: $DOWN_METHODS"
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
### 6. Inject SQL Objects (Functions, Views, SP)
|
|
135
|
+
|
|
136
|
+
EF Core ne génère PAS de DDL pour les TVF, vues et procédures stockées.
|
|
137
|
+
Les scripts SQL source sont dans `Persistence/SqlObjects/` (Embedded Resources).
|
|
138
|
+
Après un squash, il faut les réinjecter dans la migration consolidée.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Check if SqlObjects folder exists with .sql files
|
|
142
|
+
SQL_OBJECTS_DIR="$INFRA_PROJECT_DIR/Persistence/SqlObjects"
|
|
143
|
+
SQL_FILES=$(find "$SQL_OBJECTS_DIR" -name "*.sql" 2>/dev/null | wc -l)
|
|
144
|
+
|
|
145
|
+
if [ "$SQL_FILES" -gt 0 ]; then
|
|
146
|
+
echo ""
|
|
147
|
+
echo "Found $SQL_FILES SQL object(s) in SqlObjects/"
|
|
148
|
+
echo "Injecting SqlObjectHelper.ApplyAll(migrationBuilder) into migration..."
|
|
149
|
+
|
|
150
|
+
# Add using directive if not present
|
|
151
|
+
if ! grep -q "using SmartStack.Infrastructure.Persistence.SqlObjects;" "$MIGRATION_FILE"; then
|
|
152
|
+
sed -i '1s/^/using SmartStack.Infrastructure.Persistence.SqlObjects;\n/' "$MIGRATION_FILE"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Add SqlObjectHelper.ApplyAll at the end of Up() method
|
|
156
|
+
# Find the closing brace of Up() and insert before it
|
|
157
|
+
sed -i '/protected override void Up/,/^ }/ {
|
|
158
|
+
/^ }/ i\
|
|
159
|
+
\ // Apply SQL objects (TVF, Views, SP) from embedded resources\
|
|
160
|
+
\ SqlObjectHelper.ApplyAll(migrationBuilder);
|
|
161
|
+
}' "$MIGRATION_FILE"
|
|
162
|
+
|
|
163
|
+
echo " ✅ SqlObjectHelper.ApplyAll(migrationBuilder) injected"
|
|
164
|
+
find "$SQL_OBJECTS_DIR" -name "*.sql" -exec basename {} \; | while read f; do
|
|
165
|
+
echo " 📄 $f"
|
|
166
|
+
done
|
|
167
|
+
else
|
|
168
|
+
echo ""
|
|
169
|
+
echo "No SQL objects found in SqlObjects/ - skipping injection"
|
|
170
|
+
fi
|
|
171
|
+
```
|
|
172
|
+
|
|
134
173
|
---
|
|
135
174
|
|
|
136
175
|
## EXPECTED RESULT:
|
|
@@ -108,7 +108,7 @@ The loop only stops when this exact tag is output or max iterations reached.
|
|
|
108
108
|
</ralph_concept>
|
|
109
109
|
|
|
110
110
|
<workflow>
|
|
111
|
-
**Standard flow:**
|
|
111
|
+
**Standard flow (single module):**
|
|
112
112
|
1. Parse flags and task description
|
|
113
113
|
2. Verify MCP servers are available (MANDATORY)
|
|
114
114
|
3. Initialize .ralph/ structure and state files
|
|
@@ -117,6 +117,15 @@ The loop only stops when this exact tag is output or max iterations reached.
|
|
|
117
117
|
6. Commit changes, update progress
|
|
118
118
|
7. Check completion criteria
|
|
119
119
|
8. If complete: generate final report
|
|
120
|
+
|
|
121
|
+
**Multi-module flow (from BA handoff):**
|
|
122
|
+
1-3. Same as standard flow
|
|
123
|
+
4. Detect `prd-*.json` files → create `modules-queue.json`
|
|
124
|
+
5. Copy current module's prd to `prd.json`
|
|
125
|
+
6. Execute all tasks for current module (standard loop: steps 01→02→03→04)
|
|
126
|
+
7. When module complete: advance to next module in queue
|
|
127
|
+
8. Repeat steps 5-7 for each module
|
|
128
|
+
9. When all modules done: generate cross-module report
|
|
120
129
|
</workflow>
|
|
121
130
|
|
|
122
131
|
<state_variables>
|
|
@@ -136,6 +145,8 @@ The loop only stops when this exact tag is output or max iterations reached.
|
|
|
136
145
|
| `{task_category}` | string | Task category (domain/application/infrastructure/api/frontend/i18n/test/validation) |
|
|
137
146
|
| `{files_created}` | string[] | Files created during current task |
|
|
138
147
|
| `{files_modified}` | string[] | Files modified during current task |
|
|
148
|
+
| `{current_module}` | string\|null | Current module code (multi-module only) |
|
|
149
|
+
| `{modules_queue}` | object\|null | Module queue state (multi-module only) |
|
|
139
150
|
|
|
140
151
|
</state_variables>
|
|
141
152
|
|
|
@@ -184,14 +195,33 @@ Before ANY work, verify MCP servers:
|
|
|
184
195
|
|
|
185
196
|
```
|
|
186
197
|
.ralph/
|
|
187
|
-
├── prd.json
|
|
188
|
-
├── progress.txt
|
|
198
|
+
├── prd.json # Task list with status (current module or single)
|
|
199
|
+
├── progress.txt # Persistent memory between iterations
|
|
200
|
+
├── modules-queue.json # Multi-module tracking (only if multiple prd-*.json exist)
|
|
201
|
+
├── prd-{module1}.json # Per-module PRD from BA handoff (source, not modified)
|
|
202
|
+
├── prd-{module2}.json # Per-module PRD from BA handoff (source, not modified)
|
|
189
203
|
├── logs/
|
|
190
204
|
│ └── {timestamp}.log
|
|
191
205
|
└── reports/
|
|
192
206
|
└── {feature-name}.md
|
|
193
207
|
```
|
|
194
208
|
|
|
209
|
+
**modules-queue.json structure (multi-module only):**
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"modules": [
|
|
213
|
+
{
|
|
214
|
+
"code": "module-code",
|
|
215
|
+
"prdFile": ".ralph/prd-module-code.json",
|
|
216
|
+
"status": "pending|in-progress|completed|failed|partial"
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
"currentIndex": 0,
|
|
220
|
+
"totalModules": 3,
|
|
221
|
+
"completedModules": 0
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
195
225
|
**prd.json structure:**
|
|
196
226
|
```json
|
|
197
227
|
{
|
|
@@ -267,6 +297,8 @@ Before ANY work, verify MCP servers:
|
|
|
267
297
|
- Completion promise output when genuinely complete
|
|
268
298
|
- Final report generated in `.ralph/reports/`
|
|
269
299
|
- `prd.json` top-level `status` set to `"completed"` or `"partial"`
|
|
300
|
+
- **Multi-module:** All modules in `modules-queue.json` processed sequentially
|
|
301
|
+
- **Multi-module:** Cross-module aggregation in final report
|
|
270
302
|
</success_criteria>
|
|
271
303
|
|
|
272
304
|
<available_commands>
|
|
@@ -163,6 +163,22 @@ fi
|
|
|
163
163
|
- Read `prd.config.completion_promise` → `{completion_promise}`
|
|
164
164
|
- Read `prd.config.max_iterations` → `{max_iterations}`
|
|
165
165
|
- Read progress.txt for context
|
|
166
|
+
|
|
167
|
+
6. **Restore multi-module state (if applicable):**
|
|
168
|
+
```javascript
|
|
169
|
+
if (fileExists('.ralph/modules-queue.json')) {
|
|
170
|
+
const queue = readJSON('.ralph/modules-queue.json');
|
|
171
|
+
const currentModule = queue.modules[queue.currentIndex];
|
|
172
|
+
|
|
173
|
+
// Restore module state
|
|
174
|
+
{modules_queue} = queue;
|
|
175
|
+
{current_module} = currentModule.code;
|
|
176
|
+
|
|
177
|
+
console.log(`Resuming multi-module: ${currentModule.code} (${queue.currentIndex + 1}/${queue.totalModules})`);
|
|
178
|
+
console.log(`Modules completed: ${queue.completedModules}/${queue.totalModules}`);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
166
182
|
- Continue to step-01
|
|
167
183
|
|
|
168
184
|
### 4. Initialize .ralph/ Structure (new loop)
|
|
@@ -183,6 +199,80 @@ mkdir -p .ralph/logs
|
|
|
183
199
|
mkdir -p .ralph/reports
|
|
184
200
|
```
|
|
185
201
|
|
|
202
|
+
### 4b. Detect Multi-Module PRDs (from BA Handoff)
|
|
203
|
+
|
|
204
|
+
**After creating `.ralph/` directory, check for per-module PRD files:**
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Count prd-*.json files (generated by BA handoff via ss derive-prd)
|
|
208
|
+
PRD_FILES=$(ls .ralph/prd-*.json 2>/dev/null)
|
|
209
|
+
PRD_COUNT=$(echo "$PRD_FILES" | grep -c "prd-" 2>/dev/null || echo "0")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**If multiple prd-*.json files found (PRD_COUNT > 0):**
|
|
213
|
+
|
|
214
|
+
1. **Read module order from master feature.json (if available):**
|
|
215
|
+
```bash
|
|
216
|
+
# Look for master feature.json that references modules
|
|
217
|
+
MASTER_FEATURE=$(find docs/business -maxdepth 4 -name "feature.json" -path "*/business-analyse/*" | head -1)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
2. **Build module queue:**
|
|
221
|
+
```javascript
|
|
222
|
+
const modules = [];
|
|
223
|
+
|
|
224
|
+
if (MASTER_FEATURE && masterJson.metadata?.workflow?.moduleOrder) {
|
|
225
|
+
// Use order from BA master feature.json
|
|
226
|
+
for (const mod of masterJson.metadata.workflow.moduleOrder) {
|
|
227
|
+
const prdFile = `.ralph/prd-${mod.code}.json`;
|
|
228
|
+
if (fileExists(prdFile)) {
|
|
229
|
+
modules.push({ code: mod.code, prdFile, status: "pending" });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
// Fallback: alphabetical order from prd-*.json filenames
|
|
234
|
+
for (const file of prdFiles) {
|
|
235
|
+
const code = file.match(/prd-(.+)\.json$/)[1];
|
|
236
|
+
modules.push({ code, prdFile: `.ralph/${file}`, status: "pending" });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
3. **Create modules-queue.json:**
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"modules": [
|
|
245
|
+
{ "code": "mod1", "prdFile": ".ralph/prd-mod1.json", "status": "pending" },
|
|
246
|
+
{ "code": "mod2", "prdFile": ".ralph/prd-mod2.json", "status": "pending" }
|
|
247
|
+
],
|
|
248
|
+
"currentIndex": 0,
|
|
249
|
+
"totalModules": 2,
|
|
250
|
+
"completedModules": 0
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
4. **Set first module as active:**
|
|
255
|
+
```javascript
|
|
256
|
+
modules[0].status = "in-progress";
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
5. **Log detection:**
|
|
260
|
+
```
|
|
261
|
+
Multi-module detected: {PRD_COUNT} modules
|
|
262
|
+
Queue: {module codes joined by " → "}
|
|
263
|
+
Starting with: {modules[0].code}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**If only `.ralph/prd.json` exists (single module):**
|
|
267
|
+
- Skip queue creation (backward compatible)
|
|
268
|
+
- Proceed normally
|
|
269
|
+
|
|
270
|
+
**Store:**
|
|
271
|
+
```
|
|
272
|
+
{modules_queue} = queue object or null
|
|
273
|
+
{current_module} = first module code or null
|
|
274
|
+
```
|
|
275
|
+
|
|
186
276
|
### 5. Validate Completion Promise
|
|
187
277
|
|
|
188
278
|
**If {completion_promise} is null:**
|
|
@@ -251,10 +341,12 @@ Branch: {CURRENT_BRANCH}
|
|
|
251
341
|
║ MCP: ✅ Ready ║
|
|
252
342
|
║ Schema: v2.0.0 ║
|
|
253
343
|
║ Branch: {CURRENT_BRANCH} ║
|
|
344
|
+
║ {modules_queue ? "Modules: " + totalModules + " (" + module_codes.join(" → ") + ")" : "Mode: single module"} ║
|
|
254
345
|
╠══════════════════════════════════════════════════════════════════╣
|
|
255
346
|
║ Files: ║
|
|
256
347
|
║ - .ralph/prd.json (tasks) ║
|
|
257
348
|
║ - .ralph/progress.txt (memory) ║
|
|
349
|
+
║ {modules_queue ? "- .ralph/modules-queue.json (module tracking)" : ""} ║
|
|
258
350
|
╚══════════════════════════════════════════════════════════════════╝
|
|
259
351
|
|
|
260
352
|
-> Loading tasks...
|
|
@@ -273,6 +365,7 @@ Branch: {CURRENT_BRANCH}
|
|
|
273
365
|
- Metadata collected (branch, version, MCP status)
|
|
274
366
|
- prd.json v2 schema validated (if resume)
|
|
275
367
|
- Branch integrity validated (if resume)
|
|
368
|
+
- Multi-module prd files detected and modules-queue.json created (if applicable)
|
|
276
369
|
- Output is COMPACT
|
|
277
370
|
- Proceeded to step-01 immediately after summary
|
|
278
371
|
|