@atlashub/smartstack-cli 3.25.0 → 3.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/index.js +3 -0
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +11 -5
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -2
  6. package/templates/skills/apex/SKILL.md +26 -5
  7. package/templates/skills/apex/_shared.md +3 -3
  8. package/templates/skills/apex/references/agent-teams-protocol.md +8 -8
  9. package/templates/skills/apex/references/challenge-questions.md +165 -0
  10. package/templates/skills/apex/{steps/step-04-validate.md → references/post-checks.md} +82 -214
  11. package/templates/skills/apex/references/smartstack-api.md +91 -14
  12. package/templates/skills/apex/references/smartstack-layers.md +16 -4
  13. package/templates/skills/apex/steps/step-00-init.md +84 -56
  14. package/templates/skills/apex/steps/step-01-analyze.md +73 -87
  15. package/templates/skills/apex/steps/step-03-execute.md +2 -2
  16. package/templates/skills/apex/steps/step-04-examine.md +198 -0
  17. package/templates/skills/apex/steps/{step-05-examine.md → step-05-deep-review.md} +6 -6
  18. package/templates/skills/apex/steps/step-06-resolve.md +2 -2
  19. package/templates/skills/business-analyse/SKILL.md +28 -0
  20. package/templates/skills/business-analyse/references/agent-module-prompt.md +255 -0
  21. package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +26 -10
  22. package/templates/skills/business-analyse/references/team-orchestration.md +437 -0
  23. package/templates/skills/business-analyse/steps/step-02-decomposition.md +31 -4
  24. package/templates/skills/business-analyse/steps/step-03a1-setup.md +21 -0
  25. package/templates/skills/business-analyse/steps/step-03d-validate.md +84 -0
  26. package/templates/skills/ralph-loop/references/core-seed-data.md +45 -10
  27. package/templates/skills/ralph-loop/steps/step-02-execute.md +47 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "3.25.0",
3
+ "version": "3.27.0",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -113,6 +113,5 @@
113
113
  "vitest": "^2.1.0"
114
114
  },
115
115
  "optionalDependencies": {
116
- "msnodesqlv8": "^5.1.3"
117
116
  }
118
117
  }
@@ -33,7 +33,7 @@ Execute incremental SmartStack development using the APEX methodology. This skil
33
33
  | Flag | Description |
34
34
  |------|-------------|
35
35
  | `-a` | Auto mode: skip confirmations |
36
- | `-x` | Examine mode: adversarial code review |
36
+ | `-x` | Deep review: adversarial code review (beyond step-04 automated checks) |
37
37
  | `-s` | Save mode: output to `.claude/output/apex/` |
38
38
  | `-t` | Test mode: scaffold + run tests via MCP |
39
39
  | `-e` | Economy mode: no subagents |
@@ -57,11 +57,17 @@ Execute incremental SmartStack development using the APEX methodology. This skil
57
57
  | `{context_code}` | string | "business", "platform", "personal" |
58
58
  | `{app_name}` | string | Application name |
59
59
  | `{module_code}` | string | Module code |
60
- | `{sections}` | string[] | Sections being added/modified |
60
+ | `{sections}` | object[] | Sections (MANDATORY, min 1) with code/labels/icon/displayOrder |
61
+ | `{entities}` | string[] | Main entities to manage (from need-challenge) |
62
+ | `{module_complexity}` | string | "simple-crud", "crud-rules", "crud-workflow", "complex" |
63
+ | `{has_dependencies}` | string | "none", "references", "unknown" |
64
+ | `{key_properties}` | string[] | Key business properties mentioned by user |
61
65
  | `{prd_path}` | string? | `.ralph/prd-{module}.json` if exists |
62
66
  | `{feature_path}` | string? | `docs/business/.../feature.json` if exists |
63
67
  | `{needs_seed_data}` | boolean | Seed data creation required |
64
68
  | `{needs_migration}` | boolean | EF Core migration required |
69
+ | `{needs_workflow}` | boolean | Workflow integration required |
70
+ | `{needs_notification}` | boolean | Notification integration required |
65
71
  </state_variables>
