@atlashub/smartstack-cli 4.73.0 → 4.75.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 +111 -36
- 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/project/Dockerfile.backend.template +2 -2
- package/templates/project/docker-compose.yml.template +20 -0
- 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/infrastructure-checks.sh +47 -10
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/apex/references/post-checks.md +5 -2
- package/templates/skills/apex/references/smartstack-frontend.md +53 -7
- package/templates/skills/apex/steps/step-00-init.md +74 -0
- package/templates/skills/apex/steps/step-03-execute.md +16 -4
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +39 -6
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +102 -2
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/business-analyse/SKILL.md +14 -0
- package/templates/skills/business-analyse/_shared.md +27 -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 +213 -0
- package/templates/skills/business-analyse/references/03-post-check-validation.md +144 -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/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/validation-checklist.md +30 -1
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +37 -4
- 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 +652 -229
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +308 -287
- 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 +208 -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 +306 -81
- package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +15 -2
- package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +88 -33
- package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +116 -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 +141 -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 +22 -1
- package/templates/skills/business-analyse-html/references/data-mapping.md +40 -5
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +12 -555
- package/templates/skills/business-analyse-review/SKILL.md +10 -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
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Report Reconciliation: Post-Execution Validation
|
|
2
|
+
|
|
3
|
+
> **LESSON LEARNED (audit ba-002):** Simple "missing files" warnings were ignored.
|
|
4
|
+
> Structured reconciliation tables make gaps impossible to miss.
|
|
5
|
+
|
|
6
|
+
## Reconciliation 1: Handoff File Coverage
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
const filesToCreate = prd.implementation?.filesToCreate || {};
|
|
10
|
+
const handoffReconciliation = { categories: [], totalDeclared: 0, totalPresent: 0, missingFiles: [] };
|
|
11
|
+
|
|
12
|
+
for (const [cat, files] of Object.entries(filesToCreate)) {
|
|
13
|
+
let declared = 0, present = 0;
|
|
14
|
+
for (const file of (files || [])) {
|
|
15
|
+
declared++;
|
|
16
|
+
const filePath = file.path || file;
|
|
17
|
+
if (fileExists(filePath)) {
|
|
18
|
+
present++;
|
|
19
|
+
} else {
|
|
20
|
+
handoffReconciliation.missingFiles.push({ category: cat, path: filePath });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
handoffReconciliation.categories.push({
|
|
24
|
+
category: cat, declared, present, missing: declared - present,
|
|
25
|
+
coverage: declared > 0 ? Math.round((present / declared) * 100) : 100
|
|
26
|
+
});
|
|
27
|
+
handoffReconciliation.totalDeclared += declared;
|
|
28
|
+
handoffReconciliation.totalPresent += present;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const totalHandoffCoverage = handoffReconciliation.totalDeclared > 0
|
|
32
|
+
? Math.round((handoffReconciliation.totalPresent / handoffReconciliation.totalDeclared) * 100)
|
|
33
|
+
: 100;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Reconciliation 2: Business Rule Coverage
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
const brMapping = prd.implementation?.brToCodeMapping || [];
|
|
40
|
+
const brReconciliation = { total: brMapping.length, implemented: 0, missing: [], notTested: [] };
|
|
41
|
+
|
|
42
|
+
for (const br of brMapping) {
|
|
43
|
+
const componentFile = br.component || br.file;
|
|
44
|
+
const methodName = br.method || br.function;
|
|
45
|
+
|
|
46
|
+
if (!componentFile || !fileExists(componentFile)) {
|
|
47
|
+
brReconciliation.missing.push({ id: br.id, rule: br.rule, reason: 'file not found' });
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (methodName) {
|
|
51
|
+
const content = readFile(componentFile);
|
|
52
|
+
if (!content.includes(methodName)) {
|
|
53
|
+
brReconciliation.missing.push({ id: br.id, rule: br.rule, reason: `method ${methodName} not found` });
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
brReconciliation.implemented++;
|
|
58
|
+
|
|
59
|
+
if (br.testFile && !fileExists(br.testFile)) {
|
|
60
|
+
brReconciliation.notTested.push({ id: br.id, rule: br.rule });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Reconciliation 3: API Endpoint Coverage
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
const apiEndpoints = prd.implementation?.apiEndpointSummary || [];
|
|
69
|
+
const apiReconciliation = { total: apiEndpoints.length, found: 0, missing: [] };
|
|
70
|
+
|
|
71
|
+
const ctrlFilesForReconciliation = glob('src/**/Controllers/**/*Controller.cs');
|
|
72
|
+
for (const ep of apiEndpoints) {
|
|
73
|
+
const opName = ep.operation || ep.name;
|
|
74
|
+
let found = false;
|
|
75
|
+
for (const f of ctrlFilesForReconciliation) {
|
|
76
|
+
const content = readFile(f);
|
|
77
|
+
if (content.includes(opName)) { found = true; break; }
|
|
78
|
+
}
|
|
79
|
+
if (found) {
|
|
80
|
+
apiReconciliation.found++;
|
|
81
|
+
} else {
|
|
82
|
+
apiReconciliation.missing.push({ operation: opName, method: ep.method, path: ep.path });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Log summary
|
|
87
|
+
console.log(`Handoff files: ${handoffReconciliation.totalPresent}/${handoffReconciliation.totalDeclared} (${totalHandoffCoverage}%)`);
|
|
88
|
+
console.log(`Business rules: ${brReconciliation.implemented}/${brReconciliation.total} implemented`);
|
|
89
|
+
console.log(`API endpoints: ${apiReconciliation.found}/${apiReconciliation.total} found`);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Build & Test Verification (Truth Check)
|
|
93
|
+
|
|
94
|
+
> **LESSON LEARNED (audit ba-002):** "92/92 COMPLETE" + "Build PASS" was reported but the code
|
|
95
|
+
> had compilation errors and critical security flaws. The report MUST reflect actual build/test
|
|
96
|
+
> state, not just PRD task statuses.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# REAL build verification — overrides any previous "Build PASS" claim
|
|
100
|
+
dotnet build --no-restore --verbosity quiet
|
|
101
|
+
FINAL_BUILD_RC=$?
|
|
102
|
+
|
|
103
|
+
FINAL_TEST_RC=-1
|
|
104
|
+
if [ $FINAL_BUILD_RC -eq 0 ]; then
|
|
105
|
+
dotnet test --no-build --verbosity quiet
|
|
106
|
+
FINAL_TEST_RC=$?
|
|
107
|
+
fi
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// Override PRD-based build/test status with REAL results
|
|
112
|
+
const buildStatus = FINAL_BUILD_RC === 0 ? 'PASS' : 'FAIL';
|
|
113
|
+
const testStatus = FINAL_TEST_RC === 0 ? 'PASS' : (FINAL_TEST_RC === -1 ? 'SKIPPED (build failed)' : 'FAIL');
|
|
114
|
+
|
|
115
|
+
// CRITICAL: If build fails despite all tasks "completed", flag this prominently
|
|
116
|
+
if (FINAL_BUILD_RC !== 0 && stats.tasks.completed === stats.tasks.total) {
|
|
117
|
+
console.error('INTEGRITY WARNING: All tasks marked COMPLETE but build FAILS');
|
|
118
|
+
console.error('This indicates phantom task completion — review code quality');
|
|
119
|
+
stats.buildIntegrityWarning = true;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## MCP Security Scan (Final Gate)
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
// Quick MCP security validation on the final codebase
|
|
127
|
+
const securityScan = await mcp__smartstack__validate_security();
|
|
128
|
+
const conventionScan = await mcp__smartstack__validate_conventions();
|
|
129
|
+
|
|
130
|
+
// Check for write endpoints with Read permissions (semantic permission check)
|
|
131
|
+
const permissionWarnings = [];
|
|
132
|
+
const ctrlFiles = glob('src/**/Controllers/**/*Controller.cs');
|
|
133
|
+
for (const f of ctrlFiles) {
|
|
134
|
+
const content = readFile(f);
|
|
135
|
+
const writeWithRead = content.matchAll(/\[(HttpPost|HttpPut|HttpDelete|HttpPatch)[^\]]*\][^[]*\[RequirePermission\([^\)]*\.Read\)\]/gs);
|
|
136
|
+
for (const m of writeWithRead) {
|
|
137
|
+
permissionWarnings.push(`${f}: ${m[1]} uses Read permission`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Report Template Structure
|
|
2
|
+
|
|
3
|
+
Template for generating the final feature report markdown (written to `.ralph/reports/{feature-slug}.md`).
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
# Feature Report: {feature}
|
|
7
|
+
|
|
8
|
+
## Summary
|
|
9
|
+
| Field | Value |
|
|
10
|
+
|-------|-------|
|
|
11
|
+
| Status | {status} |
|
|
12
|
+
| Iterations | {iterations_used} / {max} |
|
|
13
|
+
| Branch | {branch} |
|
|
14
|
+
| Duration | {totalDuration}s ({min} min) |
|
|
15
|
+
| Execution | Delegated to /apex |
|
|
16
|
+
|
|
17
|
+
## Tasks
|
|
18
|
+
| # | Task | Category | Status | Commit |
|
|
19
|
+
|---|------|----------|--------|--------|
|
|
20
|
+
{for each task:}
|
|
21
|
+
| {id} | {description} | {category} | {status_emoji} | {commit_hash} |
|
|
22
|
+
|
|
23
|
+
**{completed}/{total} completed, {failed} failed, {blocked} blocked**
|
|
24
|
+
|
|
25
|
+
{if moduleStats:}
|
|
26
|
+
## Modules
|
|
27
|
+
| Module | Status | Tasks | Completed | Failed | Files | Commits |
|
|
28
|
+
|--------|--------|-------|-----------|--------|-------|---------|
|
|
29
|
+
{for each mod:}
|
|
30
|
+
| {code} | {status} | {total} | {completed} | {failed} | {filesCreated} | {commits} |
|
|
31
|
+
|
|
32
|
+
**{completedModules}/{totalModules} modules completed**
|
|
33
|
+
{end if}
|
|
34
|
+
|
|
35
|
+
{if prd._sectionSplit?.enabled:}
|
|
36
|
+
## Section Split Execution
|
|
37
|
+
| Phase | Type | Section | Entities | Status |
|
|
38
|
+
|-------|------|---------|----------|--------|
|
|
39
|
+
{for each phase:}
|
|
40
|
+
| {phase} | {type} | {sectionCode || '-'} | {entities.length} | {status} |
|
|
41
|
+
|
|
42
|
+
{end if}
|
|
43
|
+
|
|
44
|
+
{if handoffReconciliation.totalDeclared > 0:}
|
|
45
|
+
## Handoff Reconciliation
|
|
46
|
+
|
|
47
|
+
### File Coverage by Category
|
|
48
|
+
| Category | Declared | Present | Missing | Coverage |
|
|
49
|
+
|----------|----------|---------|---------|----------|
|
|
50
|
+
{for each cat in handoffReconciliation.categories:}
|
|
51
|
+
| {category} | {declared} | {present} | {missing} | {coverage}% |
|
|
52
|
+
{end for}
|
|
53
|
+
|
|
54
|
+
**Total: {totalPresent}/{totalDeclared} ({totalHandoffCoverage}%)**
|
|
55
|
+
|
|
56
|
+
{if handoffReconciliation.missingFiles.length > 0:}
|
|
57
|
+
### Missing Files
|
|
58
|
+
{for each mf in handoffReconciliation.missingFiles:}
|
|
59
|
+
- **{mf.category}**: `{mf.path}`
|
|
60
|
+
{end for}
|
|
61
|
+
{end if}
|
|
62
|
+
{end if}
|
|
63
|
+
|
|
64
|
+
{if brReconciliation.total > 0:}
|
|
65
|
+
### Business Rule Coverage
|
|
66
|
+
| Metric | Value |
|
|
67
|
+
|--------|-------|
|
|
68
|
+
| Total Rules | {brReconciliation.total} |
|
|
69
|
+
| Implemented | {brReconciliation.implemented} |
|
|
70
|
+
| Missing | {brReconciliation.missing.length} |
|
|
71
|
+
| Not Tested | {brReconciliation.notTested.length} |
|
|
72
|
+
|
|
73
|
+
{if brReconciliation.missing.length > 0:}
|
|
74
|
+
**Missing BR implementations:**
|
|
75
|
+
{for each br in brReconciliation.missing:}
|
|
76
|
+
- `{br.id}`: {br.rule} — {br.reason}
|
|
77
|
+
{end for}
|
|
78
|
+
{end if}
|
|
79
|
+
{end if}
|
|
80
|
+
|
|
81
|
+
{if apiReconciliation.total > 0:}
|
|
82
|
+
### API Endpoint Coverage
|
|
83
|
+
| Metric | Value |
|
|
84
|
+
|--------|-------|
|
|
85
|
+
| Total Endpoints | {apiReconciliation.total} |
|
|
86
|
+
| Found | {apiReconciliation.found} |
|
|
87
|
+
| Missing | {apiReconciliation.missing.length} |
|
|
88
|
+
|
|
89
|
+
{if apiReconciliation.missing.length > 0:}
|
|
90
|
+
**Missing API endpoints:**
|
|
91
|
+
{for each ep in apiReconciliation.missing:}
|
|
92
|
+
- `{ep.method} {ep.path}` — operation: `{ep.operation}`
|
|
93
|
+
{end for}
|
|
94
|
+
{end if}
|
|
95
|
+
{end if}
|
|
96
|
+
|
|
97
|
+
## Build & Test Verification (Actual)
|
|
98
|
+
|
|
99
|
+
> These results come from REAL `dotnet build` and `dotnet test` execution,
|
|
100
|
+
> not from PRD task statuses.
|
|
101
|
+
|
|
102
|
+
| Check | Result |
|
|
103
|
+
|-------|--------|
|
|
104
|
+
| `dotnet build` | {buildStatus} |
|
|
105
|
+
| `dotnet test` | {testStatus} |
|
|
106
|
+
| MCP validate_security | {securityScan.status} |
|
|
107
|
+
| MCP validate_conventions | {conventionScan.status} |
|
|
108
|
+
| Permission semantic check | {permissionWarnings.length === 0 ? 'PASS' : `${permissionWarnings.length} issues`} |
|
|
109
|
+
|
|
110
|
+
{if stats.buildIntegrityWarning:}
|
|
111
|
+
> **INTEGRITY WARNING:** All tasks marked COMPLETE but the build FAILS.
|
|
112
|
+
> This means some generated code references types or methods that don't exist.
|
|
113
|
+
> Review the build output and fix before considering this feature done.
|
|
114
|
+
{end if}
|
|
115
|
+
|
|
116
|
+
{if permissionWarnings.length > 0:}
|
|
117
|
+
> **PERMISSION WARNINGS:** Write endpoints using Read permissions detected:
|
|
118
|
+
{for each warning:}
|
|
119
|
+
> - {warning}
|
|
120
|
+
{end for}
|
|
121
|
+
{end if}
|
|
122
|
+
|
|
123
|
+
## Test Metrics (PRD-based)
|
|
124
|
+
| Metric | Value |
|
|
125
|
+
|--------|-------|
|
|
126
|
+
| Test Tasks | {testTasks.length} |
|
|
127
|
+
| Passed | {testsPassed} |
|
|
128
|
+
| Failed | {testsFailed} |
|
|
129
|
+
|
|
130
|
+
## Failed Tasks
|
|
131
|
+
{table of failed tasks with error messages, or "None"}
|
|
132
|
+
|
|
133
|
+
## Files
|
|
134
|
+
- Created: {filesCreated.length}
|
|
135
|
+
- Modified: {filesModified.length}
|
|
136
|
+
|
|
137
|
+
## Commits
|
|
138
|
+
{unique commits list}
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
*Auto-generated by Ralph Loop — SmartStack CLI*
|
|
142
|
+
```
|
|
@@ -79,146 +79,7 @@ If `{currentPrdPath}` exists:
|
|
|
79
79
|
- **Run CATEGORY COMPLETENESS CHECK (section 4b) before proceeding**
|
|
80
80
|
- Skip directly to section 5 (find next task)
|
|
81
81
|
2b. **v3 filesToCreate PATH:** If `$version === "3.0.0"` AND `implementation.filesToCreate` exists AND NO `tasks[]`:
|
|
82
|
-
→
|
|
83
|
-
|
|
84
|
-
```javascript
|
|
85
|
-
const ftc = prd.implementation.filesToCreate;
|
|
86
|
-
const tasks = [];
|
|
87
|
-
let taskId = 1;
|
|
88
|
-
|
|
89
|
-
// CATEGORY ORDER: domain → infrastructure → application → api → seedData → frontend → test → documentation
|
|
90
|
-
const categoryOrder = ['domain', 'infrastructure', 'application', 'api', 'seedData', 'frontend', 'tests', 'documentation'];
|
|
91
|
-
|
|
92
|
-
// Load companion specs if available (for rich acceptance criteria)
|
|
93
|
-
const specFiles = prd.specificationFiles || {};
|
|
94
|
-
const specsDir = '.ralph';
|
|
95
|
-
let specEntities = null, specRules = null, specUsecases = null, specScreens = null, specPermissions = null;
|
|
96
|
-
try {
|
|
97
|
-
if (specFiles.entities) specEntities = readJSON(`${specsDir}/${specFiles.entities}`);
|
|
98
|
-
if (specFiles.rules) specRules = readJSON(`${specsDir}/${specFiles.rules}`);
|
|
99
|
-
if (specFiles.usecases) specUsecases = readJSON(`${specsDir}/${specFiles.usecases}`);
|
|
100
|
-
if (specFiles.screens) specScreens = readJSON(`${specsDir}/${specFiles.screens}`);
|
|
101
|
-
if (specFiles.permissions) specPermissions = readJSON(`${specsDir}/${specFiles.permissions}`);
|
|
102
|
-
} catch (e) { /* companion files absent — fallback to generic AC */ }
|
|
103
|
-
|
|
104
|
-
function deriveAcceptanceCriteria(file, category, prd) {
|
|
105
|
-
const fileName = (file.path || file).split('/').pop().replace(/\.\w+$/, '');
|
|
106
|
-
|
|
107
|
-
// If no companion specs available, fallback to generic AC
|
|
108
|
-
if (!specEntities && !specRules) {
|
|
109
|
-
return `File ${file.path || file} exists and compiles`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
switch (category) {
|
|
113
|
-
case 'domain': {
|
|
114
|
-
const entityName = fileName;
|
|
115
|
-
const entity = (specEntities?.entities || []).find(e => e.name === entityName);
|
|
116
|
-
if (entity && entity.attributes) {
|
|
117
|
-
const attrs = entity.attributes.map(a => `${a.name}:${a.type}`).join(', ');
|
|
118
|
-
const rels = (entity.relationships || []).map(r => `${r.type} ${r.target}`).join(', ');
|
|
119
|
-
return `Entity ${entityName} with attributes [${attrs}]${rels ? '. Relations: [' + rels + ']' : ''}`;
|
|
120
|
-
}
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
case 'application': {
|
|
124
|
-
const linkedBRs = (prd.brToCodeMapping || [])
|
|
125
|
-
.filter(br => br.implementationPoints?.some(ip => ip.component?.includes(fileName)))
|
|
126
|
-
.map(br => `${br.ruleId}: ${br.statement || br.title}`);
|
|
127
|
-
const linkedUCs = (file.linkedUCs || []).join(', ');
|
|
128
|
-
if (linkedBRs.length > 0 || linkedUCs) {
|
|
129
|
-
const parts = [];
|
|
130
|
-
if (linkedBRs.length > 0) parts.push(`Implements BRs: [${linkedBRs.join('; ')}]`);
|
|
131
|
-
if (linkedUCs) parts.push(`Handles UCs: [${linkedUCs}]`);
|
|
132
|
-
return parts.join('. ');
|
|
133
|
-
}
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
case 'infrastructure': {
|
|
137
|
-
const entityName = fileName.replace('Configuration', '');
|
|
138
|
-
const entity = (specEntities?.entities || []).find(e => e.name === entityName);
|
|
139
|
-
if (entity && entity.attributes) {
|
|
140
|
-
const props = entity.attributes.map(a => a.name).join(', ');
|
|
141
|
-
return `EF Config for ${entityName}. Attributes: [${props}]`;
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
case 'api': {
|
|
146
|
-
const entityName = fileName.replace('Controller', '');
|
|
147
|
-
const endpoints = (prd.apiEndpointSummary || [])
|
|
148
|
-
.filter(ep => ep.operation?.includes(entityName))
|
|
149
|
-
.map(ep => `${ep.method} ${ep.route}`);
|
|
150
|
-
const perms = (specPermissions?.permissionPaths || [])
|
|
151
|
-
.filter(p => p.toLowerCase().includes(entityName.toLowerCase()))
|
|
152
|
-
.slice(0, 5);
|
|
153
|
-
const parts = [`Controller ${entityName}`];
|
|
154
|
-
if (endpoints.length > 0) parts.push(`Endpoints: [${endpoints.join(', ')}]`);
|
|
155
|
-
if (perms.length > 0) parts.push(`Permissions: [${perms.join(', ')}]`);
|
|
156
|
-
return parts.join('. ');
|
|
157
|
-
}
|
|
158
|
-
case 'frontend': {
|
|
159
|
-
const screen = (specScreens?.screens || []).find(s =>
|
|
160
|
-
fileName.toLowerCase().includes(s.code?.toLowerCase() || s.name?.toLowerCase() || '')
|
|
161
|
-
);
|
|
162
|
-
if (screen) {
|
|
163
|
-
const parts = [file.type || 'Page'];
|
|
164
|
-
if (screen.columns) parts.push(`columns [${screen.columns.map(c => c.key || c.name || c).join(', ')}]`);
|
|
165
|
-
if (screen.filters) parts.push(`filters [${screen.filters.map(f => f.key || f.name || f).join(', ')}]`);
|
|
166
|
-
if (screen.actions) parts.push(`actions [${screen.actions.map(a => a.key || a.name || a).join(', ')}]`);
|
|
167
|
-
if (screen.kpis) parts.push(`KPIs [${screen.kpis.map(k => k.label || k.name || k).join(', ')}]`);
|
|
168
|
-
return `${parts.join(' with ')}`;
|
|
169
|
-
}
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
case 'seedData': {
|
|
173
|
-
if (file.category === 'business') {
|
|
174
|
-
const entityName = fileName.replace('SeedData', '');
|
|
175
|
-
const entity = (specEntities?.entities || []).find(e => e.name === entityName);
|
|
176
|
-
if (entity?.seedValues) {
|
|
177
|
-
const names = entity.seedValues.map(v => v.name || v.label || v.code).filter(Boolean).slice(0, 5);
|
|
178
|
-
return `Seeds ${entityName} with ${entity.seedValues.length} values: [${names.join(', ')}]`;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
|
-
case 'test': case 'tests': {
|
|
184
|
-
const linkedBRs = (prd.brToCodeMapping || [])
|
|
185
|
-
.filter(br => br.implementationPoints?.some(ip =>
|
|
186
|
-
ip.layer === 'Domain' || ip.layer === 'Application'
|
|
187
|
-
))
|
|
188
|
-
.map(br => br.ruleId);
|
|
189
|
-
const linkedUCs = (file.linkedUCs || []);
|
|
190
|
-
const parts = [];
|
|
191
|
-
if (linkedBRs.length > 0) parts.push(`Covers BRs: [${linkedBRs.join(', ')}]`);
|
|
192
|
-
if (linkedUCs.length > 0) parts.push(`Covers UCs: [${linkedUCs.join(', ')}]`);
|
|
193
|
-
if (parts.length > 0) return parts.join('. ');
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
// Fallback: generic AC
|
|
198
|
-
return `File ${file.path || file} exists and compiles`;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
for (const category of categoryOrder) {
|
|
202
|
-
const files = ftc[category] || [];
|
|
203
|
-
for (const file of files) {
|
|
204
|
-
tasks.push({
|
|
205
|
-
id: `T${String(taskId++).padStart(3, '0')}`,
|
|
206
|
-
description: `Create ${file.type || category}: ${(file.path || file).split('/').pop()}`,
|
|
207
|
-
status: 'pending',
|
|
208
|
-
category: category === 'tests' ? 'test' : category, // normalize
|
|
209
|
-
dependencies: [], // implicit ordering via category
|
|
210
|
-
acceptance_criteria: deriveAcceptanceCriteria(file, category === 'tests' ? 'test' : category, prd),
|
|
211
|
-
path: file.path || file,
|
|
212
|
-
started_at: null, completed_at: null, iteration: null,
|
|
213
|
-
commit_hash: null, files_changed: [], validation: null, error: null
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
prd.tasks = tasks;
|
|
219
|
-
prd.config = { current_iteration: 1, max_iterations: 50 };
|
|
220
|
-
writeJSON(currentPrdPath, prd);
|
|
221
|
-
```
|
|
82
|
+
→ **Load** `references/prd-v3-transformation.md` for the filesToCreate → tasks transformation algorithm and deriveAcceptanceCriteria() function.
|
|
222
83
|
→ Run CATEGORY COMPLETENESS CHECK (section 4b) — will detect if seedData is missing
|
|
223
84
|
→ Skip to section 5 (find next task)
|
|
224
85
|
3. **v2 legacy:** If `$version === "2.0.0"` → find next eligible task (section 5)
|
|
@@ -228,44 +89,11 @@ If `{currentPrdPath}` does not exist: continue to section 1b.
|
|
|
228
89
|
|
|
229
90
|
### 1b. BA Handoff Quality Gate (BLOCKING when BA artifacts present)
|
|
230
91
|
|
|
231
|
-
> **
|
|
232
|
-
> A missing handoff means no frontend files, no test plan, no BR-to-code mapping.
|
|
92
|
+
> **Load** `references/handoff-quality-gate.md` for full BA handoff validation checks.
|
|
233
93
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
```javascript
|
|
239
|
-
const sourceFeatureJson = prd?.metadata?.sourceFeatureJson
|
|
240
|
-
|| findFile('docs/**/business-analyse/**/index.json')
|
|
241
|
-
|| findFile('docs/business/**/business-analyse/**/feature.json'); // legacy fallback
|
|
242
|
-
|
|
243
|
-
if (!sourceFeatureJson) {
|
|
244
|
-
// Manual mode: no BA artifacts found — skip quality gate
|
|
245
|
-
console.log('Manual mode: no BA artifacts detected — tasks will be generated from task description');
|
|
246
|
-
// Continue to section 2 (Analyze Task Description)
|
|
247
|
-
} else {
|
|
248
|
-
const feature = readJSON(sourceFeatureJson);
|
|
249
|
-
const handoff = feature.handoff || {};
|
|
250
|
-
|
|
251
|
-
// CHECK 1: Handoff status must be "handed-off"
|
|
252
|
-
if (handoff.status !== 'handed-off') {
|
|
253
|
-
console.error(`BLOCKING: BA HANDOFF INCOMPLETE
|
|
254
|
-
handoff.status = "${handoff.status || 'missing'}" (expected "handed-off")
|
|
255
|
-
Run /business-analyse-handoff to generate the handoff, then re-run /business-analyse-develop.`);
|
|
256
|
-
STOP;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// CHECK 2: filesToCreate must have all categories
|
|
260
|
-
const filesToCreate = handoff.filesToCreate || {};
|
|
261
|
-
const requiredCategories = ['domain', 'application', 'infrastructure', 'api', 'frontend', 'seedData', 'tests', 'documentation'];
|
|
262
|
-
const missingInHandoff = requiredCategories.filter(c => !filesToCreate[c] || filesToCreate[c].length === 0);
|
|
263
|
-
|
|
264
|
-
if (missingInHandoff.length > 0) {
|
|
265
|
-
console.warn(`⚠ Handoff has empty categories: ${missingInHandoff.join(', ')}`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
```
|
|
94
|
+
Quick check:
|
|
95
|
+
- If no BA artifacts detected (`sourceFeatureJson` is null): skip gate, proceed in manual mode
|
|
96
|
+
- If BA artifacts present: verify `feature.handoff.status === "handed-off"` and `filesToCreate[]` has all categories
|
|
269
97
|
|
|
270
98
|
## 2. Analyze Task Description
|
|
271
99
|
|
|
@@ -6,6 +6,8 @@ next_step: steps/step-03-commit.md
|
|
|
6
6
|
|
|
7
7
|
# Step 2: Delegate to /apex
|
|
8
8
|
|
|
9
|
+
> **REMINDER:** Ralph NEVER pauses. Execute ALL steps through completion. Stopping to ask = VIOLATION.
|
|
10
|
+
|
|
9
11
|
> **CONTEXT OPTIMIZATION:** Read ONCE (first iteration). Subsequent iterations use compact-loop.md.
|
|
10
12
|
|
|
11
13
|
## YOUR TASK:
|
|
@@ -163,12 +165,11 @@ const failed = moduleTasks.filter(t => t.status === 'failed').length;
|
|
|
163
165
|
const pending = moduleTasks.filter(t => t.status === 'pending').length;
|
|
164
166
|
|
|
165
167
|
if (failed > 0) {
|
|
166
|
-
console.log(`WARNING: ${failed} tasks failed
|
|
167
|
-
// Failed tasks will be retried in compact loop
|
|
168
|
+
console.log(`WARNING: ${failed} tasks failed — WILL BE RETRIED IMMEDIATELY in compact loop (next iteration)`);
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
if (pending > 0) {
|
|
171
|
-
console.log(`INFO: ${pending} tasks
|
|
172
|
+
console.log(`INFO: ${pending} tasks pending — WILL BE PROCESSED IMMEDIATELY in compact loop (next iteration)`);
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
console.log(`Apex completed: ${completed}/${moduleTasks.length} tasks`);
|
|
@@ -190,6 +191,18 @@ appendFile('.ralph/progress.txt', progressEntry);
|
|
|
190
191
|
|
|
191
192
|
---
|
|
192
193
|
|
|
194
|
+
## TRANSITION RULE (ABSOLUTE — NO EXCEPTIONS)
|
|
195
|
+
|
|
196
|
+
+==============================================================================+
|
|
197
|
+
| AFTER APEX RETURNS, YOU MUST IMMEDIATELY PROCEED TO STEP 03. |
|
|
198
|
+
| DO NOT pause. DO NOT summarize. DO NOT ask the user. |
|
|
199
|
+
| DO NOT display a progress report and wait. |
|
|
200
|
+
| Regardless of task failures, pending items, or scope size: |
|
|
201
|
+
| -> LOG the status (section 4-5 above) |
|
|
202
|
+
| -> IMMEDIATELY load step-03-commit.md |
|
|
203
|
+
| Any other behavior = EXECUTION GUARANTEE VIOLATION. |
|
|
204
|
+
+==============================================================================+
|
|
205
|
+
|
|
193
206
|
## CONSTRAINTS:
|
|
194
207
|
|
|
195
208
|
- **DO:** Delegate to apex, verify results, maintain PRD state
|
|
@@ -200,4 +213,4 @@ appendFile('.ralph/progress.txt', progressEntry);
|
|
|
200
213
|
|
|
201
214
|
## NEXT STEP:
|
|
202
215
|
|
|
203
|
-
|
|
216
|
+
IMMEDIATELY proceed to `./step-03-commit.md` — NO PAUSE.
|
|
@@ -6,6 +6,8 @@ next_step: steps/step-04-check.md
|
|
|
6
6
|
|
|
7
7
|
# Step 3: Commit PRD State
|
|
8
8
|
|
|
9
|
+
> **REMINDER:** Ralph NEVER pauses. Execute ALL steps through completion. Stopping to ask = VIOLATION.
|
|
10
|
+
|
|
9
11
|
> **CONTEXT OPTIMIZATION:** Read ONCE (first iteration). Subsequent iterations use compact-loop.md.
|
|
10
12
|
|
|
11
13
|
## YOUR TASK:
|
|
@@ -98,6 +100,8 @@ git log -2 --oneline
|
|
|
98
100
|
|
|
99
101
|
---
|
|
100
102
|
|
|
101
|
-
## NEXT STEP
|
|
103
|
+
## NEXT STEP — IMMEDIATE (NO PAUSE)
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
IMMEDIATELY proceed to `./step-04-check.md`.
|
|
106
|
+
DO NOT pause. DO NOT summarize to the user. DO NOT ask for confirmation.
|
|
107
|
+
The compact loop in step-04 handles ALL remaining work automatically.
|
|
@@ -6,6 +6,8 @@ next_step: steps/step-05-report.md OR steps/step-01-task.md
|
|
|
6
6
|
|
|
7
7
|
# Step 4: Check Completion
|
|
8
8
|
|
|
9
|
+
> **REMINDER:** Ralph NEVER pauses. Execute ALL steps through completion. Stopping to ask = VIOLATION.
|
|
10
|
+
|
|
9
11
|
> **STATE RECOVERY (executable):** If context was compressed:
|
|
10
12
|
```javascript
|
|
11
13
|
if (fileExists('.ralph/ralph-state.json')) {
|
|
@@ -19,6 +21,10 @@ if (fileExists('.ralph/ralph-state.json')) {
|
|
|
19
21
|
}
|
|
20
22
|
```
|
|
21
23
|
|
|
24
|
+
> **POST-RECOVERY RULE:** After restoring state from ralph-state.json,
|
|
25
|
+
> IMMEDIATELY re-enter the execution loop below. DO NOT pause. DO NOT summarize.
|
|
26
|
+
> Route to the correct section and CONTINUE. Stopping here = VIOLATION.
|
|
27
|
+
|
|
22
28
|
## YOUR TASK:
|
|
23
29
|
|
|
24
30
|
Check if all tasks are complete and decide: output completion promise, advance module, or continue loop.
|