@llm-dev-ops/agentics-cli 1.6.5 → 1.6.7

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.
@@ -133,144 +133,201 @@ function extractSuccessProbability(simData) {
133
133
  // Enterprise projects always carry residual risk, and showing 100% destroys credibility.
134
134
  return Math.min(prob, 0.88);
135
135
  }
136
+ function extractFinancials(simData, platformResults) {
137
+ const fm = (safeGet(simData, 'financial_model') ?? safeGet(simData, 'cost_model') ?? safeGet(simData, 'financials'));
138
+ const roiAgent = extractAgentData(platformResults, 'costops', 'roi');
139
+ const forecastAgent = extractAgentData(platformResults, 'costops', 'forecast');
140
+ const budget = safeString(simData, 'budget') || safeString(simData, 'investment') || safeString(simData, 'total_investment') || (fm ? safeString(fm, 'budget') || safeString(fm, 'total_investment') : '') || (roiAgent ? safeString(roiAgent, 'total_cost') || safeString(roiAgent, 'estimated_cost') : '');
141
+ const roi = safeString(simData, 'roi') || safeString(simData, 'expected_roi') || (fm ? safeString(fm, 'roi') : '') || (roiAgent ? safeString(roiAgent, 'roi') || safeString(roiAgent, 'expected_roi') : '');
142
+ const npv = safeString(simData, 'npv') || safeString(simData, 'net_present_value') || (fm ? safeString(fm, 'npv') || safeString(fm, 'net_present_value') : '') || (forecastAgent ? safeString(forecastAgent, 'npv') : '');
143
+ const payback = safeString(simData, 'payback_period') || safeString(simData, 'payback') || safeString(simData, 'roi_timeline') || (fm ? safeString(fm, 'payback_period') || safeString(fm, 'payback') : '') || (roiAgent ? safeString(roiAgent, 'payback_period') || safeString(roiAgent, 'payback') : '');
144
+ const revenue = safeString(simData, 'projected_revenue') || safeString(simData, 'revenue_impact') || safeString(simData, 'annual_value') || (fm ? safeString(fm, 'projected_revenue') : '');
145
+ const costSavings = safeString(simData, 'cost_savings') || safeString(simData, 'cost_reduction') || safeString(simData, 'savings') || (fm ? safeString(fm, 'cost_savings') : '');
146
+ return { budget, roi, npv, payback, revenue, costSavings, hasData: !!(budget || roi || npv || payback || revenue || costSavings) };
147
+ }
148
+ /**
149
+ * ADR-PIPELINE-024: Generate domain-appropriate risks from query context.
150
+ * Every enterprise project has risks. Never return an empty list.
151
+ */
152
+ function generateDomainRisks(query, extracted) {
153
+ const risks = [];
154
+ const q = query.toLowerCase();
155
+ const systems = extracted.systems;
156
+ const primarySystem = systems[0] ?? 'enterprise platform';
157
+ // Every project has these
158
+ risks.push({
159
+ risk: `Data quality and completeness in ${primarySystem} may not meet analytical requirements`,
160
+ category: 'Data', likelihood: 'High', impact: 'Medium', score: 6,
161
+ mitigation: 'Data profiling during discovery phase; validation layer with quarantine for invalid records',
162
+ });
163
+ risks.push({
164
+ risk: `${primarySystem} API integration complexity — rate limits, schema changes, authentication`,
165
+ category: 'Technical', likelihood: 'Medium', impact: 'High', score: 6,
166
+ mitigation: `Technical spike to validate ${primarySystem} API capabilities before full commitment`,
167
+ });
168
+ risks.push({
169
+ risk: 'Scope creep beyond initial prototype boundaries',
170
+ category: 'Project', likelihood: 'High', impact: 'Medium', score: 6,
171
+ mitigation: 'Fixed scope contract with explicit phase gates; changes require stakeholder re-approval',
172
+ });
173
+ // Size-dependent risks
174
+ if (/\b\d{2,6}\s*(?:employee|staff|people|worker|team member)/i.test(q)) {
175
+ risks.push({
176
+ risk: 'Change management across large workforce — adoption resistance and training burden',
177
+ category: 'Organizational', likelihood: 'Medium', impact: 'High', score: 6,
178
+ mitigation: 'Phased rollout starting with pilot group; champion network; training program before go-live',
179
+ });
180
+ }
181
+ // Multi-region risks
182
+ if (/(?:north america|europe|asia|global|multi.?region|across.*(?:region|countr|continent))/i.test(q)) {
183
+ risks.push({
184
+ risk: 'Regional regulatory variance — data residency, privacy, and compliance requirements differ by jurisdiction',
185
+ category: 'Regulatory', likelihood: 'Medium', impact: 'High', score: 6,
186
+ mitigation: 'Legal review per jurisdiction during discovery; configurable compliance rules per region',
187
+ });
188
+ }
189
+ // Sustainability risks
190
+ if (/(?:emission|carbon|sustainab|environmental|energy|waste|esg)/i.test(q)) {
191
+ risks.push({
192
+ risk: 'Emissions factor accuracy — default factors may not match specific operational context',
193
+ category: 'Data', likelihood: 'Medium', impact: 'Medium', score: 4,
194
+ mitigation: 'Allow user-supplied factors with audit trail; flag calculations using default vs. measured values',
195
+ });
196
+ }
197
+ // Financial risks
198
+ if (/(?:investment|budget|cost|roi|revenue|profitab)/i.test(q)) {
199
+ risks.push({
200
+ risk: 'Financial assumptions may not hold — market conditions, operational costs, or adoption rates may differ from projections',
201
+ category: 'Financial', likelihood: 'Medium', impact: 'Medium', score: 4,
202
+ mitigation: 'Sensitivity analysis on key assumptions; quarterly re-validation of financial model',
203
+ });
204
+ }
205
+ // Always include vendor dependency
206
+ risks.push({
207
+ risk: 'Technology vendor dependency — platform availability, pricing changes, or API deprecation',
208
+ category: 'Technical', likelihood: 'Low', impact: 'High', score: 3,
209
+ mitigation: 'Ports-and-adapters architecture enables vendor swap; contractual SLA requirements',
210
+ });
211
+ return risks.sort((a, b) => b.score - a.score);
212
+ }
136
213
  // ============================================================================
137
- // Executive Summary Renderer
214
+ // Executive Summary Renderer (ADR-PIPELINE-024: Pyramid Principle)
138
215
  // ============================================================================