66
72
 
67
73
  <entry_point>
@@ -75,17 +81,32 @@ Execute incremental SmartStack development using the APEX methodology. This skil
75
81
 
76
82
  | Step | File | Model | Purpose |
77
83
  |------|------|-------|---------|
78
- | 00 | `steps/step-00-init.md` | Sonnet | Parse flags, detect SmartStack context, verify MCP |
84
+ | 00 | `steps/step-00-init.md` | Sonnet | Parse flags, detect context, verify MCP, define hierarchy (5 levels), challenge need |
79
85
  | 01 | `steps/step-01-analyze.md` | Opus | Explore existing code (Agent Teams or direct) |
80
86
  | 02 | `steps/step-02-plan.md` | Opus | Layer-by-layer plan with skill/MCP mapping |
81
87
  | 03 | `steps/step-03-execute.md` | Opus | Orchestrate execution via skills and MCP |
82
- | 04 | `steps/step-04-validate.md` | Opus | MCP validation, build, seed data check |
83
- | 05 | `steps/step-05-examine.md` | Opus | Adversarial review (if -x) |
88
+ | 04 | `steps/step-04-examine.md` | Opus | eXamine: MCP validation, build, 21 POST-CHECKs, acceptance criteria |
89
+ | 05 | `steps/step-05-deep-review.md` | Opus | Deep Review: adversarial code review (if -x) |
84
90
  | 06 | `steps/step-06-resolve.md` | Opus | Fix BLOCKING findings (if any) |
85
91
  | 07 | `steps/step-07-tests.md` | Opus | Scaffold tests via MCP (if -t) |
86
92
  | 08 | `steps/step-08-run-tests.md` | Opus | Run tests until 100% pass (if -t) |
87
93
  </step_files>
88
94
 
95
+ <apex_phases>
96
+ **APEX = Analyze → Plan → Execute → eXamine**
97
+
98
+ | Phase | Step | Obligatory | Description |
99
+ |-------|------|------------|-------------|
100
+ | *Init* | 00 | Yes | Setup, hierarchy, challenge the need |
101
+ | **A** — Analyze | 01 | Yes | Explore existing code |
102
+ | **P** — Plan | 02 | Yes | File-by-file plan with skill/MCP mapping |
103
+ | **E** — Execute | 03 | Yes | Orchestrate creation via skills and MCP |
104
+ | **X** — eXamine | 04 | Yes | 21 POST-CHECKs, MCP validation, build, acceptance criteria |
105
+ | *Deep Review* | 05 (if -x) | No | Adversarial code review beyond automated checks |
106
+ | *Resolve* | 06 (if BLOCKING) | No | Fix BLOCKING findings |
107
+ | *Tests* | 07-08 (if -t) | No | Scaffold and run tests |
108
+ </apex_phases>
109
+
89
110
  <reference_files>
90
111
  **Loaded conditionally by steps that need them:**
91
112
 
@@ -30,7 +30,7 @@
30
30
 
31
31
  | Tool | Purpose | Step |
32
32
  |------|---------|------|
33
- | `validate_conventions` | Validate SmartStack conventions | 00 (check), 04 (validate) |
33
+ | `validate_conventions` | Validate SmartStack conventions | 00 (check), 04 (examine) |
34
34
 
35
35
  ### Generation (step-03)
36
36
 
@@ -42,7 +42,7 @@
42
42
  | `scaffold_api_client` | Generate TypeScript API client | Frontend changes |
43
43
  | `scaffold_routes` | Generate React Router routes | Frontend changes |
44
44
 
45
- ### Validation (step-04)
45
+ ### eXamine (step-04)
46
46
 
47
47
  | Tool | Purpose | Condition |
48
48
  |------|---------|-----------|
@@ -65,7 +65,7 @@
65
65
  | `suggest_test_scenarios` | Suggest test scenarios |
66
66
  | `analyze_test_coverage` | Check coverage percentage |
67
67
 
