@llm-dev-ops/agentics-cli 2.3.0 โ 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pipeline/auto-chain.d.ts +117 -0
- package/dist/pipeline/auto-chain.d.ts.map +1 -1
- package/dist/pipeline/auto-chain.js +1047 -35
- package/dist/pipeline/auto-chain.js.map +1 -1
- package/dist/pipeline/phase2/phases/prompt-generator.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/prompt-generator.js +152 -6
- package/dist/pipeline/phase2/phases/prompt-generator.js.map +1 -1
- package/dist/pipeline/phase4-5-pre-render/financial-model.d.ts +51 -0
- package/dist/pipeline/phase4-5-pre-render/financial-model.d.ts.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/financial-model.js +118 -0
- package/dist/pipeline/phase4-5-pre-render/financial-model.js.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/post-render-reconciler.d.ts +53 -0
- package/dist/pipeline/phase4-5-pre-render/post-render-reconciler.d.ts.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/post-render-reconciler.js +130 -0
- package/dist/pipeline/phase4-5-pre-render/post-render-reconciler.js.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/pre-render-coordinator.d.ts +47 -0
- package/dist/pipeline/phase4-5-pre-render/pre-render-coordinator.d.ts.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/pre-render-coordinator.js +105 -0
- package/dist/pipeline/phase4-5-pre-render/pre-render-coordinator.js.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/sector-baselines.d.ts +42 -0
- package/dist/pipeline/phase4-5-pre-render/sector-baselines.d.ts.map +1 -0
- package/dist/pipeline/phase4-5-pre-render/sector-baselines.js +117 -0
- package/dist/pipeline/phase4-5-pre-render/sector-baselines.js.map +1 -0
- package/dist/pipeline/phase5-build/phases/post-generation-validator.d.ts.map +1 -1
- package/dist/pipeline/phase5-build/phases/post-generation-validator.js +341 -1
- package/dist/pipeline/phase5-build/phases/post-generation-validator.js.map +1 -1
- package/dist/pipeline/types.d.ts +4 -1
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/pipeline/types.js +9 -1
- package/dist/pipeline/types.js.map +1 -1
- package/dist/synthesis/domain-unit-registry.d.ts +1 -1
- package/dist/synthesis/domain-unit-registry.d.ts.map +1 -1
- package/dist/synthesis/domain-unit-registry.js +26 -0
- package/dist/synthesis/domain-unit-registry.js.map +1 -1
- package/dist/synthesis/financial-claim-extractor.d.ts +20 -0
- package/dist/synthesis/financial-claim-extractor.d.ts.map +1 -1
- package/dist/synthesis/financial-claim-extractor.js +31 -0
- package/dist/synthesis/financial-claim-extractor.js.map +1 -1
- package/dist/synthesis/financial-consistency-rules.d.ts +4 -0
- package/dist/synthesis/financial-consistency-rules.d.ts.map +1 -1
- package/dist/synthesis/financial-consistency-rules.js +51 -0
- package/dist/synthesis/financial-consistency-rules.js.map +1 -1
- package/dist/synthesis/roadmap-dates.d.ts +72 -0
- package/dist/synthesis/roadmap-dates.d.ts.map +1 -0
- package/dist/synthesis/roadmap-dates.js +203 -0
- package/dist/synthesis/roadmap-dates.js.map +1 -0
- package/dist/synthesis/simulation-artifact-generator.d.ts.map +1 -1
- package/dist/synthesis/simulation-artifact-generator.js +46 -0
- package/dist/synthesis/simulation-artifact-generator.js.map +1 -1
- package/dist/synthesis/simulation-renderers.d.ts.map +1 -1
- package/dist/synthesis/simulation-renderers.js +139 -34
- package/dist/synthesis/simulation-renderers.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
* permitted I/O path and never throws.
|
|
15
15
|
*/
|
|
16
16
|
import { loadUnitEconomics, buildFinancialModelFromUnitEconomics, enforceManifestConsistency, } from './unit-economics-loader.js';
|
|
17
|
+
import { fcvTag, countFcvTags } from './financial-claim-extractor.js';
|
|
17
18
|
import { classifyLaborIntensity, isLaborIntensive, workforceRiskTemplate, workforceRaciTemplate, workforceSensitivityRow, estimateWorkforceExposure, } from './domain-labor-classifier.js';
|
|
18
19
|
import { populateConsensusSnapshot, consensusBanner, consensusOpeningParagraph, whyNotMoreConfidentSection, consensusGate, analyticalUncertaintyRisk, } from './consensus-tiers.js';
|
|
20
|
+
import { resolvePilotStart, projectDates, } from './roadmap-dates.js';
|
|
19
21
|
// ============================================================================
|
|
20
22
|
// Helper: safe extraction from unknown agent responses
|
|
21
23
|
// ============================================================================
|
|
@@ -1238,6 +1240,24 @@ function extractCoreDomainNoun(query) {
|
|
|
1238
1240
|
*/
|
|
1239
1241
|
const SYNTHESIS_BASE_RULES = `You are a senior partner at McKinsey & Company rewriting an enterprise decision document.
|
|
1240
1242
|
|
|
1243
|
+
๐ CRITICAL โ PRESERVE HTML COMMENT TAGS (ADR-PIPELINE-073)
|
|
1244
|
+
|
|
1245
|
+
The skeleton document contains HTML comment tags like
|
|
1246
|
+
<!-- fcv:kind=investment scope=pilot doc=decision-memo -->
|
|
1247
|
+
These are financial consistency tags. You MUST:
|
|
1248
|
+
|
|
1249
|
+
1. NEVER remove or modify any <!-- fcv:... --> tag
|
|
1250
|
+
2. NEVER move a tag away from the money figure it precedes
|
|
1251
|
+
3. NEVER introduce a money figure without a preceding tag
|
|
1252
|
+
4. If you rewrite a section, keep every tag attached to its rewritten figure
|
|
1253
|
+
5. If you split a figure into two, duplicate the tag so each resulting line
|
|
1254
|
+
has its own tag
|
|
1255
|
+
6. NEVER change a tag's doc= value โ it must match the document type you
|
|
1256
|
+
are rewriting (executive-summary / decision-memo / financial-analysis)
|
|
1257
|
+
|
|
1258
|
+
These tags drive a downstream validator. If you remove or misplace them,
|
|
1259
|
+
the pipeline will discard your output and fall back to the skeleton.
|
|
1260
|
+
|
|
1241
1261
|
ABSOLUTE RULES โ violating any of these means the document fails:
|
|
1242
1262
|
1. Lead with the recommendation and quantified impact (Pyramid Principle)
|
|
1243
1263
|
2. Every financial figure MUST show its derivation (unit ร rate ร volume = total)
|
|
@@ -1250,7 +1270,7 @@ ABSOLUTE RULES โ violating any of these means the document fails:
|
|
|
1250
1270
|
9. No sentence fragments, no echoing the user's query, no template placeholders
|
|
1251
1271
|
10. Every paragraph must add insight or evidence, not just rearrange data points
|
|
1252
1272
|
|
|
1253
|
-
PRESERVE the markdown structure (headings, tables, bullet points) but REWRITE the prose.
|
|
1273
|
+
PRESERVE the markdown structure (headings, tables, bullet points, HTML comments) but REWRITE the prose.
|
|
1254
1274
|
Do NOT change financial figures โ keep the same numbers but improve how they're presented and justified.
|
|
1255
1275
|
Output ONLY the rewritten document โ no preamble, no commentary.`;
|
|
1256
1276
|
const SYNTHESIS_TYPE_INSTRUCTIONS = {
|
|
@@ -1294,6 +1314,11 @@ export async function synthesizeExecutiveDocument(skeleton, query, documentType,
|
|
|
1294
1314
|
'',
|
|
1295
1315
|
`DOCUMENT TO REWRITE:\n${skeleton}`,
|
|
1296
1316
|
].filter(Boolean).join('\n');
|
|
1317
|
+
// ADR-PIPELINE-073: tag-survival checking. We count fcv tags in the
|
|
1318
|
+
// skeleton before LLM synthesis and require the output to preserve the
|
|
1319
|
+
// same count. Any LLM output that drops a tag gets discarded โ fall
|
|
1320
|
+
// back to the skeleton rather than shipping an unlabeled document.
|
|
1321
|
+
const skeletonTagCount = countFcvTags(skeleton);
|
|
1297
1322
|
// Tier 1: Claude binary (uses user's Claude subscription, no API key needed)
|
|
1298
1323
|
try {
|
|
1299
1324
|
const { execSync } = await import('node:child_process');
|
|
@@ -1305,8 +1330,17 @@ export async function synthesizeExecutiveDocument(skeleton, query, documentType,
|
|
|
1305
1330
|
try {
|
|
1306
1331
|
const result = execSync(`${claudeBin} --print < "${tmpFile}"`, { encoding: 'utf-8', timeout: 90_000, maxBuffer: 1_000_000, shell: '/bin/sh' });
|
|
1307
1332
|
if (result && result.trim().length > skeleton.length * 0.3) {
|
|
1308
|
-
|
|
1309
|
-
|
|
1333
|
+
const trimmed = result.trim();
|
|
1334
|
+
const synthTagCount = countFcvTags(trimmed);
|
|
1335
|
+
if (synthTagCount < skeletonTagCount) {
|
|
1336
|
+
process.stderr.write(`[exec-docs] ADR-073 tag survival check FAILED for ${documentType} ` +
|
|
1337
|
+
`(skeleton=${skeletonTagCount} tags, synthesized=${synthTagCount}) โ ` +
|
|
1338
|
+
`discarding LLM output, using skeleton\n`);
|
|
1339
|
+
return skeleton;
|
|
1340
|
+
}
|
|
1341
|
+
process.stderr.write(`[exec-docs] LLM synthesis succeeded for ${documentType} ` +
|
|
1342
|
+
`(${trimmed.length} chars, ${synthTagCount} fcv tags preserved)\n`);
|
|
1343
|
+
return trimmed;
|
|
1310
1344
|
}
|
|
1311
1345
|
}
|
|
1312
1346
|
finally {
|
|
@@ -1342,7 +1376,16 @@ export async function synthesizeExecutiveDocument(skeleton, query, documentType,
|
|
|
1342
1376
|
const parsed = JSON.parse(result);
|
|
1343
1377
|
const text = parsed?.content?.[0]?.text;
|
|
1344
1378
|
if (text && text.length > skeleton.length * 0.3) {
|
|
1345
|
-
|
|
1379
|
+
// ADR-PIPELINE-073: tag-survival check on the API path too.
|
|
1380
|
+
const synthTagCount = countFcvTags(text);
|
|
1381
|
+
if (synthTagCount < skeletonTagCount) {
|
|
1382
|
+
process.stderr.write(`[exec-docs] ADR-073 tag survival check FAILED for ${documentType} ` +
|
|
1383
|
+
`(skeleton=${skeletonTagCount}, synthesized=${synthTagCount}) โ ` +
|
|
1384
|
+
`discarding API output, using skeleton\n`);
|
|
1385
|
+
return skeleton;
|
|
1386
|
+
}
|
|
1387
|
+
process.stderr.write(`[exec-docs] API synthesis succeeded for ${documentType} ` +
|
|
1388
|
+
`(${text.length} chars, ${synthTagCount} fcv tags preserved)\n`);
|
|
1346
1389
|
return text;
|
|
1347
1390
|
}
|
|
1348
1391
|
}
|
|
@@ -1404,15 +1447,22 @@ export function renderExecutiveSummary(query, simulationResult, platformResults)
|
|
|
1404
1447
|
lines.push('', opening);
|
|
1405
1448
|
}
|
|
1406
1449
|
if (fin.hasData) {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1450
|
+
// ADR-PIPELINE-073: split the impact line into per-metric bullets so
|
|
1451
|
+
// each gets its own authoritative fcv tag. One tag per line; the
|
|
1452
|
+
// extractor reads the inline tag as the kind/scope of the first money
|
|
1453
|
+
// match on the line.
|
|
1454
|
+
if (fin.budget || fin.payback || fin.npv) {
|
|
1455
|
+
lines.push('Projected impact:');
|
|
1456
|
+
if (fin.budget) {
|
|
1457
|
+
lines.push(`- ${fcvTag('investment', 'full-program', 'executive-summary')} ${fin.budget} investment`);
|
|
1458
|
+
}
|
|
1459
|
+
if (fin.payback) {
|
|
1460
|
+
lines.push(`- ${fcvTag('timeline', 'full-program', 'executive-summary')} ${fin.payback} payback`);
|
|
1461
|
+
}
|
|
1462
|
+
if (fin.npv) {
|
|
1463
|
+
lines.push(`- ${fcvTag('npv', 'full-program', 'executive-summary')} ${fin.npv} 5-year NPV`);
|
|
1464
|
+
}
|
|
1465
|
+
lines.push('');
|
|
1416
1466
|
}
|
|
1417
1467
|
}
|
|
1418
1468
|
// ADR-PIPELINE-025 ยง4: Success probability with domain-aware decomposition
|
|
@@ -1474,21 +1524,25 @@ export function renderExecutiveSummary(query, simulationResult, platformResults)
|
|
|
1474
1524
|
}
|
|
1475
1525
|
lines.push('');
|
|
1476
1526
|
// Financial Impact
|
|
1527
|
+
// ADR-PIPELINE-073: every money cell gets an inline fcv tag so FCR-011
|
|
1528
|
+
// doesn't fire on the rendered output. All rows here describe the
|
|
1529
|
+
// program-level figures (Total Investment, 5-Year NPV, etc.) so they
|
|
1530
|
+
// carry scope=full-program.
|
|
1477
1531
|
if (fin.hasData) {
|
|
1478
1532
|
lines.push('## Financial Impact', '');
|
|
1479
1533
|
lines.push('| Metric | Value |', '|--------|-------|');
|
|
1480
1534
|
if (fin.budget)
|
|
1481
|
-
lines.push(`| Total Investment | ${fin.budget} |`);
|
|
1535
|
+
lines.push(`| Total Investment | ${fcvTag('investment', 'full-program', 'executive-summary')} ${fin.budget} |`);
|
|
1482
1536
|
if (fin.roi)
|
|
1483
|
-
lines.push(`| Expected ROI | ${fin.roi} |`);
|
|
1537
|
+
lines.push(`| Expected ROI | ${fcvTag('roi', 'full-program', 'executive-summary')} ${fin.roi} |`);
|
|
1484
1538
|
if (fin.npv)
|
|
1485
|
-
lines.push(`| 5-Year NPV | ${fin.npv} |`);
|
|
1539
|
+
lines.push(`| 5-Year NPV | ${fcvTag('npv', 'full-program', 'executive-summary')} ${fin.npv} |`);
|
|
1486
1540
|
if (fin.payback)
|
|
1487
|
-
lines.push(`| Payback Period | ${fin.payback} |`);
|
|
1541
|
+
lines.push(`| Payback Period | ${fcvTag('timeline', 'full-program', 'executive-summary')} ${fin.payback} |`);
|
|
1488
1542
|
if (fin.revenue)
|
|
1489
|
-
lines.push(`| Revenue Impact | ${fin.revenue} |`);
|
|
1543
|
+
lines.push(`| Revenue Impact | ${fcvTag('savings', 'full-program', 'executive-summary')} ${fin.revenue} |`);
|
|
1490
1544
|
if (fin.costSavings)
|
|
1491
|
-
lines.push(`| Cost Savings | ${fin.costSavings} |`);
|
|
1545
|
+
lines.push(`| Cost Savings | ${fcvTag('savings', 'full-program', 'executive-summary')} ${fin.costSavings} |`);
|
|
1492
1546
|
lines.push('');
|
|
1493
1547
|
}
|
|
1494
1548
|
// Risk Profile โ never empty
|
|
@@ -1626,23 +1680,28 @@ export function renderDecisionMemo(query, simulationResult, platformResults) {
|
|
|
1626
1680
|
const fmt = (n) => n >= 1_000_000 ? `$${(n / 1_000_000).toFixed(1)}M` : `$${(n / 1000).toFixed(0)}K`;
|
|
1627
1681
|
pilotBudget = `${fmt(pilotVal)} - ${fmt(pilotVal * 1.5)}`;
|
|
1628
1682
|
}
|
|
1629
|
-
|
|
1630
|
-
//
|
|
1683
|
+
// ADR-PIPELINE-073: Options Considered rows carry distinct scope labels โ
|
|
1684
|
+
// row A is the pilot, row B is the full program, row C has a savings
|
|
1685
|
+
// figure scoped to full-program. Each row gets an inline fcv tag so
|
|
1686
|
+
// FCR-001/003 can cross-check them against the executive summary.
|
|
1687
|
+
lines.push(`| **A. Scoped Pilot** | Validate with subset of data and ${extracted.domain_entities.slice(0, 2).join(', ') || 'core entities'} | ${fcvTag('investment', 'pilot', 'decision-memo')} ${pilotBudget} | 8-12 weeks | Low | **Recommended** |`, `| **B. Full Deployment** | Enterprise-wide rollout across all ${extracted.systems.length > 0 ? extracted.systems.join(', ') : 'systems'} | ${fcvTag('investment', 'full-program', 'decision-memo')} ${fullBudget} | ${safeString(simData, 'timeline_estimate') || '16-24 weeks'} | Medium | After pilot validation |`, `| **C. Do Nothing** | Continue with manual processes | $0 upfront | N/A | High | Not recommended โ ${fin.costSavings ? fcvTag('savings', 'full-program', 'decision-memo') + ' ' + fin.costSavings + ' annual waste continues' : fin.revenue ? fcvTag('savings', 'full-program', 'decision-memo') + ' ' + fin.revenue + ' in annual savings foregone' : 'costs compound without intervention'} |`, '');
|
|
1688
|
+
// Financial Impact โ ADR-PIPELINE-073: every row gets an inline fcv tag
|
|
1689
|
+
// with scope=full-program (the table describes the overall program cost).
|
|
1631
1690
|
lines.push('## Financial Impact', '');
|
|
1632
1691
|
if (fin.hasData) {
|
|
1633
1692
|
lines.push('| Metric | Value |', '|--------|-------|');
|
|
1634
1693
|
if (fin.budget)
|
|
1635
|
-
lines.push(`| Total Investment | ${fin.budget} |`);
|
|
1694
|
+
lines.push(`| Total Investment | ${fcvTag('investment', 'full-program', 'decision-memo')} ${fin.budget} |`);
|
|
1636
1695
|
if (fin.roi)
|
|
1637
|
-
lines.push(`| Expected ROI | ${fin.roi} |`);
|
|
1696
|
+
lines.push(`| Expected ROI | ${fcvTag('roi', 'full-program', 'decision-memo')} ${fin.roi} |`);
|
|
1638
1697
|
if (fin.npv)
|
|
1639
|
-
lines.push(`| 5-Year NPV | ${fin.npv} |`);
|
|
1698
|
+
lines.push(`| 5-Year NPV | ${fcvTag('npv', 'full-program', 'decision-memo')} ${fin.npv} |`);
|
|
1640
1699
|
if (fin.payback)
|
|
1641
|
-
lines.push(`| Payback Period | ${fin.payback} |`);
|
|
1700
|
+
lines.push(`| Payback Period | ${fcvTag('timeline', 'full-program', 'decision-memo')} ${fin.payback} |`);
|
|
1642
1701
|
if (fin.revenue)
|
|
1643
|
-
lines.push(`| Revenue Impact | ${fin.revenue} |`);
|
|
1702
|
+
lines.push(`| Revenue Impact | ${fcvTag('savings', 'full-program', 'decision-memo')} ${fin.revenue} |`);
|
|
1644
1703
|
if (fin.costSavings)
|
|
1645
|
-
lines.push(`| Cost Savings | ${fin.costSavings} |`);
|
|
1704
|
+
lines.push(`| Cost Savings | ${fcvTag('savings', 'full-program', 'decision-memo')} ${fin.costSavings} |`);
|
|
1646
1705
|
lines.push('');
|
|
1647
1706
|
}
|
|
1648
1707
|
else {
|
|
@@ -3001,6 +3060,40 @@ export function buildRoadmapArtifact(query, simulationResult, platformResults) {
|
|
|
3001
3060
|
// ADR-PIPELINE-071: Week-4 consensus gate on contested runs.
|
|
3002
3061
|
const roadmapConsensus = populateConsensusSnapshot(simulationResult, platformResults);
|
|
3003
3062
|
const consensusGateInfo = consensusGate(roadmapConsensus);
|
|
3063
|
+
// ADR-PIPELINE-079: Resolve pilot start date and project absolute dates
|
|
3064
|
+
// onto every phase + gate so the roadmap anchors to real calendar dates.
|
|
3065
|
+
const pilotStart = resolvePilotStart(query, null, null);
|
|
3066
|
+
const { datedPhases, datedGates } = projectDates(pilotStart.startDate, defaultPhases.map(p => ({
|
|
3067
|
+
id: p['id'] ?? 'phase',
|
|
3068
|
+
name: p['name'] ?? 'Phase',
|
|
3069
|
+
duration: p['duration'] ?? '3 weeks',
|
|
3070
|
+
})));
|
|
3071
|
+
// Enrich the default phases with absolute dates
|
|
3072
|
+
const enrichedPhases = defaultPhases.map((phase, i) => {
|
|
3073
|
+
const dated = datedPhases[i];
|
|
3074
|
+
if (!dated)
|
|
3075
|
+
return phase;
|
|
3076
|
+
return {
|
|
3077
|
+
...phase,
|
|
3078
|
+
startDate: dated.startDate,
|
|
3079
|
+
endDate: dated.endDate,
|
|
3080
|
+
durationWeeks: dated.durationWeeks,
|
|
3081
|
+
};
|
|
3082
|
+
});
|
|
3083
|
+
// Enrich the phase gates with absolute dates
|
|
3084
|
+
const gates = buildPhaseGates(query, extracted, primarySystem);
|
|
3085
|
+
const enrichedGates = gates.map((gate) => {
|
|
3086
|
+
const afterPhase = gate.after_phase;
|
|
3087
|
+
const datedGate = datedGates.find(g => g.afterPhase === afterPhase);
|
|
3088
|
+
return {
|
|
3089
|
+
after_phase: gate.after_phase,
|
|
3090
|
+
gate: gate.gate,
|
|
3091
|
+
criteria: gate.criteria,
|
|
3092
|
+
decision_authority: gate.decision_authority,
|
|
3093
|
+
overall_decision: gate.overall_decision,
|
|
3094
|
+
...(datedGate ? { gate_date: datedGate.gateDate } : {}),
|
|
3095
|
+
};
|
|
3096
|
+
});
|
|
3004
3097
|
return {
|
|
3005
3098
|
metadata: {
|
|
3006
3099
|
title: `Roadmap: ${query}`,
|
|
@@ -3009,7 +3102,13 @@ export function buildRoadmapArtifact(query, simulationResult, platformResults) {
|
|
|
3009
3102
|
estimated_duration: timeline,
|
|
3010
3103
|
status: 'draft',
|
|
3011
3104
|
},
|
|
3012
|
-
|
|
3105
|
+
// ADR-PIPELINE-079: absolute pilot start date with source metadata
|
|
3106
|
+
pilot_start: {
|
|
3107
|
+
date: pilotStart.startDate,
|
|
3108
|
+
source: pilotStart.source,
|
|
3109
|
+
reasoning: pilotStart.reasoning,
|
|
3110
|
+
},
|
|
3111
|
+
phases: enrichedPhases,
|
|
3013
3112
|
success_criteria: safeArray(simData, 'recommendations').map(r => String(r)),
|
|
3014
3113
|
// ADR-PIPELINE-024: Always include domain-appropriate risks
|
|
3015
3114
|
risk_factors: generateDomainRisks(query, extracted).map(r => ({
|
|
@@ -3027,8 +3126,7 @@ export function buildRoadmapArtifact(query, simulationResult, platformResults) {
|
|
|
3027
3126
|
implementation_plan: extractAgentData(platformResults, 'copilot', 'planner'),
|
|
3028
3127
|
resource_requirements: extractAgentData(platformResults, 'costops', 'budget'),
|
|
3029
3128
|
// ADR-PIPELINE-061: Quantified phase gate criteria with derived decision authority
|
|
3030
|
-
|
|
3031
|
-
phase_gates: buildPhaseGates(query, extracted, primarySystem),
|
|
3129
|
+
phase_gates: enrichedGates,
|
|
3032
3130
|
// ADR-PIPELINE-071: Consensus tier metadata + Week-4 gate when contested.
|
|
3033
3131
|
consensus: {
|
|
3034
3132
|
tier: roadmapConsensus.tier,
|
|
@@ -3425,7 +3523,10 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
|
|
|
3425
3523
|
lines.push('> โ ๏ธ **Unit economics consistency warnings:**', ...manifestWarnings.map(v => `> - ${v}`), '');
|
|
3426
3524
|
}
|
|
3427
3525
|
}
|
|
3428
|
-
|
|
3526
|
+
// ADR-PIPELINE-073: tag every row in the financial-analysis Investment
|
|
3527
|
+
// Summary table with inline fcv comments. Kind-specific scopes so the
|
|
3528
|
+
// extractor + FCR-011 / FCR-012 see authoritative labels.
|
|
3529
|
+
lines.push('---', '', `## Investment Summary${fin.isEstimated ? ' (Estimated from Organization Profile)' : unitEconomicsSource === 'manifest' ? ' (from Prototype Unit Economics)' : ''}`, '', '| Metric | Value |', '|--------|-------|', `| Total Investment | ${fcvTag('investment', 'full-program', 'financial-analysis')} ${fin.budget} |`, `| Expected ROI | ${fcvTag('roi', 'full-program', 'financial-analysis')} ${fin.roi} |`, `| 5-Year NPV | ${fcvTag('npv', 'full-program', 'financial-analysis')} ${fin.npv} |`, `| Payback Period | ${fcvTag('timeline', 'full-program', 'financial-analysis')} ${fin.payback} |`, `| Revenue / Savings Impact | ${fcvTag('savings', 'full-program', 'financial-analysis')} ${fin.revenue || fin.costSavings} |`, '');
|
|
3429
3530
|
// ADR-PIPELINE-070: Workforce exposure block when intensity โฅ medium.
|
|
3430
3531
|
// Mandatory for hospitality/retail/fleet/healthcare/CRE/etc. โ calls out
|
|
3431
3532
|
// role count, EMEA union exposure, change-mgmt budget, and reallocation
|
|
@@ -3532,9 +3633,13 @@ export function renderFinancialAnalysis(query, simulationResult, platformResults
|
|
|
3532
3633
|
pessCostStr = fmt(baseVal * 1.4);
|
|
3533
3634
|
}
|
|
3534
3635
|
}
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3636
|
+
// ADR-PIPELINE-073: tag scenario rows so they're not flagged as untagged
|
|
3637
|
+
// money figures. All three variants describe the full-program cost; the
|
|
3638
|
+
// variance is visible in the prose ("ยฑ20% cost variance"), not the scope.
|
|
3639
|
+
const scenarioTag = fcvTag('investment', 'full-program', 'financial-analysis');
|
|
3640
|
+
lines.push(`| **Base Case** | Plan executes as modeled | ${scenarioTag} ${baseCostStr} | ${fin.roi || 'Projected'} | 50% |`);
|
|
3641
|
+
lines.push(`| Optimistic | Faster adoption, lower integration costs | ${scenarioTag} ${optCostStr} | ${fin.roi ? fin.roi.replace(/\d+/, m => String(Math.round(parseInt(m) * 1.3))) : 'Above base'} | 25% |`);
|
|
3642
|
+
lines.push(`| Pessimistic | Slower adoption, scope growth | ${scenarioTag} ${pessCostStr} | ${fin.roi ? fin.roi.replace(/\d+/, m => String(Math.round(parseInt(m) * 0.6))) : 'Below base'} | 25% |`);
|
|
3538
3643
|
lines.push('', '*Scenario analysis assumes ยฑ20% cost variance and ยฑ30% timeline variance from base case.*', '');
|
|
3539
3644
|
// ADR-PIPELINE-063: Multi-variable sensitivity tornado
|
|
3540
3645
|
// Implements ADR-PIPELINE-057 ยง1 โ replaces the old single-variable loop
|