@atlashub/smartstack-cli 3.33.0 → 3.35.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 (65) hide show
  1. package/.documentation/agents.html +5 -1
  2. package/.documentation/apex.html +644 -0
  3. package/.documentation/business-analyse.html +81 -1
  4. package/.documentation/cli-commands.html +5 -1
  5. package/.documentation/commands.html +5 -1
  6. package/.documentation/efcore.html +5 -1
  7. package/.documentation/gitflow.html +5 -1
  8. package/.documentation/hooks.html +5 -1
  9. package/.documentation/index.html +60 -2
  10. package/.documentation/init.html +414 -1
  11. package/.documentation/installation.html +5 -1
  12. package/.documentation/ralph-loop.html +365 -216
  13. package/.documentation/test-web.html +5 -1
  14. package/dist/index.js +32 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/mcp-entry.mjs +7 -24
  17. package/dist/mcp-entry.mjs.map +1 -1
  18. package/package.json +1 -2
  19. package/templates/agents/ba-writer.md +142 -15
  20. package/templates/mcp-scaffolding/controller.cs.hbs +5 -1
  21. package/templates/skills/apex/SKILL.md +9 -3
  22. package/templates/skills/apex/_shared.md +49 -4
  23. package/templates/skills/{ralph-loop → apex}/references/core-seed-data.md +20 -11
  24. package/templates/skills/{ralph-loop → apex}/references/error-classification.md +2 -1
  25. package/templates/skills/apex/references/post-checks.md +463 -3
  26. package/templates/skills/apex/references/smartstack-api.md +76 -8
  27. package/templates/skills/apex/references/smartstack-frontend.md +74 -1
  28. package/templates/skills/apex/references/smartstack-layers.md +21 -3
  29. package/templates/skills/apex/steps/step-00-init.md +121 -1
  30. package/templates/skills/apex/steps/step-01-analyze.md +58 -0
  31. package/templates/skills/apex/steps/step-02-plan.md +36 -0
  32. package/templates/skills/apex/steps/step-03-execute.md +114 -7
  33. package/templates/skills/apex/steps/step-04-examine.md +116 -2
  34. package/templates/skills/business-analyse/SKILL.md +31 -20
  35. package/templates/skills/business-analyse/_module-loop.md +68 -9
  36. package/templates/skills/business-analyse/_shared.md +80 -21
  37. package/templates/skills/business-analyse/questionnaire/00-application.md +4 -2
  38. package/templates/skills/business-analyse/questionnaire/00b-project.md +85 -0
  39. package/templates/skills/business-analyse/references/deploy-modes.md +69 -0
  40. package/templates/skills/business-analyse/references/team-orchestration.md +158 -7
  41. package/templates/skills/business-analyse/schemas/application-schema.json +15 -1
  42. package/templates/skills/business-analyse/schemas/project-schema.json +490 -0
  43. package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +2 -1
  44. package/templates/skills/business-analyse/steps/step-00-init.md +220 -38
  45. package/templates/skills/business-analyse/steps/step-01-cadrage.md +184 -5
  46. package/templates/skills/business-analyse/steps/step-01b-applications.md +423 -0
  47. package/templates/skills/business-analyse/steps/step-02-decomposition.md +23 -6
  48. package/templates/skills/business-analyse/steps/step-03c-compile.md +14 -2
  49. package/templates/skills/business-analyse/steps/step-03d-validate.md +32 -7
  50. package/templates/skills/business-analyse/steps/step-04a-collect.md +111 -0
  51. package/templates/skills/business-analyse/steps/step-05a-handoff.md +296 -103
  52. package/templates/skills/business-analyse/steps/step-05b-deploy.md +46 -14
  53. package/templates/skills/documentation/SKILL.md +92 -2
  54. package/templates/skills/ralph-loop/SKILL.md +14 -17
  55. package/templates/skills/ralph-loop/references/category-rules.md +63 -683
  56. package/templates/skills/ralph-loop/references/compact-loop.md +188 -428
  57. package/templates/skills/ralph-loop/references/section-splitting.md +439 -0
  58. package/templates/skills/ralph-loop/references/team-orchestration.md +13 -14
  59. package/templates/skills/ralph-loop/steps/step-01-task.md +27 -0
  60. package/templates/skills/ralph-loop/steps/step-02-execute.md +80 -691
  61. package/templates/skills/ralph-loop/steps/step-03-commit.md +38 -79
  62. package/templates/skills/ralph-loop/steps/step-04-check.md +39 -58
  63. package/templates/skills/ralph-loop/steps/step-05-report.md +31 -123
  64. package/scripts/health-check.sh +0 -168
  65. package/scripts/postinstall.js +0 -18