68
- ### Review (step-05, if -x)
68
+ ### Deep Review (step-05, if -x)
69
69
 
70
70
  | Tool | Purpose |
71
71
  |------|---------|
@@ -22,7 +22,7 @@ Always provide both `team_name` and `description`.
22
22
 
23
23
  ```yaml
24
24
  Task:
25
- subagent_type: "general-purpose"
25
+ subagent_type: "Explore" | "general-purpose" # See assignment table below
26
26
  team_name: "apex-{phase}" # Must match TeamCreate
27
27
  name: "{teammate-name}" # e.g., "scan-backend", "exec-frontend"
28
28
  model: "sonnet" | "opus" # sonnet for scan, opus for dev (T02/T06)
@@ -30,14 +30,14 @@ Task:
30
30
  prompt: "{detailed task prompt}"
31
31
  ```
32
32
 
33
- ### Model Assignment (T02/T06)
33
+ ### Model & Agent Assignment (T02/T03/T06)
34
34
 
35
- | Task Type | Model | Justification |
36
- |-----------|-------|---------------|
37
- | Scan/read files | Sonnet | Read-only, no analysis needed |
38
- | Read context (PRD, feature.json) | Sonnet | Read-only extraction |
39
- | Code development | Opus | Complex generation via skills/MCP |
40
- | Fix/resolve | Opus | Requires reasoning |
35
+ | Task Type | subagent_type | Model | Justification |
36
+ |-----------|---------------|-------|---------------|
37
+ | Scan/read files | Explore | Sonnet | Read-only (Glob, Grep, Read) |
38
+ | Read context (PRD, feature.json) | Explore | Sonnet | Read-only extraction |
39
+ | Code development | general-purpose | Opus | Full tools via skills/MCP |
40
+ | Fix/resolve | general-purpose | Opus | Requires reasoning + editing |
41
41
 
42
42
  ---
43
43
 
