@llm-dev-ops/agentics-cli 2.7.36 → 2.7.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/cli/index.js +1 -1
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/commands/agents.d.ts.map +1 -1
  4. package/dist/commands/agents.js +24 -70
  5. package/dist/commands/agents.js.map +1 -1
  6. package/dist/mcp/agent-event-parser.d.ts +1 -11
  7. package/dist/mcp/agent-event-parser.d.ts.map +1 -1
  8. package/dist/mcp/agent-event-parser.js +7 -153
  9. package/dist/mcp/agent-event-parser.js.map +1 -1
  10. package/dist/mcp/mcp-server.js +0 -58
  11. package/dist/mcp/mcp-server.js.map +1 -1
  12. package/dist/pipeline/auto-chain.d.ts.map +1 -1
  13. package/dist/pipeline/auto-chain.js +27 -169
  14. package/dist/pipeline/auto-chain.js.map +1 -1
  15. package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts +21 -18
  16. package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts.map +1 -1
  17. package/dist/pipeline/local-fallback/phase5a-local-fallback.js +92 -397
  18. package/dist/pipeline/local-fallback/phase5a-local-fallback.js.map +1 -1
  19. package/dist/pipeline/phase2/phases/adr-generator.d.ts +29 -1
  20. package/dist/pipeline/phase2/phases/adr-generator.d.ts.map +1 -1
  21. package/dist/pipeline/phase2/phases/adr-generator.js +709 -1399
  22. package/dist/pipeline/phase2/phases/adr-generator.js.map +1 -1
  23. package/dist/pipeline/phase2/phases/ddd-generator.d.ts.map +1 -1
  24. package/dist/pipeline/phase2/phases/ddd-generator.js +7 -42
  25. package/dist/pipeline/phase2/phases/ddd-generator.js.map +1 -1
  26. package/dist/pipeline/phase2/phases/research-dossier.d.ts.map +1 -1
  27. package/dist/pipeline/phase2/phases/research-dossier.js +2 -33
  28. package/dist/pipeline/phase2/phases/research-dossier.js.map +1 -1
  29. package/dist/pipeline/phase2/phases/sparc-specification.d.ts.map +1 -1
  30. package/dist/pipeline/phase2/phases/sparc-specification.js +2 -27
  31. package/dist/pipeline/phase2/phases/sparc-specification.js.map +1 -1
  32. package/dist/pipeline/phase2/types.d.ts +19 -57
  33. package/dist/pipeline/phase2/types.d.ts.map +1 -1
  34. package/dist/pipeline/phase4-adrs/adr-index-extractor.d.ts +75 -0
  35. package/dist/pipeline/phase4-adrs/adr-index-extractor.d.ts.map +1 -0
  36. package/dist/pipeline/phase4-adrs/adr-index-extractor.js +200 -0
  37. package/dist/pipeline/phase4-adrs/adr-index-extractor.js.map +1 -0
  38. package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.d.ts.map +1 -1
  39. package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.js +70 -68
  40. package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.js.map +1 -1
  41. package/dist/pipeline/phases/adr-ddd-generator.d.ts.map +1 -1
  42. package/dist/pipeline/phases/adr-ddd-generator.js +48 -2
  43. package/dist/pipeline/phases/adr-ddd-generator.js.map +1 -1
  44. package/dist/pipeline/phases/prompt-generator.js +191 -80
  45. package/dist/pipeline/phases/prompt-generator.js.map +1 -1
  46. package/dist/pipeline/ruflo-phase-executor.d.ts.map +1 -1
  47. package/dist/pipeline/ruflo-phase-executor.js +69 -17
  48. package/dist/pipeline/ruflo-phase-executor.js.map +1 -1
  49. package/dist/pipeline/types.d.ts +14 -1
  50. package/dist/pipeline/types.d.ts.map +1 -1
  51. package/dist/synthesis/ask-artifact-writer.d.ts +1 -1
  52. package/dist/synthesis/ask-artifact-writer.d.ts.map +1 -1
  53. package/dist/synthesis/ask-artifact-writer.js +9 -9
  54. package/dist/synthesis/ask-artifact-writer.js.map +1 -1
  55. package/dist/synthesis/simulation-artifact-generator.d.ts +1 -27
  56. package/dist/synthesis/simulation-artifact-generator.d.ts.map +1 -1
  57. package/dist/synthesis/simulation-artifact-generator.js +38 -128
  58. package/dist/synthesis/simulation-artifact-generator.js.map +1 -1
  59. package/package.json +1 -1
  60. package/dist/cli/ui/heartbeat.d.ts +0 -88
  61. package/dist/cli/ui/heartbeat.d.ts.map +0 -1
  62. package/dist/cli/ui/heartbeat.js +0 -158
  63. package/dist/cli/ui/heartbeat.js.map +0 -1
  64. package/dist/synthesis/agent-fleet-decomposer.d.ts +0 -124
  65. package/dist/synthesis/agent-fleet-decomposer.d.ts.map +0 -1
  66. package/dist/synthesis/agent-fleet-decomposer.js +0 -696
  67. package/dist/synthesis/agent-fleet-decomposer.js.map +0 -1