@@ -0,0 +1,439 @@
1
+ # Section-Level Splitting — Large Module Handling
2
+
3
+ > **Loaded by:** step-01 section 4c (detection) and compact-loop.md (execution)
4
+ > **Purpose:** When a module has >4 domain entities AND >1 architecture section,
5
+ > split `/apex -d` calls per SECTION instead of sending the whole module at once.
6
+ > **Threshold:** `domainTaskCount > 4 AND sectionCount > 1`
7
+ > **Backward compatible:** Modules with <=4 entities are UNAFFECTED.
8
+
9
+ ---
10
+
11
+ ## Why Section-Level Splitting?
12
+
13
+ When a module has 7+ entities (e.g., HR with Employee, Department, Position, LeaveRequest, LeaveType, TimeTracking, WorkLog), a single `/apex -d` saturates the context window. Result: migrations incomplete, pages missing, conventions lost. Success rate drops from ~95% to ~30%.
14
+
15
+ **Solution:** Phase 0 builds ALL entities + ONE migration (foundation). Phase 1..N build services/controllers/pages PER SECTION. Each section has 1-3 entities — comfortably within apex's safe zone.
16
+
17
+ ---
18
+
19
+ ## Architecture: Phases
20
+
21
+ ```
22
+ Phase 0: FOUNDATION (1 apex call)
23
+ - ALL entity classes (Domain layer)
24
+ - ALL EF configurations (Infrastructure layer)
25
+ - ONE migration covering ALL entities
26
+ - Application + Module navigation seed data
27
+ - DbContext registration + DI skeleton
28
+ -> Eliminates migration conflicts between sections
29
+
30
+ Phase 1..N: PER SECTION (1 apex call each)
31
+ - Services + DTOs + Validators for section entities
32
+ - Controllers for section entities
33
+ - Section-level seed data (NavigationSection, permissions, roles)
34
+ - Frontend pages (List, Detail, Create, Edit) for section entities
35
+ - i18n for section entities
36
+ - Tests for section entities
37
+
38
+ Phase Final: CROSS-VALIDATION (inline in step-04)
39
+ - dotnet build (full project)
40
+ - npm run typecheck
41
+ - MCP validate_conventions
42
+ ```
43
+
44
+ ### Why ALL Entities in Phase 0?
45
+
46
+ EF Core creates a single ModelSnapshot per DbContext. If Phase 1 creates a migration for Employee+Department and Phase 2 for LeaveRequest+LeaveType, the second migration fails when LeaveRequest has a FK to Employee (ModelSnapshot is inconsistent). **Phase 0 = all entities + 1 migration.** Section phases add services/controllers/pages on top of existing entities.
47
+
48
+ ---
49
+
50
+ ## 1. Detection
51
+
52
+ ```javascript
53
+ const prd = readJSON('.ralph/prd.json');
54
+ const domainTasks = prd.tasks.filter(t => t.category === 'domain');
55
+ const sections = prd.architecture?.sections ?? [];
56
+
57
+ const shouldSplit = domainTasks.length > 4 && sections.length > 1;
58
+
59
+ if (!shouldSplit) {
60
+ // Standard execution — no splitting needed
61
+ return;
62
+ }
63
+
64
+ console.log(`SECTION SPLIT: ${domainTasks.length} domain tasks, ${sections.length} sections → activating`);
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 2. Entity-to-Section Mapping
70
+
71
+ Build from `prd.architecture.sections[].resources[].entity`:
72
+
73
+ ```javascript
74
+ const entityToSection = {};
75
+ for (const section of prd.architecture.sections) {
76
+ for (const resource of section.resources ?? []) {
77
+ if (resource.entity) {
78
+ entityToSection[resource.entity] = section.code;
79
+ }
80
+ }
81
+ }
82
+
83
+ // Orphan entities (not in any section) go into Phase 0
84
+ const allEntities = prd.architecture.entities?.map(e => e.name) ?? [];
85
+ const orphans = allEntities.filter(e => !entityToSection[e]);
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 3. FK Dependency Resolution
91
+
92
+ Build section dependency graph from `prd.architecture.entities[].relationships[]`:
93
+
94
+ ```javascript
95
+ const sectionDeps = {}; // sectionCode -> Set<sectionCode>
96
+ for (const entity of prd.architecture.entities ?? []) {
97
+ const entitySection = entityToSection[entity.name];
98
+ if (!entitySection) continue;
99
+
100
+ for (const rel of entity.relationships ?? []) {
101
+ const targetSection = entityToSection[rel.target];
102
+ // If target is in a DIFFERENT section, this section depends on that one
103
+ if (targetSection && targetSection !== entitySection) {
104
+ sectionDeps[entitySection] = sectionDeps[entitySection] || new Set();
105
+ sectionDeps[entitySection].add(targetSection);
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 4. Topological Sort of Sections
114
+
115
+ Order sections by FK dependencies (sections with no deps first):
116
+
117
+ ```javascript
118
+ function topoSort(sections, sectionDeps) {
119
+ const sorted = [];
120
+ const visited = new Set();
121
+ const visiting = new Set();
122
+
123
+ function visit(code) {
124
+ if (visited.has(code)) return;
125
+ if (visiting.has(code)) {
126
+ // Circular dependency — break cycle, include as-is
127
+ console.warn(`Circular section dependency detected involving: ${code}`);
128
+ return;
129
+ }
130
+ visiting.add(code);
131
+ for (const dep of sectionDeps[code] || []) {
132
+ visit(dep);
133
+ }
134
+ visiting.delete(code);
135
+ visited.add(code);
136
+ sorted.push(code);
137
+ }
138
+
139
+ for (const section of sections) {
140
+ visit(section.code);
141
+ }
142
+ return sorted;
143
+ }
144
+
145
+ const orderedSections = topoSort(prd.architecture.sections, sectionDeps);
146
+ ```
147
+
148
+ ---
149
+
150
+ ## 5. Phase Construction
151
+
152
+ ### 5a. Phase 0 — Foundation PRD
153
+
154
+ Copy the master PRD and keep ONLY foundation tasks:
155
+
156
+ ```javascript
157
+ const phase0Prd = deepClone(prd);
158
+ phase0Prd.tasks = prd.tasks.filter(t =>
159
+ t.category === 'domain' ||
160
+ t.category === 'infrastructure' ||
161
+ // Module-level seed data (NavigationApplicationSeedData, NavigationModuleSeedData)
162
+ (t.category === 'seedData' && !t.section)
163
+ );
164
+
165
+ // Remove section-specific content from architecture (keep all entities for EF)
166
+ // Keep ALL entities, ALL relationships — Phase 0 needs the full domain model
167
+
168
+ phase0Prd._phaseInfo = { phase: 0, type: 'foundation' };
169
+ writeJSON(`.ralph/prd-${moduleCode}-phase0.json`, phase0Prd);
170
+ ```
171
+
172
+ **Phase 0 includes:**
173
+ - ALL `domain` tasks (entity classes, enums, value objects)
174
+ - ALL `infrastructure` tasks (EF configs, DbContext, migration)
175
+ - Module-level `seedData` tasks (NavigationApplication, NavigationModule seed data)
176
+
177
+ **Phase 0 excludes:**
178
+ - `application` tasks (services, DTOs, validators)
179
+ - `api` tasks (controllers)
180
+ - `frontend` tasks (pages, routes, i18n)
181
+ - `test` tasks
182
+ - Section-level `seedData` tasks (NavigationSection, permissions per section)
183
+
184
+ ### 5b. Section Phase PRDs (Phase 1..N)
185
+
186
+ For each section in topological order:
187
+
188
+ ```javascript
189
+ for (let i = 0; i < orderedSections.length; i++) {
190
+ const sectionCode = orderedSections[i];
191
+ const phaseNum = i + 1;
192
+
193
+ const sectionPrd = deepClone(prd);
194
+
195
+ // Filter tasks by section
196
+ sectionPrd.tasks = prd.tasks.filter(t =>
197
+ t.section === sectionCode && (
198
+ t.category === 'application' ||
199
+ t.category === 'api' ||
200
+ t.category === 'frontend' ||
201
+ t.category === 'i18n' ||
202
+ t.category === 'test' ||
203
+ t.category === 'validation' ||
204
+ // Section-level seed data
205
+ (t.category === 'seedData' && t.section === sectionCode)
206
+ )
207
+ );
208
+
209
+ // Filter architecture to section-relevant entities only
210
+ const sectionEntities = new Set();
211
+ const section = prd.architecture.sections.find(s => s.code === sectionCode);
212
+ for (const resource of section?.resources ?? []) {
213
+ if (resource.entity) sectionEntities.add(resource.entity);
214
+ }
215
+ sectionPrd.architecture.entities = prd.architecture.entities?.filter(
216
+ e => sectionEntities.has(e.name)
217
+ ) ?? [];
218
+ sectionPrd.architecture.sections = [section];
219
+
220
+ // Filter seedData to section-relevant parts
221
+ if (sectionPrd.seedData?.coreSeedData) {
222
+ const csd = sectionPrd.seedData.coreSeedData;
223
+ if (csd.navigationSections) {
224
+ csd.navigationSections = csd.navigationSections.filter(
225
+ s => s.code === sectionCode
226
+ );
227
+ }
228
+ if (csd.navigationResources) {
229
+ csd.navigationResources = csd.navigationResources.filter(
230
+ r => sectionEntities.has(r.entity)
231
+ );
232
+ }
233
+ }
234
+
235
+ // Resolve phase dependencies
236
+ const deps = [0]; // All sections depend on Phase 0
237
+ for (const depSection of sectionDeps[sectionCode] || []) {
238
+ const depPhaseNum = orderedSections.indexOf(depSection) + 1;
239
+ if (depPhaseNum > 0) deps.push(depPhaseNum);
240
+ }
241
+
242
+ sectionPrd._phaseInfo = { phase: phaseNum, type: 'section', sectionCode };
243
+ writeJSON(`.ralph/prd-${moduleCode}-section-${sectionCode}.json`, sectionPrd);
244
+ }
245
+ ```
246
+
247
+ ### 5c. Orphan Entities
248
+
249
+ Entities not mapped to any section are included in Phase 0 with their services/controllers:
250
+
251
+ ```javascript
252
+ if (orphans.length > 0) {
253
+ // Add orphan application/api/frontend tasks to Phase 0 PRD
254
+ const orphanTasks = prd.tasks.filter(t =>
255
+ !t.section && (
256
+ t.category === 'application' ||
257
+ t.category === 'api' ||
258
+ t.category === 'frontend' ||
259
+ t.category === 'test'
260
+ )
261
+ );
262
+ phase0Prd.tasks.push(...orphanTasks);
263
+ writeJSON(`.ralph/prd-${moduleCode}-phase0.json`, phase0Prd);
264
+ }
265
+ ```
266
+
267
+ ---
268
+
269
+ ## 6. Build _sectionSplit State
270
+
271
+ ```javascript
272
+ const phases = [
273
+ {
274
+ phase: 0,
275
+ type: 'foundation',
276
+ sectionCode: undefined,
277
+ entities: allEntities,
278
+ prdFile: `.ralph/prd-${moduleCode}-phase0.json`,
279
+ status: 'pending',
280
+ dependsOn: []
281
+ }
282
+ ];
283
+
284
+ for (let i = 0; i < orderedSections.length; i++) {
285
+ const sectionCode = orderedSections[i];
286
+ const sectionEntities = [];
287
+ const section = prd.architecture.sections.find(s => s.code === sectionCode);
288
+ for (const resource of section?.resources ?? []) {
289
+ if (resource.entity) sectionEntities.push(resource.entity);
290
+ }
291
+
292
+ const deps = [0]; // Phase 0
293
+ for (const depSection of sectionDeps[sectionCode] || []) {
294
+ const depPhaseNum = orderedSections.indexOf(depSection) + 1;
295
+ if (depPhaseNum > 0) deps.push(depPhaseNum);
296
+ }
297
+
298
+ phases.push({
299
+ phase: i + 1,
300
+ type: 'section',
301
+ sectionCode,
302
+ entities: sectionEntities,
303
+ prdFile: `.ralph/prd-${moduleCode}-section-${sectionCode}.json`,
304
+ status: 'pending',
305
+ dependsOn: deps
306
+ });
307
+ }
308
+
309
+ prd._sectionSplit = {
310
+ enabled: true,
311
+ phases,
312
+ currentPhase: 0,
313
+ entityToSection
314
+ };
315
+
316
+ writeJSON('.ralph/prd.json', prd);
317
+ ```
318
+
319
+ ---
320
+
321
+ ## 7. Execution (in compact-loop.md)
322
+
323
+ ```javascript
324
+ // Find next pending phase with dependencies met
325
+ const nextPhase = prd._sectionSplit.phases.find(p => p.status === 'pending');
326
+ if (!nextPhase) {
327
+ // All phases done — fall through to standard completion check
328
+ return;
329
+ }
330
+
331
+ // Check phase dependencies
332
+ const depsOk = nextPhase.dependsOn.every(depIdx =>
333
+ prd._sectionSplit.phases[depIdx].status === 'completed'
334
+ );
335
+ if (!depsOk) {
336
+ // Phase blocked — this should not happen with topological sort
337
+ console.warn(`Phase ${nextPhase.phase} blocked by incomplete dependencies`);
338
+ return;
339
+ }
340
+
341
+ // INVOKE /apex -d {nextPhase.prdFile}
342
+ // apex sees a normal PRD (smaller scope) and executes normally
343
+
344
+ // After apex returns:
345
+ nextPhase.status = 'completed';
346
+ prd._sectionSplit.currentPhase = nextPhase.phase;
347
+ writeJSON('.ralph/prd.json', prd);
348
+ ```
349
+
350
+ ---
351
+
352
+ ## 8. Result Merging
353
+
354
+ After each phase apex call, merge task statuses back into the master PRD:
355
+
356
+ ```javascript
357
+ const phasePrd = readJSON(nextPhase.prdFile);
358
+
359
+ // Map phase task statuses back to master PRD
360
+ for (const phaseTask of phasePrd.tasks) {
361
+ const masterTask = prd.tasks.find(t => t.id === phaseTask.id);
362
+ if (masterTask) {
363
+ masterTask.status = phaseTask.status;
364
+ masterTask.completed_at = phaseTask.completed_at;
365
+ masterTask.commit_hash = phaseTask.commit_hash;
366
+ masterTask.files_changed = phaseTask.files_changed;
367
+ masterTask.error = phaseTask.error;
368
+ masterTask.validation = phaseTask.validation;
369
+ }
370
+ }
371
+
372
+ writeJSON('.ralph/prd.json', prd);
373
+ ```
374
+
375
+ ---
376
+
377
+ ## 9. Phase Failure Handling
378
+
379
+ If a phase fails (apex returns with failed tasks):
380
+
381
+ ```javascript
382
+ if (phasePrd.tasks.some(t => t.status === 'failed')) {
383
+ nextPhase.status = 'failed';
384
+
385
+ // Check retries
386
+ const retryCount = nextPhase._retryCount || 0;
387
+ if (retryCount < 2) {
388
+ nextPhase.status = 'pending';
389
+ nextPhase._retryCount = retryCount + 1;
390
+ console.log(`Phase ${nextPhase.phase} failed — retry ${retryCount + 1}/2`);
391
+
392
+ // Reset failed tasks in phase PRD
393
+ for (const task of phasePrd.tasks) {
394
+ if (task.status === 'failed') {
395
+ task.status = 'pending';
396
+ task.error = null;
397
+ }
398
+ }
399
+ writeJSON(nextPhase.prdFile, phasePrd);
400
+ } else {
401
+ console.error(`Phase ${nextPhase.phase} failed after 2 retries — marking failed`);
402
+ }
403
+ }
404
+ ```
405
+
406
+ ---
407
+
408
+ ## 10. Cleanup (in step-05-report.md)
409
+
410
+ After all phases complete or on final report:
411
+
412
+ ```javascript
413
+ if (prd._sectionSplit?.enabled) {
414
+ // Delete temporary phase PRD files
415
+ for (const phase of prd._sectionSplit.phases) {
416
+ if (fileExists(phase.prdFile) && phase.prdFile !== '.ralph/prd.json') {
417
+ deleteFile(phase.prdFile);
418
+ }
419
+ }
420
+ // Remove split state from master PRD
421
+ delete prd._sectionSplit;
422
+ writeJSON('.ralph/prd.json', prd);
423
+ }
424
+ ```
425
+
426
+ ---
427
+
428
+ ## Summary Table
429
+
430
+ | Phase | Content | Depends On | Entities |
431
+ |-------|---------|------------|----------|
432
+ | Phase 0 | ALL domain + infrastructure + migration + module seed data | — | ALL |
433
+ | Phase 1 | Section A: services, controllers, seed, pages, tests | Phase 0 | Section A entities |
434
+ | Phase 2 | Section B: idem | Phase 0 (+ Phase 1 if FK) | Section B entities |
435
+ | Phase N | Section N: idem | Phase 0 (+ earlier phases if FK) | Section N entities |
436
+ | Final | Cross-validation (dotnet build, typecheck, MCP) | All phases | — |
437
+
438
+ **Threshold:** `> 4 domain tasks` AND `> 1 section`
439
+ **Backward compatible:** `<= 4 domain tasks` OR `1 section` → no splitting, zero impact
@@ -82,29 +82,28 @@ for (const layer of layers) {
82
82
 
83
83
  ## 4. Teammate Prompt Template
84
84
 
85
- Each teammate receives a self-contained prompt with all context:
85
+ Each teammate receives a self-contained prompt that delegates to `/apex`:
86
86
 
87
87
  ```