@@ -0,0 +1,165 @@
1
+ # Challenge Questions — APEX
2
+
3
+ > **Referenced by:** step-00-init.md
4
+ > Question templates for context detection, hierarchy validation, and need challenging.
5
+
6
+ ---
7
+
8
+ ## Context Detection (section 2)
9
+
10
+ If hierarchy cannot be inferred, ask the user:
11
+
12
+ ```yaml
13
+ questions:
14
+ - header: "Context"
15
+ question: "What is the SmartStack context for this work?"
16
+ options:
17
+ - label: "Business (Recommended)"
18
+ description: "Business application module"
19
+ - label: "Platform"
20
+ description: "Platform administration or support"
21
+ - label: "Personal"
22
+ description: "Personal user space"
23
+ multiSelect: false
24
+ ```
25
+
26
+ ---
27
+
28
+ ## 4a. Application Validation
29
+
30
+ If `{app_name}` was NOT clearly inferred from the task description:
31
+
32
+ ```yaml
33
+ questions:
34
+ - header: "Application"
35
+ question: "Which application does this module belong to?"
36
+ options:
37
+ - label: "<best guess from task> (Recommended)"
38
+ description: "Inferred from your task description"
39
+ - label: "New application"
40
+ description: "Create a new application in the {context_code} context"
41
+ - label: "Existing application"
42
+ description: "Add to an existing application (specify in Other)"
43
+ multiSelect: false
44
+ ```
45
+
46
+ If "New application": collect `{app_name}`, `{app_code}`, `{app_icon}`, `{app_labels}` (4 langs).
47
+ If "Existing application": scan `**/Seeding/Data/**/NavigationApplicationSeedData.cs` and present discovered apps.
48
+
49
+ ---
50
+
51
+ ## 4b. Module Validation
52
+
53
+ If `{module_code}` was NOT clearly inferred from the task description:
54
+
55
+ ```yaml
56
+ questions:
57
+ - header: "Module"
58
+ question: "What is the module code? (kebab-case, e.g., 'order-management', 'employees')"
59
+ options:
60
+ - label: "<inferred module code> (Recommended)"
61
+ description: "Inferred from your task description"
62
+ - label: "<alternative suggestion>"
63
+ description: "Alternative based on keywords"
64
+ multiSelect: false
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 4c. Section Selection
70
+
71
+ > **BLOCKING:** This question MUST be asked. `{sections}` MUST contain at least one entry before proceeding.
72
+
73
+ Infer section suggestions from:
74
+ 1. Task description (extract nouns/concepts that suggest functional sub-areas)
75
+ 2. PRD/feature.json if available (module.sections)
76
+ 3. Common patterns: "list" (default for simple CRUD), "dashboard", "settings", "reports"
77
+
78
+ ```yaml
79
+ questions:
80
+ - header: "Sections"
81
+ question: "What sections should the module '{module_code}' contain? (Select at least one — use 'Other' to add custom sections)"
82
+ options:
83
+ - label: "<inferred section 1>"
84
+ description: "Primary functional area based on module purpose"
85
+ - label: "<inferred section 2>"
86
+ description: "Secondary functional area"
87
+ - label: "<inferred section 3>"
88
+ description: "Additional area inferred from context"
89
+ multiSelect: true
90
+ ```
91
+
92
+ **Validation (BLOCKING):**
93
+ ```
94
+ IF {sections}.length == 0:
95
+ DISPLAY: "Every module must have at least one section. Please select or define at least one."
96
+ → Re-ask the sections question
97
+ → DO NOT proceed to next step
98
+ ```
99
+
100
+ **Store for each section:**
101
+ ```yaml
102
+ sections:
103
+ - code: "section-kebab"
104
+ labels: { fr: "...", en: "...", it: "...", de: "..." }
105
+ icon: "LucideIconName"
106
+ displayOrder: 10
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 5a. Entity Scope & Relationships
112
+
113
+ ```yaml
114
+ questions:
115
+ - header: "Entities"
116
+ question: "What are the main entities this module manages? (e.g., 'Order, OrderLine, OrderStatus')"
117
+ options:
118
+ - label: "<inferred primary entity>"
119
+ description: "Main entity inferred from module name"
120
+ - label: "<inferred primary + secondary>"
121
+ description: "Primary entity plus related entities from context"
122
+ - label: "Only the primary entity"
123
+ description: "Simple module — single entity '{module_code}' with standard CRUD"
124
+ multiSelect: false
125
+ - header: "Complexity"
126
+ question: "What best describes this module's behavior?"
127
+ options:
128
+ - label: "Simple CRUD (Recommended)"
129
+ description: "Standard list/create/edit/delete — no special business logic"
130
+ - label: "CRUD + Business rules"
131
+ description: "CRUD with validations, computed fields, status transitions, or constraints"
132
+ - label: "CRUD + Workflow/Notifications"
133
+ description: "CRUD with automated actions (emails, approvals, webhooks)"
134
+ - label: "Complex module"
135
+ description: "Multiple interrelated entities with specific business logic"
136
+ multiSelect: false
137
+ ```
138
+
139
+ ---
140
+
141
+ ## 5b. Dependencies & Key Properties
142
+
143
+ ```yaml
144
+ questions:
145
+ - header: "Dependencies"
146
+ question: "Does this module reference entities from other existing modules?"
147
+ options:
148
+ - label: "No dependencies"
149
+ description: "Standalone module — no FK relationships to other modules"
150
+ - label: "Yes, has FK references"
151
+ description: "References entities from other modules (specify in Other)"
152
+ - label: "Not sure yet"
153
+ description: "Will determine during analysis — may require EntityLookup components"
154
+ multiSelect: false
155
+ - header: "Key fields"
156
+ question: "Beyond standard fields (Id, TenantId, Audit), what are the key business properties of the main entity?"
157
+ options:
158
+ - label: "<inferred properties from context>"
159
+ description: "Properties inferred from module purpose"
160
+ - label: "Standard fields only"
161
+ description: "I'll define properties later during implementation"
162
+ - label: "I have specific requirements"
163
+ description: "Describe your fields in 'Other'"
164
+ multiSelect: false
165
+ ```
@@ -1,145 +1,6 @@
1
- ---
2
- name: step-04-validate
3
- description: MCP validation, build verification, seed data check, acceptance criteria
4
- model: opus
5
- prev_step: steps/step-03-execute.md
6
- next_step: steps/step-05-examine.md
7
- ---
8
-
9
- # Step 4: Validate
10
-
11
- **Goal:** Verify everything works. MCP conventions, build, seed data, acceptance criteria.
12
-
13
- ---
14
-
15
- ## 1. MCP Convention Validation
16
-
17
- ```
18
- Call: mcp__smartstack__validate_conventions
19
-
20
- Expected: 0 errors
21
- If errors found:
22
- → Fix each error (use appropriate skill/MCP)
23
- → Re-validate until 0 errors
24
- ```
25
-
26
- ---
27
-
28
- ## 2. EF Core Migration Check (if needs_migration)
29
-
30
- ```
31
- Call: mcp__smartstack__check_migrations
32
-
33
- Verify:
34
- - Migration exists and is applied
35
- - No pending model changes
36
- - ModelSnapshot matches
37
- ```
38
-
39
- ---
40
-
41
- ## 3. Frontend Route Validation (if frontend modified)
42
-
43
- ```
44
- Call: mcp__smartstack__validate_frontend_routes
45
-
46
- Verify:
47
- - Routes nested inside correct Layout wrapper
48
- - Route paths match controller patterns
49
- - No orphan routes
50
- ```
51
-
52
- ---
53
-
54
- ## 4. Build Verification
55
-
56
- ```bash
57
- # Cleanup corrupted EF Core design-time artifacts (Roslyn BuildHost bug on Windows)
58
- for d in src/*/bin?Debug; do [ -d "$d" ] && echo "Removing corrupted artifact: $d" && rm -rf "$d"; done
59
-
60
- # Backend
61
- dotnet clean && dotnet restore && dotnet build
62
-
63
- # Frontend (if applicable)
64
- npm run typecheck
65
- ```
66
-
67
- **BLOCKING:** Both must pass. If failure, fix and retry.
68
-
69
- ---
70
-
71
- ## 5. Database & Migration Validation (if needs_migration)
72
-
73
- ### 5a. Pending Model Changes Check
74
-
75
- ```bash
76
- INFRA_PROJECT=$(ls src/*Infrastructure*/*.csproj 2>/dev/null | head -1)
77
- API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
78
-
79
- dotnet ef migrations has-pending-model-changes \
80
- --project "$INFRA_PROJECT" \
81
- --startup-project "$API_PROJECT"
82
- ```
83
-
84
- **BLOCKING** if pending changes detected → migration is missing.
85
-
86
- ### 5b. Migration Application Test (SQL Server LocalDB)
87
-
88
- ```bash
89
- DB_NAME="SmartStack_Apex_Validate_$(date +%s)"
90
- CONN_STRING="Server=(localdb)\\MSSQLLocalDB;Database=$DB_NAME;Integrated Security=true;TrustServerCertificate=true;Connect Timeout=120;"
91
-
92
- dotnet ef database update \
93
- --connection "$CONN_STRING" \
94
- --project "$INFRA_PROJECT" \
95
- --startup-project "$API_PROJECT"
96
- ```
97
-
98
- **BLOCKING** if migration fails on SQL Server. Common issues:
99
- - SQLite-only syntax in migrations (fix: regenerate migration)
100
- - Column type mismatches (fix: update EF configuration)
101
- - Missing foreign key targets (fix: reorder migrations)
102
-
103
- ### 5c. Integration Tests on Real SQL Server
104
-
105
- ```bash
106
- # Integration tests use DatabaseFixture → real SQL Server LocalDB
107
- # This validates: LINQ→SQL, multi-tenant isolation, soft delete, EF configs
108
- INT_TEST_PROJECT=$(ls tests/*Tests.Integration*/*.csproj 2>/dev/null | head -1)
109
- if [ -n "$INT_TEST_PROJECT" ]; then
110
- dotnet test "$INT_TEST_PROJECT" --no-build --verbosity normal
111
- fi
112
- ```
113
-
114
- Tests running against SQL Server catch issues that SQLite misses:
115
- - Case sensitivity in string comparisons
116
- - Date/time function differences
117
- - IDENTITY vs AUTOINCREMENT behavior
118
- - Global query filter translation to T-SQL
119
-
120
- ### 5d. Cleanup
121
-
122
- ```bash
123
- sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN ALTER DATABASE [$DB_NAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$DB_NAME]; END" 2>/dev/null
124
- ```
125
-
126
- ---
127
-
128
- ## 6. Seed Data Completeness Check (if needs_seed_data)
129
-
130
- | File | Checks |
131
- |------|--------|
132
- | NavigationApplicationSeedData | MUST be first, deterministic GUID, 4 lang translations |
133
- | NavigationModuleSeedData | Deterministic GUIDs (SHA256), 4 languages, GetModuleEntry + GetTranslationEntries |
134
- | PermissionsSeedData | MCP generate_permissions used, paths match Permissions.cs, wildcard + CRUD |
135
- | RolesSeedData | Admin=wildcard, Manager=CRU, Contributor=CR, Viewer=R |
136
- | IClientSeedDataProvider | 3 Seed methods, idempotent, factory methods, SaveChanges per group |
137
- | DI Registration | `services.AddScoped<IClientSeedDataProvider, {App}SeedDataProvider>()` |
138
-
139
- ---
140
-
141
- ## 6b. BLOCKING POST-CHECKs (bash verification on real files)
1
+ # BLOCKING POST-CHECKs
142
2
 
