@atlashub/smartstack-cli 3.21.0 → 3.22.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 +17 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +68 -3
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/application/references/application-roles-template.md +2 -2
- package/templates/skills/application/steps/step-05-frontend.md +40 -35
- package/templates/skills/application/templates-frontend.md +64 -36
- package/templates/skills/business-analyse/html/ba-interactive.html +80 -6
- package/templates/skills/business-analyse/html/src/scripts/05-render-specs.js +38 -6
- package/templates/skills/business-analyse/html/src/styles/06-wireframes.css +42 -0
- package/templates/skills/business-analyse/references/acceptance-criteria.md +169 -0
- package/templates/skills/business-analyse/references/deploy-data-build.md +5 -3
- package/templates/skills/business-analyse/references/handoff-file-templates.md +2 -1
- package/templates/skills/business-analyse/references/naming-conventions.md +245 -0
- package/templates/skills/business-analyse/references/validate-incremental-html.md +26 -4
- package/templates/skills/business-analyse/references/validation-checklist.md +31 -11
- package/templates/skills/business-analyse/references/wireframe-svg-style-guide.md +335 -0
- package/templates/skills/business-analyse/steps/step-03b-ui.md +59 -0
- package/templates/skills/business-analyse/steps/step-03c-compile.md +114 -0
- package/templates/skills/business-analyse/steps/step-03d-validate.md +144 -22
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +114 -2
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +28 -0
- package/templates/skills/ralph-loop/references/category-rules.md +5 -2
- package/templates/skills/ralph-loop/references/compact-loop.md +52 -1
- package/templates/skills/ralph-loop/references/core-seed-data.md +232 -21
- package/templates/skills/ralph-loop/steps/step-01-task.md +36 -4
- package/templates/skills/ralph-loop/steps/step-02-execute.md +81 -0
|
@@ -127,10 +127,11 @@ const EMBEDDED_ARTIFACTS = {
|
|
|
127
127
|
// FOR EACH module: extract from specification.uiWireframes[] OR specification.wireframes[] (SAFETY NET)
|
|
128
128
|
// IMPORTANT: The agent may write wireframes under either key name — always check BOTH
|
|
129
129
|
[moduleCode]: (moduleFeature.specification.uiWireframes || moduleFeature.specification.wireframes || []).map(wf => ({
|
|
130
|
-
screen: wf.screen || wf.name || wf.id || "", // SAFETY NET: fallback name/id → screen
|
|
130
|
+
screen: wf.screen || wf.name || wf.title || wf.id || "", // SAFETY NET: fallback name/title/id → screen
|
|
131
131
|
section: wf.section || "", // e.g. "list"
|
|
132
132
|
format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
|
|
133
|
-
content: wf.mockup,
|
|
133
|
+
content: wf.mockup || wf.ascii || wf.content || "", // SAFETY NET: mockup/ascii/content → content
|
|
134
|
+
svgContent: null, // Populated by SVG generation step (see wireframe-svg-style-guide.md)
|
|
134
135
|
description: wf.description || "",
|
|
135
136
|
elements: wf.elements || [], // [{ id, type, label }] or ["DataGrid", ...]
|
|
136
137
|
actions: wf.actions || [], // [{ trigger, action }] or ["filter", ...]
|
|
@@ -163,10 +164,11 @@ const EMBEDDED_ARTIFACTS = {
|
|
|
163
164
|
|
|
164
165
|
### Artifact Gathering
|
|
165
166
|
|
|
166
|
-
1. For EACH module: read `specification.uiWireframes[]` OR `specification.wireframes[]` (check BOTH keys — agent may use either), **rename fields** (`mockupFormat`→`format`, `mockup`→`content`), store under `wireframes[moduleCode]`
|
|
167
|
+
1. For EACH module: read `specification.uiWireframes[]` OR `specification.wireframes[]` (check BOTH keys — agent may use either), **rename fields** (`mockupFormat`→`format`, `mockup`/`ascii`/`content`→`content`, `screen`/`name`/`title`→`screen`), store under `wireframes[moduleCode]`
|
|
167
168
|
2. Read master's `consolidation.e2eFlows[]` and build e2eFlows array with diagram generation
|
|
168
169
|
3. Read master's `dependencyGraph` and build nodes/edges
|
|
169
170
|
4. Serialize as JSON with 2-space indentation
|
|
171
|
+
5. **SVG Wireframe Enrichment** (after wireframe extraction): For EACH wireframe with `content` (ASCII) and `svgContent === null`, generate SVG using parallel Task(sonnet) agents. See [wireframe-svg-style-guide.md](wireframe-svg-style-guide.md) for the complete prompt template and orchestration process. If generation fails for any wireframe → leave `svgContent` as null (graceful fallback to ASCII).
|
|
170
172
|
|
|
171
173
|
## Placeholder Replacement
|
|
172
174
|
|
|
@@ -82,10 +82,11 @@ From `specification.uiWireframes[]`, `specification.dashboards[]` and `analysis.
|
|
|
82
82
|
|
|
83
83
|
## 4.6 SeedData Files
|
|
84
84
|
|
|
85
|
-
**OBLIGATORY:
|
|
85
|
+
**OBLIGATORY: 6 CORE (1 app-level + 5 per module) + business per module:**
|
|
86
86
|
|
|
87
87
|
```json
|
|
88
88
|
"seedData": [
|
|
89
|
+
{ "path": "src/Infrastructure/Persistence/Seeding/Data/NavigationApplicationSeedData.cs", "type": "SeedData", "category": "core", "source": "specification.seedDataCore.navigationApplications", "module": "shared", "description": "Application-level navigation seed data. Created ONCE per application (FIRST). Provides ApplicationId for modules and roles." },
|
|
89
90
|
{ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/NavigationModuleSeedData.cs", "type": "SeedData", "category": "core", "source": "specification.seedDataCore.navigationModules", "module": "{moduleCode}" },
|
|
90
91
|
{ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/PermissionsSeedData.cs", "type": "SeedData", "category": "core", "source": "specification.seedDataCore.permissions", "module": "{moduleCode}" },
|
|
91
92
|
{ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/RolesSeedData.cs", "type": "SeedData", "category": "core", "source": "specification.seedDataCore.roles", "module": "{moduleCode}" },
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Naming Conventions - SmartStack
|
|
2
|
+
|
|
3
|
+
> **Loaded by:** business-analyse steps when generating codes and routes
|
|
4
|
+
> **Purpose:** Define transformation rules between code identifiers (PascalCase) and URL routes (kebab-case)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Module & Application Codes
|
|
9
|
+
|
|
10
|
+
### In feature.json
|
|
11
|
+
|
|
12
|
+
- `modules[].code` = **PascalCase** (e.g., `"HumanResources"`, `"TimeManagement"`)
|
|
13
|
+
- `metadata.application` = **PascalCase** (e.g., `"HumanResources"`)
|
|
14
|
+
- Used for: C# namespaces, file paths, class names, folder structure
|
|
15
|
+
|
|
16
|
+
### In URL Routes
|
|
17
|
+
|
|
18
|
+
- **kebab-case lowercase** (e.g., `"/business/human-resources/employees"`)
|
|
19
|
+
- Transform: `PascalCase` → `kebab-case` via helper function
|
|
20
|
+
- Used for: Web URLs, navigation routes, API paths
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Transformation Rules
|
|
25
|
+
|
|
26
|
+
| Source | Format | Example | Usage |
|
|
27
|
+
|--------|--------|---------|-------|
|
|
28
|
+
| Module code | `PascalCase` | `HumanResources` | C# files, classes, namespaces |
|
|
29
|
+
| Application code | `PascalCase` | `HumanResources` | Namespaces, folders |
|
|
30
|
+
| Context code | `lowercase` | `business` | URLs, routes, contexts |
|
|
31
|
+
| Route path | `kebab-case` | `/business/human-resources` | Web URLs, navigation |
|
|
32
|
+
| Section code | `kebab-case` | `time-tracking`, `approve` | URLs, API paths, sections |
|
|
33
|
+
| Resource code | `kebab-case` | `repair-grid`, `employee-form` | Component IDs, resources |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Why These Conventions?
|
|
38
|
+
|
|
39
|
+
### PascalCase for Code
|
|
40
|
+
- **C# Standard**: Namespaces, classes, properties follow PascalCase
|
|
41
|
+
- **File Structure**: Matches .NET project conventions
|
|
42
|
+
- **Compile-time**: Enforced by compiler and naming analyzers
|
|
43
|
+
|
|
44
|
+
### kebab-case for URLs
|
|
45
|
+
- **Web Standard**: Readable, SEO-friendly, case-insensitive
|
|
46
|
+
- **REST API Convention**: Lowercase routes with hyphens
|
|
47
|
+
- **Frontend Compatibility**: React Router, Vue Router expect lowercase
|
|
48
|
+
- **Database Storage**: Navigation routes stored lowercase prevent case mismatch errors
|
|
49
|
+
|
|
50
|
+
### Separation of Concerns
|
|
51
|
+
- **Code Identity** ≠ **URL Identity**
|
|
52
|
+
- Backend uses PascalCase internally
|
|
53
|
+
- URLs transform to kebab-case at persistence layer (seed data)
|
|
54
|
+
- Frontend consumes kebab-case routes from database
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Helper Functions
|
|
59
|
+
|
|
60
|
+
### C# (Backend Seed Data)
|
|
61
|
+
|
|
62
|
+
**Location:** `NavigationSeedData.cs` templates in core-seed-data.md
|
|
63
|
+
|
|
64
|
+
**Usage:**
|
|
65
|
+
```csharp
|
|
66
|
+
Route = ToKebabCase($"/{contextCode}/{appCode}/{moduleCode}")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Transformation Examples:**
|
|
70
|
+
- `HumanResources` → `human-resources`
|
|
71
|
+
- `TimeManagement` → `time-management`
|
|
72
|
+
- `Projects` → `projects` (single word, no change)
|
|
73
|
+
- `AI` → `ai` (acronym lowercase)
|
|
74
|
+
|
|
75
|
+
**Implementation:** See `templates/skills/ralph-loop/references/core-seed-data.md` line 162
|
|
76
|
+
|
|
77
|
+
### JavaScript (BA Handoff Generation)
|
|
78
|
+
|
|
79
|
+
**Location:** Used in step-05a-handoff.md when building seedDataCore
|
|
80
|
+
|
|
81
|
+
**Usage:**
|
|
82
|
+
```javascript
|
|
83
|
+
const route = `/${contextCode}/${toKebabCase(appCode)}/${toKebabCase(moduleCode)}`;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Implementation:**
|
|
87
|
+
```javascript
|
|
88
|
+
function toKebabCase(code) {
|
|
89
|
+
return code
|
|
90
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
91
|
+
.toLowerCase();
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### TypeScript (Frontend MCP)
|
|
96
|
+
|
|
97
|
+
**Location:** Used in scaffold_routes and validate_frontend_routes
|
|
98
|
+
|
|
99
|
+
**Usage:**
|
|
100
|
+
```typescript
|
|
101
|
+
const webPath = `/${navRoute.split('.').map(toKebabCase).join('/')}`;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Implementation:**
|
|
105
|
+
```typescript
|
|
106
|
+
function toKebabCase(str: string): string {
|
|
107
|
+
return str
|
|
108
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
109
|
+
.toLowerCase();
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Validation
|
|
116
|
+
|
|
117
|
+
### During Generation (ralph-loop)
|
|
118
|
+
|
|
119
|
+
POST-CHECK after NavigationSeedData generation:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Detect routes with uppercase
|
|
123
|
+
grep -E 'Route = "?/[^"]*[A-Z]' Infrastructure/Persistence/Seeding/Data/*/NavigationSeedData.cs
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If match found → ERROR, routes not transformed to kebab-case.
|
|
127
|
+
|
|
128
|
+
### Via MCP
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
validate_frontend_routes
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Detects:**
|
|
135
|
+
- Routes with uppercase in URLs
|
|
136
|
+
- Seed data routes not matching frontend expectations
|
|
137
|
+
- PascalCase URLs without kebab-case conversion
|
|
138
|
+
|
|
139
|
+
**Output Example:**
|
|
140
|
+
```
|
|
141
|
+
❌ Case mismatch detected (1 routes with uppercase):
|
|
142
|
+
Route "business.humanresources" uses PascalCase in URL.
|
|
143
|
+
Found: business/HumanResources → Expected: business/human-resources
|
|
144
|
+
Fix: Use ToKebabCase() in NavigationSeedData route generation
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Common Pitfalls
|
|
150
|
+
|
|
151
|
+
### ❌ Generating Routes Without Transformation
|
|
152
|
+
|
|
153
|
+
**Wrong (causes 404 on menu click):**
|
|
154
|
+
```csharp
|
|
155
|
+
Route = $"/{contextCode}/{appCode}/{moduleCode}"
|
|
156
|
+
// Result: /business/HumanResources/Projects
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Correct:**
|
|
160
|
+
```csharp
|
|
161
|
+
Route = ToKebabCase($"/{contextCode}/{appCode}/{moduleCode}")
|
|
162
|
+
// Result: /business/human-resources/projects
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### ❌ Hardcoding Routes in lowercase
|
|
166
|
+
|
|
167
|
+
**Wrong (loses traceability to code):**
|
|
168
|
+
```csharp
|
|
169
|
+
Route = "/business/humanresources" // Flattens multi-word into single word
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Correct:**
|
|
173
|
+
```csharp
|
|
174
|
+
Route = ToKebabCase($"/{contextCode}/{appCode}")
|
|
175
|
+
// If appCode = "HumanResources" → /business/human-resources
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### ❌ Inconsistent Section/Resource Codes
|
|
179
|
+
|
|
180
|
+
**Wrong (mixing conventions):**
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"code": "TimeTracking", // PascalCase
|
|
184
|
+
"route": "/time-tracking" // kebab-case route doesn't match
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Correct:**
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"code": "time-tracking", // kebab-case from start
|
|
192
|
+
"route": "/business/human-resources/time-tracking"
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Sections and resources ALWAYS use kebab-case (no transformation needed).
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Examples
|
|
201
|
+
|
|
202
|
+
### Full Hierarchy Example
|
|
203
|
+
|
|
204
|
+
**BA Input (feature.json):**
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"metadata": {
|
|
208
|
+
"context": "business",
|
|
209
|
+
"application": "HumanResources"
|
|
210
|
+
},
|
|
211
|
+
"modules": [
|
|
212
|
+
{ "code": "TimeManagement" },
|
|
213
|
+
{ "code": "Projects" }
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Generated Routes (seed data):**
|
|
219
|
+
```
|
|
220
|
+
Application: /business/human-resources
|
|
221
|
+
Module 1: /business/human-resources/time-management
|
|
222
|
+
Module 2: /business/human-resources/projects
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**C# Code Structure:**
|
|
226
|
+
```
|
|
227
|
+
src/Domain/Entities/Business/HumanResources/TimeManagement/TimeEntry.cs
|
|
228
|
+
src/Application/Services/Business/HumanResources/TimeManagement/TimeEntryService.cs
|
|
229
|
+
src/API/Controllers/Business/HumanResources/TimeManagementController.cs
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Frontend Routes (React Router):**
|
|
233
|
+
```tsx
|
|
234
|
+
<Route path="/business/human-resources/time-management" element={<TimeManagementPage />} />
|
|
235
|
+
<Route path="/business/human-resources/projects" element={<ProjectsPage />} />
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## References
|
|
241
|
+
|
|
242
|
+
- **Template:** `templates/skills/ralph-loop/references/core-seed-data.md`
|
|
243
|
+
- **Validation:** `src/mcp/tools/validate-frontend-routes.ts`
|
|
244
|
+
- **POST-CHECK:** `templates/skills/ralph-loop/steps/step-02-execute.md` (section 5)
|
|
245
|
+
- **Handoff:** `templates/skills/business-analyse/steps/step-05a-handoff.md` (section 4.6)
|
|
@@ -46,10 +46,11 @@ const EMBEDDED_ARTIFACTS = {
|
|
|
46
46
|
// FOR EACH completed module: extract wireframes with RENAMED fields
|
|
47
47
|
// SAFETY NET: check BOTH key names (agent may use either)
|
|
48
48
|
[moduleCode]: (moduleFeature.specification.uiWireframes || moduleFeature.specification.wireframes || []).map(wf => ({
|
|
49
|
-
screen: wf.screen,
|
|
50
|
-
section: wf.section,
|
|
49
|
+
screen: wf.screen || wf.name || wf.title || wf.id || "", // SAFETY NET: fallback name/title/id → screen
|
|
50
|
+
section: wf.section || "",
|
|
51
51
|
format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
|
|
52
|
-
content: wf.mockup,
|
|
52
|
+
content: wf.mockup || wf.ascii || wf.content || "", // SAFETY NET: mockup/ascii/content → content
|
|
53
|
+
svgContent: null, // Populated by Step 3-bis SVG generation
|
|
53
54
|
description: wf.description || "",
|
|
54
55
|
elements: wf.elements || [],
|
|
55
56
|
actions: wf.actions || [],
|
|
@@ -74,6 +75,27 @@ const EMBEDDED_ARTIFACTS = {
|
|
|
74
75
|
> The HTML renderer reads `format` and `content`. You MUST rename these fields.
|
|
75
76
|
> Failure to rename = empty mockup display in the browser.
|
|
76
77
|
|
|
78
|
+
### Step 3-bis: Generate SVG Wireframes (Parallel Task Agents)
|
|
79
|
+
|
|
80
|
+
> **Purpose:** Enrich each ASCII wireframe with a professional SVG version for dual-view rendering.
|
|
81
|
+
> **Cost:** ~$0.01 per wireframe (Sonnet model). Negligible for 2-6 wireframes per module.
|
|
82
|
+
> **Fallback:** If ANY SVG generation fails, proceed with ASCII only (svgContent stays null).
|
|
83
|
+
|
|
84
|
+
See [references/wireframe-svg-style-guide.md](wireframe-svg-style-guide.md) for the complete SVG style specification, prompt template, and orchestration process.
|
|
85
|
+
|
|
86
|
+
**Process summary:**
|
|
87
|
+
|
|
88
|
+
1. **Read** `references/wireframe-svg-style-guide.md` to get the prompt template
|
|
89
|
+
2. **Collect** all wireframes in `EMBEDDED_ARTIFACTS.wireframes` where `content` exists and `svgContent` is null
|
|
90
|
+
3. **Spawn parallel Task(sonnet) agents** — ONE per wireframe, ALL in a single message
|
|
91
|
+
4. **Collect and validate** results: strip markdown fences if present, verify SVG starts with `<svg` and contains `</svg>`
|
|
92
|
+
5. **Inject** valid SVGs into `EMBEDDED_ARTIFACTS.wireframes[moduleCode][index].svgContent`
|
|
93
|
+
6. **Display** summary: `SVG wireframes: {generated}/{total} generated successfully`
|
|
94
|
+
|
|
95
|
+
> **CRITICAL:** This step is NEVER blocking. If all SVG generations fail, deployment
|
|
96
|
+
> continues with ASCII-only wireframes. The HTML renderer checks for `svgContent` before
|
|
97
|
+
> showing the SVG view. SVG is an enhancement, not a requirement.
|
|
98
|
+
|
|
77
99
|
### Step 4: Replace Placeholders in Template
|
|
78
100
|
|
|
79
101
|
- Serialize the FEATURE_DATA object as JSON (2-space indentation)
|
|
@@ -93,7 +115,7 @@ const EMBEDDED_ARTIFACTS = {
|
|
|
93
115
|
Modules included: {completedModules.length}/{totalModules} specified
|
|
94
116
|
- {completedModule1}: {uc_count} UCs, {br_count} BRs, {wireframe_count} wireframes
|
|
95
117
|
- {completedModule2}: ...
|
|
96
|
-
Visual artifacts: {total_wireframes} wireframes embedded
|
|
118
|
+
Visual artifacts: {total_wireframes} wireframes embedded ({svg_count} with SVG, {ascii_only_count} ASCII only)
|
|
97
119
|
Remaining: {pendingModules.join(', ')} (will be added after specification)
|
|
98
120
|
→ Client can open in browser to review completed modules now.
|
|
99
121
|
```
|
|
@@ -139,16 +139,16 @@ const checklist = {
|
|
|
139
139
|
|
|
140
140
|
wireframes: {
|
|
141
141
|
minimum: specification.sections.length, // 1 wireframe PER section
|
|
142
|
-
actual: specification.uiWireframes.length,
|
|
142
|
+
actual: (specification.uiWireframes || specification.wireframes || []).length, // Check BOTH key names
|
|
143
143
|
status: actual >= minimum ? "PASS" : "FAIL",
|
|
144
144
|
blocking: true,
|
|
145
|
-
details: "EVERY section MUST have a wireframe (ASCII/SVG)"
|
|
145
|
+
details: "EVERY section MUST have a wireframe (ASCII/SVG). Check both uiWireframes and wireframes keys."
|
|
146
146
|
},
|
|
147
147
|
|
|
148
148
|
wireframeSchemaCompliance: {
|
|
149
149
|
check: "All wireframes have required fields: screen, section, mockupFormat, elements[], componentMapping[], layout (object), permissionsRequired[]",
|
|
150
|
-
status: specification.uiWireframes.every(wf =>
|
|
151
|
-
wf.screen && wf.section && wf.mockupFormat &&
|
|
150
|
+
status: (specification.uiWireframes || specification.wireframes || []).every(wf =>
|
|
151
|
+
(wf.screen || wf.title) && wf.section && (wf.mockupFormat || wf.mockup || wf.ascii) &&
|
|
152
152
|
Array.isArray(wf.elements) && wf.elements.length > 0 &&
|
|
153
153
|
Array.isArray(wf.componentMapping) && wf.componentMapping.length > 0 &&
|
|
154
154
|
typeof wf.layout === 'object' && wf.layout !== null &&
|
|
@@ -156,8 +156,9 @@ const checklist = {
|
|
|
156
156
|
) ? "PASS" : "FAIL",
|
|
157
157
|
blocking: true,
|
|
158
158
|
details: "Wireframes missing metadata render as empty frames in HTML documentation. " +
|
|
159
|
-
"Check: screen (not name/id), section, mockupFormat, elements[] non-empty, " +
|
|
160
|
-
"componentMapping[] as array of {wireframeElement, reactComponent}, layout as object (not string)"
|
|
159
|
+
"Check: screen (not name/id/title), section, mockupFormat, elements[] non-empty, " +
|
|
160
|
+
"componentMapping[] as array of {wireframeElement, reactComponent}, layout as object (not string). " +
|
|
161
|
+
"Also see references/acceptance-criteria.md for bash-verifiable checks."
|
|
161
162
|
},
|
|
162
163
|
|
|
163
164
|
navigation: {
|
|
@@ -240,12 +241,31 @@ const checklist = {
|
|
|
240
241
|
details: "Modules need field validation rules"
|
|
241
242
|
},
|
|
242
243
|
|
|
243
|
-
// SECTION 10: GHERKIN SCENARIOS (WARNING)
|
|
244
|
-
|
|
244
|
+
// SECTION 10: GHERKIN SCENARIOS (BLOCKING for format, WARNING for count)
|
|
245
|
+
gherkinFormat: {
|
|
246
|
+
check: "gherkinScenarios is ARRAY (not single object)",
|
|
247
|
+
status: Array.isArray(specification.gherkinScenarios) ? "PASS" : "FAIL",
|
|
248
|
+
blocking: true,
|
|
249
|
+
details: "gherkinScenarios MUST be an array [{feature, scenarios}], not a single object. " +
|
|
250
|
+
"Auto-fix: wrap in array [gherkinScenarios]. See step-03c ABSOLUTE FORMAT CHECKS."
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
gherkinContent: {
|
|
254
|
+
check: "Each gherkin entry has feature (string) + scenarios (array)",
|
|
255
|
+
status: (Array.isArray(specification.gherkinScenarios) &&
|
|
256
|
+
specification.gherkinScenarios.every(g => g.feature && Array.isArray(g.scenarios))
|
|
257
|
+
) ? "PASS" : "FAIL",
|
|
258
|
+
blocking: true,
|
|
259
|
+
details: "Each gherkin entry must have {feature: string, scenarios: [{name, tags, given[], when[], then[]}]}"
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
gherkinScenarioCount: {
|
|
245
263
|
minimum: 2,
|
|
246
|
-
actual: specification.gherkinScenarios
|
|
264
|
+
actual: (Array.isArray(specification.gherkinScenarios)
|
|
265
|
+
? specification.gherkinScenarios.reduce((sum, g) => sum + (g.scenarios || []).length, 0)
|
|
266
|
+
: 0),
|
|
247
267
|
status: actual >= minimum ? "PASS" : "FAIL",
|
|
248
|
-
blocking: false, // WARNING only
|
|
268
|
+
blocking: false, // WARNING only — count is advisory
|
|
249
269
|
details: "Gherkin scenarios enable automated testing"
|
|
250
270
|
}
|
|
251
271
|
};
|
|
@@ -297,7 +317,7 @@ ELSE:
|
|
|
297
317
|
| Seed Data | 2 | {n} | {n} | {n} |
|
|
298
318
|
| API Endpoints | 2 | {n} | {n} | {n} |
|
|
299
319
|
| Validations | 1 | {n} | {n} | {n} |
|
|
300
|
-
| Gherkin |
|
|
320
|
+
| Gherkin | 3 | {n} | {n} | {n} |
|
|
301
321
|
|
|
302
322
|
TOTAL: {total_checks} checks | {passed} ✓ | {failed} ✗ | {warnings} ⚠
|
|
303
323
|
|