@@ -1,25 +1,28 @@
1
1
  /**
2
- * ADR-PIPELINE-094 Decision 8 + ADR-PIPELINE-099 D1+D2 — Phase 5a fallback.
2
+ * ADR-PIPELINE-094 Decision 8 — Phase 5a local fallback generator.
3
3
  *
4
- * Produces N coherent implementation prompts (≥4 in every code path; ≥6 when
5
- * the fleet decomposer + planner outputs are present) plus a valid
6
- * `prompts/execution-plan.json`. Replaces the pre-099 single-prompt
7
- * `impl-001-phase1-consensus.md` dump that the user reported as
8
- * "thumbs up thumbs down garbage".
4
+ * Produces minimal implementation prompts (`prompts/impl-001-*.md`) and
5
+ * `prompts/execution-plan.json` from Phase-1 simulator consensus when Ruflo
6
+ * is unavailable. Output is sufficient to satisfy ADR-094 Decision 3's
7
+ * Phase 5b hard-block (`phase5a/execution-plan.json` 50 bytes).
9
8
  *
10
- * Precedence inside this module (mirrors ADR-099 §D1):
11
- * tier-3: agent-fleet decomposition (decomposer.sub_objectives +
12
- * planner.steps + clarifier.assumptions). Emits ≥6 prompts when
13
- * the fleet returned ≥6 sub-objectives.
14
- * tier-4: success-criterion fan-out — one prompt per
15
- * `scenario.success_criteria[]` entry, with manifest brief +
16
- * decision-memo + scenario inlined as guardrails. Emits ≥4
17
- * prompts when at least 4 success criteria are present.
9
+ * The prompt-generator already has its own Phase-1 fallback path
10
+ * (ADR-094 D2). This module exists for the case where the gate's Ruflo
11
+ * invocation hits us before the prompt-generator runs — typically via
12
+ * `runPrimaryPhaseExecution(phase5a-prompts, ...)` on the unavailable path.
18
13
  *
19
- * The two earlier tiers (Ruflo writer-agent and ADR/DDD/SPARC chain) live
20
- * in the prompt-generator and the auto-chain phase 4.5 block; this fallback
21
- * only runs when both of them produced nothing.
14
+ * For consistency with the prompt-generator, output paths and the prompt
15
+ * frontmatter shape match D2's output.
22
16
  */
23
17
  import type { LocalFallbackResult } from './phase3-local-fallback.js';
24
- export declare function runPhase5aLocalFallback(runDir: string, queryOverride?: string): LocalFallbackResult;
18
+ /**
19
+ * Run the Phase-5a fallback. Writes:
20
+ * - phase5a/execution-plan.json
21
+ * - prompts/impl-001-phase1-consensus.md
22
+ *
23
+ * If `phase5a/execution-plan.json` already exists (e.g. from the
24
+ * prompt-generator's D2 path), this is a no-op success — we never overwrite
25
+ * a richer execution plan with a fallback one.
26
+ */
27
+ export declare function runPhase5aLocalFallback(runDir: string): LocalFallbackResult;
25
28
  //# sourceMappingURL=phase5a-local-fallback.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"phase5a-local-fallback.d.ts","sourceRoot":"","sources":["../../../src/pipeline/local-fallback/phase5a-local-fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAatE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAwKnG"}