3
+ > **Referenced by:** step-04-examine.md (section 6b)
143
4
  > These checks run on the actual generated files. Model-interpreted checks are unreliable.
144
5
 
145
6
  ### POST-CHECK 1: Navigation routes must be full paths starting with /
@@ -210,15 +71,17 @@ if [ -n "$SEED_FILES" ]; then
210
71
  fi
211
72
  ```
212
73
 
213
- ### POST-CHECK 5: Services must inject ICurrentUser
74
+ ### POST-CHECK 5: Services must inject ICurrentTenantService (tenant isolation)
214
75
 
215
76
  ```bash
216
77
  SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
217
78
  if [ -n "$SERVICE_FILES" ]; then
218
79
  for f in $SERVICE_FILES; do
219
- if ! grep -q "ICurrentUser" "$f"; then
220
- echo "BLOCKING: Service missing ICurrentUser injection: $f"
221
- echo "All services MUST inject ICurrentUser for tenant isolation"
80
+ # Accept either ICurrentTenantService or ICurrentUser (legacy) for tenant context
81
+ if ! grep -qE "ICurrentTenantService|ICurrentUser" "$f"; then
82
+ echo "BLOCKING: Service missing tenant context injection: $f"
83
+ echo "All services MUST inject ICurrentTenantService for tenant isolation"
84
+ echo "Pattern: private readonly ICurrentTenantService _currentTenant;"
222
85
  exit 1
