@atlashub/smartstack-cli 4.74.0 → 4.76.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.
- package/dist/index.js +152 -31
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +14 -3
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/agents/ba-reader.md +17 -15
- package/templates/agents/ba-writer.md +49 -51
- package/templates/skills/apex/SKILL.md +2 -2
- package/templates/skills/apex/_shared.md +1 -1
- package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
- package/templates/skills/apex/references/checks/frontend-checks.sh +26 -0
- package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
- package/templates/skills/apex/references/checks/seed-checks.sh +47 -7
- package/templates/skills/apex/references/core-seed-data.md +20 -18
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/apex/references/post-checks.md +23 -3
- package/templates/skills/apex/references/smartstack-api.md +4 -4
- package/templates/skills/apex/references/smartstack-frontend.md +54 -8
- package/templates/skills/apex/references/smartstack-layers.md +6 -6
- package/templates/skills/apex/steps/step-00-init.md +75 -1
- package/templates/skills/apex/steps/step-03-execute.md +16 -4
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +65 -6
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +226 -4
- package/templates/skills/apex/steps/step-04-examine.md +163 -0
- package/templates/skills/apex-verify/SKILL.md +110 -0
- package/templates/skills/apex-verify/references/audit-rules.md +50 -0
- package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
- package/templates/skills/apex-verify/steps/step-01-nav-audit.md +92 -0
- package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
- package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
- package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
- package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/application/templates-frontend.md +2 -2
- package/templates/skills/business-analyse/SKILL.md +17 -3
- package/templates/skills/business-analyse/_shared.md +64 -0
- package/templates/skills/business-analyse/patterns/suggestion-catalog.md +34 -26
- package/templates/skills/business-analyse/questionnaire/01-context.md +13 -9
- package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +20 -27
- package/templates/skills/business-analyse/questionnaire.md +86 -9
- package/templates/skills/business-analyse/references/03-json-schemas.md +221 -0
- package/templates/skills/business-analyse/references/03-post-check-validation.md +208 -0
- package/templates/skills/business-analyse/references/03-smartstack-entity-guards.md +32 -0
- package/templates/skills/business-analyse/references/04-cross-module-validation.md +95 -0
- package/templates/skills/business-analyse/references/04-file-allocation.md +162 -0
- package/templates/skills/business-analyse/references/04-naming-audit-checks.md +174 -0
- package/templates/skills/business-analyse/references/04-semantic-validation-matrix.md +118 -0
- package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
- package/templates/skills/business-analyse/references/domain-research-playbook.md +234 -0
- package/templates/skills/business-analyse/references/entity-sourcing-presentation.md +166 -0
- package/templates/skills/business-analyse/references/init-resume-logic.md +70 -0
- package/templates/skills/business-analyse/references/module-completeness-challenge.md +174 -0
- package/templates/skills/business-analyse/references/multi-app-detection.md +149 -0
- package/templates/skills/business-analyse/references/portal-classification.md +52 -0
- package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
- package/templates/skills/business-analyse/references/validation-checklist.md +35 -6
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +50 -6
- package/templates/skills/business-analyse/steps/step-00-init.md +22 -190
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +365 -269
- package/templates/skills/business-analyse/steps/step-02-structure.md +98 -20
- package/templates/skills/business-analyse/steps/step-03-specify.md +810 -229
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +509 -278
- package/templates/skills/business-analyse-design/SKILL.md +10 -0
- package/templates/skills/business-analyse-design/references/screens-post-check.md +221 -0
- package/templates/skills/business-analyse-design/references/screens-type-mapping.md +138 -0
- package/templates/skills/business-analyse-design/references/smartcomponents-templates.md +225 -0
- package/templates/skills/{business-analyse → business-analyse-design}/references/spec-auto-inference.md +117 -117
- package/templates/skills/business-analyse-design/steps/step-01-screens.md +36 -162
- package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +8 -7
- package/templates/skills/business-analyse-design/steps/step-03-navigation.md +89 -42
- package/templates/skills/business-analyse-develop/references/compact-loop.md +9 -0
- package/templates/skills/business-analyse-develop/references/handoff-quality-gate.md +132 -0
- package/templates/skills/business-analyse-develop/references/prd-v3-transformation.md +326 -0
- package/templates/skills/business-analyse-develop/references/report-reconciliation.md +140 -0
- package/templates/skills/business-analyse-develop/references/report-template.md +142 -0
- package/templates/skills/business-analyse-develop/steps/step-01-task.md +5 -177
- package/templates/skills/business-analyse-develop/steps/step-02-execute.md +17 -4
- package/templates/skills/business-analyse-develop/steps/step-03-commit.md +6 -2
- package/templates/skills/business-analyse-develop/steps/step-04-check.md +6 -0
- package/templates/skills/business-analyse-develop/steps/step-05-report.md +3 -269
- package/templates/skills/business-analyse-handoff/SKILL.md +10 -0
- package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +211 -0
- package/templates/skills/business-analyse-handoff/references/context-isolation-pattern.md +47 -0
- package/templates/skills/business-analyse-handoff/references/handoff-file-inventory.md +49 -0
- package/templates/skills/business-analyse-handoff/references/handoff-global-validation.md +142 -0
- package/templates/skills/business-analyse-handoff/references/prd-validation-checks.md +125 -0
- package/templates/skills/business-analyse-handoff/references/project-index-update.md +98 -0
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +9 -160
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +10 -99
- package/templates/skills/business-analyse-html/SKILL.md +10 -0
- package/templates/skills/business-analyse-html/html/ba-interactive.html +504 -97
- package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +79 -2
- package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
- package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +94 -36
- package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +162 -0
- package/templates/skills/business-analyse-html/html/src/styles/10-diagrams.css +73 -0
- package/templates/skills/business-analyse-html/html/src/template.html +2 -0
- package/templates/skills/business-analyse-html/references/02-embedded-artifacts-building.md +144 -0
- package/templates/skills/business-analyse-html/references/02-feature-data-building.md +143 -0
- package/templates/skills/business-analyse-html/references/02-mapping-tables.md +442 -0
- package/templates/skills/business-analyse-html/references/02-normalization-helpers.md +139 -0
- package/templates/skills/business-analyse-html/references/02-screen-format-detection.md +283 -0
- package/templates/skills/business-analyse-html/references/02-self-check-validation.md +199 -0
- package/templates/skills/business-analyse-html/references/data-build.md +24 -1
- package/templates/skills/business-analyse-html/references/data-mapping.md +119 -17
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +18 -555
- package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
- package/templates/skills/business-analyse-quick/SKILL.md +807 -0
- package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
- package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
- package/templates/skills/business-analyse-review/SKILL.md +10 -0
- package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
- package/templates/skills/business-analyse-status/SKILL.md +8 -0
- package/templates/skills/dev-start/SKILL.md +143 -307
- package/templates/skills/efcore/SKILL.md +13 -0
- package/templates/skills/sketch/SKILL.md +15 -153
- package/templates/skills/ui-components/SKILL.md +1 -1
- package/templates/skills/ui-components/patterns/data-table.md +1 -1
|
@@ -14,7 +14,7 @@ next_step: none
|
|
|
14
14
|
- ALWAYS validate permission coherence across modules
|
|
15
15
|
- ALWAYS execute semantic validation checks
|
|
16
16
|
- NEVER duplicate module content - work with summaries only
|
|
17
|
-
-
|
|
17
|
+
- ALWAYS ask for client approval, even for single-module projects (play devil's advocate)
|
|
18
18
|
|
|
19
19
|
## Context Recovery
|
|
20
20
|
|
|
@@ -50,98 +50,151 @@ IF status already "consolidated":
|
|
|
50
50
|
STOP
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
###
|
|
54
|
-
|
|
55
|
-
**2a. Load Module Index Files**
|
|
53
|
+
### 1b. Analysis Quality Self-Assessment (MANDATORY)
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
> **Score the analysis quality BEFORE presenting to the client.**
|
|
56
|
+
> This catches low-quality output before it reaches consolidation.
|
|
58
57
|
|
|
58
|
+
#### 1b-i. Research Coverage
|
|
59
59
|
```javascript
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
module
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
let researchScore = 0;
|
|
61
|
+
if (domain_research?.source === "built-in-only") {
|
|
62
|
+
researchScore = 2;
|
|
63
|
+
} else {
|
|
64
|
+
// +2 per application with Level 1 research
|
|
65
|
+
for (const app of applications) {
|
|
66
|
+
if (domain_research?.applications?.[app.code]) researchScore += 2;
|
|
67
|
+
}
|
|
68
|
+
// +1 per module with Level 2 research (cap at 4)
|
|
69
|
+
let moduleResearchCount = 0;
|
|
70
|
+
for (const module of completedModules) {
|
|
71
|
+
if (module.domainResearchSource !== "built-in-only") moduleResearchCount++;
|
|
72
|
+
}
|
|
73
|
+
researchScore += Math.min(moduleResearchCount, 4);
|
|
74
74
|
}
|
|
75
|
+
researchScore = Math.min(10, researchScore);
|
|
75
76
|
```
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Build entity registry and validate cross-module references:
|
|
80
|
-
|
|
78
|
+
#### 1b-ii. Module Completeness (per app)
|
|
81
79
|
```javascript
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
for (const app of applications) {
|
|
81
|
+
const archetype = loadArchetype(app.type); // from module-completeness-challenge.md
|
|
82
|
+
const corePresent = archetype.coreModules.filter(m => appHasModule(app, m)).length;
|
|
83
|
+
const coreTotal = archetype.coreModules.length;
|
|
84
|
+
app.completenessScore = (corePresent / coreTotal) * 10;
|
|
85
|
+
// Penalty if CORE excluded without justification
|
|
86
|
+
const unjustified = archetype.coreModules.filter(m =>
|
|
87
|
+
!appHasModule(app, m) && !isExplicitlyExcluded(app, m)
|
|
88
|
+
);
|
|
89
|
+
if (unjustified.length > 0) app.completenessScore -= 3;
|
|
91
90
|
}
|
|
91
|
+
const avgModuleScore = average(applications.map(a => a.completenessScore));
|
|
92
|
+
```
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
#### 1b-iii. Section Depth (per module)
|
|
95
|
+
```javascript
|
|
95
96
|
for (const module of completedModules) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
97
|
+
const sectionCount = module.anticipatedSections?.length || 0;
|
|
98
|
+
if (module.featureType === "workflow") {
|
|
99
|
+
if (sectionCount < 5) module.sectionScore = 4;
|
|
100
|
+
else if (sectionCount < 7) module.sectionScore = 7;
|
|
101
|
+
else module.sectionScore = 9;
|
|
102
|
+
// Bonus for contextual views
|
|
103
|
+
const hasContextual = module.anticipatedSections?.some(s =>
|
|
104
|
+
["open-requests", "rejected", "history", "my-balance", "my-tasks", "overdue"].includes(s.code)
|
|
105
|
+
);
|
|
106
|
+
if (hasContextual) module.sectionScore = Math.min(10, module.sectionScore + 1);
|
|
107
|
+
} else {
|
|
108
|
+
module.sectionScore = sectionCount >= 3 ? 8 : sectionCount >= 2 ? 6 : 4;
|
|
111
109
|
}
|
|
112
110
|
}
|
|
111
|
+
const avgSectionScore = average(completedModules.map(m => m.sectionScore));
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
#### 1b-iv. Business Rule Depth (per module)
|
|
117
115
|
```javascript
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
for (const module of completedModules) {
|
|
117
|
+
const rules = module.rules || [];
|
|
118
|
+
const domainSpecific = rules.filter(r => r.domainSpecific === true || r.source === "domain-research").length;
|
|
119
|
+
const total = rules.length;
|
|
120
|
+
if (total === 0) { module.ruleScore = 0; continue; }
|
|
121
|
+
const genericRatio = (total - domainSpecific) / total;
|
|
122
|
+
if (genericRatio > 0.8) module.ruleScore = 3; // >80% generic = poor
|
|
123
|
+
else if (genericRatio > 0.5) module.ruleScore = 6; // 50-80% generic = acceptable
|
|
124
|
+
else module.ruleScore = 9; // <50% generic = excellent
|
|
126
125
|
}
|
|
126
|
+
const avgRuleScore = average(completedModules.map(m => m.ruleScore));
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
#### 1b-v. Global Quality Score
|
|
130
|
+
```javascript
|
|
131
|
+
const qualityScore = Math.round(
|
|
132
|
+
(researchScore + avgModuleScore + avgSectionScore + avgRuleScore) / 4
|
|
133
|
+
);
|
|
134
|
+
```
|
|
130
135
|
|
|
136
|
+
Display:
|
|
131
137
|
```
|
|
132
|
-
|
|
133
|
-
CROSS-MODULE INTERACTIONS VALIDATED
|
|
134
|
-
═══════════════════════════════════════════════════════════════
|
|
138
|
+
### Auto-evaluation qualite de l'analyse
|
|
135
139
|
|
|
136
|
-
|
|
|
137
|
-
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
+
| Dimension | Score | Detail |
|
|
141
|
+
|-----------|-------|--------|
|
|
142
|
+
| Recherche web | {researchScore}/10 | {N} apps recherchees, {M} modules recherches |
|
|
143
|
+
| Completude modules | {avgModuleScore}/10 | {details per app} |
|
|
144
|
+
| Profondeur sections | {avgSectionScore}/10 | {details per module} |
|
|
145
|
+
| Profondeur regles metier | {avgRuleScore}/10 | {domainSpecific}/{total} regles specifiques domaine |
|
|
146
|
+
| **GLOBAL** | **{qualityScore}/10** | |
|
|
147
|
+
```
|
|
140
148
|
|
|
141
|
-
Total: {count} cross-module references
|
|
142
|
-
Shared entities: {count}
|
|
143
|
-
═══════════════════════════════════════════════════════════════
|
|
144
149
|
```
|
|
150
|
+
IF qualityScore < 7:
|
|
151
|
+
WARNING: "Score qualite inferieur a 7/10.
|
|
152
|
+
Recommandation : relancer les etapes deficientes avec WebSearch active."
|
|
153
|
+
Display: "Dimensions a ameliorer: {list dimensions < 7}"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Store in `validation.json` as `qualityAssessment`.
|
|
157
|
+
|
|
158
|
+
### 1c. Business Process Coverage Validation (BLOCKING for multi-app)
|
|
159
|
+
|
|
160
|
+
> **Verify that all identified business processes are covered by modules.**
|
|
161
|
+
> A process step without a covering module = a GAP in the application.
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
IF cadrage._preAnalysis?.businessProcesses?.length > 0:
|
|
165
|
+
const gaps = [];
|
|
166
|
+
for (const process of cadrage._preAnalysis.businessProcesses) {
|
|
167
|
+
for (const step of process.steps) {
|
|
168
|
+
if (!step.covered) {
|
|
169
|
+
gaps.push({ process: process.name, step: step.name, apps: process.apps });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Display:
|
|
175
|
+
### Couverture des processus metier
|
|
176
|
+
| Processus | Etapes | Couvertes | Gaps |
|
|
177
|
+
|-----------|--------|-----------|------|
|
|
178
|
+
{for each process: name, steps.length, covered count, gap names}
|
|
179
|
+
|
|
180
|
+
IF gaps.length > 0:
|
|
181
|
+
WARNING: "{gaps.length} etapes de processus non couvertes."
|
|
182
|
+
// Not BLOCKING at consolidation (should have been caught in step-01/02)
|
|
183
|
+
// But display as warning for final visibility
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Store in `validation.json` as `processCoverage`.
|
|
187
|
+
|
|
188
|
+
### 2. Cross-Module Interaction Analysis
|
|
189
|
+
|
|
190
|
+
→ **Load** `references/04-cross-module-validation.md` for FK validation rules, cycle detection, and interaction mapping.
|
|
191
|
+
|
|
192
|
+
**Execution:**
|
|
193
|
+
- Load module index files and granular JSON (entities, permissions)
|
|
194
|
+
- Build entity registry and detect shared entities
|
|
195
|
+
- Validate foreign key references across modules
|
|
196
|
+
- Detect circular dependencies (blocking error if any found)
|
|
197
|
+
- Display cross-module interaction map with validation status
|
|
145
198
|
|
|
146
199
|
### 3. Permission Coherence Check
|
|
147
200
|
|
|
@@ -184,43 +237,124 @@ const hierarchy = ["Admin", "Manager", "Contributor", "Viewer"];
|
|
|
184
237
|
|
|
185
238
|
### 4. Semantic Validation (MANDATORY)
|
|
186
239
|
|
|
187
|
-
|
|
240
|
+
→ **Load** `references/04-semantic-validation-matrix.md` and execute ALL semantic validation checks.
|
|
241
|
+
|
|
242
|
+
This includes:
|
|
243
|
+
- 13 semantic checks per module (permission orphans, UC coverage, entity doubles, permission ghosts, etc.)
|
|
244
|
+
- 5 contract verification checks (BR formulas, computed attributes, UC counts, permission counts, versioned attributes)
|
|
245
|
+
- Blocking rule: 0 ERROR → PASS, ≥1 ERROR → BLOCK (user must fix before proceeding)
|
|
188
246
|
|
|
247
|
+
**BR-EXAMPLES-COMPLETE check — qualité test-ready (NEW):**
|
|
189
248
|
```javascript
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
249
|
+
for (const module of completedModules) {
|
|
250
|
+
const rules = module.rules || [];
|
|
251
|
+
if (rules.length === 0) continue;
|
|
252
|
+
|
|
253
|
+
// 1. Couverture : toutes les règles doivent avoir des exemples
|
|
254
|
+
const withExamples = rules.filter(r => r.examples?.length > 0);
|
|
255
|
+
const exampleRate = withExamples.length / rules.length;
|
|
256
|
+
|
|
257
|
+
if (exampleRate < 0.4) {
|
|
258
|
+
ERROR(`Module ${module.code}: ${withExamples.length}/${rules.length} BRs ont des exemples (${Math.round(exampleRate*100)}% < 40% minimum) — BLOQUANT`);
|
|
259
|
+
} else if (exampleRate < 0.7) {
|
|
260
|
+
WARNING(`Module ${module.code}: ${withExamples.length}/${rules.length} BRs ont des exemples (${Math.round(exampleRate*100)}% — cible: 100%)`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// 2. Format test-ready : exemples avec given/when/then
|
|
264
|
+
const testReady = rules.filter(r =>
|
|
265
|
+
r.examples?.some(e => e.given && e.when && e.then)
|
|
266
|
+
);
|
|
267
|
+
const proseOnly = rules.filter(r =>
|
|
268
|
+
r.examples?.length > 0 && !r.examples.some(e => e.given && e.when && e.then)
|
|
269
|
+
);
|
|
205
270
|
|
|
271
|
+
if (testReady.length < 4 && module.featureType !== 'portal') {
|
|
272
|
+
WARNING(`Module ${module.code}: ${testReady.length}/4 BRs au format test-ready {given, when, then}`);
|
|
273
|
+
}
|
|
274
|
+
if (proseOnly.length > 0) {
|
|
275
|
+
WARNING(`Module ${module.code}: ${proseOnly.length} BRs avec exemples en prose — convertir en format test-ready pour génération de tests`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 3. BR-CALC : formule + exemple chiffré obligatoires
|
|
279
|
+
const calcRules = rules.filter(r => r.category === 'calculation');
|
|
280
|
+
const calcWithoutFormula = calcRules.filter(r => !r.formula);
|
|
281
|
+
const calcWithoutNumericExample = calcRules.filter(r =>
|
|
282
|
+
!r.examples?.some(e =>
|
|
283
|
+
(e.scenario === 'calculation') ||
|
|
284
|
+
(e.then && Object.values(e.then).some(v => typeof v === 'number'))
|
|
285
|
+
)
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
if (calcWithoutFormula.length > 0) {
|
|
289
|
+
ERROR(`Module ${module.code}: ${calcWithoutFormula.length} BR-CALC sans champ formula`);
|
|
290
|
+
}
|
|
291
|
+
if (calcWithoutNumericExample.length > 0) {
|
|
292
|
+
WARNING(`Module ${module.code}: ${calcWithoutNumericExample.length} BR-CALC sans exemple chiffré — les tests de calcul nécessitent des valeurs numériques`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// 4. Couverture scénarios : chaque règle devrait avoir happy_path + error
|
|
296
|
+
const withBothScenarios = rules.filter(r =>
|
|
297
|
+
r.examples?.some(e => e.scenario === 'happy_path' || e.then?.result === 'success') &&
|
|
298
|
+
r.examples?.some(e => e.scenario === 'error' || e.then?.result === 'error')
|
|
299
|
+
);
|
|
300
|
+
if (withBothScenarios.length < rules.length * 0.5 && module.featureType !== 'portal') {
|
|
301
|
+
WARNING(`Module ${module.code}: ${withBothScenarios.length}/${rules.length} BRs couvrent happy_path + error — cible: 100%`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 4b. Language Coherence Check (MANDATORY)
|
|
307
|
+
|
|
308
|
+
Verify that ALL generated content respects `{language}` from config:
|
|
309
|
+
|
|
310
|
+
```javascript
|
|
311
|
+
const expectedLang = language; // from config.json
|
|
312
|
+
|
|
313
|
+
// Heuristics for language detection
|
|
314
|
+
const frIndicators = /\b(le|la|les|un|une|des|du|de|est|sont|doit|peut|dans|pour|avec|sur|par|cette|tout|qui)\b/i;
|
|
315
|
+
const enIndicators = /\b(the|a|an|is|are|must|can|in|for|with|on|by|this|all|who|should|when|each)\b/i;
|
|
316
|
+
|
|
317
|
+
function detectLang(text) {
|
|
318
|
+
if (!text || text.length < 10) return null;
|
|
319
|
+
const frScore = (text.match(frIndicators) || []).length;
|
|
320
|
+
const enScore = (text.match(enIndicators) || []).length;
|
|
321
|
+
if (frScore > enScore * 1.5) return 'fr';
|
|
322
|
+
if (enScore > frScore * 1.5) return 'en';
|
|
323
|
+
return null; // ambiguous
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const langIssues = [];
|
|
206
327
|
for (const module of completedModules) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
warnings.push({module: module.code, check: check.check, details: result.details});
|
|
328
|
+
// Sample entity descriptions
|
|
329
|
+
(module.entities || []).forEach(e => {
|
|
330
|
+
const detected = detectLang(e.description);
|
|
331
|
+
if (detected && detected !== expectedLang) {
|
|
332
|
+
langIssues.push({ module: module.code, type: 'entity', name: e.name, detected, text: e.description?.substring(0, 60) });
|
|
213
333
|
}
|
|
214
|
-
}
|
|
334
|
+
});
|
|
335
|
+
// Sample BR statements
|
|
336
|
+
(module.rules || []).forEach(r => {
|
|
337
|
+
const detected = detectLang(r.statement);
|
|
338
|
+
if (detected && detected !== expectedLang) {
|
|
339
|
+
langIssues.push({ module: module.code, type: 'rule', name: r.id, detected, text: r.statement?.substring(0, 60) });
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
// Sample UC names
|
|
343
|
+
(module.useCases || module.usecases || []).forEach(u => {
|
|
344
|
+
const detected = detectLang(u.name);
|
|
345
|
+
if (detected && detected !== expectedLang) {
|
|
346
|
+
langIssues.push({ module: module.code, type: 'useCase', name: u.id || u.name, detected, text: u.name });
|
|
347
|
+
}
|
|
348
|
+
});
|
|
215
349
|
}
|
|
216
350
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
351
|
+
if (langIssues.length > 0) {
|
|
352
|
+
WARNING(`${langIssues.length} content items detected in wrong language (expected: ${expectedLang})`);
|
|
353
|
+
Display(langIssues.slice(0, 10).map(i => ` - ${i.module}/${i.type} "${i.name}": detected ${i.detected}, text: "${i.text}"`).join('\n'));
|
|
354
|
+
|
|
355
|
+
if (langIssues.length > completedModules.length * 3) {
|
|
356
|
+
BLOCKING_ERROR(`Too many language violations (${langIssues.length}). Re-specify affected modules in ${expectedLang}.`);
|
|
222
357
|
}
|
|
223
|
-
STOP - User must fix before proceeding
|
|
224
358
|
}
|
|
225
359
|
```
|
|
226
360
|
|
|
@@ -259,6 +393,234 @@ Display("Global Entity Count: {count}")
|
|
|
259
393
|
Display("Global Relationships: {count}")
|
|
260
394
|
```
|
|
261
395
|
|
|
396
|
+
### 5a. Cross-Module Contracts (MANDATORY)
|
|
397
|
+
|
|
398
|
+
> **Generate explicit contracts for every cross-module FK dependency.**
|
|
399
|
+
> These contracts ensure both producer and consumer modules agree on the data shape.
|
|
400
|
+
> They prevent the #1 cross-module integration failure: wrong field type/name/nullability.
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
const crossModuleContracts = [];
|
|
404
|
+
|
|
405
|
+
for (const rel of globalRelationships) {
|
|
406
|
+
// Only for cross-module relationships
|
|
407
|
+
if (rel.sourceModule !== rel.targetModule) {
|
|
408
|
+
// Resolve the FK field from the source entity's attributes
|
|
409
|
+
const sourceEntity = findEntity(rel.sourceModule, rel.sourceEntity);
|
|
410
|
+
const fkField = sourceEntity.attributes.find(a =>
|
|
411
|
+
a.name.toLowerCase() === (rel.targetEntity.toLowerCase() + 'id') ||
|
|
412
|
+
a.description?.includes('FK vers ' + rel.targetEntity)
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
crossModuleContracts.push({
|
|
416
|
+
consumer: `${rel.sourceModule}.${rel.sourceEntity}`,
|
|
417
|
+
provider: `${rel.targetModule}.${rel.targetEntity}`,
|
|
418
|
+
field: fkField?.name || `${rel.targetEntity.charAt(0).toLowerCase() + rel.targetEntity.slice(1)}Id`,
|
|
419
|
+
type: fkField?.type || "guid",
|
|
420
|
+
required: fkField?.required || false,
|
|
421
|
+
nullable: !fkField?.required,
|
|
422
|
+
resolvedVia: `FK → ${rel.targetEntity}.Id`,
|
|
423
|
+
cardinality: rel.cardinality,
|
|
424
|
+
cascadeDelete: rel.cascadeDelete,
|
|
425
|
+
description: `${rel.sourceEntity} references ${rel.targetEntity} from ${rel.targetModule}`
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Display:
|
|
432
|
+
```
|
|
433
|
+
### Contrats cross-module ({crossModuleContracts.length})
|
|
434
|
+
|
|
435
|
+
| Consumer | Provider | FK Field | Type | Required | Cascade |
|
|
436
|
+
|----------|----------|----------|------|----------|---------|
|
|
437
|
+
{for each contract: | {consumer} | {provider} | {field} | {type} | {required} | {cascadeDelete} |}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Store in `consolidation.json` as `crossModuleContracts[]`.
|
|
441
|
+
|
|
442
|
+
> These contracts are consumed by `/business-analyse-handoff` and `/business-analyse-develop`
|
|
443
|
+
> to ensure correct FK generation, DTO mapping, and navigation property creation across modules.
|
|
444
|
+
|
|
445
|
+
### 5b. Mermaid Diagram Generation (MANDATORY)
|
|
446
|
+
|
|
447
|
+
> Generate 3 types of Mermaid diagrams as text, stored in consolidation.json.
|
|
448
|
+
> These diagrams are rendered in the interactive HTML and exported with handoff.
|
|
449
|
+
|
|
450
|
+
#### 5b-i. ERD (Entity-Relationship Diagram)
|
|
451
|
+
|
|
452
|
+
From `globalEntities` and `globalRelationships` built in section 5, generate Mermaid ERD:
|
|
453
|
+
|
|
454
|
+
```javascript
|
|
455
|
+
let erd = "erDiagram\n";
|
|
456
|
+
for (const entity of globalEntities) {
|
|
457
|
+
erd += ` ${entity.name} {\n`;
|
|
458
|
+
for (const attr of entity.topAttributes) { // top 5-8 attributes
|
|
459
|
+
erd += ` ${attr.type} ${attr.name}\n`;
|
|
460
|
+
}
|
|
461
|
+
erd += " }\n";
|
|
462
|
+
}
|
|
463
|
+
for (const rel of globalRelationships) {
|
|
464
|
+
const card = rel.cardinality === "1:N" ? "||--o{" :
|
|
465
|
+
rel.cardinality === "N:1" ? "}o--||" :
|
|
466
|
+
rel.cardinality === "N:M" ? "}o--o{" : "||--||";
|
|
467
|
+
erd += ` ${rel.sourceEntity} ${card} ${rel.targetEntity} : "${rel.description}"\n`;
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Store as `consolidation.mermaidDiagrams.erd` (string).
|
|
472
|
+
|
|
473
|
+
#### 5b-ii. State Machine Diagrams (per entity lifecycle)
|
|
474
|
+
|
|
475
|
+
For EACH `lifeCycle` found in all modules' `usecases.json`:
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
let sm = "stateDiagram-v2\n";
|
|
479
|
+
sm += ` [*] --> ${lifecycle.initialState}\n`;
|
|
480
|
+
for (const transition of lifecycle.transitions) {
|
|
481
|
+
sm += ` ${transition.from} --> ${transition.to} : ${transition.action}\n`;
|
|
482
|
+
}
|
|
483
|
+
for (const state of lifecycle.states.filter(s => s.isTerminal)) {
|
|
484
|
+
sm += ` ${state.id} --> [*]\n`;
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Store as `consolidation.mermaidDiagrams.stateMachines[{entity}]` (string).
|
|
489
|
+
|
|
490
|
+
#### 5b-iii. Sequence Diagrams (per E2E flow)
|
|
491
|
+
|
|
492
|
+
For EACH e2eFlow identified in section 6:
|
|
493
|
+
|
|
494
|
+
```javascript
|
|
495
|
+
let seq = "sequenceDiagram\n";
|
|
496
|
+
for (const step of flow.steps) {
|
|
497
|
+
seq += ` ${step.actor || step.module}->>+${step.targetModule || "System"}: ${step.action}\n`;
|
|
498
|
+
if (step.result) {
|
|
499
|
+
seq += ` ${step.targetModule || "System"}-->>-${step.actor || step.module}: ${step.result}\n`;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Store as `consolidation.mermaidDiagrams.sequences[{flowName}]` (string).
|
|
505
|
+
|
|
506
|
+
#### 5b-iv. Use Case Diagrams (per module)
|
|
507
|
+
|
|
508
|
+
For EACH module, generate a Mermaid use case diagram showing actors and their interactions:
|
|
509
|
+
|
|
510
|
+
```javascript
|
|
511
|
+
const useCaseDiagrams = {};
|
|
512
|
+
|
|
513
|
+
for (const module of completedModules) {
|
|
514
|
+
const usecases = module.useCases || module.usecases || [];
|
|
515
|
+
if (usecases.length === 0) continue;
|
|
516
|
+
|
|
517
|
+
// Collect unique actors
|
|
518
|
+
const actors = [...new Set(usecases.map(uc => uc.primaryActor || uc.actor).filter(Boolean))];
|
|
519
|
+
|
|
520
|
+
// Build flowchart-based UC diagram (Mermaid does not have native usecase syntax)
|
|
521
|
+
let diagram = "flowchart LR\n";
|
|
522
|
+
|
|
523
|
+
// Add actors (left side)
|
|
524
|
+
actors.forEach((actor, i) => {
|
|
525
|
+
const actorId = 'actor_' + actor.replace(/[^a-zA-Z0-9]/g, '_');
|
|
526
|
+
diagram += ` ${actorId}[/"👤 ${actor}"\\]\n`;
|
|
527
|
+
diagram += ` style ${actorId} fill:#e1f5fe,stroke:#0288d1,color:#01579b\n`;
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// Group UCs by section
|
|
531
|
+
const sections = [...new Set(usecases.map(uc => uc.sectionCode).filter(Boolean))];
|
|
532
|
+
|
|
533
|
+
sections.forEach(section => {
|
|
534
|
+
const sectionUCs = usecases.filter(uc => uc.sectionCode === section);
|
|
535
|
+
diagram += ` subgraph ${section}["${section}"]\n`;
|
|
536
|
+
sectionUCs.forEach(uc => {
|
|
537
|
+
const ucId = (uc.id || uc.name).replace(/[^a-zA-Z0-9]/g, '_');
|
|
538
|
+
diagram += ` ${ucId}(("${uc.name}"))\n`;
|
|
539
|
+
});
|
|
540
|
+
diagram += ` end\n`;
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
// UCs without section
|
|
544
|
+
const noSectionUCs = usecases.filter(uc => !uc.sectionCode);
|
|
545
|
+
noSectionUCs.forEach(uc => {
|
|
546
|
+
const ucId = (uc.id || uc.name).replace(/[^a-zA-Z0-9]/g, '_');
|
|
547
|
+
diagram += ` ${ucId}(("${uc.name}"))\n`;
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// Connect actors to UCs
|
|
551
|
+
usecases.forEach(uc => {
|
|
552
|
+
const actor = uc.primaryActor || uc.actor;
|
|
553
|
+
if (!actor) return;
|
|
554
|
+
const actorId = 'actor_' + actor.replace(/[^a-zA-Z0-9]/g, '_');
|
|
555
|
+
const ucId = (uc.id || uc.name).replace(/[^a-zA-Z0-9]/g, '_');
|
|
556
|
+
diagram += ` ${actorId} --> ${ucId}\n`;
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
useCaseDiagrams[module.code] = diagram;
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
Store as `consolidation.mermaidDiagrams.useCases` (object: moduleCode → diagram string).
|
|
564
|
+
|
|
565
|
+
#### 5b-v. MCD (Modèle Conceptuel de Données)
|
|
566
|
+
|
|
567
|
+
Generate a simplified conceptual data model showing ONLY entity names and named relationships with cardinalities. Unlike the ERD which shows all attributes, the MCD focuses on the conceptual structure.
|
|
568
|
+
|
|
569
|
+
```javascript
|
|
570
|
+
let mcd = "erDiagram\n";
|
|
571
|
+
|
|
572
|
+
// Entities: name + PK only (no attributes)
|
|
573
|
+
for (const ent of globalEntities) {
|
|
574
|
+
mcd += ` ${ent.name} {\n`;
|
|
575
|
+
mcd += ` ${ent.pk || 'guid'} Id PK\n`;
|
|
576
|
+
mcd += ` }\n`;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Named relationships with cardinalities
|
|
580
|
+
for (const rel of globalRelationships) {
|
|
581
|
+
const card = rel.cardinality === "1:N" ? "||--o{" :
|
|
582
|
+
rel.cardinality === "N:1" ? "}o--||" :
|
|
583
|
+
rel.cardinality === "N:M" ? "}o--o{" :
|
|
584
|
+
rel.cardinality === "1:1" ? "||--||" : "||--o{";
|
|
585
|
+
|
|
586
|
+
// Use description as relationship label, or derive from cardinality
|
|
587
|
+
const label = rel.description ||
|
|
588
|
+
(rel.cardinality === "1:N" ? "contient" :
|
|
589
|
+
rel.cardinality === "N:1" ? "appartient" : "associe");
|
|
590
|
+
|
|
591
|
+
mcd += ` ${rel.sourceEntity} ${card} ${rel.targetEntity} : "${label}"\n`;
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
Store as `consolidation.mermaidDiagrams.mcd` (string).
|
|
596
|
+
|
|
597
|
+
#### 5b-vi. Storage
|
|
598
|
+
|
|
599
|
+
Write to `consolidation.json`:
|
|
600
|
+
|
|
601
|
+
```json
|
|
602
|
+
{
|
|
603
|
+
"mermaidDiagrams": {
|
|
604
|
+
"erd": "erDiagram\n Employee {\n guid id\n string code\n ...\n }\n ...",
|
|
605
|
+
"mcd": "erDiagram\n Employee {\n guid Id PK\n }\n Employee ||--o{ Contract : \"contient\"\n ...",
|
|
606
|
+
"useCases": {
|
|
607
|
+
"Employees": "flowchart LR\n actor_RH[/\"👤 RH Admin\"\\]\n ...",
|
|
608
|
+
"Absences": "flowchart LR\n ..."
|
|
609
|
+
},
|
|
610
|
+
"stateMachines": {
|
|
611
|
+
"Absence": "stateDiagram-v2\n [*] --> Draft\n Draft --> Submitted : submit\n ...",
|
|
612
|
+
"Invoice": "stateDiagram-v2\n [*] --> Draft\n ..."
|
|
613
|
+
},
|
|
614
|
+
"sequences": {
|
|
615
|
+
"CycleCommercial": "sequenceDiagram\n Commercial->>+CRM: Creer opportunite\n ...",
|
|
616
|
+
"CycleFacturation": "sequenceDiagram\n ..."
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
Display diagrams as markdown Mermaid code blocks for the client to preview before approval (section 9).
|
|
623
|
+
|
|
262
624
|
### 6. E2E Flow Validation
|
|
263
625
|
|
|
264
626
|
Identify business processes spanning multiple modules:
|
|
@@ -334,172 +696,15 @@ Les critères d'acceptation sont écrits dans `validation.json` au même niveau
|
|
|
334
696
|
|
|
335
697
|
### 7ter. Naming Audit (MANDATORY)
|
|
336
698
|
|
|
337
|
-
|
|
338
|
-
> during the BA must be reviewed for coherence, convention compliance, and clarity.
|
|
699
|
+
→ **Load** `references/04-naming-audit-checks.md` for all naming validation rules and user interaction flows.
|
|
339
700
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
route: toKebabCase(applicationCode) // kebab-case
|
|
348
|
-
},
|
|
349
|
-
modules: completedModules.map(m => ({
|
|
350
|
-
label: m.name,
|
|
351
|
-
code: m.code, // PascalCase
|
|
352
|
-
route: toKebabCase(m.code) // kebab-case
|
|
353
|
-
})),
|
|
354
|
-
entities: completedModules.flatMap(m =>
|
|
355
|
-
m.entities.map(e => ({
|
|
356
|
-
name: e.name, // PascalCase (C# class name)
|
|
357
|
-
module: m.code,
|
|
358
|
-
tableName: e.tableName || pluralize(e.name) // Plural convention
|
|
359
|
-
}))
|
|
360
|
-
),
|
|
361
|
-
permissionRoots: [...new Set(
|
|
362
|
-
permissionPaths.map(p => p.path.split('.').slice(0, 2).join('.'))
|
|
363
|
-
)]
|
|
364
|
-
};
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
**7ter-b. Display naming recap table:**
|
|
368
|
-
|
|
369
|
-
```
|
|
370
|
-
═══════════════════════════════════════════════════════════════
|
|
371
|
-
NAMING AUDIT — {application_name}
|
|
372
|
-
═══════════════════════════════════════════════════════════════
|
|
373
|
-
|
|
374
|
-
APPLICATION
|
|
375
|
-
| Label | Code (PascalCase) | Route (kebab-case) |
|
|
376
|
-
|-------|-------------------|--------------------|
|
|
377
|
-
| {application_name} | {applicationCode} | /{route} |
|
|
378
|
-
|
|
379
|
-
MODULES
|
|
380
|
-
| # | Label | Code (PascalCase) | Route (kebab-case) |
|
|
381
|
-
|---|-------|-------------------|--------------------|
|
|
382
|
-
{for each module: index | label | code | /app-route/module-route}
|
|
383
|
-
|
|
384
|
-
ENTITIES
|
|
385
|
-
| Entity (PascalCase) | Module | Table (plural) |
|
|
386
|
-
|----------------------|--------|----------------|
|
|
387
|
-
{for each entity: name | module | tableName}
|
|
388
|
-
|
|
389
|
-
PERMISSION ROOTS
|
|
390
|
-
{for each root: path}
|
|
391
|
-
═══════════════════════════════════════════════════════════════
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
**7ter-c. Coherence checks:**
|
|
395
|
-
|
|
396
|
-
```javascript
|
|
397
|
-
const namingIssues = [];
|
|
398
|
-
|
|
399
|
-
// 1. Duplicate entity names across modules
|
|
400
|
-
const entityNames = namingRegistry.entities.map(e => e.name);
|
|
401
|
-
const duplicates = entityNames.filter((n, i) => entityNames.indexOf(n) !== i);
|
|
402
|
-
if (duplicates.length > 0) {
|
|
403
|
-
namingIssues.push({ severity: "ERROR", issue: `Duplicate entity names: ${[...new Set(duplicates)].join(', ')}` });
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// 2. Module code vs label coherence (code should derive logically from label)
|
|
407
|
-
for (const mod of namingRegistry.modules) {
|
|
408
|
-
if (!mod.code || mod.code.length < 2) {
|
|
409
|
-
namingIssues.push({ severity: "ERROR", issue: `Module "${mod.label}" has invalid code: "${mod.code}"` });
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// 3. Permission root alignment with module codes
|
|
414
|
-
for (const root of namingRegistry.permissionRoots) {
|
|
415
|
-
const [appSegment, moduleSegment] = root.split('.');
|
|
416
|
-
const matchingModule = namingRegistry.modules.find(m =>
|
|
417
|
-
m.code.toLowerCase() === moduleSegment.toLowerCase()
|
|
418
|
-
);
|
|
419
|
-
if (!matchingModule) {
|
|
420
|
-
namingIssues.push({ severity: "WARNING", issue: `Permission root "${root}" has no matching module code` });
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// 4. Route collision detection
|
|
425
|
-
const allRoutes = namingRegistry.modules.map(m =>
|
|
426
|
-
`/${namingRegistry.application.route}/${m.route}`
|
|
427
|
-
);
|
|
428
|
-
const routeDuplicates = allRoutes.filter((r, i) => allRoutes.indexOf(r) !== i);
|
|
429
|
-
if (routeDuplicates.length > 0) {
|
|
430
|
-
namingIssues.push({ severity: "ERROR", issue: `Route collisions: ${routeDuplicates.join(', ')}` });
|
|
431
|
-
}
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
**7ter-d. MCP validation:**
|
|
435
|
-
|
|
436
|
-
```
|
|
437
|
-
mcp__smartstack__validate_conventions({
|
|
438
|
-
checks: ["tables"],
|
|
439
|
-
context: {
|
|
440
|
-
applicationCode: applicationCode,
|
|
441
|
-
modules: namingRegistry.modules.map(m => m.code),
|
|
442
|
-
entities: namingRegistry.entities.map(e => e.name)
|
|
443
|
-
}
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
→ Merge MCP findings into namingIssues[]
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
**7ter-e. Present findings and confirm:**
|
|
450
|
-
|
|
451
|
-
```
|
|
452
|
-
IF namingIssues.length > 0:
|
|
453
|
-
Display issues table:
|
|
454
|
-
| # | Severity | Issue |
|
|
455
|
-
|---|----------|-------|
|
|
456
|
-
{for each issue}
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
Ask via AskUserQuestion:
|
|
460
|
-
```
|
|
461
|
-
question: "{language == 'fr'
|
|
462
|
-
? 'Validez-vous les noms ci-dessus pour l\\'ensemble de l\\'application ?'
|
|
463
|
-
: 'Do you approve all the names above for the entire application?'}"
|
|
464
|
-
header: "Naming Audit"
|
|
465
|
-
options:
|
|
466
|
-
- label: "{language == 'fr' ? 'Approuvé' : 'Approved'}"
|
|
467
|
-
description: "{language == 'fr' ? 'Tous les noms sont corrects' : 'All names are correct'}"
|
|
468
|
-
- label: "{language == 'fr' ? 'Renommer certains éléments' : 'Rename some elements'}"
|
|
469
|
-
description: "{language == 'fr' ? 'Corriger des noms avant de finaliser' : 'Fix names before finalizing'}"
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
**IF "Renommer certains éléments":**
|
|
473
|
-
|
|
474
|
-
Ask via AskUserQuestion (open-ended):
|
|
475
|
-
```
|
|
476
|
-
question: "{language == 'fr'
|
|
477
|
-
? 'Quels éléments souhaitez-vous renommer ? (ex: \"Module Ventes → Commerce\", \"Entity Invoice → BillingDocument\")'
|
|
478
|
-
: 'Which elements do you want to rename? (e.g., \"Module Sales → Commerce\", \"Entity Invoice → BillingDocument\")'}"
|
|
479
|
-
header: "Renaming"
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
Process user response:
|
|
483
|
-
1. Parse rename instructions
|
|
484
|
-
2. Update `applicationCode`, module codes, entity names, permission paths accordingly in JSON files via ba-writer
|
|
485
|
-
3. Re-run 7ter-c and 7ter-d checks on updated names
|
|
486
|
-
4. Re-display the naming recap table for final confirmation
|
|
487
|
-
|
|
488
|
-
**IF "Approuvé":**
|
|
489
|
-
→ Store naming audit result in `validation.json`:
|
|
490
|
-
```javascript
|
|
491
|
-
ba-writer.enrichSection({
|
|
492
|
-
featureId: {feature_id},
|
|
493
|
-
section: "namingAudit",
|
|
494
|
-
data: {
|
|
495
|
-
auditedAt: now(),
|
|
496
|
-
issues: namingIssues,
|
|
497
|
-
approved: true,
|
|
498
|
-
renames: [] // or list of applied renames
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
```
|
|
502
|
-
→ Continue to section 8
|
|
701
|
+
This includes:
|
|
702
|
+
- Collect all application, module, entity, and permission names into a registry
|
|
703
|
+
- Display naming recap table (application code, module routes, entity tables, permission roots)
|
|
704
|
+
- Execute coherence checks (duplicate entities, route collisions, permission root alignment)
|
|
705
|
+
- Run MCP `validate_conventions` on entity/module names
|
|
706
|
+
- Present findings via AskUserQuestion with approval and rename options
|
|
707
|
+
- Process rename instructions if needed, re-validate, and continue to section 8
|
|
503
708
|
|
|
504
709
|
### 8. Consolidation Summary Display
|
|
505
710
|
|
|
@@ -537,16 +742,10 @@ RISKS
|
|
|
537
742
|
|
|
538
743
|
### 9. Client Approval (BLOCKING)
|
|
539
744
|
|
|
540
|
-
**
|
|
745
|
+
**Toujours demander l'approbation** — meme pour un module unique, jouer l'avocat du diable :
|
|
746
|
+
proposer au moins 1 cas non mentionne ou 1 question de completude avant validation.
|
|
541
747
|
|
|
542
|
-
|
|
543
|
-
IF completedModules.length === 1:
|
|
544
|
-
Display: "Module unique - consolidation automatique ✓"
|
|
545
|
-
approval = { approved: true, reason: "Single module", approvedAt: now() }
|
|
546
|
-
SKIP to section 10
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
**Multi-Module Mode:** Ask via AskUserQuestion:
|
|
748
|
+
Ask via AskUserQuestion:
|
|
550
749
|
|
|
551
750
|
```
|
|
552
751
|
question: "La consolidation est complète. Validez-vous l'ensemble ?"
|
|
@@ -568,6 +767,14 @@ IF "Modifier les interactions":
|
|
|
568
767
|
|
|
569
768
|
### 10. Write Consolidation Data
|
|
570
769
|
|
|
770
|
+
→ **Load** `references/04-file-allocation.md` for strict data allocation rules.
|
|
771
|
+
|
|
772
|
+
**MANDATORY:** Data must be written to correct files:
|
|
773
|
+
- `consolidation.json`: crossModuleInteractions, sharedEntities, permissionCoherence, e2eFlows, decision
|
|
774
|
+
- `validation.json`: semanticChecks, contractChecks, namingAudit, acceptanceCriteria, globalRiskAssessment
|
|
775
|
+
|
|
776
|
+
Mixing contents across files = BLOCKING ERROR.
|
|
777
|
+
|
|
571
778
|
```javascript
|
|
572
779
|
ba-writer.enrichSection({
|
|
573
780
|
featureId: {feature_id},
|
|
@@ -594,10 +801,6 @@ ba-writer.enrichSection({
|
|
|
594
801
|
warnings: []
|
|
595
802
|
},
|
|
596
803
|
e2eFlows: e2eFlows,
|
|
597
|
-
globalRiskAssessment: risks,
|
|
598
|
-
semanticChecks: [
|
|
599
|
-
{ check: "permission-orpheline", status: "PASS|WARNING", details: "..." }
|
|
600
|
-
],
|
|
601
804
|
decision: {
|
|
602
805
|
approved: approval.approved,
|
|
603
806
|
reason: approval.reason,
|
|
@@ -607,6 +810,34 @@ ba-writer.enrichSection({
|
|
|
607
810
|
}
|
|
608
811
|
});
|
|
609
812
|
|
|
813
|
+
// Write validation.json — quality/audit data for downstream skills (C1)
|
|
814
|
+
ba-writer.enrichSection({
|
|
815
|
+
featureId: {feature_id},
|
|
816
|
+
section: "validation",
|
|
817
|
+
data: {
|
|
818
|
+
semanticChecks: semanticChecks.map(check => ({
|
|
819
|
+
check: check.check,
|
|
820
|
+
status: errors.some(e => e.check === check.check) ? "ERROR"
|
|
821
|
+
: warnings.some(w => w.check === check.check) ? "WARNING" : "PASS",
|
|
822
|
+
details: [...errors, ...warnings]
|
|
823
|
+
.filter(r => r.check === check.check)
|
|
824
|
+
.map(r => `[${r.module}] ${r.details}`)
|
|
825
|
+
})),
|
|
826
|
+
contractChecks: [...errors, ...warnings].filter(r =>
|
|
827
|
+
["br-calc-sans-formula", "computed-sans-br-calc", "uc-count-critical",
|
|
828
|
+
"uc-count-low", "permission-count-low", "missing-versioned-attributes"].includes(r.check)
|
|
829
|
+
),
|
|
830
|
+
namingAudit: {
|
|
831
|
+
auditedAt: now(),
|
|
832
|
+
issues: namingIssues,
|
|
833
|
+
approved: true,
|
|
834
|
+
renames: []
|
|
835
|
+
},
|
|
836
|
+
acceptanceCriteria: acceptanceCriteria, // from section 7bis
|
|
837
|
+
globalRiskAssessment: risks // from section 7
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
|
|
610
841
|
// Add changelog entry
|
|
611
842
|
ba-writer.enrichSection({
|
|
612
843
|
featureId: {feature_id},
|
|
@@ -681,7 +912,7 @@ BA workflow complete. Next steps:
|
|
|
681
912
|
- ✓ Permission coherence validated
|
|
682
913
|
- ✓ Semantic checks: 0 errors
|
|
683
914
|
- ✓ Naming audit completed and approved
|
|
684
|
-
- ✓ Client approval obtained
|
|
915
|
+
- ✓ Client approval obtained
|
|
685
916
|
- ✓ Consolidation section written to validation.json
|
|
686
917
|
- ✓ Status updated to "consolidated"
|
|
687
918
|
- ✓ Workflow state saved for resume support
|