88
88
  You are a Ralph Loop module worker for module "${moduleCode}".
89
89
 
90
90
  ## Your Mission
91
- Implement ALL tasks in the PRD below, following SmartStack conventions.
92
- Execute autonomously: domain infrastructure MIGRATION seed data → application → api → frontend → i18n → tests → validation.
91
+ Execute ALL tasks in the PRD by delegating to /apex.
92
+ You are an ORCHESTRATOR you NEVER generate code directly.
93
93
 
94
- ## PRD (your task list)
95
- ${JSON.stringify(prdContent, null, 2)}
94
+ ## PRD File
95
+ ${prdFile}
96
96
 
97
- ## Execution Rules
98
- 1. Read the skill file at: templates/skills/ralph-loop/references/category-rules.md
99
- 2. For seed data tasks, also read: templates/skills/ralph-loop/references/core-seed-data.md
100
- 3. Follow SmartStack conventions (MCP validation after each batch)
101
- 4. MIGRATION is MANDATORY after EF configs: mcp suggest_migration → dotnet ef migrations add → database update
102
- 5. Tests MUST pass before proceeding (dotnet test = 0 failures)
103
- 6. Frontend in src/pages/{Context}/{App}/{Module}/ (NOT flat)
104
- 7. Commit after each batch: git add + git commit
97
+ ## Execution
98
+ 1. INVOKE `/apex -d ${prdFile}`
99
+ Apex handles all layers: domain → infrastructure → migration → seed data application api → frontend → tests
100
+ Apex runs POST-CHECKs, MCP validation, build verification, and commits per layer
101
+ Apex updates task statuses in the PRD file directly
102
+ 2. After apex returns, re-read ${prdFile} to check task statuses
103
+ 3. If tasks remain pending/failed, re-invoke `/apex -d ${prdFile}`
105
104
 