223
86
  fi
224
87
  done
@@ -509,81 +372,86 @@ if [ -n "$CREATE_VALIDATORS" ]; then
509
372
  fi
510
373
  ```
511
374
 
512
- **If ANY POST-CHECK fails fix in step-03, re-validate.**
513
-
514
- ---
515
-
516
- ## 7. Acceptance Criteria POST-CHECK
517
-
518
- For each AC inferred in step-01:
519
-
520
- ```
521
- AC1: {criterion} → PASS / FAIL (evidence: {file:line or test})
522
- AC2: {criterion} → PASS / FAIL (evidence: {file:line or test})
523
- ...
524
- ```
525
-
526
- **All ACs must PASS. If any FAIL, go back to step-03 to fix.**
527
-
528
- ---
529
-
530
- ## 8. Validation Summary
375
+ ### POST-CHECK 19: SeedConstants must NOT contain ContextId (pre-seeded by SmartStack core)
531
376
 
377
+ ```bash
378
+ # NavigationContext IDs (business, platform, personal) are pre-seeded by SmartStack core
379
+ # with hardcoded GUIDs. Client code MUST look them up by code at runtime, NEVER generate them.
380
+ SEED_CONST_FILES=$(find src/ -path "*/Seeding/*" -name "SeedConstants.cs" 2>/dev/null)
381
+ SEED_ALL_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
382
+ if [ -n "$SEED_CONST_FILES" ]; then
383
+ BAD_CONTEXT_ID=$(grep -Pn 'ContextId\s*=' $SEED_CONST_FILES 2>/dev/null)
384
+ if [ -n "$BAD_CONTEXT_ID" ]; then
385
+ echo "BLOCKING: SeedConstants must NOT contain a ContextId constant"
386
+ echo "NavigationContext IDs are pre-seeded by SmartStack core with hardcoded GUIDs"
387
+ echo "Fix: Remove ContextId from SeedConstants. In SeedDataProvider, query:"
388
+ echo " var ctx = await db.NavigationContexts.FirstOrDefaultAsync(c => c.Code == \"business\", ct);"
389
+ echo "$BAD_CONTEXT_ID"
390
+ exit 1
391
+ fi
392
+ fi
393
+ if [ -n "$SEED_ALL_FILES" ]; then
394
+ BAD_CTX_GUID=$(grep -Pn 'DeterministicGuid\("nav:(business|platform|personal)"\)' $SEED_ALL_FILES 2>/dev/null)
395
+ if [ -n "$BAD_CTX_GUID" ]; then
396
+ echo "BLOCKING: Deterministic GUID for NavigationContext detected"
397
+ echo "Context IDs (business, platform, personal) are pre-seeded by SmartStack core"
398
+ echo "Fix: Look up context by code at runtime in SeedDataProvider.SeedNavigationAsync()"
399
+ echo "$BAD_CTX_GUID"
400
+ exit 1
401
+ fi
402
+ fi
532
403
  ```
533
- **APEX SmartStack - Validation Complete**
534
-
535
- | Check | Status |
536
- |-------|--------|
537
- | MCP validate_conventions | PASS (0 errors) |
538
- | EF Core migrations | PASS / N/A |
539
- | DB: Migrations apply (SQL Server) | PASS / N/A |
540
- | DB: Integration tests (SQL Server) | PASS / N/A |
541
- | Frontend routes | PASS / N/A |
542
- | dotnet build | PASS |
543
- | npm typecheck | PASS / N/A |
544
- | Seed data | PASS / N/A |
545
- | I18n: 4 languages per namespace | PASS / N/A |
546
- | Lazy loading: no static page imports | PASS / N/A |
547
- | Forms: full pages, zero modals | PASS / N/A |
548
- | Forms: create/edit pages exist | PASS / N/A |
549
- | Forms: test files exist | PASS / N/A |
550
- | FK fields: EntityLookup, no plain text | PASS / N/A |
551
- | APIs: search parameter on GetAll | PASS / N/A |
552
- | CSS variables: no hardcoded colors | PASS / N/A |
553
- | Routes: seed data vs frontend match | PASS / N/A |
554
- | HasQueryFilter: no Guid.Empty pattern | PASS / N/A |
555
- | GetAll: PaginatedResult required | PASS / N/A |
556
- | I18n: required key structure | PASS / N/A |
557
- | Entities: IAuditableEntity + validators | PASS / N/A |
558
- | Acceptance criteria | {X}/{Y} PASS |
559
- ```
560
-
561
- ---
562
-
563
- ## 9. Save Output (if save_mode)
564
-
565
- Write to `{output_dir}/04-validate.md` with validation results.
566
-
567
- ---
568
404
 
