@atlashub/smartstack-cli 3.30.0 → 3.32.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/.documentation/installation.html +7 -2
- package/README.md +7 -1
- package/dist/index.js +33 -37
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +547 -97
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/scripts/health-check.sh +2 -1
- package/templates/mcp-scaffolding/controller.cs.hbs +10 -7
- package/templates/mcp-scaffolding/entity-extension.cs.hbs +132 -124
- package/templates/mcp-scaffolding/frontend/api-client.ts.hbs +4 -4
- package/templates/mcp-scaffolding/tests/controller.test.cs.hbs +38 -15
- package/templates/mcp-scaffolding/tests/service.test.cs.hbs +20 -8
- package/templates/skills/apex/SKILL.md +7 -9
- package/templates/skills/apex/_shared.md +9 -2
- package/templates/skills/apex/references/code-generation.md +412 -0
- package/templates/skills/apex/references/post-checks.md +377 -37
- package/templates/skills/apex/references/smartstack-api.md +229 -5
- package/templates/skills/apex/references/smartstack-frontend.md +368 -11
- package/templates/skills/apex/references/smartstack-layers.md +54 -7
- package/templates/skills/apex/steps/step-00-init.md +1 -2
- package/templates/skills/apex/steps/step-01-analyze.md +45 -2
- package/templates/skills/apex/steps/step-02-plan.md +23 -2
- package/templates/skills/apex/steps/step-03-execute.md +195 -5
- package/templates/skills/apex/steps/step-04-examine.md +18 -5
- package/templates/skills/apex/steps/step-05-deep-review.md +9 -11
- package/templates/skills/apex/steps/step-06-resolve.md +5 -9
- package/templates/skills/apex/steps/step-07-tests.md +66 -1
- package/templates/skills/apex/steps/step-08-run-tests.md +12 -3
- package/templates/skills/application/references/provider-template.md +62 -39
- package/templates/skills/application/templates-backend.md +3 -3
- package/templates/skills/application/templates-frontend.md +12 -12
- package/templates/skills/application/templates-seed.md +14 -4
- package/templates/skills/business-analyse/SKILL.md +10 -7
- package/templates/skills/business-analyse/questionnaire/04-data.md +8 -0
- package/templates/skills/business-analyse/references/agent-module-prompt.md +84 -5
- package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +83 -19
- package/templates/skills/business-analyse/references/consolidation-structural-checks.md +6 -2
- package/templates/skills/business-analyse/references/team-orchestration.md +470 -113
- package/templates/skills/business-analyse/references/validation-checklist.md +5 -4
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +44 -0
- package/templates/skills/business-analyse/steps/step-03a2-analysis.md +72 -1
- package/templates/skills/business-analyse/steps/step-03c-compile.md +93 -7
- package/templates/skills/business-analyse/steps/step-03d-validate.md +34 -2
- package/templates/skills/business-analyse/steps/step-04b-analyze.md +40 -0
- package/templates/skills/controller/references/controller-code-templates.md +2 -2
- package/templates/skills/controller/templates.md +12 -12
- package/templates/skills/feature-full/steps/step-01-implementation.md +4 -4
- package/templates/skills/ralph-loop/references/category-rules.md +44 -2
- package/templates/skills/ralph-loop/references/compact-loop.md +37 -0
- package/templates/skills/ralph-loop/references/core-seed-data.md +51 -20
- package/templates/skills/review-code/references/owasp-api-top10.md +1 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
> **Loaded by:** step-02 when multi-module detected (`moduleOrder.length >= 2`)
|
|
4
4
|
> **Purpose:** Delegate module specification to autonomous agents with user review.
|
|
5
5
|
> **Rule:** Single module = NO team. Only create team for 2+ modules.
|
|
6
|
+
> **Execution:** Parallel by dependency layer — all modules in the same layer run simultaneously.
|
|
6
7
|
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -10,51 +11,141 @@
|
|
|
10
11
|
|
|
11
12
|
After step-02 decomposition is complete and client has approved the module structure:
|
|
12
13
|
|
|
14
|
+
### 1a. Clean Up Old Team Data (MANDATORY)
|
|
15
|
+
|
|
16
|
+
Before creating the team, clean up any leftover data from previous sessions to prevent stale task collisions:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Remove leftover task files from previous runs
|
|
20
|
+
rm -f ~/.claude/tasks/ba-{appName}/*.json 2>/dev/null
|
|
21
|
+
# Remove leftover team directory (TeamDelete may leave remnants)
|
|
22
|
+
rm -rf ~/.claude/teams/ba-{appName} 2>/dev/null
|
|
13
23
|
```
|
|
14
|
-
|
|
24
|
+
|
|
25
|
+
> **Why:** If a previous session used the same team name and crashed or was interrupted,
|
|
26
|
+
> leftover task files will be picked up by new agents, causing them to receive stale
|
|
27
|
+
> task_assignment notifications for wrong modules.
|
|
28
|
+
|
|
29
|
+
### 1b. Create Team and Capture Actual Name
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
const result = TeamCreate({ team_name: "ba-{appName}" });
|
|
33
|
+
// CRITICAL: TeamCreate may return a DIFFERENT name than requested!
|
|
34
|
+
// Always use the RETURNED team_name, not the requested one.
|
|
35
|
+
const actualTeamName = result.team_name;
|
|
15
36
|
```
|
|
16
37
|
|
|
17
38
|
Store team context for the session:
|
|
18
39
|
```javascript
|
|
19
40
|
const teamContext = {
|
|
20
|
-
teamName: "ba-{appName}"
|
|
41
|
+
teamName: actualTeamName, // ← RETURNED name, NOT "ba-{appName}"
|
|
21
42
|
moduleOrder: metadata.workflow.moduleOrder,
|
|
22
|
-
dependencyLayers: dependencyGraph.layers
|
|
23
|
-
currentModuleIdx: 0,
|
|
43
|
+
dependencyLayers: dependencyGraph.layers, // ← from step-02 topological sort
|
|
24
44
|
completedModules: [],
|
|
45
|
+
completedLayers: [],
|
|
25
46
|
mode: "propose-review"
|
|
26
47
|
};
|
|
27
48
|
```
|
|
28
49
|
|
|
50
|
+
> **WARNING:** NEVER hardcode `"ba-{appName}"` in subsequent calls.
|
|
51
|
+
> Always use `teamContext.teamName` (the actual name returned by TeamCreate).
|
|
52
|
+
|
|
29
53
|
---
|
|
30
54
|
|
|
31
|
-
## 2. Module Agent Spawn —
|
|
55
|
+
## 2. Module Agent Spawn — Parallel by Dependency Layer
|
|
56
|
+
|
|
57
|
+
Process modules **layer by layer**. Within each layer, spawn ALL agents **simultaneously**.
|
|
32
58
|
|
|
33
|
-
|
|
59
|
+
```
|
|
60
|
+
FOR each layer in dependencyGraph.layers:
|
|
61
|
+
Execute §2a → §2b → §2c → §2d → §2e → §3 → §4
|
|
62
|
+
```
|
|
34
63
|
|
|
35
|
-
### 2a.
|
|
64
|
+
### 2a. Pre-Spawn Cross-Module Analysis
|
|
36
65
|
|
|
37
|
-
|
|
66
|
+
**ALWAYS executed for layers with 2+ modules.** Analyze the module definitions within this layer to identify cross-module touchpoints BEFORE spawning agents.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
IF layer.modules.length >= 2:
|
|
70
|
+
|
|
71
|
+
ULTRATHINK: Analyze module definitions for same-layer interactions:
|
|
72
|
+
|
|
73
|
+
1. Shared entity names
|
|
74
|
+
→ Do any modules reference the same entity? (e.g., both "Products" and "Inventory"
|
|
75
|
+
might reference a "Category" entity)
|
|
76
|
+
|
|
77
|
+
2. Potential FK overlaps
|
|
78
|
+
→ Do any modules anticipate creating entities that others might reference?
|
|
79
|
+
→ E.g., Products creates "Product" entity, Orders references "Product" via FK
|
|
80
|
+
|
|
81
|
+
3. Naming conventions
|
|
82
|
+
→ Will both modules use similar attribute names? (e.g., "Code", "Name", "Status")
|
|
83
|
+
→ Agree on a consistent naming pattern
|
|
84
|
+
|
|
85
|
+
4. Shared lookup data
|
|
86
|
+
→ Do any modules reference common reference tables?
|
|
87
|
+
→ E.g., both use a "Status" enum, a "Country" lookup, a "Currency" type
|
|
88
|
+
|
|
89
|
+
5. Permission path consistency
|
|
90
|
+
→ Verify permission paths won't collide:
|
|
91
|
+
{context}.{app}.{module1}.{entity}.{action}
|
|
92
|
+
{context}.{app}.{module2}.{entity}.{action}
|
|
93
|
+
|
|
94
|
+
Build coordinationNotes for EACH module in the layer:
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**coordinationNotes template** (injected into each agent's prompt):
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
## Same-Layer Coordination Notes
|
|
101
|
+
|
|
102
|
+
You are running IN PARALLEL with: {otherModuleCodes.join(", ")}
|
|
103
|
+
|
|
104
|
+
### Known Touchpoints
|
|
105
|
+
- {otherModule} will define entity "{EntityName}" — if you need to reference it,
|
|
106
|
+
use CROSS_MODULE_QUERY to get the exact attribute structure
|
|
107
|
+
- Naming convention: use {convention} for shared concepts (e.g., "Status" enum values)
|
|
108
|
+
- Shared lookups: {list any common reference data both modules might create}
|
|
109
|
+
|
|
110
|
+
### Your Responsibilities vs Theirs
|
|
111
|
+
- You own: {your entities — list}
|
|
112
|
+
- They own: {their entities — list}
|
|
113
|
+
- Contested/shared: {entities both might create — QUERY before defining}
|
|
114
|
+
|
|
115
|
+
### Cross-Module FK Convention
|
|
116
|
+
When referencing an entity owned by a same-layer module:
|
|
117
|
+
1. Send CROSS_MODULE_QUERY to team lead asking for the entity's attribute structure
|
|
118
|
+
2. WAIT for the answer before defining your FK field
|
|
119
|
+
3. Use the exact entity name and primary key type from the answer
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
> **IF layer has only 1 module:** Skip §2a entirely. No coordination notes needed.
|
|
123
|
+
|
|
124
|
+
### 2b. Prepare Agent Context (per module)
|
|
125
|
+
|
|
126
|
+
For EACH module in the layer, gather the context the agent needs:
|
|
38
127
|
|
|
39
128
|
```
|
|
40
129
|
1. ba-reader.readApplicationContext({feature_id})
|
|
41
130
|
→ Extract: appName, featureId, context, language
|
|
42
131
|
|
|
43
132
|
2. Read module decomposition data from master feature.json:
|
|
44
|
-
→ modules[
|
|
45
|
-
anticipatedSections, dependencies, detailTabs
|
|
133
|
+
→ modules[moduleCode]: code, name, description, featureType, entities,
|
|
134
|
+
anticipatedSections, dependencies, detailTabs, estimatedComplexity, priority
|
|
46
135
|
|
|
47
136
|
3. ba-reader.getCompletedModulesSummary({feature_id})
|
|
48
|
-
→ Compact summary of already-specified modules (max 100 lines)
|
|
137
|
+
→ Compact summary of already-specified modules from COMPLETED LAYERS (max 100 lines)
|
|
49
138
|
→ Includes: entity names, FK relationships, permission paths, shared types
|
|
50
139
|
```
|
|
51
140
|
|
|
52
|
-
###
|
|
141
|
+
### 2c. Spawn ALL Layer Agents Simultaneously
|
|
142
|
+
|
|
143
|
+
**For layers with 1 module** — single spawn (same as standard):
|
|
53
144
|
|
|
54
145
|
```javascript
|
|
55
146
|
Task({
|
|
56
147
|
subagent_type: "general-purpose",
|
|
57
|
-
team_name:
|
|
148
|
+
team_name: teamContext.teamName,
|
|
58
149
|
name: "mod-{moduleCode}",
|
|
59
150
|
model: "opus",
|
|
60
151
|
mode: "bypassPermissions",
|
|
@@ -68,7 +159,10 @@ Task({
|
|
|
68
159
|
anticipatedSections: module.anticipatedSections,
|
|
69
160
|
dependencies: module.dependencies,
|
|
70
161
|
detailTabs: module.detailTabs,
|
|
162
|
+
estimatedComplexity: module.estimatedComplexity,
|
|
163
|
+
priority: module.priority,
|
|
71
164
|
completedModulesSummary,
|
|
165
|
+
coordinationNotes: "", // empty for single-module layer
|
|
72
166
|
language: metadata.language,
|
|
73
167
|
docsDir: "docs/business/{appName}/{moduleCode}/business-analyse/v{version}/"
|
|
74
168
|
}),
|
|
@@ -76,75 +170,220 @@ Task({
|
|
|
76
170
|
});
|
|
77
171
|
```
|
|
78
172
|
|
|
79
|
-
**
|
|
173
|
+
**For layers with 2+ modules** — spawn ALL in a **single message** (parallel):
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
// CRITICAL: All Task() calls MUST be in ONE message for parallel execution.
|
|
177
|
+
// Do NOT await between them — they MUST be sent together.
|
|
178
|
+
|
|
179
|
+
// Agent 1:
|
|
180
|
+
Task({
|
|
181
|
+
subagent_type: "general-purpose",
|
|
182
|
+
team_name: teamContext.teamName,
|
|
183
|
+
name: "mod-{moduleCode1}",
|
|
184
|
+
model: "opus",
|
|
185
|
+
mode: "bypassPermissions",
|
|
186
|
+
prompt: BUILD_PROMPT(references/agent-module-prompt.md, {
|
|
187
|
+
...moduleContext1,
|
|
188
|
+
coordinationNotes: coordinationNotesForModule1, // ← NEW
|
|
189
|
+
}),
|
|
190
|
+
description: "Specify {moduleCode1}"
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Agent 2 (IN SAME MESSAGE):
|
|
194
|
+
Task({
|
|
195
|
+
subagent_type: "general-purpose",
|
|
196
|
+
team_name: teamContext.teamName,
|
|
197
|
+
name: "mod-{moduleCode2}",
|
|
198
|
+
model: "opus",
|
|
199
|
+
mode: "bypassPermissions",
|
|
200
|
+
prompt: BUILD_PROMPT(references/agent-module-prompt.md, {
|
|
201
|
+
...moduleContext2,
|
|
202
|
+
coordinationNotes: coordinationNotesForModule2, // ← NEW
|
|
203
|
+
}),
|
|
204
|
+
description: "Specify {moduleCode2}"
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// ... repeat for all modules in this layer
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**BUILD_PROMPT**: Read `references/agent-module-prompt.md`, replace all `{placeholders}` with actual values (including the new `{coordinationNotes}`), and pass as the `prompt` parameter.
|
|
80
211
|
|
|
81
|
-
###
|
|
212
|
+
### 2d. Track Layer State
|
|
82
213
|
|
|
83
|
-
|
|
84
|
-
- Wait for MODULE_COMPLETE before spawning the next
|
|
85
|
-
- Reason: later modules may reference entities/FKs from earlier modules
|
|
86
|
-
- **Future optimization**: modules in the same dependency layer with no cross-refs COULD run in parallel
|
|
214
|
+
After spawning, initialize layer tracking:
|
|
87
215
|
|
|
88
|
-
|
|
216
|
+
```javascript
|
|
217
|
+
const layerState = {
|
|
218
|
+
layerIndex: L,
|
|
219
|
+
modules: layer.modules, // ["Customers", "Products"]
|
|
220
|
+
pendingProposals: [...layer.modules], // agents not yet PROPOSAL_READY
|
|
221
|
+
receivedProposals: {}, // { moduleCode: proposalSummary }
|
|
222
|
+
approvedModules: [], // modules approved by user
|
|
223
|
+
crossModuleQueries: [], // log of queries handled
|
|
224
|
+
};
|
|
225
|
+
```
|
|
89
226
|
|
|
90
|
-
|
|
227
|
+
### 2e. Wait for Layer Completion — Message Handling Loop
|
|
228
|
+
|
|
229
|
+
After spawning all agents in the layer, the team lead enters a **message handling loop**.
|
|
91
230
|
Messages from teammates are delivered automatically — do NOT poll or re-spawn.
|
|
92
231
|
|
|
93
|
-
|
|
94
|
-
|
|
232
|
+
```
|
|
233
|
+
WHILE layerState.pendingProposals.length > 0:
|
|
234
|
+
|
|
235
|
+
Wait for next message from any agent in this layer.
|
|
236
|
+
|
|
237
|
+
CASE message matches "PROPOSAL_READY:{moduleCode}":
|
|
238
|
+
→ Remove moduleCode from pendingProposals
|
|
239
|
+
→ Store proposal in receivedProposals[moduleCode]
|
|
240
|
+
→ Display: "✓ Module {moduleCode} proposal received ({received}/{total})"
|
|
241
|
+
→ IF pendingProposals is now empty:
|
|
242
|
+
→ All agents in this layer have proposed
|
|
243
|
+
→ Proceed to §3 (Layer Review)
|
|
244
|
+
|
|
245
|
+
CASE message matches "CROSS_MODULE_QUERY:{targetModule}":
|
|
246
|
+
→ Handle per §2-bis (Cross-Module Coordination Protocol)
|
|
247
|
+
|
|
248
|
+
CASE message matches "CROSS_MODULE_ANSWER_RELAY:{requestingModule}":
|
|
249
|
+
→ Forward to requesting agent per §2-bis
|
|
250
|
+
|
|
251
|
+
CASE message matches "ERROR:{moduleCode}:{description}":
|
|
252
|
+
→ Handle per §8 (Error Recovery)
|
|
253
|
+
→ Remove from pendingProposals if module is skipped
|
|
254
|
+
→ IF pendingProposals is now empty → proceed to §3
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
> **This loop may take several minutes** as agents work autonomously.
|
|
258
|
+
> The team lead does nothing except handle cross-module queries during this time.
|
|
95
259
|
|
|
96
260
|
---
|
|
97
261
|
|
|
98
|
-
##
|
|
262
|
+
## 2-bis. Cross-Module Coordination Protocol (Runtime Relay)
|
|
99
263
|
|
|
100
|
-
|
|
264
|
+
When an agent sends `CROSS_MODULE_QUERY:{targetModule}`, the team lead routes the query based on the target module's state:
|
|
101
265
|
|
|
102
|
-
|
|
266
|
+
### Case 1: Target is in a COMPLETED layer
|
|
267
|
+
|
|
268
|
+
The target module's specification is already written to feature.json.
|
|
103
269
|
|
|
104
270
|
```
|
|
105
|
-
|
|
271
|
+
→ Read target module's entities/attributes from completedModulesSummary
|
|
272
|
+
→ Send answer directly to requesting agent:
|
|
106
273
|
|
|
107
|
-
|
|
274
|
+
SendMessage({
|
|
275
|
+
type: "message",
|
|
276
|
+
recipient: "mod-{requestingModule}",
|
|
277
|
+
content: "CROSS_MODULE_ANSWER:{requestingModule}\nAnswer: {entity structure from completed module data}",
|
|
278
|
+
summary: "Answer from completed {targetModule}"
|
|
279
|
+
})
|
|
280
|
+
```
|
|
108
281
|
|
|
109
|
-
###
|
|
110
|
-
| Entity | Attributes | Relationships |
|
|
111
|
-
|--------|-----------|---------------|
|
|
112
|
-
| ... | ... | ... |
|
|
282
|
+
### Case 2: Target is in CURRENT layer AND has sent PROPOSAL_READY
|
|
113
283
|
|
|
114
|
-
|
|
115
|
-
| Section | Description | Resources |
|
|
116
|
-
|---------|-------------|-----------|
|
|
117
|
-
| ... | ... | ... |
|
|
284
|
+
The target agent has finished its proposal — we have its specification data.
|
|
118
285
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- ...
|
|
286
|
+
```
|
|
287
|
+
→ Extract relevant entity/attribute info from receivedProposals[targetModule]
|
|
288
|
+
→ Send answer directly to requesting agent:
|
|
123
289
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-
|
|
290
|
+
SendMessage({
|
|
291
|
+
type: "message",
|
|
292
|
+
recipient: "mod-{requestingModule}",
|
|
293
|
+
content: "CROSS_MODULE_ANSWER:{requestingModule}\nAnswer: {entity structure from proposal data}",
|
|
294
|
+
summary: "Answer from {targetModule} proposal"
|
|
295
|
+
})
|
|
296
|
+
```
|
|
127
297
|
|
|
128
|
-
###
|
|
129
|
-
- {context}.{app}.{module}.{action}
|
|
130
|
-
- ...
|
|
298
|
+
### Case 3: Target is in CURRENT layer AND still working (no PROPOSAL_READY yet)
|
|
131
299
|
|
|
132
|
-
|
|
133
|
-
- Modules: {count} | Sections: {count} | Resources: {count}
|
|
134
|
-
- Translations: {count} | Permissions: {count} | Role mappings: {count}
|
|
300
|
+
The target agent is still specifying — relay the question.
|
|
135
301
|
|
|
136
|
-
### Wireframes
|
|
137
|
-
- {section}: {1-line description}
|
|
138
|
-
- ...
|
|
139
302
|
```
|
|
303
|
+
→ Forward question to target agent:
|
|
140
304
|
|
|
141
|
-
|
|
305
|
+
SendMessage({
|
|
306
|
+
type: "message",
|
|
307
|
+
recipient: "mod-{targetModule}",
|
|
308
|
+
content: "CROSS_MODULE_QUERY_RELAY:{requestingModule}\nQuestion: {original question}",
|
|
309
|
+
summary: "Relay query from {requestingModule}"
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
→ Wait for target agent to respond with CROSS_MODULE_ANSWER_RELAY
|
|
313
|
+
→ Forward answer to requesting agent:
|
|
314
|
+
|
|
315
|
+
SendMessage({
|
|
316
|
+
type: "message",
|
|
317
|
+
recipient: "mod-{requestingModule}",
|
|
318
|
+
content: "CROSS_MODULE_ANSWER:{requestingModule}\nAnswer: {answer from target agent}",
|
|
319
|
+
summary: "Answer from {targetModule}"
|
|
320
|
+
})
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Case 4: Circular query (A asks about B, B asks about A simultaneously)
|
|
324
|
+
|
|
325
|
+
Both agents are blocked waiting for each other. The team lead MUST resolve this autonomously.
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
→ ULTRATHINK: Based on SmartStack conventions and module descriptions,
|
|
329
|
+
make a consistent design decision for BOTH modules.
|
|
330
|
+
→ Send CROSS_MODULE_ANSWER to BOTH agents with compatible entity structures.
|
|
331
|
+
→ Log resolution in layerState.crossModuleQueries[] for later review.
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
> **Every cross-module query is logged** in `layerState.crossModuleQueries[]` for display during §3 review.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 3. Layer Review — Quality-First Protocol
|
|
339
|
+
|
|
340
|
+
When ALL agents in a layer have sent PROPOSAL_READY, the team lead presents the results to the user.
|
|
341
|
+
|
|
342
|
+
### 3a. Cross-Module Interaction Analysis (layers with 2+ modules)
|
|
343
|
+
|
|
344
|
+
**ALWAYS displayed FIRST** for multi-module layers. This gives the user a bird's-eye view of how modules in this layer interact.
|
|
345
|
+
|
|
346
|
+
```
|
|
347
|
+
═══════════════════════════════════════════════════════════
|
|
348
|
+
Layer {L} — {N} modules terminés — Analyse croisée
|
|
349
|
+
═══════════════════════════════════════════════════════════
|
|
350
|
+
|
|
351
|
+
### Interactions cross-module détectées
|
|
352
|
+
|
|
353
|
+
| Module A | Module B | Type | Détail |
|
|
354
|
+
|----------|----------|------|--------|
|
|
355
|
+
| {mod1} | {mod2} | FK | {mod1}.{entity}.{field} → {mod2}.{entity} |
|
|
356
|
+
| {mod1} | {mod2} | Concept partagé | Les deux définissent "{concept}" |
|
|
357
|
+
| {mod1} | {mod2} | Lookup | {mod1} référence {mod2}.{entity} comme donnée de ref |
|
|
358
|
+
|
|
359
|
+
### Requêtes cross-module résolues pendant la spécification ({count})
|
|
360
|
+
{FOR each query in layerState.crossModuleQueries:}
|
|
361
|
+
- {requestingModule} → {targetModule}: {question summary} → {answer summary}
|
|
362
|
+
|
|
363
|
+
### Points d'attention
|
|
364
|
+
- {naming inconsistencies detected between module proposals}
|
|
365
|
+
- {potential permission path conflicts}
|
|
366
|
+
- {shared entity definition differences}
|
|
367
|
+
|
|
368
|
+
─────────────────────────────────────────────────────────
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
> **For single-module layers:** Skip §3a entirely — no cross-module analysis needed.
|
|
372
|
+
|
|
373
|
+
### 3b. Individual Module Review (ALWAYS — for quality)
|
|
374
|
+
|
|
375
|
+
Review each module's proposal individually. For multi-module layers, the user has already seen the cross-module context from §3a.
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
FOR each module in layer (respecting topologicalOrder within layer):
|
|
379
|
+
```
|
|
142
380
|
|
|
143
381
|
**Step 1:** Format and display the proposal:
|
|
144
382
|
|
|
145
383
|
```
|
|
146
384
|
═══════════════════════════════════════════════════════════
|
|
147
|
-
Proposition pour le module {moduleCode}
|
|
385
|
+
Proposition pour le module {moduleCode}
|
|
386
|
+
(Layer {L} — module {idx+1}/{layerTotal} — global {globalIdx+1}/{totalModules})
|
|
148
387
|
═══════════════════════════════════════════════════════════
|
|
149
388
|
|
|
150
389
|
{structured summary from agent — displayed as-is}
|
|
@@ -155,11 +394,11 @@ PROPOSAL_READY:{moduleCode}
|
|
|
155
394
|
**Step 2:** Ask the user via AskUserQuestion:
|
|
156
395
|
|
|
157
396
|
```
|
|
158
|
-
Validez-vous cette
|
|
397
|
+
Validez-vous cette spécification ?
|
|
159
398
|
Options:
|
|
160
399
|
1. "Valider" → approve as-is
|
|
161
400
|
2. "Modifier" → provide feedback for revision
|
|
162
|
-
3. "Voir
|
|
401
|
+
3. "Voir détail" → team lead reads module feature.json and displays full content
|
|
163
402
|
```
|
|
164
403
|
|
|
165
404
|
**Step 3 — IMMEDIATELY after AskUserQuestion returns, handle the response:**
|
|
@@ -174,7 +413,9 @@ SendMessage({
|
|
|
174
413
|
})
|
|
175
414
|
```
|
|
176
415
|
→ CRITICAL: You MUST send this message. Do NOT skip this step.
|
|
177
|
-
→ Then WAIT for the agent to send `MODULE_COMPLETE:{moduleCode}
|
|
416
|
+
→ Then WAIT for the agent to send `MODULE_COMPLETE:{moduleCode}`.
|
|
417
|
+
→ Add moduleCode to `layerState.approvedModules`.
|
|
418
|
+
→ Continue to next module in this layer.
|
|
178
419
|
|
|
179
420
|
**IF user selected "Modifier" (revision):**
|
|
180
421
|
→ Ask user for specific feedback via AskUserQuestion
|
|
@@ -187,9 +428,10 @@ SendMessage({
|
|
|
187
428
|
summary: "{moduleCode} revision requested"
|
|
188
429
|
})
|
|
189
430
|
```
|
|
190
|
-
→ Then WAIT for the agent to send a new `PROPOSAL_READY` →
|
|
431
|
+
→ Then WAIT for the agent to send a new `PROPOSAL_READY` → re-display this module's proposal.
|
|
432
|
+
→ Other modules in the layer are NOT blocked — their proposals remain in receivedProposals.
|
|
191
433
|
|
|
192
|
-
**IF user selected "Voir
|
|
434
|
+
**IF user selected "Voir détail":**
|
|
193
435
|
→ Read module feature.json via ba-reader.readSection({feature_id, section})
|
|
194
436
|
→ Display relevant sections in detail
|
|
195
437
|
→ Go back to Step 2 (re-ask the validation question)
|
|
@@ -198,58 +440,120 @@ SendMessage({
|
|
|
198
440
|
|
|
199
441
|
- Max **3 revision cycles** per module
|
|
200
442
|
- After 3 rejections: team lead asks user if they want to switch to **inline interactive mode** for this module
|
|
201
|
-
- If yes: team lead loads step-03a1-setup.md and executes interactively
|
|
443
|
+
- If yes: shutdown agent, team lead loads step-03a1-setup.md and executes interactively
|
|
202
444
|
- If no: mark module as "needs-review" and continue to next module
|
|
203
445
|
|
|
446
|
+
### 3d. Layer Consistency Check (layers with 2+ modules)
|
|
447
|
+
|
|
448
|
+
After ALL modules in a layer are approved, perform a final cross-module consistency verification:
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
IF layer.modules.length >= 2 AND all modules approved:
|
|
452
|
+
|
|
453
|
+
ULTRATHINK: Verify cross-module consistency:
|
|
454
|
+
|
|
455
|
+
1. FK references: Do FK field names match actual entity names across modules?
|
|
456
|
+
→ e.g., if Products.CategoryId references Categories.Category, names must match
|
|
457
|
+
|
|
458
|
+
2. Permission paths: Are paths consistent and non-colliding?
|
|
459
|
+
→ business.{app}.{module1}.{entity}.read vs business.{app}.{module2}.{entity}.read
|
|
460
|
+
|
|
461
|
+
3. i18n keys: Do keys follow consistent patterns? No collisions?
|
|
462
|
+
→ {module1}.labels.name vs {module2}.labels.name (OK — namespaced)
|
|
463
|
+
|
|
464
|
+
4. Seed data IDs: Are deterministic GUIDs unique across modules?
|
|
465
|
+
→ Check DeterministicGuid inputs don't collide
|
|
466
|
+
|
|
467
|
+
5. Entity attribute types: Are shared concepts typed consistently?
|
|
468
|
+
→ If both modules define "Status", is it the same enum type?
|
|
469
|
+
|
|
470
|
+
IF inconsistency found:
|
|
471
|
+
Display warning with specific issue:
|
|
472
|
+
"⚠ Incohérence détectée entre {mod1} et {mod2}: {description}"
|
|
473
|
+
|
|
474
|
+
AskUserQuestion:
|
|
475
|
+
question: "Corriger automatiquement cette incohérence ?"
|
|
476
|
+
options:
|
|
477
|
+
1. "Corriger" → send REVISION to affected agent(s) with fix instructions
|
|
478
|
+
2. "Ignorer" → proceed (will be caught in consolidation)
|
|
479
|
+
|
|
480
|
+
IF "Corriger":
|
|
481
|
+
→ Send REVISION:{moduleCode}\n{auto-fix instructions} to affected agent
|
|
482
|
+
→ Wait for new PROPOSAL_READY
|
|
483
|
+
→ Re-approve (no full re-review needed — only the fix)
|
|
484
|
+
|
|
485
|
+
IF no inconsistency found:
|
|
486
|
+
Display: "✓ Cohérence cross-module vérifiée pour le layer {L}"
|
|
487
|
+
```
|
|
488
|
+
|
|
204
489
|
---
|
|
205
490
|
|
|
206
|
-
## 4.
|
|
491
|
+
## 4. Layer Completion & Agent Shutdown
|
|
492
|
+
|
|
493
|
+
After ALL modules in a layer are approved AND consistency check passed:
|
|
494
|
+
|
|
495
|
+
### 4a. Shutdown ALL Layer Agents (MANDATORY — do NOT skip)
|
|
496
|
+
|
|
497
|
+
**IMMEDIATELY** after layer is fully approved, send shutdown_request to ALL agents in this layer:
|
|
498
|
+
|
|
499
|
+
```javascript
|
|
500
|
+
// Send shutdown to ALL layer agents
|
|
501
|
+
FOR each moduleCode in layer.modules:
|
|
502
|
+
SendMessage({
|
|
503
|
+
type: "shutdown_request",
|
|
504
|
+
recipient: "mod-{moduleCode}",
|
|
505
|
+
content: "Layer complete, shutting down"
|
|
506
|
+
})
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Wait for ALL agents to confirm shutdown (`shutdown_response approve: true`).
|
|
207
510
|
|
|
208
|
-
|
|
511
|
+
> **WARNING:** If you skip this step, agents will remain running indefinitely.
|
|
512
|
+
> Agents CANNOT self-terminate — they NEED shutdown_request from you.
|
|
209
513
|
|
|
210
|
-
###
|
|
514
|
+
### 4b. Update Layer Tracking
|
|
211
515
|
|
|
212
516
|
```javascript
|
|
213
|
-
|
|
214
|
-
teamContext.
|
|
517
|
+
FOR each moduleCode in layer.modules:
|
|
518
|
+
teamContext.completedModules.push(moduleCode);
|
|
519
|
+
ba-writer.updateModuleStatus({feature_id, moduleCode, status: "specified"});
|
|
215
520
|
|
|
216
|
-
|
|
217
|
-
ba-writer.updateModuleStatus({feature_id, moduleCode, status: "specified"});
|
|
521
|
+
teamContext.completedLayers.push(layerState.layerIndex);
|
|
218
522
|
|
|
219
|
-
Display:
|
|
523
|
+
Display:
|
|
524
|
+
"═══ Layer {L} complete — {layer.modules.length} modules specified ═══"
|
|
525
|
+
"═══ Progress: {completedModules.length}/{moduleOrder.length} modules ═══"
|
|
220
526
|
```
|
|
221
527
|
|
|
222
|
-
###
|
|
528
|
+
### 4c. Build Updated Context for Next Layer
|
|
223
529
|
|
|
224
|
-
|
|
530
|
+
Before spawning the next layer's agents, rebuild the `completedModulesSummary`:
|
|
225
531
|
|
|
226
532
|
```
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
})
|
|
533
|
+
ba-reader.getCompletedModulesSummary({feature_id})
|
|
534
|
+
→ Now includes ALL modules from completed layers
|
|
535
|
+
→ This summary is injected into next layer's agent prompts
|
|
536
|
+
→ Agents in the next layer will have full context of everything specified so far
|
|
232
537
|
```
|
|
233
538
|
|
|
234
|
-
|
|
235
|
-
**Wait for the agent to confirm shutdown** before spawning the next agent.
|
|
539
|
+
### 4d. Next Layer or Consolidation
|
|
236
540
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
### 4c. Next Module or Consolidation
|
|
541
|
+
```
|
|
542
|
+
IF more layers remain in dependencyGraph.layers:
|
|
543
|
+
→ Go back to §2 for the next layer
|
|
241
544
|
|
|
242
|
-
|
|
243
|
-
|
|
545
|
+
IF all layers complete (all modules specified):
|
|
546
|
+
→ Proceed to §5 (Consolidation)
|
|
547
|
+
```
|
|
244
548
|
|
|
245
549
|
---
|
|
246
550
|
|
|
247
551
|
## 5. Consolidation Phase
|
|
248
552
|
|
|
249
|
-
After ALL modules are specified:
|
|
553
|
+
After ALL modules are specified (all layers complete):
|
|
250
554
|
|
|
251
555
|
```
|
|
252
|
-
Display: "═══ All modules specified — Starting consolidation ═══"
|
|
556
|
+
Display: "═══ All {moduleOrder.length} modules specified — Starting consolidation ═══"
|
|
253
557
|
```
|
|
254
558
|
|
|
255
559
|
### 5a. Spawn Consolidation Agent
|
|
@@ -257,7 +561,7 @@ Display: "═══ All modules specified — Starting consolidation ═══"
|
|
|
257
561
|
```javascript
|
|
258
562
|
Task({
|
|
259
563
|
subagent_type: "general-purpose",
|
|
260
|
-
team_name:
|
|
564
|
+
team_name: teamContext.teamName, // ← ACTUAL name from TeamCreate result
|
|
261
565
|
name: "consolidation",
|
|
262
566
|
model: "opus",
|
|
263
567
|
mode: "bypassPermissions",
|
|
@@ -272,6 +576,7 @@ Execute cross-module consolidation (steps 04a + 04b):
|
|
|
272
576
|
## Context
|
|
273
577
|
- Feature ID: {featureId}
|
|
274
578
|
- Modules: {moduleOrder.join(", ")}
|
|
579
|
+
- Dependency layers: {JSON.stringify(dependencyGraph.layers)}
|
|
275
580
|
- All modules have status "specified"
|
|
276
581
|
|
|
277
582
|
## Output
|
|
@@ -305,7 +610,7 @@ When CONSOLIDATION_READY received:
|
|
|
305
610
|
|
|
306
611
|
AskUserQuestion: "Approuvez-vous la consolidation ?"
|
|
307
612
|
- "Approuver" → send APPROVED to agent → agent writes consolidation to master feature.json
|
|
308
|
-
- "
|
|
613
|
+
- "Réviser" → send feedback → agent adjusts
|
|
309
614
|
|
|
310
615
|
After approval → shutdown consolidation agent → proceed to §6.
|
|
311
616
|
|
|
@@ -316,7 +621,7 @@ After approval → shutdown consolidation agent → proceed to §6.
|
|
|
316
621
|
```javascript
|
|
317
622
|
Task({
|
|
318
623
|
subagent_type: "general-purpose",
|
|
319
|
-
team_name:
|
|
624
|
+
team_name: teamContext.teamName, // ← ACTUAL name from TeamCreate result
|
|
320
625
|
name: "handoff",
|
|
321
626
|
model: "sonnet",
|
|
322
627
|
mode: "bypassPermissions",
|
|
@@ -370,7 +675,7 @@ After handoff complete:
|
|
|
370
675
|
|
|
371
676
|
```javascript
|
|
372
677
|
// Safety net: shutdown ALL remaining agents (module agents + consolidation + handoff)
|
|
373
|
-
// Module agents should already be shut down in §
|
|
678
|
+
// Module agents should already be shut down in §4a, but this catches any missed ones.
|
|
374
679
|
const allAgents = [
|
|
375
680
|
...teamContext.moduleOrder.map(m => `mod-${m}`),
|
|
376
681
|
"consolidation",
|
|
@@ -399,28 +704,32 @@ Display: "═══ Business-analyse complete — Team cleaned up ═══"
|
|
|
399
704
|
|
|
400
705
|
## 8. Error Recovery
|
|
401
706
|
|
|
402
|
-
### Agent Crash
|
|
707
|
+
### Agent Crash in Parallel Layer
|
|
403
708
|
|
|
404
|
-
If an agent stops responding or sends ERROR:
|
|
709
|
+
If an agent stops responding or sends ERROR while other agents in the same layer are still working:
|
|
405
710
|
|
|
406
711
|
```javascript
|
|
407
|
-
// 1.
|
|
712
|
+
// 1. Do NOT disrupt other agents in the layer — they continue working
|
|
713
|
+
// 2. Check module status in feature.json
|
|
408
714
|
const moduleStatus = ba-reader.getModuleStatus({feature_id});
|
|
409
715
|
|
|
410
|
-
//
|
|
411
|
-
// → Spawn new agent for same module
|
|
716
|
+
// 3. If module has partial data (status = "in-progress"):
|
|
717
|
+
// → Spawn new agent for same module (joins existing layer)
|
|
412
718
|
// → New agent detects partial state and continues
|
|
413
719
|
// → Include in prompt: "Resume specification — partial data exists in feature.json"
|
|
414
720
|
|
|
415
|
-
//
|
|
721
|
+
// 4. Track retry count per module
|
|
416
722
|
if (retryCount[moduleCode] >= 3) {
|
|
417
723
|
Display: "Agent failed 3 times for module {moduleCode}."
|
|
418
724
|
AskUserQuestion: "Fallback to inline interactive mode for this module?"
|
|
419
|
-
// If yes:
|
|
725
|
+
// If yes: remove from pendingProposals, will handle inline after layer completes
|
|
420
726
|
// If no: skip module, mark as "needs-review"
|
|
421
727
|
}
|
|
422
728
|
```
|
|
423
729
|
|
|
730
|
+
> **Key difference from sequential mode:** Other agents in the layer keep running.
|
|
731
|
+
> The crashed module is retried independently without blocking the layer.
|
|
732
|
+
|
|
424
733
|
### Context Exhaustion on Team Lead
|
|
425
734
|
|
|
426
735
|
The team lead should stay under 30% context usage. If approaching limits:
|
|
@@ -436,8 +745,13 @@ If the entire session crashes:
|
|
|
436
745
|
1. User restarts `/business-analyse`
|
|
437
746
|
2. Step-00 detects existing feature.json with `status: "decomposed"` or partial modules
|
|
438
747
|
3. Reads `metadata.workflow.completedModules` to know which modules are done
|
|
439
|
-
4.
|
|
440
|
-
|
|
748
|
+
4. Determines which layer to resume from:
|
|
749
|
+
- Find the first layer where not all modules are in `completedModules`
|
|
750
|
+
- Modules already completed in that layer are skipped
|
|
751
|
+
5. **Cleans up old team/task data** (§1a cleanup step) before creating new team
|
|
752
|
+
6. Creates new team (§1b — captures actual team name)
|
|
753
|
+
7. Spawns agents ONLY for incomplete modules in the current layer
|
|
754
|
+
8. Continues normally (parallel within layer, sequential between layers)
|
|
441
755
|
|
|
442
756
|
---
|
|
443
757
|
|
|
@@ -447,25 +761,68 @@ If the entire session crashes:
|
|
|
447
761
|
|-----------|--------|
|
|
448
762
|
| 1 module | NO team, classic inline execution |
|
|
449
763
|
| 2+ modules | Team mode (Propose & Review) |
|
|
450
|
-
| Modules in same dependency layer
|
|
451
|
-
| Modules
|
|
452
|
-
|
|
|
764
|
+
| Modules in same dependency layer | Spawn ALL in parallel (single message) |
|
|
765
|
+
| Modules in different layers | Sequential — complete layer N before spawning layer N+1 |
|
|
766
|
+
| Layer with 1 module | Standard single-agent propose-review |
|
|
767
|
+
| Layer with 2+ modules | Pre-inject coordination notes + parallel spawn + batch review |
|
|
768
|
+
| Cross-module query (completed layer) | Answer from completedModulesSummary |
|
|
769
|
+
| Cross-module query (same layer, proposed) | Answer from receivedProposals |
|
|
770
|
+
| Cross-module query (same layer, working) | Relay to target agent |
|
|
771
|
+
| Circular cross-query (A↔B) | Team lead resolves autonomously |
|
|
772
|
+
| Agent error in parallel layer | Other agents continue; retry crashed module |
|
|
453
773
|
| User rejects 3 times | Offer fallback to inline interactive |
|
|
774
|
+
| Layer consistency check fails | Auto-fix via targeted REVISION |
|
|
454
775
|
| Context > 50% on team lead | Minimize presentation, suggest auto-approve |
|
|
455
|
-
| Session crash | Resume from feature.json
|
|
776
|
+
| Session crash | Resume from feature.json + completedModules state |
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## Message Protocol Summary
|
|
781
|
+
|
|
782
|
+
### Standard Messages (unchanged)
|
|
783
|
+
|
|
784
|
+
| Message | Direction | Purpose |
|
|
785
|
+
|---------|-----------|---------|
|
|
786
|
+
| `PROPOSAL_READY:{moduleCode}\n{summary}` | agent → lead | Specification complete |
|
|
787
|
+
| `APPROVED:{moduleCode}` | lead → agent | User approved |
|
|
788
|
+
| `REVISION:{moduleCode}\n{feedback}` | lead → agent | User wants changes |
|
|
789
|
+
| `MODULE_COMPLETE:{moduleCode}` | agent → lead | After approval confirmed |
|
|
790
|
+
| `CONSOLIDATION_READY:{appName}\n{report}` | agent → lead | Consolidation done |
|
|
791
|
+
| `HANDOFF_READY:{appName}\n{report}` | agent → lead | Handoff done |
|
|
792
|
+
| `ERROR:{moduleCode}:{description}` | agent → lead | Blocking error |
|
|
793
|
+
| `shutdown_request` / `shutdown_response` | lead ↔ agent | Termination |
|
|
794
|
+
|
|
795
|
+
### Cross-Module Messages (NEW — for parallel execution)
|
|
796
|
+
|
|
797
|
+
| Message | Direction | Purpose |
|
|
798
|
+
|---------|-----------|---------|
|
|
799
|
+
| `CROSS_MODULE_QUERY:{targetModule}\nQuestion:{q}\nContext:{ctx}` | agent → lead | Ask about same-layer module |
|
|
800
|
+
| `CROSS_MODULE_ANSWER:{requestingModule}\nAnswer:{a}` | lead → agent | Response to query |
|
|
801
|
+
| `CROSS_MODULE_QUERY_RELAY:{requestingModule}\nQuestion:{q}` | lead → target agent | Relay query to working agent |
|
|
802
|
+
| `CROSS_MODULE_ANSWER_RELAY:{requestingModule}\nAnswer:{a}` | target agent → lead | Response to relayed query |
|
|
456
803
|
|
|
457
804
|
---
|
|
458
805
|
|
|
459
806
|
## Token Budget Estimates
|
|
460
807
|
|
|
461
|
-
| Phase | Agent |
|
|
462
|
-
|
|
463
|
-
| Init + Cadrage + Decomposition | Team lead (inline) | 20-30% |
|
|
464
|
-
|
|
|
465
|
-
|
|
|
466
|
-
|
|
|
467
|
-
|
|
|
468
|
-
|
|
|
469
|
-
|
|
|
470
|
-
|
|
471
|
-
**
|
|
808
|
+
| Phase | Agent | Est. Context % | Notes |
|
|
809
|
+
|-------|-------|---------------|-------|
|
|
810
|
+
| Init + Cadrage + Decomposition | Team lead (inline) | 20-30% | Sequential, interactive |
|
|
811
|
+
| Pre-spawn analysis (per layer) | Team lead | +1-3% per layer | Cross-module touchpoint detection |
|
|
812
|
+
| Module specification (per module) | mod-{code} agent | 40-60% | Parallel within layer, fresh context |
|
|
813
|
+
| Cross-module relay (per query) | Team lead | +1-2% per query | Lightweight relay |
|
|
814
|
+
| Layer review (per layer) | Team lead | +3-5% per layer | Proposals + consistency check |
|
|
815
|
+
| Consolidation | consolidation agent | 30-40% | Cross-module validation |
|
|
816
|
+
| Handoff | handoff agent | 40-50% | Artifact generation |
|
|
817
|
+
| **Total team lead** | — | **30-50%** | Same budget, more throughput |
|
|
818
|
+
| **Total per module agent** | — | **40-60%** | Independent contexts |
|
|
819
|
+
|
|
820
|
+
**Key insight:** Team lead never exceeds 50% even with 10+ modules, because:
|
|
821
|
+
- Module specifications happen in separate parallel contexts
|
|
822
|
+
- Cross-module relay is lightweight (forward message, not re-analyze)
|
|
823
|
+
- Layer reviews are incremental (only current layer proposals)
|
|
824
|
+
|
|
825
|
+
**Wall-clock time improvement:**
|
|
826
|
+
- Layer with 3 independent modules: 1x (parallel) vs 3x (sequential) = **66% reduction**
|
|
827
|
+
- Typical 4-module app (2 layers of 2): ~50% wall-clock reduction
|
|
828
|
+
- Full benefit: apps with many independent foundation modules (layer 0)
|