106
105
  ## Communication Protocol
107
- - After domain + infrastructure + migration are done and build passes:
106
+ - After apex completes and build passes:
108
107
  SendMessage({ type: "message", recipient: "team-lead", content: "LAYER_READY:${moduleCode}", summary: "${moduleCode} foundation ready" })
109
108
  - When ALL tasks complete:
110
109
  SendMessage({ type: "message", recipient: "team-lead", content: "MODULE_COMPLETE:${moduleCode}", summary: "${moduleCode} complete" })
@@ -261,6 +261,33 @@ if (missingCategories.length > 0) {
261
261
 
262
262
  **Why this matters:** In test-v4-005, the PRD was generated with only backend categories (domain, infrastructure, application, api, seedData, validation). The frontend and test categories were entirely absent, resulting in 0 frontend pages and 0 tests generated across 3 modules.
263
263
 
264
+ ### 4c. Section Split Detection (Large Module)
265
+
266
+ > **Purpose:** Modules with >4 domain entities overwhelm a single `/apex -d` call.
267
+ > Split execution into Phase 0 (foundation) + Phase 1..N (per section).
268
+
269
+ ```javascript
270
+ const domainTasks = prd.tasks.filter(t => t.category === 'domain');
271
+ const sections = prd.architecture?.sections ?? [];
272
+
273
+ if (domainTasks.length > 4 && sections.length > 1 && !prd._sectionSplit?.enabled) {
274
+ console.log(`SECTION SPLIT: ${domainTasks.length} domain tasks, ${sections.length} sections → activating`);
275
+
276
+ // Read references/section-splitting.md for full logic
277
+ // 1. Build entity-to-section mapping from architecture.sections[].resources[].entity
278
+ // 2. Build section dependency graph from architecture.entities[].relationships[]
279
+ // 3. Topological sort sections by FK dependencies
280
+ // 4. Create Phase 0 PRD (all domain + infrastructure + module seed data)
281
+ // 5. Create Section PRDs (per-section: application + api + seedData + frontend + i18n + test)
282
+ // 6. Set prd._sectionSplit state
283
+
284
+ // LOAD references/section-splitting.md — execute sections 2-6
285
+ }
286
+ ```
287
+
288
+ **Activation threshold:** `> 4 domain tasks` AND `> 1 architecture section`
289
+ **No-op when:** `<= 4 domain tasks` OR `<= 1 section` OR `_sectionSplit.enabled` already set
290
+
264
291
  ## 5. Find Current Task
265
292
 
266
293
  ```javascript