569
- ## 10. Route to Next Step
405
+ ### POST-CHECK 20: RolePermission seed data must NOT use deterministic role GUIDs
570
406
 
407
+ ```bash
408
+ # System roles (admin, manager, contributor, viewer) are pre-seeded by SmartStack core.
409
+ # RolePermission mappings MUST look up roles by Code at runtime, NEVER use deterministic GUIDs.
410
+ SEED_ALL_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
411
+ SEED_CONST_FILES=$(find src/ -path "*/Seeding/*" -name "SeedConstants.cs" 2>/dev/null)
412
+ if [ -n "$SEED_ALL_FILES" ]; then
413
+ BAD_ROLE_GUID=$(grep -Pn 'DeterministicGuid\("role:' $SEED_ALL_FILES $SEED_CONST_FILES 2>/dev/null)
414
+ if [ -n "$BAD_ROLE_GUID" ]; then
415
+ echo "BLOCKING: Deterministic GUID for role detected (e.g., DeterministicGuid(\"role:admin\"))"
416
+ echo "System roles are pre-seeded by SmartStack core with their own IDs"
417
+ echo "Fix: In SeedRolePermissionsAsync(), look up roles by Code:"
418
+ echo " var roles = await context.Roles.Where(r => r.IsSystem || r.ApplicationId != null).ToListAsync(ct);"
419
+ echo " var role = roles.FirstOrDefault(r => r.Code == mapping.RoleCode);"
420
+ echo "$BAD_ROLE_GUID"
421
+ exit 1
422
+ fi
423
+ fi
424
+ # Also check for GenerateRoleGuid usage in RolePermission mapping files (not in ApplicationRolesSeedData itself)
425
+ ROLE_PERM_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*RolesSeedData.cs" 2>/dev/null)
426
+ if [ -n "$ROLE_PERM_FILES" ]; then
427
+ BAD_ROLE_REF=$(grep -Pn 'GenerateRoleGuid|GetAdminRoleId|GetManagerRoleId|GetViewerRoleId|GetContributorRoleId' $ROLE_PERM_FILES 2>/dev/null)
428
+ if [ -n "$BAD_ROLE_REF" ]; then
429
+ echo "WARNING: RolesSeedData uses hardcoded role GUID helpers instead of Code-based lookup"
430
+ echo "Fix: Use RoleCode string (e.g., 'admin') and resolve in SeedRolePermissionsAsync()"
431
+ echo "$BAD_ROLE_REF"
432
+ fi
433
+ fi
571
434
  ```