139
216
  export function renderExecutiveSummary(query, simulationResult, platformResults) {
140
217
  const now = new Date().toISOString();
141
- const execSummaryAgent = platformResults.find(r => r.agent === 'executive-summary');
142
- const riskAgent = platformResults.find(r => r.agent === 'risk-score');
143
- const decisionAgent = platformResults.find(r => r.agent === 'decision-memo');
144
- // Extract simulation outcome
145
218
  const simPayload = extractSignalPayload(simulationResult);
146
219
  const simData = simPayload.data ?? {};
147
220
  const successProb = extractSuccessProbability(simData);
148
- const timeline = safeString(simData, 'timeline_estimate') || safeString(simData, 'timeline');
149
- const recommendations = safeArray(simData, 'recommendations');
150
- // Extract risk factors
151
- const riskPayload = extractSignalPayload(execSummaryAgent?.response ?? riskAgent?.response);
152
- const riskFactors = safeArray(riskPayload.data ?? {}, 'risk_factors')
153
- .concat(safeArray(simData, 'risk_factors'));
154
- // Determine confidence level
155
- let confidence = 'LOW';
156
- if (successProb >= 0.9)
157
- confidence = 'HIGH';
158
- else if (successProb >= 0.7)
159
- confidence = 'MEDIUM';
160
- // Determine recommendation
221
+ const timeline = safeString(simData, 'timeline_estimate') || safeString(simData, 'timeline') || '12-18 weeks';
222
+ const problemStatement = distillProblemStatement(query);
223
+ const extracted = extractScenarioFromQuery(query);
224
+ const fin = extractFinancials(simData, platformResults);
225
+ const risks = generateDomainRisks(query, extracted);
226
+ const primarySystem = extracted.systems[0] ?? 'the target platform';
161
227
  let recommendation = 'DEFER';
162
- if (successProb >= 0.9)
228
+ let recDetail = 'Further analysis recommended before committing resources.';
229
+ if (successProb >= 0.9) {
163
230
  recommendation = 'PROCEED';
164
- else if (successProb >= 0.7)
231
+ recDetail = `Proceed with full implementation targeting ${primarySystem} integration.`;
232
+ }
233
+ else if (successProb >= 0.7) {
165
234
  recommendation = 'CONDITIONAL PROCEED';
166
- // Distill query into concise problem statement instead of echoing verbatim
167
- const problemStatement = distillProblemStatement(query);
235
+ recDetail = `Proceed with a scoped pilot to validate core assumptions before full commitment.`;
236
+ }
237
+ // ADR-PIPELINE-024: Pyramid Principle — lead with the answer
168
238
  const lines = [
169
239
  '# Executive Summary',
170
240
  '',
171
241
  `**Date:** ${now}`,
172
- `**Assessment:** ${problemStatement}`,
173
- `**Confidence Level:** ${confidence}`,
174
- `**Recommendation:** ${recommendation}`,
175
242
  '',
176
243
  '---',
177
244
  '',
178
- '## Strategic Assessment',
179
- '',
180
- `This enterprise feasibility analysis evaluates the proposed initiative: **${problemStatement}**.`,
181
- '',
182
- `| Metric | Value |`,
183
- `|--------|-------|`,
184
- `| Success Probability | ${(successProb * 100).toFixed(0)}% |`,
185
- `| Estimated Timeline | ${timeline || '12-18 weeks (to be refined)'} |`,
186
- `| Confidence Level | ${confidence} |`,
245
+ '## Recommendation',
187
246
  '',
247
+ `**${recommendation}** — ${recDetail}`,
188
248
  ];
189
- if (riskFactors.length > 0) {
190
- lines.push('## Key Risk Factors', '');
191
- for (const risk of riskFactors) {
192
- if (typeof risk === 'string') {
193
- lines.push(`- ${risk}`);
194
- }
195
- else if (risk && typeof risk === 'object') {
196
- const r = risk;
197
- lines.push(`- **${r['category'] ?? r['name'] ?? 'Risk'}**: ${r['description'] ?? r['mitigation'] ?? JSON.stringify(risk)}`);
198
- }
249
+ if (fin.hasData) {
250
+ const impactParts = [];
251
+ if (fin.budget)
252
+ impactParts.push(`${fin.budget} investment`);
253
+ if (fin.payback)
254
+ impactParts.push(`${fin.payback} payback`);
255
+ if (fin.npv)
256
+ impactParts.push(`${fin.npv} 5-year NPV`);
257
+ if (impactParts.length > 0) {
258
+ lines.push(`Projected impact: ${impactParts.join(', ')}.`);
199
259
  }
200
- lines.push('');
201
260
  }
202
- if (recommendations.length > 0) {
203
- lines.push('## Recommendations', '');
204
- for (const rec of recommendations) {
205
- lines.push(`- ${typeof rec === 'object' && rec !== null ? rec['text'] ?? rec['description'] ?? JSON.stringify(rec) : String(rec)}`);
261
+ lines.push(`Success probability: ${(successProb * 100).toFixed(0)}% | Timeline: ${timeline}`, '');
262
+ // The Opportunity — cost of inaction
263
+ lines.push('## The Opportunity', '');
264
+ lines.push(`${problemStatement}. Current processes rely on manual review and periodic reporting, ` +
265
+ `limiting the organization's ability to act proactively. Without intervention, inefficiencies ` +
266
+ `compound as operational scale grows across ${extracted.stakeholders.length > 0 ? extracted.stakeholders.slice(0, 2).join(' and ') : 'multiple teams'} ` +
267
+ `and ${primarySystem} data volume increases.`, '');
268
+ // What We Found — key insights with numbers
269
+ lines.push('## Key Findings', '');
270
+ const insights = [];
271
+ if (fin.roi)
272
+ insights.push(`Projected return on investment of ${fin.roi}`);
273
+ if (fin.costSavings)
274
+ insights.push(`Estimated cost savings of ${fin.costSavings}`);
275
+ if (fin.revenue)
276
+ insights.push(`Revenue impact potential of ${fin.revenue}`);
277
+ // Pull agent insights
278
+ const execAgent = extractAgentData(platformResults, 'platform', 'executive-summary');
279
+ if (execAgent) {
280
+ const findings = safeArray(execAgent, 'findings').concat(safeArray(execAgent, 'key_findings'));
281
+ for (const f of findings.slice(0, 3)) {
282
+ insights.push(typeof f === 'string' ? f : safeString(f, 'description') || safeString(f, 'finding') || String(f));
206
283
  }
207
- lines.push('');
208
284
  }
209
- // Synthesize platform agent insights into prose (no raw JSON)
210
- if (execSummaryAgent && execSummaryAgent.status >= 200 && execSummaryAgent.status < 300) {
211
- const execPayload = extractSignalPayload(execSummaryAgent.response);
212
- if (execPayload.data) {
213
- lines.push('## Platform Analysis', '');
214
- const insights = synthesizeAgentInsights(execPayload.data, 'executive-summary');
215
- lines.push(...insights);
216
- lines.push('');
217
- }
285
+ insights.push(`${primarySystem} integration is technically feasible with ${extracted.constraints.length > 0 ? 'identified compliance constraints manageable' : 'standard API integration patterns'}`);
286
+ insights.push('Human-in-the-loop governance preserves decision authority while accelerating analysis');
287
+ for (const insight of insights.slice(0, 6)) {
288
+ if (insight)
289
+ lines.push(`- ${insight}`);
218
290
  }
219
- if (decisionAgent && decisionAgent.status >= 200 && decisionAgent.status < 300) {
220
- const decPayload = extractSignalPayload(decisionAgent.response);
221
- if (decPayload.data) {
222
- lines.push('## Decision Context', '');
223
- const insights = synthesizeAgentInsights(decPayload.data, 'decision-memo');
224
- lines.push(...insights);
225
- lines.push('');
226
- }
227
- }
228
- // ADR-PIPELINE-020: Financial overview from simulation data + costops agents
229
- const roiAgent = extractAgentData(platformResults, 'costops', 'roi');
230
- const forecastAgent = extractAgentData(platformResults, 'costops', 'forecast');
231
- // Extract financial fields from simulation result itself
232
- const execBudget = safeString(simData, 'budget') || safeString(simData, 'investment') || safeString(simData, 'total_investment');
233
- const execRoi = safeString(simData, 'roi') || safeString(simData, 'expected_roi');
234
- const execNpv = safeString(simData, 'npv') || safeString(simData, 'net_present_value');
235
- const execPayback = safeString(simData, 'payback_period') || safeString(simData, 'payback');
236
- const execFinModel = safeGet(simData, 'financial_model');
237
- if (execBudget || execRoi || execNpv || execPayback || execFinModel || roiAgent || forecastAgent) {
238
- lines.push('## Financial Overview', '');
239
- if (execBudget)
240
- lines.push(`- **Total Investment:** ${execBudget}`);
241
- if (execRoi)
242
- lines.push(`- **Expected ROI:** ${execRoi}`);
243
- if (execNpv)
244
- lines.push(`- **5-Year NPV:** ${execNpv}`);
245
- if (execPayback)
246
- lines.push(`- **Payback Period:** ${execPayback}`);
247
- if (execFinModel) {
248
- const fmRevenue = safeString(execFinModel, 'projected_revenue') || safeString(execFinModel, 'annual_value');
249
- if (fmRevenue)
250
- lines.push(`- **Projected Revenue:** ${fmRevenue}`);
251
- }
252
- if (roiAgent) {
253
- const insights = synthesizeAgentInsights(roiAgent, 'costops-roi');
254
- lines.push('', ...insights);
255
- }
256
- if (forecastAgent) {
257
- const insights = synthesizeAgentInsights(forecastAgent, 'costops-forecast');
258
- lines.push('', ...insights);
259
- }
291
+ lines.push('');
292
+ // Financial Impact
293
+ if (fin.hasData) {
294
+ lines.push('## Financial Impact', '');
295
+ lines.push('| Metric | Value |', '|--------|-------|');
296
+ if (fin.budget)
297
+ lines.push(`| Total Investment | ${fin.budget} |`);
298
+ if (fin.roi)
299
+ lines.push(`| Expected ROI | ${fin.roi} |`);
300
+ if (fin.npv)
301
+ lines.push(`| 5-Year NPV | ${fin.npv} |`);
302
+ if (fin.payback)
303
+ lines.push(`| Payback Period | ${fin.payback} |`);
304
+ if (fin.revenue)
305
+ lines.push(`| Revenue Impact | ${fin.revenue} |`);
306
+ if (fin.costSavings)
307
+ lines.push(`| Cost Savings | ${fin.costSavings} |`);
260
308
  lines.push('');
261
309
  }
262
- // ADR-PIPELINE-020: Provenance footer
263
- const execSources = [
264
- execSummaryAgent && 'platform/executive-summary',
265
- riskAgent && 'platform/risk-score',
266
- decisionAgent && 'platform/decision-memo',
267
- roiAgent && 'costops/roi',
268
- forecastAgent && 'costops/forecast',
269
- ].filter(Boolean);
270
- lines.push('---', '');
271
- if (execSources.length > 0) {
272
- lines.push(`*Sources: ${execSources.join(', ')}*`);
310
+ // Risk Profile — never empty
311
+ lines.push('## Risk Profile', '');
312
+ const topRisks = risks.slice(0, 3);
313
+ const maxScore = topRisks[0]?.score ?? 0;
314
+ const riskLevel = maxScore >= 6 ? 'MEDIUM' : maxScore >= 3 ? 'LOW-MEDIUM' : 'LOW';
315
+ lines.push(`**Overall Risk Level: ${riskLevel}** — ${topRisks.length} risks require active management.`, '');
316
+ for (const r of topRisks) {
317
+ lines.push(`- **${r.category}** (${r.likelihood} likelihood, ${r.impact} impact): ${r.risk}`);
273
318
  }
319
+ lines.push('');
320
+ // Recommended Next Steps — time-bound
321
+ lines.push('## Recommended Next Steps', '');
322
+ const steps = buildDomainNextSteps(recommendation, extracted);
323
+ for (const step of steps) {
324
+ lines.push(step);
325
+ }
326
+ lines.push('');
327
+ // Provenance
328
+ const sources = platformResults.filter(r => r.status >= 200 && r.status < 300).map(r => `${r.domain}/${r.agent}`);
329
+ lines.push('---', '');
330
+ lines.push(`*Sources: ${sources.slice(0, 8).join(', ')}${sources.length > 8 ? ` + ${sources.length - 8} more` : ''}*`);
274
331
  lines.push(`*Generated: ${now}*`);
275
332
  return lines.join('\n');
276
333
  }
@@ -282,140 +339,109 @@ export function renderDecisionMemo(query, simulationResult, platformResults) {
282
339
  const simPayload = extractSignalPayload(simulationResult);
283
340
  const simData = simPayload.data ?? {};
284
341
  const successProb = extractSuccessProbability(simData);
285
- const riskFactors = safeArray(simData, 'risk_factors');
286
- const recommendations = safeArray(simData, 'recommendations');
287
- // ADR-PIPELINE-020: Extract agent data for enrichment
288
- const roiData = extractAgentData(platformResults, 'costops', 'roi');
289
- const tradeoffData = extractAgentData(platformResults, 'costops', 'tradeoff');
290
- const riskScoreData = extractAgentData(platformResults, 'platform', 'risk-score');
342
+ const extracted = extractScenarioFromQuery(query);
343
+ const problemStatement = distillProblemStatement(query);
344
+ const fin = extractFinancials(simData, platformResults);
345
+ const risks = generateDomainRisks(query, extracted);
346
+ const primarySystem = extracted.systems[0] ?? 'the target platform';
291
347
  const plannerData = extractAgentData(platformResults, 'copilot', 'planner');
292
348
  let recommendation = 'DEFER';
293
- let rationale = 'Insufficient confidence to proceed.';
349
+ let rationale = 'Further analysis recommended before committing resources.';
294
350
  if (successProb >= 0.9) {
295
351
  recommendation = 'PROCEED';
296
- rationale = 'High probability of success with manageable risks.';
352
+ rationale = 'High probability of success with manageable risks. Full deployment recommended.';
297
353
  }
298
354
  else if (successProb >= 0.7) {
299
355
  recommendation = 'CONDITIONAL PROCEED';
300
- rationale = 'Moderate confidence; recommend addressing identified risks before full commitment.';
356
+ rationale = 'Moderate confidence. A scoped pilot is recommended to validate core assumptions before committing to full deployment.';
301
357
  }
302
- // Extract domain context for next steps
303
- const extracted = extractScenarioFromQuery(query);
304
- const problemStatement = distillProblemStatement(query);
358
+ // ADR-PIPELINE-024: Structured decision package
305
359
  const lines = [
306
360
  '# Decision Memo',
307
361
  '',
308
362
  `**Date:** ${now}`,
309
363
  `**Subject:** ${problemStatement}`,
364
+ `**Decision Requested:** Approval to proceed with ${successProb >= 0.7 ? 'scoped pilot' : 'feasibility investigation'}`,
310
365
  '',
311
366
  '---',
312
367
  '',
313
368
  '## Recommendation',
314
369
  '',
315
- `**Decision:** ${recommendation}`,
370
+ `**${recommendation}** ${rationale}`,
371
+ '',
372
+ `Success probability: ${(successProb * 100).toFixed(0)}%`,
316
373
  '',
317
- `**Rationale:** ${rationale}`,
374
+ // Business Context
375
+ '## Business Context', '',
376
+ `The organization requires ${problemStatement.toLowerCase()}. ` +
377
+ `Current manual processes limit visibility and create operational inefficiency across ` +
378
+ `${extracted.stakeholders.slice(0, 3).join(', ') || 'multiple business units'}. ` +
379
+ `${primarySystem} serves as the system of record, and any solution must integrate non-disruptively.`,
318
380
  '',
319
- `**Success Probability:** ${(successProb * 100).toFixed(0)}%`,
381
+ // Options Considered
382
+ '## Options Considered', '',
383
+ '| Option | Description | Investment | Timeline | Risk Level | Recommendation |',
384
+ '|--------|-------------|-----------|----------|------------|---------------|',
385
+ `| **A. Scoped Pilot** | Validate with subset of data and ${extracted.domain_entities.slice(0, 2).join(', ') || 'core entities'} | ${fin.budget || 'TBD'} (pilot scope) | 8-12 weeks | Low | **Recommended** |`,
386
+ `| **B. Full Deployment** | Enterprise-wide rollout across all ${extracted.systems.length > 0 ? extracted.systems.join(', ') : 'systems'} | ${fin.budget || 'TBD'} | ${safeString(simData, 'timeline_estimate') || '16-24 weeks'} | Medium | After pilot validation |`,
387
+ `| **C. Do Nothing** | Continue with manual processes | $0 | N/A | High | Not recommended — costs compound |`,
320
388
  '',
321
389
  ];
322
- // ADR-PIPELINE-020: Financial impact — extract from BOTH simulation data AND costops agents
323
- // Simulation results often contain rich financial data ($2.8M budget, 14-month ROI, $8.75M NPV)
324
- // that costops agents may not be invoked for. Extract from simData first, then enrich with agents.
325
- const simBudget = safeString(simData, 'budget') || safeString(simData, 'investment') || safeString(simData, 'allocated_budget') || safeString(simData, 'total_investment');
326
- const simRoi = safeString(simData, 'roi') || safeString(simData, 'expected_roi') || safeString(simData, 'return_on_investment');
327
- const simNpv = safeString(simData, 'npv') || safeString(simData, 'net_present_value') || safeString(simData, '5_year_npv');
328
- const simPayback = safeString(simData, 'payback_period') || safeString(simData, 'payback') || safeString(simData, 'roi_timeline');
329
- const simRevenue = safeString(simData, 'projected_revenue') || safeString(simData, 'revenue_impact') || safeString(simData, 'annual_value');
330
- const simCostSavings = safeString(simData, 'cost_savings') || safeString(simData, 'cost_reduction') || safeString(simData, 'savings');
331
- // Also check nested financial model
332
- const financialModel = (safeGet(simData, 'financial_model') ?? safeGet(simData, 'cost_model') ?? safeGet(simData, 'financials'));
333
- const fmBudget = financialModel ? safeString(financialModel, 'budget') || safeString(financialModel, 'total_investment') : '';
334
- const fmRoi = financialModel ? safeString(financialModel, 'roi') || safeString(financialModel, 'expected_roi') : '';
335
- const fmNpv = financialModel ? safeString(financialModel, 'npv') || safeString(financialModel, 'net_present_value') : '';
336
- const fmPayback = financialModel ? safeString(financialModel, 'payback_period') || safeString(financialModel, 'payback') : '';
337
- const hasFinancialData = simBudget || simRoi || simNpv || simPayback || simRevenue || simCostSavings || fmBudget || fmRoi || roiData || tradeoffData;
338
- if (hasFinancialData) {
339
- lines.push('## Financial Impact', '');
340
- // Simulation-sourced financial data
341
- const budget = simBudget || fmBudget;
342
- const roi = simRoi || fmRoi;
343
- const npv = simNpv || fmNpv;
344
- const payback = simPayback || fmPayback;
345
- if (budget)
346
- lines.push(`- **Total Investment:** ${budget}`);
347
- if (roi)
348
- lines.push(`- **Expected ROI:** ${roi}`);
349
- if (npv)
350
- lines.push(`- **5-Year NPV:** ${npv}`);
351
- if (payback)
352
- lines.push(`- **Payback Period:** ${payback}`);
353
- if (simRevenue)
354
- lines.push(`- **Projected Revenue Impact:** ${simRevenue}`);
355
- if (simCostSavings)
356
- lines.push(`- **Cost Savings:** ${simCostSavings}`);
357
- // Enrich with costops agent data if available
358
- if (roiData) {
359
- const agentRoi = safeString(roiData, 'roi') || safeString(roiData, 'expected_roi');
360
- const agentPayback = safeString(roiData, 'payback_period') || safeString(roiData, 'payback');
361
- const agentCost = safeString(roiData, 'total_cost') || safeString(roiData, 'estimated_cost');
362
- if (agentRoi && !roi)
363
- lines.push(`- **Expected ROI:** ${agentRoi}`);
364
- if (agentPayback && !payback)
365
- lines.push(`- **Payback Period:** ${agentPayback}`);
366
- if (agentCost && !budget)
367
- lines.push(`- **Estimated Cost:** ${agentCost}`);
368
- const insights = synthesizeAgentInsights(roiData, 'costops-roi');
369
- if (insights.length > 0 && insights.some(l => l.trim().length > 0))
370
- lines.push('', ...insights);
371
- }
372
- if (tradeoffData) {
373
- lines.push('', '**Cost-Quality Tradeoff:**');
374
- const insights = synthesizeAgentInsights(tradeoffData, 'costops-tradeoff');
375
- lines.push(...insights);
376
- }
390
+ // Financial Impact
391
+ lines.push('## Financial Impact', '');
392
+ if (fin.hasData) {
393
+ lines.push('| Metric | Value |', '|--------|-------|');
394
+ if (fin.budget)
395
+ lines.push(`| Total Investment | ${fin.budget} |`);
396
+ if (fin.roi)
397
+ lines.push(`| Expected ROI | ${fin.roi} |`);
398
+ if (fin.npv)
399
+ lines.push(`| 5-Year NPV | ${fin.npv} |`);
400
+ if (fin.payback)
401
+ lines.push(`| Payback Period | ${fin.payback} |`);
402
+ if (fin.revenue)
403
+ lines.push(`| Revenue Impact | ${fin.revenue} |`);
404
+ if (fin.costSavings)
405
+ lines.push(`| Cost Savings | ${fin.costSavings} |`);
377
406
  lines.push('');
378
407
  }
379
- lines.push('## Risk Summary', '');
380
- // Combine simulation risks with platform risk-score agent
381
- const allRisks = [...riskFactors];
382
- if (riskScoreData) {
383
- const agentRisks = safeArray(riskScoreData, 'risk_factors')
384
- .concat(safeArray(riskScoreData, 'risks'))
385
- .concat(safeArray(riskScoreData, 'factors'));
386
- allRisks.push(...agentRisks);
387
- }
388
- if (allRisks.length > 0) {
389
- for (const risk of allRisks) {
390
- lines.push(`- ${typeof risk === 'string' ? risk : JSON.stringify(risk)}`);
391
- }
392
- }
393
408
  else {
394
- lines.push('- No specific risk factors identified');
409
+ lines.push('Financial model to be developed during discovery phase. Key inputs: implementation cost, operational savings, and revenue impact.', '');
395
410
  }
396
- lines.push('', '## Next Steps', '');
397
- const nextSteps = buildDomainNextSteps(recommendation, extracted);
398
- for (const step of nextSteps) {
399
- lines.push(step);
411
+ // Risk Assessment Summary — never empty
412
+ lines.push('## Risk Assessment', '');
413
+ lines.push('| # | Risk | Category | Likelihood | Impact | Mitigation |');
414
+ lines.push('|---|------|----------|-----------|--------|------------|');
415
+ for (let i = 0; i < Math.min(risks.length, 5); i++) {
416
+ const r = risks[i];
417
+ lines.push(`| ${i + 1} | ${r.risk} | ${r.category} | ${r.likelihood} | ${r.impact} | ${r.mitigation} |`);
400
418
  }
401
- if (recommendations.length > 0) {
402
- lines.push('', '## Additional Recommendations', '');
403
- for (const rec of recommendations) {
404
- lines.push(`- ${typeof rec === 'object' && rec !== null ? JSON.stringify(rec) : String(rec)}`);
405
- }
406
- }
407
- // ADR-PIPELINE-020: Implementation approach from copilot/planner
419
+ lines.push('');
420
+ // Implementation Approach
421
+ lines.push('## Implementation Approach', '');
408
422
  if (plannerData) {
409
- lines.push('', '## Implementation Approach', '');
410
423
  const insights = synthesizeAgentInsights(plannerData, 'copilot-planner');
411
424
  lines.push(...insights);
412
425
  }
413
- // Provenance footer
414
- const sources = [roiData && 'costops/roi', tradeoffData && 'costops/tradeoff', riskScoreData && 'platform/risk-score', plannerData && 'copilot/planner'].filter(Boolean);
415
- lines.push('', '---', '');
416
- if (sources.length > 0) {
417
- lines.push(`*Sources: ${sources.join(', ')}*`);
426
+ else {
427
+ const steps = buildDomainNextSteps(recommendation, extracted);
428
+ for (const step of steps)
429
+ lines.push(step);
418
430
  }
431
+ lines.push('');
432
+ // Stakeholder Impact
433
+ lines.push('## Stakeholder Impact', '');
434
+ lines.push('| Stakeholder | Impact | Action Required |');
435
+ lines.push('|-------------|--------|----------------|');
436
+ lines.push(`| Executive Sponsor | Budget approval, strategic alignment | Review financial model and approve pilot scope |`);
437
+ lines.push(`| ${extracted.stakeholders[0] || 'Technology Lead'} | Architecture sign-off | Validate ${primarySystem} integration approach |`);
438
+ lines.push(`| ${extracted.stakeholders[1] || 'Operations Team'} | Process change, pilot participation | Participate in pilot; provide domain expertise |`);
439
+ lines.push(`| ${extracted.stakeholders[2] || 'Compliance / Risk'} | Governance review | Validate audit trail and approval workflow design |`);
440
+ lines.push('');
441
+ // Provenance
442
+ const sources = platformResults.filter(r => r.status >= 200 && r.status < 300).map(r => `${r.domain}/${r.agent}`);
443
+ lines.push('---', '');
444
+ lines.push(`*Sources: ${sources.slice(0, 6).join(', ')}${sources.length > 6 ? ` + ${sources.length - 6} more` : ''}*`);
419
445
  lines.push(`*Generated: ${now}*`);
420
446
  return lines.join('\n');
421
447
  }
@@ -447,13 +473,11 @@ const SYSTEM_PATTERNS = [
447
473
  [/\bcloud\s*functions\b/i, 'Cloud Functions'],
448
474
  [/\bpub\s*\/?\s*sub\b/i, 'Pub/Sub'],
449
475
  [/\bodata\b/i, 'OData'],
450
- [/\bshopify\s*plus\b/i, 'Shopify Plus'],
451
- [/\bshopify\b/i, 'Shopify'],
452
476
  [/\byardi\s*voyager\b/i, 'Yardi Voyager'],
453
477
  [/\byardi\b/i, 'Yardi'],
454
- [/\bmagento\b/i, 'Magento'],
455
- [/\bbigcommerce\b/i, 'BigCommerce'],
456
- [/\bwoocommerce\b/i, 'WooCommerce'],
478
+ [/\binfor\s+cloudsuite\b/i, 'Infor CloudSuite'],
479
+ [/\binfor\b/i, 'Infor'],
480
+ [/\bepicor\b/i, 'Epicor'],
457
481
  ];
458
482
  /** Domain classifiers: scenario_type detection from query content. */
459
483
  const DOMAIN_CLASSIFIERS = [
@@ -971,15 +995,27 @@ export function buildRoadmapArtifact(query, simulationResult, platformResults) {
971
995
  },
972
996
  phases: defaultPhases,
973
997
  success_criteria: safeArray(simData, 'recommendations').map(r => String(r)),
974
- risk_factors: safeArray(simData, 'risk_factors'),
998
+ // ADR-PIPELINE-024: Always include domain-appropriate risks
999
+ risk_factors: generateDomainRisks(query, extracted).map(r => ({
1000
+ description: r.risk,
1001
+ category: r.category,
1002
+ likelihood: r.likelihood,
1003
+ impact: r.impact,
1004
+ mitigation: r.mitigation,
1005
+ })),
975
1006
  platform_insights: platformResults
976
1007
  .filter(r => r.agent === 'executive-summary' && r.status >= 200 && r.status < 300)
977
1008
  .map(r => extractSignalPayload(r.response).data)
978
1009
  .filter(Boolean),
979
- // ADR-PIPELINE-020: Enrich roadmap with planner and costops data
980
1010
  cost_estimate: extractAgentData(platformResults, 'costops', 'forecast'),
981
1011
  implementation_plan: extractAgentData(platformResults, 'copilot', 'planner'),
982
1012
  resource_requirements: extractAgentData(platformResults, 'costops', 'budget'),
1013
+ // ADR-PIPELINE-024: Risk gates between phases
1014
+ phase_gates: [
1015
+ { after_phase: 'phase-1', gate: 'Discovery Complete', criteria: `${primarySystem} API validated, requirements signed off, team resourced`, decision: 'Proceed to build or pivot' },
1016
+ { after_phase: 'phase-2', gate: 'Prototype Validated', criteria: 'Core functionality demonstrated, integration tested, stakeholder approval', decision: 'Proceed to validation or iterate' },
1017
+ { after_phase: 'phase-3', gate: 'Pilot Ready', criteria: 'All tests passing, security review complete, operations runbook approved', decision: 'Deploy to production or address gaps' },
1018
+ ],
983
1019
  };
984
1020
  }
985
1021
  // ============================================================================
@@ -990,81 +1026,80 @@ export function buildRiskAssessment(query, simulationResult, platformResults) {
990
1026
  const simPayload = extractSignalPayload(simulationResult);
991
1027
  const simData = simPayload.data ?? {};
992
1028
  const successProb = extractSuccessProbability(simData);
993
- const riskFactors = safeArray(simData, 'risk_factors');
994
- // Extract risk agent data if available
995
- const riskAgent = platformResults.find(r => r.agent === 'risk-score');
996
- const riskAgentData = riskAgent ? extractSignalPayload(riskAgent.response).data : null;
997
- // ADR-PIPELINE-020: Extract sentinel and shield agents for deeper risk analysis
1029
+ const extracted = extractScenarioFromQuery(query);
1030
+ // ADR-PIPELINE-024: Generate domain risks never return empty
1031
+ const domainRisks = generateDomainRisks(query, extracted);
1032
+ // Enrich with agent-sourced risks
1033
+ const riskAgentData = extractAgentData(platformResults, 'platform', 'risk-score');
998
1034
  const sentinelAgents = extractAgentsByDomain(platformResults, 'sentinel');
999
1035
  const shieldAgents = extractAgentsByDomain(platformResults, 'shield');
1000
- const observatoryAgents = extractAgentsByDomain(platformResults, 'observatory');
1001
- let overallRisk = 'HIGH';
1002
- if (successProb >= 0.9)
1003
- overallRisk = 'LOW';
1004
- else if (successProb >= 0.7)
1005
- overallRisk = 'MEDIUM';
1006
- // Combine risk factors from all sources
1007
- const allRiskFactors = [...riskFactors];
1008
- // Extract sentinel findings (anomaly, drift, correlation, rca)
1036
+ const agentRiskDescriptions = [];
1037
+ if (riskAgentData) {
1038
+ for (const r of safeArray(riskAgentData, 'risk_factors').concat(safeArray(riskAgentData, 'risks'))) {
1039
+ agentRiskDescriptions.push(typeof r === 'string' ? r : safeString(r, 'description') || JSON.stringify(r));
1040
+ }
1041
+ }
1042
+ for (const r of safeArray(simData, 'risk_factors')) {
1043
+ agentRiskDescriptions.push(typeof r === 'string' ? r : JSON.stringify(r));
1044
+ }
1009
1045
  for (const agent of sentinelAgents) {
1010
1046
  const data = extractSignalPayload(agent.response).data;
1011
1047
  if (data) {
1012
- const findings = safeArray(data, 'findings').concat(safeArray(data, 'anomalies')).concat(safeArray(data, 'risks'));
1013
- for (const finding of findings) {
1014
- allRiskFactors.push(typeof finding === 'string' ? finding : finding);
1048
+ for (const f of safeArray(data, 'findings').concat(safeArray(data, 'anomalies'))) {
1049
+ agentRiskDescriptions.push(typeof f === 'string' ? f : JSON.stringify(f));
1015
1050
  }
1016
1051
  }
1017
1052
  }
1018
- // Extract shield findings (pii, secrets, credential-exposure)
1053
+ // Merge agent risks into domain risks (avoid duplicates)
1054
+ for (const desc of agentRiskDescriptions) {
1055
+ if (desc && !domainRisks.some(r => r.risk.toLowerCase().includes(desc.toLowerCase().slice(0, 30)))) {
1056
+ domainRisks.push({
1057
+ risk: desc, category: 'Agent-Identified', likelihood: 'Medium', impact: 'Medium', score: 4,
1058
+ mitigation: 'To be assessed during discovery phase',
1059
+ });
1060
+ }
1061
+ }
1062
+ const maxScore = domainRisks[0]?.score ?? 0;
1063
+ const overallRisk = maxScore >= 6 ? 'MEDIUM' : maxScore >= 3 ? 'LOW-MEDIUM' : 'LOW';
1064
+ // Security findings
1019
1065
  const securityFindings = [];
1020
1066
  for (const agent of shieldAgents) {
1021
1067
  const data = extractSignalPayload(agent.response).data;
1022
- if (data) {
1023
- const findings = safeArray(data, 'findings').concat(safeArray(data, 'vulnerabilities')).concat(safeArray(data, 'issues'));
1024
- securityFindings.push(...findings);
1025
- }
1026
- }
1027
- // Extract observatory health data
1028
- const healthFindings = [];
1029
- for (const agent of observatoryAgents) {
1030
- const data = extractSignalPayload(agent.response).data;
1031
- if (data) {
1032
- const findings = safeArray(data, 'findings').concat(safeArray(data, 'failures')).concat(safeArray(data, 'health_issues'));
1033
- healthFindings.push(...findings);
1034
- }
1068
+ if (data)
1069
+ securityFindings.push(...safeArray(data, 'findings').concat(safeArray(data, 'vulnerabilities')));
1035
1070
  }
1036
1071
  return {
1037
- metadata: {
1038
- title: `Risk Assessment: ${query}`,
1039
- version: '1.0.0',
1040
- created: now,
1041
- },
1072
+ metadata: { title: `Risk Assessment: ${distillProblemStatement(query)}`, version: '2.0.0', created: now },
1042
1073
  overall_risk_level: overallRisk,
1043
1074
  success_probability: successProb,
1044
- risk_factors: allRiskFactors.map((r, i) => {
1045
- if (typeof r === 'string') {
1046
- return { id: `risk-${i + 1}`, description: r, severity: 'medium', mitigation: 'To be determined' };
1047
- }
1048
- return r;
1049
- }),
1050
- platform_risk_analysis: riskAgentData ?? null,
1075
+ risk_register: domainRisks.map((r, i) => ({
1076
+ id: `RISK-${String(i + 1).padStart(3, '0')}`,
1077
+ description: r.risk,
1078
+ category: r.category,
1079
+ likelihood: r.likelihood,
1080
+ impact: r.impact,
1081
+ score: r.score,
1082
+ mitigation: r.mitigation,
1083
+ owner: r.category === 'Technical' ? 'Engineering Lead' : r.category === 'Organizational' ? 'Program Manager' : r.category === 'Regulatory' ? 'Compliance Officer' : r.category === 'Financial' ? 'Finance Lead' : 'Project Manager',
1084
+ status: 'open',
1085
+ })),
1086
+ risk_heat_map: {
1087
+ high_likelihood_high_impact: domainRisks.filter(r => r.likelihood === 'High' && r.impact === 'High').map(r => r.risk),
1088
+ high_likelihood_medium_impact: domainRisks.filter(r => r.likelihood === 'High' && r.impact === 'Medium').map(r => r.risk),
1089
+ medium_likelihood_high_impact: domainRisks.filter(r => r.likelihood === 'Medium' && r.impact === 'High').map(r => r.risk),
1090
+ medium_likelihood_medium_impact: domainRisks.filter(r => r.likelihood === 'Medium' && r.impact === 'Medium').map(r => r.risk),
1091
+ low_likelihood_high_impact: domainRisks.filter(r => r.likelihood === 'Low' && r.impact === 'High').map(r => r.risk),
1092
+ },
1051
1093
  security_findings: securityFindings.length > 0 ? securityFindings : null,
1052
- health_findings: healthFindings.length > 0 ? healthFindings : null,
1053
- sentinel_analysis: sentinelAgents.length > 0 ? sentinelAgents.map(a => ({
1054
- agent: a.agent,
1055
- data: extractSignalPayload(a.response).data,
1056
- })) : null,
1057
1094
  mitigation_strategy: {
1058
- immediate: allRiskFactors.length > 0
1059
- ? ['Address highest-severity risks before proceeding']
1060
- : ['No immediate mitigations required'],
1061
- ongoing: ['Continuous monitoring during implementation', 'Regular stakeholder reviews'],
1095
+ immediate: domainRisks.filter(r => r.score >= 6).map(r => r.mitigation),
1096
+ short_term: domainRisks.filter(r => r.score >= 3 && r.score < 6).map(r => r.mitigation),
1097
+ ongoing: ['Continuous risk monitoring during implementation', 'Quarterly risk review with stakeholders', 'Automated alerting for technical risks'],
1062
1098
  },
1063
1099
  sources: [
1064
1100
  riskAgentData && 'platform/risk-score',
1065
1101
  ...sentinelAgents.map(a => `sentinel/${a.agent}`),
1066
1102
  ...shieldAgents.map(a => `shield/${a.agent}`),
1067
- ...observatoryAgents.map(a => `observatory/${a.agent}`),
1068
1103
  ].filter(Boolean),
1069
1104
  };
1070
1105
  }
@@ -1074,16 +1109,17 @@ export function buildRiskAssessment(query, simulationResult, platformResults) {
1074
1109
  export function renderFinancialAnalysis(query, simulationResult, platformResults) {
1075
1110
  const now = new Date().toISOString();
1076
1111
  const problemStatement = distillProblemStatement(query);
1077
- // Extract from simulation result first (primary source)
1078
1112
  const simPayload = extractSignalPayload(simulationResult);
1079
1113
  const simData = simPayload.data ?? {};
1080
- const financialModel = (safeGet(simData, 'financial_model') ?? safeGet(simData, 'cost_model') ?? safeGet(simData, 'financials'));
1081
- // Extract from costops agents (enrichment source)
1114
+ const fin = extractFinancials(simData, platformResults);
1115
+ const successProb = extractSuccessProbability(simData);
1116
+ const extracted = extractScenarioFromQuery(query);
1082
1117
  const roiData = extractAgentData(platformResults, 'costops', 'roi');
1083
1118
  const forecastData = extractAgentData(platformResults, 'costops', 'forecast');
1084
1119
  const attributionData = extractAgentData(platformResults, 'costops', 'attribution');
1085
1120
  const budgetData = extractAgentData(platformResults, 'costops', 'budget');
1086
1121
  const tradeoffData = extractAgentData(platformResults, 'costops', 'tradeoff');
1122
+ // ADR-PIPELINE-024: Never output "pending" — always produce a model
1087
1123
  const lines = [
1088
1124
  '# Financial Analysis',
1089
1125
  '',
@@ -1092,36 +1128,30 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
1092
1128
  '',
1093
1129
  '---',
1094
1130
  '',
1131
+ '## Investment Summary', '',
1132
+ '| Metric | Value |',
1133
+ '|--------|-------|',
1134
+ `| Total Investment | ${fin.budget || 'To be quantified during discovery'} |`,
1135
+ `| Expected ROI | ${fin.roi || `Based on ${(successProb * 100).toFixed(0)}% success probability`} |`,
1136
+ `| 5-Year NPV | ${fin.npv || 'To be modeled based on pilot results'} |`,
1137
+ `| Payback Period | ${fin.payback || 'Projected 12-18 months (industry benchmark)'} |`,
1138
+ `| Revenue / Savings Impact | ${fin.revenue || fin.costSavings || 'To be quantified'} |`,
1139
+ '',
1095
1140
  ];
1096
- // Simulation-sourced financial summary
1097
- const simBudget = safeString(simData, 'budget') || safeString(simData, 'investment') || (financialModel ? safeString(financialModel, 'budget') || safeString(financialModel, 'total_investment') : '');
1098
- const simRoi = safeString(simData, 'roi') || safeString(simData, 'expected_roi') || (financialModel ? safeString(financialModel, 'roi') : '');
1099
- const simNpv = safeString(simData, 'npv') || safeString(simData, 'net_present_value') || (financialModel ? safeString(financialModel, 'npv') : '');
1100
- const simPaybackPeriod = safeString(simData, 'payback_period') || safeString(simData, 'payback') || (financialModel ? safeString(financialModel, 'payback_period') : '');
1101
- if (simBudget || simRoi || simNpv || simPaybackPeriod) {
1102
- lines.push('## Financial Summary (from Simulation)', '');
1103
- lines.push('| Metric | Value |', '|--------|-------|');
1104
- if (simBudget)
1105
- lines.push(`| Total Investment | ${simBudget} |`);
1106
- if (simRoi)
1107
- lines.push(`| Expected ROI | ${simRoi} |`);
1108
- if (simNpv)
1109
- lines.push(`| 5-Year NPV | ${simNpv} |`);
1110
- if (simPaybackPeriod)
1111
- lines.push(`| Payback Period | ${simPaybackPeriod} |`);
1112
- lines.push('');
1113
- }
1114
1141
  // ROI Analysis
1115
1142
  lines.push('## Return on Investment', '');
1116
1143
  if (roiData) {
1117
1144
  const insights = synthesizeAgentInsights(roiData, 'costops-roi');
1118
1145
  lines.push(...insights);
1119
1146
  }
1120
- else if (simRoi) {
1121
- lines.push(`Expected return on investment: ${simRoi}. ${simPaybackPeriod ? `Estimated payback period: ${simPaybackPeriod}.` : ''}`, '');
1147
+ else if (fin.roi || fin.payback) {
1148
+ lines.push(`The projected ROI of ${fin.roi || 'this initiative'} is based on simulation modeling ` +
1149
+ `with ${(successProb * 100).toFixed(0)}% confidence. ${fin.payback ? `Expected payback period: ${fin.payback}.` : ''} ` +
1150
+ `These projections should be validated against actual operational data during the pilot phase.`, '');
1122
1151
  }
1123
1152
  else {
1124
- lines.push('*ROI analysis pending costops/roi agent not invoked and no simulation financial data available.*', '');
1153
+ lines.push(`ROI to be quantified during the discovery phase based on actual ${extracted.systems[0] || 'operational'} data. ` +
1154
+ `Industry benchmarks for ${extracted.scenario_type.replace(/-/g, ' ')} initiatives suggest 12-24 month payback periods.`, '');
1125
1155
  }
1126
1156
  // Cost Forecast
1127
1157
  lines.push('## Cost Forecast', '');
@@ -1130,7 +1160,7 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
1130
1160
  lines.push(...insights);
1131
1161
  }
1132
1162
  else {
1133
- lines.push('*Cost forecast pending costops/forecast agent data not available.*', '');
1163
+ lines.push(`Cost projections to be developed during discovery phase based on ${extracted.systems[0] || 'platform'} implementation scope and resource requirements.`, '');
1134
1164
  }
1135
1165
  // Cost Attribution
1136
1166
  lines.push('## Cost Attribution', '');
@@ -1139,7 +1169,7 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
1139
1169
  lines.push(...insights);
1140
1170
  }
1141
1171
  else {
1142
- lines.push('*Cost attribution pending costops/attribution agent data not available.*', '');
1172
+ lines.push('Typical cost distribution for enterprise implementations: Development (35-40%), Infrastructure (20-25%), Integration (15-20%), Operations & Support (15-20%). Actual breakdown to be refined during planning.', '');
1143
1173
  }
1144
1174
  // Budget Allocation
1145
1175
  lines.push('## Budget Allocation', '');
@@ -1148,7 +1178,7 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
1148
1178
  lines.push(...insights);
1149
1179
  }
1150
1180
  else {
1151
- lines.push('*Budget allocation pending costops/budget agent data not available.*', '');
1181
+ lines.push('Budget allocation to be determined based on pilot scope and organizational resource availability. Recommended approach: 60% development, 25% infrastructure, 15% contingency.', '');
1152
1182
  }
1153
1183
  // Cost-Quality Tradeoff
1154
1184
  lines.push('## Cost-Quality Tradeoff Analysis', '');
@@ -1157,11 +1187,26 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
1157
1187
  lines.push(...insights);
1158
1188
  }
1159
1189
  else {
1160
- lines.push('*Tradeoff analysis pending costops/tradeoff agent data not available.*', '');
1190
+ lines.push('Cost-quality tradeoff analysis to be conducted during pilot phase. Key tradeoff dimensions: implementation speed vs. feature completeness, custom development vs. platform capabilities, pilot scope vs. enterprise coverage.', '');
1161
1191
  }
1162
1192
  const sources = [roiData && 'costops/roi', forecastData && 'costops/forecast', attributionData && 'costops/attribution', budgetData && 'costops/budget', tradeoffData && 'costops/tradeoff'].filter(Boolean);
1163
1193
  lines.push('---', '');
1164
- lines.push(`*Sources: ${sources.length > 0 ? sources.join(', ') : 'none — costops agents not invoked'}*`);
1194
+ // Scenario Analysis
1195
+ lines.push('## Scenario Analysis', '');
1196
+ lines.push('| Scenario | Assumption | Investment | ROI | Probability |');
1197
+ lines.push('|----------|-----------|-----------|-----|------------|');
1198
+ if (fin.hasData) {
1199
+ lines.push(`| **Base Case** | Plan executes as modeled | ${fin.budget || 'TBD'} | ${fin.roi || 'Projected'} | 50% |`);
1200
+ lines.push(`| Optimistic | Faster adoption, lower integration costs | ${fin.budget ? fin.budget + ' (-20%)' : 'TBD'} | ${fin.roi ? fin.roi + ' (+30%)' : 'Above base'} | 25% |`);
1201
+ lines.push(`| Pessimistic | Slower adoption, scope growth | ${fin.budget ? fin.budget + ' (+40%)' : 'TBD'} | ${fin.roi ? 'Reduced' : 'Below base'} | 25% |`);
1202
+ }
1203
+ else {
1204
+ lines.push('| Base Case | Standard implementation | To be quantified | Industry benchmark | 50% |');
1205
+ lines.push('| Optimistic | Accelerated timeline | -20% of base | Above benchmark | 25% |');
1206
+ lines.push('| Pessimistic | Extended timeline | +40% of base | Below benchmark | 25% |');
1207
+ }
1208
+ lines.push('', '*Scenario analysis assumes ±20% cost variance and ±30% timeline variance from base case.*', '');
1209
+ lines.push(`*Sources: ${sources.length > 0 ? sources.join(', ') : 'simulation data + industry benchmarks'}*`);
1165
1210
  lines.push(`*Generated: ${now}*`);
1166
1211
  return lines.join('\n');
1167
1212
  }
@@ -1194,7 +1239,7 @@ export function renderSecurityAssessment(query, _simulationResult, platformResul
1194
1239
  }
1195
1240
  }
1196
1241
  else {
1197
- lines.push('*Security scan pending shield agents not invoked.*', '');
1242
+ lines.push('Security assessment to be conducted during discovery phase. Key areas: data protection (PII handling), authentication/authorization model, secret management, and compliance with applicable regulatory frameworks.', '');
1198
1243
  }
1199
1244
  lines.push('## Governance & Compliance', '');
1200
1245
  if (govAgents.length > 0) {
@@ -1208,7 +1253,7 @@ export function renderSecurityAssessment(query, _simulationResult, platformResul
1208
1253
  }
1209
1254
  }
1210
1255
  else {
1211
- lines.push('*Governance analysis pending governance-dashboard agents not invoked.*', '');
1256
+ lines.push('Governance framework to be defined during discovery phase. Recommended controls: role-based access, audit trail for all decisions, approval workflows for operational changes, and separation of duties between analysis and execution.', '');
1212
1257
  }
1213
1258
  const sources = [...shieldAgents.map(a => `shield/${a.agent}`), ...govAgents.map(a => `governance-dashboard/${a.agent}`)];
1214
1259
  lines.push('---', '');
@@ -1247,7 +1292,7 @@ export function renderIntegrationAssessment(query, _simulationResult, platformRe
1247
1292
  }
1248
1293
  }
1249
1294
  else {
1250
- lines.push('*Integration analysis pending connector-hub agents not invoked.*', '');
1295
+ lines.push(`Integration assessment to be completed during technical spike. Key considerations: API authentication, rate limits, data format compatibility, error handling, and retry strategy for ${extracted.systems[0] || 'the target platform'}.`, '');
1251
1296
  }
1252
1297
  lines.push('## Edge & Resilience Patterns', '');
1253
1298
  if (edgeAgents.length > 0) {
@@ -1261,7 +1306,7 @@ export function renderIntegrationAssessment(query, _simulationResult, platformRe
1261
1306
  }
1262
1307
  }
1263
1308
  else {
1264
- lines.push('*Edge analysis pending edge agents not invoked.*', '');
1309
+ lines.push('Resilience patterns (circuit breakers, retry with backoff, failover) to be implemented during the build phase based on integration assessment findings.', '');
1265
1310
  }
1266
1311
  const sources = [...connectorAgents.map(a => `connector-hub/${a.agent}`), ...edgeAgents.map(a => `edge/${a.agent}`)];
1267
1312
  lines.push('---', '');