1
+ {"version":3,"file":"phase5a-local-fallback.d.ts","sourceRoot":"","sources":["../../../src/pipeline/local-fallback/phase5a-local-fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAyE3E"}
@@ -1,33 +1,35 @@
1
1
  /**
2
- * ADR-PIPELINE-094 Decision 8 + ADR-PIPELINE-099 D1+D2 — Phase 5a fallback.
2
+ * ADR-PIPELINE-094 Decision 8 — Phase 5a local fallback generator.
3
3
  *
4
- * Produces N coherent implementation prompts (≥4 in every code path; ≥6 when
5
- * the fleet decomposer + planner outputs are present) plus a valid
6
- * `prompts/execution-plan.json`. Replaces the pre-099 single-prompt
7
- * `impl-001-phase1-consensus.md` dump that the user reported as
8
- * "thumbs up thumbs down garbage".
4
+ * Produces minimal implementation prompts (`prompts/impl-001-*.md`) and
5
+ * `prompts/execution-plan.json` from Phase-1 simulator consensus when Ruflo
6
+ * is unavailable. Output is sufficient to satisfy ADR-094 Decision 3's
7
+ * Phase 5b hard-block (`phase5a/execution-plan.json` 50 bytes).
9
8
  *
10
- * Precedence inside this module (mirrors ADR-099 §D1):
11
- * tier-3: agent-fleet decomposition (decomposer.sub_objectives +
12
- * planner.steps + clarifier.assumptions). Emits ≥6 prompts when
13
- * the fleet returned ≥6 sub-objectives.
14
- * tier-4: success-criterion fan-out — one prompt per
15
- * `scenario.success_criteria[]` entry, with manifest brief +
16
- * decision-memo + scenario inlined as guardrails. Emits ≥4
17
- * prompts when at least 4 success criteria are present.
9
+ * The prompt-generator already has its own Phase-1 fallback path
10
+ * (ADR-094 D2). This module exists for the case where the gate's Ruflo
11
+ * invocation hits us before the prompt-generator runs — typically via
12
+ * `runPrimaryPhaseExecution(phase5a-prompts, ...)` on the unavailable path.
18
13
  *
19
- * The two earlier tiers (Ruflo writer-agent and ADR/DDD/SPARC chain) live
20
- * in the prompt-generator and the auto-chain phase 4.5 block; this fallback
21
- * only runs when both of them produced nothing.
14
+ * For consistency with the prompt-generator, output paths and the prompt
15
+ * frontmatter shape match D2's output.
22
16
  */
23
17
  import * as fs from 'node:fs';
24
18
  import * as path from 'node:path';
25
19
  import { readPhase1Consensus, extractScenarioQuery } from './phase1-consensus-reader.js';
26
- import { decomposeAgentFleet, renderUnitPromptMarkdown } from '../../synthesis/agent-fleet-decomposer.js';
27
- export function runPhase5aLocalFallback(runDir, queryOverride) {
20
+ /**
21
+ * Run the Phase-5a fallback. Writes:
22
+ * - phase5a/execution-plan.json
23
+ * - prompts/impl-001-phase1-consensus.md
24
+ *
25
+ * If `phase5a/execution-plan.json` already exists (e.g. from the
26
+ * prompt-generator's D2 path), this is a no-op success — we never overwrite
27
+ * a richer execution plan with a fallback one.
28
+ */
29
+ export function runPhase5aLocalFallback(runDir) {
28
30
  const filesWritten = [];
29
31
  // Skip if the canonical artifacts already exist (the prompt-generator's
30
- // ADR-094 D2 path may have produced them).
32
+ // D2 fallback path may have produced them).
31
33
  const existingPlan = path.join(runDir, 'phase5a', 'execution-plan.json');
32
34
  if (fs.existsSync(existingPlan) && fs.statSync(existingPlan).size > 50) {
33
35
  return {
@@ -45,115 +47,37 @@ export function runPhase5aLocalFallback(runDir, queryOverride) {
45
47
  message: 'Phase-5a local fallback: no Phase-1 consensus on disk',
46
48
  };
47
49
  }
48
- // Caller-supplied query (the user's original `agentics ask` brief) takes
49
- // precedence over scenario.json, since the prompt-generator's D2 entry
50
- // point carries the canonical PipelineContext.query and Phase-1 may not
51
- // have written scenario.json with a `summary` field.
52
- const query = queryOverride || extractScenarioQuery(consensus) || '';
53
- const promptsDir = path.join(runDir, 'prompts');
54
- const phase5aDir = path.join(runDir, 'phase5a');
50
+ const query = extractScenarioQuery(consensus) || '';
55
51
  try {
52
+ // ── Implementation prompt ─────────────────────────────────────────────
53
+ const promptsDir = path.join(runDir, 'prompts');
56
54
  fs.mkdirSync(promptsDir, { recursive: true });
55
+ const promptId = 'impl-001-phase1-consensus';
56
+ const promptBody = buildPhase1FallbackPromptMarkdown(query, consensus.decisionMemo, consensus.scenario, consensus.executiveSummary);
57
+ fs.writeFileSync(path.join(promptsDir, `${promptId}.md`), promptBody, 'utf8');
58
+ filesWritten.push(`prompts/${promptId}.md`);
59
+ // ── Execution plan ────────────────────────────────────────────────────
60
+ const phase5aDir = path.join(runDir, 'phase5a');
57
61
  fs.mkdirSync(phase5aDir, { recursive: true });
58
- const promptEntries = [];
59
- // ── Tier 3: agent-fleet decomposition ────────────────────────────────
60
- const decomp = decomposeAgentFleet(runDir, query);
61
- if (decomp.units.length > 0) {
62
- decomp.units.forEach((unit, idx) => {
63
- const order = idx + 1;
64
- const filename = `impl-${pad3(order)}-${unit.slug}.md`;
65
- const body = renderUnitPromptMarkdown(unit, order, decomp.units.length, decomp.context, [], []);
66
- fs.writeFileSync(path.join(promptsDir, filename), body, 'utf-8');
67
- filesWritten.push(`prompts/${filename}`);
68
- promptEntries.push({
69
- id: unit.id,
70
- title: unit.title,
71
- order,
72
- path: `prompts/${filename}`,
73
- source: unit.sourceAgent,
74
- tier: unit.tier,
75
- dependencies: unit.dependencies,
76
- });
77
- });
78
- process.stderr.write(` [PROMPTS] Phase-5a tier-3 (agent-fleet): wrote ${decomp.units.length} prompts ` +
79
- `(decomposer=${decomp.provenance.decomposerCount}, planner=${decomp.provenance.plannerCount}, ` +
80
- `assumptions=${decomp.provenance.clarifierAssumptionsCount})\n`);
81
- }
82
- // ── Tier 4: success-criterion fan-out ────────────────────────────────
83
- // If tier-3 didn't reach the ≥6 floor, supplement with one prompt per
84
- // success-criterion. Even when tier-3 produced ≥6 we DON'T add tier-4
85
- // — too many prompts dilutes the build plan.
86
- if (promptEntries.length < 6) {
87
- const successCriteria = extractSuccessCriteriaList(consensus);
88
- const startingOrder = promptEntries.length + 1;
89
- successCriteria.forEach((criterion, idx) => {
90
- const order = startingOrder + idx;
91
- const slug = slugify(`validate-${criterion}`) || `success-criterion-${idx + 1}`;
92
- const filename = `impl-${pad3(order)}-${slug}.md`;
93
- const body = renderSuccessCriterionPrompt(order, startingOrder + successCriteria.length - 1, criterion, query, consensus.executiveSummary, consensus.decisionMemo, promptEntries.map(p => p.id));
94
- fs.writeFileSync(path.join(promptsDir, filename), body, 'utf-8');
95
- filesWritten.push(`prompts/${filename}`);
96
- promptEntries.push({
97
- id: `unit-${pad3(order)}-${slug}`,
98
- title: `Validate success criterion: ${truncate(criterion, 60)}`,
99
- order,
100
- path: `prompts/${filename}`,
101
- source: 'phase1/scenario.success_criteria',
102
- tier: 'validation',
103
- dependencies: promptEntries.length > 0 ? [promptEntries[0].id] : [],
104
- });
105
- });
106
- if (successCriteria.length > 0) {
107
- process.stderr.write(` [PROMPTS] Phase-5a tier-4 (success-criteria): wrote ${successCriteria.length} validation prompts ` +
108
- `(total now: ${promptEntries.length})\n`);
109
- }
110
- }
111
- // ── Last-resort safety net ───────────────────────────────────────────
112
- // If even tier-3 + tier-4 produced fewer than 4 prompts, synthesize
113
- // from the executive summary + decision memo + scenario.json — but
114
- // split into 4 distinct prompts (foundation, integration, domain,
115
- // validation), NEVER one. The pre-ADR-099 single-prompt path is gone.
116
- if (promptEntries.length < 4) {
117
- const synth = synthesizeMinimumFourPrompts(query, consensus);
118
- synth.forEach((p, idx) => {
119
- const order = promptEntries.length + idx + 1;
120
- const filename = `impl-${pad3(order)}-${p.slug}.md`;
121
- fs.writeFileSync(path.join(promptsDir, filename), p.body, 'utf-8');
122
- filesWritten.push(`prompts/${filename}`);
123
- promptEntries.push({
124
- id: `unit-${pad3(order)}-${p.slug}`,
125
- title: p.title,
126
- order,
127
- path: `prompts/${filename}`,
128
- source: 'phase1-fallback-synthesis',
129
- tier: p.tier,
130
- dependencies: p.dependsOnFirst && promptEntries.length > 0 ? [promptEntries[0].id] : [],
131
- });
132
- });
133
- process.stderr.write(` [PROMPTS] Phase-5a tier-5 (minimum-4 synthesis): wrote ${synth.length} prompts ` +
134
- `(total now: ${promptEntries.length})\n`);
135
- }
136
- // ── Execution plan (legacy + canonical paths) ────────────────────────
137
62
  const executionPlan = {
138
- generator: decomp.units.length > 0 ? 'agent-fleet' : 'phase1-fallback-multi',
139
- quality: decomp.units.length > 0 ? 'directional' : 'degraded',
140
- totalSteps: promptEntries.length,
141
- estimatedDuration: `${promptEntries.length * 5}-${promptEntries.length * 15} minutes`,
142
- implementations: promptEntries.map(e => ({
143
- id: e.id,
144
- title: e.title,
145
- boundedContext: e.tier,
146
- source: e.source,
147
- order: e.order,
148
- path: e.path,
149
- dependencies: e.dependencies,
150
- })),
151
- provenance: decomp.provenance,
63
+ generator: 'local-fallback',
64
+ quality: 'degraded',
65
+ totalSteps: 1,
66
+ estimatedDuration: '5-15 minutes',
67
+ implementations: [{
68
+ id: promptId,
69
+ title: 'Implementation: Phase-1 consensus',
70
+ boundedContext: 'phase1-consensus',
71
+ source: 'phase1-consensus',
72
+ order: 1,
73
+ path: `prompts/${promptId}.md`,
74
+ }],
152
75
  };
153
76
  const planJson = JSON.stringify(executionPlan, null, 2);
154
- fs.writeFileSync(path.join(phase5aDir, 'execution-plan.json'), planJson, 'utf-8');
77
+ fs.writeFileSync(path.join(phase5aDir, 'execution-plan.json'), planJson, 'utf8');
155
78
  filesWritten.push('phase5a/execution-plan.json');
156
- fs.writeFileSync(path.join(promptsDir, 'execution-plan.json'), planJson, 'utf-8');
79
+ // Also mirror execution-plan into prompts/ for legacy consumers.
80
+ fs.writeFileSync(path.join(promptsDir, 'execution-plan.json'), planJson, 'utf8');
157
81
  filesWritten.push('prompts/execution-plan.json');
158
82
  }
159
83
  catch (err) {
@@ -167,305 +91,76 @@ export function runPhase5aLocalFallback(runDir, queryOverride) {
167
91
  return {
168
92
  success: true,
169
93
  filesWritten,
170
- message: `Phase-5a local fallback: wrote ${filesWritten.length} prompt artifacts (${filesWritten.filter(f => f.startsWith('prompts/impl-')).length} build prompts)`,
94
+ message: `Phase-5a local fallback: wrote ${filesWritten.length} prompt artifacts (degraded)`,
171
95
  };
172
96
  }
173
- // ── Helpers ────────────────────────────────────────────────────────────────
174
- function extractSuccessCriteriaList(consensus) {
175
- if (!consensus || !consensus.scenario)
176
- return [];
177
- const sc = consensus.scenario['success_criteria'] ?? consensus.scenario['successCriteria'];
178
- const out = [];
179
- if (Array.isArray(sc)) {
180
- for (const item of sc) {
181
- if (typeof item === 'string')
182
- out.push(item);
183
- else if (item && typeof item === 'object') {
184
- const o = item;
185
- for (const key of ['description', 'criterion', 'name', 'title']) {
186
- if (typeof o[key] === 'string') {
187
- out.push(o[key]);
188
- break;
189
- }
190
- }
191
- }
192
- }
193
- }
194
- return out;
195
- }
196
- function renderSuccessCriterionPrompt(order, total, criterion, query, execSummary, decisionMemo, priorUnitIds) {
97
+ function buildPhase1FallbackPromptMarkdown(query, decisionMemo, scenario, execSummary) {
197
98
  const lines = [];
198
99
  lines.push('---');
199
- lines.push(`id: unit-${pad3(order)}-${slugify(`validate-${criterion}`)}`);
200
- lines.push(`title: ${escapeYamlString(`Validate success criterion: ${truncate(criterion, 60)}`)}`);
201
- lines.push(`order: ${order}`);
202
- lines.push('tier: validation');
203
- lines.push('generator: phase1-fallback-multi');
100
+ lines.push('id: impl-001-phase1-consensus');
101
+ lines.push('title: Phase-1 Consensus Implementation');
102
+ lines.push('order: 1');
103
+ lines.push('degraded_mode: phase1-fallback');
104
+ lines.push(`source: ${[
105
+ decisionMemo ? 'phase1/decision-memo.md' : null,
106
+ scenario ? 'phase1/scenario.json' : null,
107
+ execSummary ? 'phase1/executive-summary.md' : null,
108
+ ].filter(Boolean).join(', ') || 'phase1-consensus'}`);
204
109
  lines.push('quality: degraded');
205
- lines.push(`source: phase1/scenario.success_criteria`);
206
- if (priorUnitIds.length > 0) {
207
- lines.push('dependencies:');
208
- for (const d of priorUnitIds)
209
- lines.push(` - ${d}`);
210
- }
211
- else {
212
- lines.push('dependency_root: true');
213
- }
110
+ lines.push('generator: local-fallback');
214
111
  lines.push('---');
215
112
  lines.push('');
216
- lines.push(`# Build Step ${order} of ${total}: Validate "${truncate(criterion, 80)}"`);
217
- lines.push('');
218
- lines.push('## Project Brief');
219
- lines.push('');
220
- lines.push(query || '(no brief recorded)');
113
+ lines.push('# Implementation: Phase-1 Consensus');
221
114
  lines.push('');
222
- lines.push('## Success Criterion This Step Verifies');
115
+ lines.push('> **Generated by local fallback** (ADR-PIPELINE-094 Decision 8). The full SPARC → ADR → DDD chain was unavailable for this run; this prompt was produced directly from Phase-1 simulator consensus. Quality: **degraded**.');
223
116
  lines.push('');
224
- lines.push(`> ${criterion}`);
225
- lines.push('');
226
- if (decisionMemo) {
227
- lines.push('## Decision Memo (rationale, truncated)');
117
+ if (query) {
118
+ lines.push('## Brief');
228
119
  lines.push('');
229
- lines.push(truncate(decisionMemo.trim(), 800));
120
+ lines.push(query);
230
121
  lines.push('');
231
122
  }
232
- // ADR-PIPELINE-102 — copy-paste-ready Implementation Prompt block.
233
- lines.push('## Implementation Prompt');
234
- lines.push('');
235
- lines.push('Copy the block below into your coding agent verbatim. It is a complete validation slice that proves the criterion end-to-end.');
236
- lines.push('');
237
- lines.push('```');
238
- lines.push(`Build a validation slice that proves the following success criterion is met:`);
239
- lines.push('');
240
- lines.push(` "${criterion}"`);
241
- lines.push('');
242
- lines.push('Project brief (full context for the slice):');
243
- lines.push('');
244
- for (const ql of (query || '(no brief recorded)').split('\n')) {
245
- lines.push(ql);
246
- }
247
- lines.push('');
248
- if (priorUnitIds.length > 0) {
249
- lines.push(`Depends on (already implemented): ${priorUnitIds.join(', ')}.`);
250
- lines.push('Import their public API instead of redefining types.');
251
- lines.push('');
252
- }
253
- lines.push('Implementation requirements:');
254
- lines.push('1. Identify the smallest end-to-end slice that exercises the criterion. Examples: a CLI that ingests a fixture file and prints the metric the criterion measures; an HTTP endpoint that returns the criterion-relevant response; a smoke test that walks the request → analysis → decision → integration path.');
255
- lines.push('2. Write the test FIRST. The test name must literally reference the criterion text. The test must fail before any production code exists, then pass after.');
256
- lines.push('3. Implement only the production code needed to make the test pass. Real logic, no stubs, no TODO scaffolds.');
257
- lines.push('4. Validate ALL external input at module boundaries. Reject malformed input with typed errors, not panics.');
258
- lines.push('5. Export the public API needed by downstream slices. Document each export.');
259
- lines.push('6. Structured logging via the project logger. Every public-API call logs entry + completion + duration with a correlation id.');
260
- lines.push('7. Zero compilation errors. Zero `any`-typed domain values.');
261
- lines.push('');
262
- lines.push('Verification before marking this step complete:');
263
- lines.push('- The criterion-named test passes.');
264
- lines.push('- The full unit + integration test suite passes.');
265
- lines.push('- Lint/typecheck passes.');
266
- lines.push('- The criterion is observable: a human running the slice can confirm it visually OR a test asserts the observable outcome.');
267
- lines.push('```');
268
- lines.push('');
269
123
  if (execSummary) {
270
- lines.push('## Reference: Executive Summary (context only)');
124
+ lines.push('## Executive Summary');
271
125
  lines.push('');
272
- lines.push(truncate(execSummary.trim(), 800));
126
+ lines.push(execSummary.trim());
273
127
  lines.push('');
274
128
  }
275
- return lines.join('\n');
276
- }
277
- function synthesizeMinimumFourPrompts(query, consensus) {
278
- const lang = consensus.projectLanguage ?? 'typescript';
279
- const slices = [
280
- {
281
- slug: 'foundation-types-and-config',
282
- title: 'Foundation: Domain Types + AppConfig + Logger',
283
- tier: 'foundation',
284
- description: 'Build the core domain types, the typed AppConfig (env-driven, Zod-validated), the structured logger, and the typed AppError hierarchy. Every later step imports from this slice.',
285
- dependsOnFirst: false,
286
- },
287
- {
288
- slug: 'analysis-layer',
289
- title: 'Domain: Analysis Layer (pure functions)',
290
- tier: 'domain',
291
- description: 'Implement the analysis layer as pure functions over the domain types. No I/O, no side-effects. Unit-tested against fixtures.',
292
- dependsOnFirst: true,
293
- },
294
- {
295
- slug: 'integration-and-decisions',
296
- title: 'Integration: External Surface + Decision Layer',
297
- tier: 'integration',
298
- description: 'Wire the analysis layer to the inbound API and outbound integration (HTTP/ERP/webhook as the brief requires). Idempotency keys on writes, retry with backoff, circuit breaker.',
299
- dependsOnFirst: true,
300
- },
301
- {
302
- slug: 'smoke-and-validation',
303
- title: 'Validation: End-to-end Smoke + Health Check',
304
- tier: 'validation',
305
- description: 'Smoke test that walks the full request → analysis → decision → integration path. Health-check endpoint. Verify the executive-summary success metrics are observable.',
306
- dependsOnFirst: true,
307
- },
308
- ];
309
- return slices.map((slice, idx) => ({
310
- slug: slice.slug,
311
- title: slice.title,
312
- tier: slice.tier,
313
- dependsOnFirst: slice.dependsOnFirst,
314
- body: renderSynthesizedPromptBody(idx + 1, slices.length, slice, query, lang, consensus),
315
- }));
316
- }
317
- function renderSynthesizedPromptBody(order, total, slice, query, lang, consensus) {
318
- const lines = [];
319
- lines.push('---');
320
- lines.push(`id: unit-${pad3(order)}-${slice.slug}`);
321
- lines.push(`title: ${escapeYamlString(slice.title)}`);
322
- lines.push(`order: ${order}`);
323
- lines.push(`tier: ${slice.tier}`);
324
- lines.push('generator: phase1-fallback-multi');
325
- lines.push('quality: degraded');
326
- lines.push('source: phase1-fallback-synthesis');
327
- if (slice.dependsOnFirst) {
328
- lines.push('dependencies:');
329
- lines.push(' - unit-001-foundation-types-and-config');
129
+ if (decisionMemo) {
130
+ lines.push('## Decision Memo');
131
+ lines.push('');
132
+ lines.push(decisionMemo.trim());
133
+ lines.push('');
330
134
  }
331
- else {
332
- lines.push('dependency_root: true');
135
+ if (scenario) {
136
+ lines.push('## Scenario');
137
+ lines.push('');
138
+ lines.push('```json');
139
+ lines.push(JSON.stringify(scenario, null, 2));
140
+ lines.push('```');
141
+ lines.push('');
333
142
  }
334
- lines.push('---');
335
- lines.push('');
336
- lines.push(`# Build Step ${order} of ${total}: ${slice.title}`);
337
- lines.push('');
338
- lines.push(`**Tier:** ${slice.tier} · **Language:** ${lang}`);
339
- lines.push('');
340
- lines.push('## Project Brief');
341
- lines.push('');
342
- lines.push(query || '(no brief recorded)');
343
- lines.push('');
344
- lines.push('## What This Step Builds');
143
+ lines.push('## Implementation Directive');
345
144
  lines.push('');
346
- lines.push(slice.description);
145
+ lines.push('Implement the system described in the Brief, using the Decision Memo and');
146
+ lines.push('Executive Summary above as architectural rationale. Produce a single deployable');
147
+ lines.push('service in the language declared by `phase1/manifest.json` (`project.language`).');
347
148
  lines.push('');
348
- // ADR-PIPELINE-102 — copy-paste-ready Implementation Prompt block.
349
- lines.push('## Implementation Prompt');
350
- lines.push('');
351
- lines.push('Copy the block below into your coding agent verbatim. It is a complete build instruction for this slice.');
149
+ lines.push('Layered structure:');
352
150
  lines.push('');
353
151
  lines.push('```');
354
- lines.push(`Build Step ${order} of ${total}: ${slice.title}.`);
355
- lines.push('');
356
- lines.push(`Language: ${lang}.`);
357
- lines.push('');
358
- lines.push('Project brief (full context):');
359
- lines.push('');
360
- for (const ql of (query || '(no brief recorded)').split('\n')) {
361
- lines.push(ql);
362
- }
363
- lines.push('');
364
- lines.push(`Slice scope: ${slice.description}`);
365
- lines.push('');
366
- if (slice.dependsOnFirst) {
367
- lines.push('Depends on (already implemented): unit-001-foundation-types-and-config.');
368
- lines.push('Import its types, config object, logger, and error hierarchy. Do not redefine them.');
369
- lines.push('');
370
- }
371
- // Slice-specific deliverables.
372
- for (const item of synthesizedSliceDeliverables(slice.slug, lang)) {
373
- lines.push(item);
374
- }
375
- lines.push('');
376
- lines.push('Implementation requirements:');
377
- lines.push('1. Tests first (London-school TDD). Each test must name the behavior it asserts. Mock dependencies from prior slices.');
378
- lines.push('2. Real domain logic. No stubs, no TODO scaffolds, no placeholder bodies.');
379
- lines.push('3. Validate ALL external input at module boundaries (Zod for TS, serde+validator for Rust, pydantic for Python).');
380
- lines.push('4. Export the public API needed by downstream slices. Document each export.');
381
- lines.push('5. Structured logging via the project logger — never console.log/print/println in production code.');
382
- lines.push('6. Typed errors via the AppError hierarchy. Never throw generic Error / panic.');
383
- lines.push('7. Zero compilation errors. Zero `any`-typed domain values.');
384
- lines.push('');
385
- lines.push('Verification before marking this slice complete:');
386
- lines.push('- All new tests pass.');
387
- lines.push('- Full test suite + lint + typecheck pass.');
388
- lines.push('- Public API surface compiles in isolation (no leaking internal types).');
389
- lines.push('- Run the slice end-to-end against a fixture and observe the outcome described in the slice scope.');
152
+ lines.push('src/');
153
+ lines.push(' index.ts # entry point');
154
+ lines.push(' config.ts # AppConfig + environment loading');
155
+ lines.push(' errors.ts # typed AppError classes');
156
+ lines.push(' analysis.ts # analysis layer (pure functions)');
157
+ lines.push(' decisions.ts # decision layer (pure functions)');
158
+ lines.push(' integration.ts # outbound integration (HTTP/ERP)');
159
+ lines.push('tests/');
160
+ lines.push(' analysis.test.ts');
161
+ lines.push(' decisions.test.ts');
390
162
  lines.push('```');
391
163
  lines.push('');
392
- if (consensus.decisionMemo) {
393
- lines.push('## Reference: Decision Memo (rationale, truncated)');
394
- lines.push('');
395
- lines.push(truncate(consensus.decisionMemo.trim(), 1000));
396
- lines.push('');
397
- }
398
164
  return lines.join('\n');
399
165
  }
400
- /**
401
- * Slice-specific deliverable lists for the 4-prompt synthesis safety net.
402
- * Each slice has a concrete to-build list so the prompt isn't "do something
403
- * with the foundation".
404
- */
405
- function synthesizedSliceDeliverables(slug, lang) {
406
- const isTS = lang === 'typescript' || lang === 'javascript';
407
- const isPy = lang === 'python';
408
- const isRust = lang === 'rust';
409
- switch (slug) {
410
- case 'foundation-types-and-config':
411
- return [
412
- 'Implement the following:',
413
- '1. Domain type module (src/types/ or pe-core equivalent) — every typed entity from the brief: aggregates, value objects, command/query payloads. Each type has a constructor that validates its invariants and rejects malformed input.',
414
- '2. AppConfig — typed config loaded from environment variables, validated at startup. Refuse to start on invalid config with a clear error.',
415
- '3. Logger — structured JSON logger emitting {timestamp, level, service, event, correlationId, ...data} to stderr.',
416
- '4. AppError hierarchy — base class + at least these subclasses: ValidationError, NotFoundError, IntegrationError, AuthorizationError. Each carries a stable error code.',
417
- '5. Result/Either helper if the language lacks one (Rust: use std::result; TS: use a Result<T,E> discriminated union; Python: use a Result class).',
418
- isTS ? '6. Zod schemas paralleling each domain type — used to parse external input.' :
419
- isPy ? '6. Pydantic models paralleling each domain type.' :
420
- isRust ? '6. serde Deserialize impls paralleling each domain type with validator-style invariant checks.' :
421
- '6. Validation schemas paralleling each domain type.',
422
- ];
423
- case 'analysis-layer':
424
- return [
425
- 'Implement the analysis layer as pure functions over the foundation types:',
426
- '1. Each analysis function takes typed input and returns a typed output. No I/O, no side effects, no global state.',
427
- '2. Cover at least one analytical operation explicitly named in the brief (e.g. anomaly detection, scoring, ranking, summarization).',
428
- '3. Decompose multi-step analysis into smaller pure functions; the public API exposes the orchestrator only.',
429
- '4. Unit-tested against fixtures: at least 3 inputs (happy path, edge case, malformed-rejected). The malformed input must be rejected by the validator from the foundation, not silently absorbed.',
430
- ];
431
- case 'integration-and-decisions':
432
- return [
433
- 'Wire the analysis layer into an external surface and a decision layer:',
434
- '1. Inbound surface — a CLI subcommand or HTTP endpoint that takes a typed request, runs the analysis, returns a typed response.',
435
- '2. Decision layer — pure function that maps analysis output to a recommendation/action. No I/O.',
436
- '3. Outbound integration — wraps the external system named in the brief (HTTP, ERP, webhook). Idempotency key on every write (hash of stable inputs). Retry with exponential backoff (1s → 2s → 4s, max 3 attempts) on 429/503/timeout. Circuit breaker (open after 5 consecutive failures, half-open after 30s).',
437
- '4. Correlation ID threaded from the inbound request through analysis → decision → integration. Every log line includes it.',
438
- '5. End-to-end happy-path test that mocks the outbound integration and asserts the request → recommendation → write sequence.',
439
- ];
440
- case 'smoke-and-validation':
441
- return [
442
- 'Implement validation + observability:',
443
- '1. Smoke test — runs the slice end-to-end against a fixture, asserts the headline success metric from the brief\'s executive summary is observable.',
444
- '2. Health check endpoint or CLI command — reports liveness + dependency status (config valid, integration reachable).',
445
- '3. Metrics endpoint or stderr emission — counts of requests, errors, integration calls, p50/p95 latency.',
446
- '4. Hypercare runbook — short markdown document at docs/runbook.md listing: how to deploy, how to roll back, how to interpret each log event, how to verify the success metric.',
447
- ];
448
- default:
449
- return [
450
- 'Implement the slice scope above.',
451
- ];
452
- }
453
- }
454
- function pad3(n) {
455
- return String(n).padStart(3, '0');
456
- }
457
- function slugify(text) {
458
- return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '').slice(0, 60);
459
- }
460
- function truncate(text, max) {
461
- if (!text)
462
- return '';
463
- return text.length > max ? text.slice(0, max - 1) + '…' : text;
464
- }
465
- function escapeYamlString(s) {
466
- if (/[:#&*!|>'"%@`?[\]{},]/.test(s)) {
467
- return `"${s.replace(/"/g, '\\"').replace(/\\/g, '\\\\')}"`;
468
- }
469
- return s;
470
- }
471
166
  //# sourceMappingURL=phase5a-local-fallback.js.map