572
- IF examine_mode = true:
573
- → Load steps/step-05-examine.md
574
435
 
575
- ELSE IF test_mode = true:
576
- → Load steps/step-07-tests.md
436
+ ### POST-CHECK 21: Services must NOT use TenantId!.Value (null-forgiving crash pattern)
577
437
 
578
- ELSE IF pr_mode = true:
579
- Create PR and show final summary
580
-
581
- ELSE:
582
- Show final summary and exit
438
+ ```bash
439
+ # The !.Value pattern on Guid? throws InvalidOperationException (500) instead of clean 401
440
+ SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
441
+ if [ -n "$SERVICE_FILES" ]; then
442
+ BAD_PATTERN=$(grep -Pn 'TenantId!\s*\.Value|TenantId!\s*\.ToString|\.TenantId!' $SERVICE_FILES 2>/dev/null)
443
+ if [ -n "$BAD_PATTERN" ]; then
444
+ echo "BLOCKING: Services use TenantId!.Value — causes 500 instead of 401 when tenant context is missing"
445
+ echo "$BAD_PATTERN"
446
+ echo ""
447
+ echo "Fix: Replace with guard clause at the start of every method:"
448
+ echo " var tenantId = _currentTenant.TenantId"
449
+ echo " ?? throw new UnauthorizedAccessException(\"Tenant context is required\");"
450
+ echo ""
451
+ echo "This produces a clean 401 via GlobalExceptionHandlerMiddleware instead of an opaque 500."
452
+ exit 1
453
+ fi
454
+ fi
583
455
  ```
584
456
 
585
- ---
586
-
587
- ## FINAL SUMMARY (if no more steps)
588
-
589
- Display: task, context, files created/modified, validation status, commits count, next steps (git diff, dotnet test, deploy).
457
+ **If ANY POST-CHECK fails → fix in step-03, re-validate.**