@llm-dev-ops/agentics-cli 2.7.36 → 2.7.38
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/adapters/base-adapter.d.ts.map +1 -1
- package/dist/adapters/base-adapter.js.map +1 -1
- package/dist/agents/repo-agent-runner.d.ts.map +1 -1
- package/dist/agents/repo-agent-runner.js +0 -2
- package/dist/agents/repo-agent-runner.js.map +1 -1
- package/dist/agents/system-prompts.d.ts.map +1 -1
- package/dist/agents/system-prompts.js +0 -19
- package/dist/agents/system-prompts.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/agents.d.ts +4 -24
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +30 -106
- package/dist/commands/agents.js.map +1 -1
- package/dist/mcp/agent-event-parser.d.ts +1 -11
- package/dist/mcp/agent-event-parser.d.ts.map +1 -1
- package/dist/mcp/agent-event-parser.js +7 -153
- package/dist/mcp/agent-event-parser.js.map +1 -1
- package/dist/mcp/mcp-server.js +0 -58
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/pipeline/auto-chain.d.ts.map +1 -1
- package/dist/pipeline/auto-chain.js +27 -169
- package/dist/pipeline/auto-chain.js.map +1 -1
- package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts +21 -18
- package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts.map +1 -1
- package/dist/pipeline/local-fallback/phase5a-local-fallback.js +92 -397
- package/dist/pipeline/local-fallback/phase5a-local-fallback.js.map +1 -1
- package/dist/pipeline/phase2/phases/adr-generator.d.ts +29 -1
- package/dist/pipeline/phase2/phases/adr-generator.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/adr-generator.js +709 -1399
- package/dist/pipeline/phase2/phases/adr-generator.js.map +1 -1
- package/dist/pipeline/phase2/phases/ddd-generator.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/ddd-generator.js +7 -42
- package/dist/pipeline/phase2/phases/ddd-generator.js.map +1 -1
- package/dist/pipeline/phase2/phases/research-dossier.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/research-dossier.js +2 -33
- package/dist/pipeline/phase2/phases/research-dossier.js.map +1 -1
- package/dist/pipeline/phase2/phases/sparc-specification.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/sparc-specification.js +2 -27
- package/dist/pipeline/phase2/phases/sparc-specification.js.map +1 -1
- package/dist/pipeline/phase2/types.d.ts +19 -57
- package/dist/pipeline/phase2/types.d.ts.map +1 -1
- package/dist/pipeline/phase4-adrs/adr-index-extractor.d.ts +75 -0
- package/dist/pipeline/phase4-adrs/adr-index-extractor.d.ts.map +1 -0
- package/dist/pipeline/phase4-adrs/adr-index-extractor.js +200 -0
- package/dist/pipeline/phase4-adrs/adr-index-extractor.js.map +1 -0
- package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.d.ts.map +1 -1
- package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.js +70 -68
- package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.js.map +1 -1
- package/dist/pipeline/phase7/deliverables-registry.js +1 -1
- package/dist/pipeline/phase7/deliverables-registry.js.map +1 -1
- package/dist/pipeline/phases/adr-ddd-generator.d.ts.map +1 -1
- package/dist/pipeline/phases/adr-ddd-generator.js +48 -2
- package/dist/pipeline/phases/adr-ddd-generator.js.map +1 -1
- package/dist/pipeline/phases/prompt-generator.js +191 -80
- package/dist/pipeline/phases/prompt-generator.js.map +1 -1
- package/dist/pipeline/ruflo-phase-executor.d.ts +2 -5
- package/dist/pipeline/ruflo-phase-executor.d.ts.map +1 -1
- package/dist/pipeline/ruflo-phase-executor.js +72 -23
- package/dist/pipeline/ruflo-phase-executor.js.map +1 -1
- package/dist/pipeline/types.d.ts +14 -1
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/routing/domain-boundary.d.ts +4 -20
- package/dist/routing/domain-boundary.d.ts.map +1 -1
- package/dist/routing/domain-boundary.js +6 -81
- package/dist/routing/domain-boundary.js.map +1 -1
- package/dist/routing/graph-router.d.ts.map +1 -1
- package/dist/routing/graph-router.js +0 -22
- package/dist/routing/graph-router.js.map +1 -1
- package/dist/synthesis/ask-artifact-writer.d.ts +1 -1
- package/dist/synthesis/ask-artifact-writer.d.ts.map +1 -1
- package/dist/synthesis/ask-artifact-writer.js +9 -9
- package/dist/synthesis/ask-artifact-writer.js.map +1 -1
- package/dist/synthesis/simulation-artifact-generator.d.ts +1 -27
- package/dist/synthesis/simulation-artifact-generator.d.ts.map +1 -1
- package/dist/synthesis/simulation-artifact-generator.js +38 -128
- package/dist/synthesis/simulation-artifact-generator.js.map +1 -1
- package/docs/ecosystem.graph.json +15 -65
- package/package.json +1 -1
- package/dist/cli/ui/heartbeat.d.ts +0 -88
- package/dist/cli/ui/heartbeat.d.ts.map +0 -1
- package/dist/cli/ui/heartbeat.js +0 -158
- package/dist/cli/ui/heartbeat.js.map +0 -1
- package/dist/config/qe-gating.d.ts +0 -81
- package/dist/config/qe-gating.d.ts.map +0 -1
- package/dist/config/qe-gating.js +0 -138
- package/dist/config/qe-gating.js.map +0 -1
- package/dist/pipeline/phase5-build/qe-gating-executor.d.ts +0 -73
- package/dist/pipeline/phase5-build/qe-gating-executor.d.ts.map +0 -1
- package/dist/pipeline/phase5-build/qe-gating-executor.js +0 -134
- package/dist/pipeline/phase5-build/qe-gating-executor.js.map +0 -1
- package/dist/synthesis/agent-fleet-decomposer.d.ts +0 -124
- package/dist/synthesis/agent-fleet-decomposer.d.ts.map +0 -1
- package/dist/synthesis/agent-fleet-decomposer.js +0 -696
- package/dist/synthesis/agent-fleet-decomposer.js.map +0 -1
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ADR-PIPELINE-094 Decision 8
|
|
2
|
+
* ADR-PIPELINE-094 Decision 8 — Phase 5a local fallback generator.
|
|
3
3
|
*
|
|
4
|
-
* Produces
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
-
*
|
|
20
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
|
2
|
+
* ADR-PIPELINE-094 Decision 8 — Phase 5a local fallback generator.
|
|
3
3
|
*
|
|
4
|
-
* Produces
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
-
*
|
|
20
|
-
*
|
|
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
|
-
|
|
27
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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:
|
|
139
|
-
quality:
|
|
140
|
-
totalSteps:
|
|
141
|
-
estimatedDuration:
|
|
142
|
-
implementations:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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, '
|
|
77
|
+
fs.writeFileSync(path.join(phase5aDir, 'execution-plan.json'), planJson, 'utf8');
|
|
155
78
|
filesWritten.push('phase5a/execution-plan.json');
|
|
156
|
-
|
|
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 (
|
|
94
|
+
message: `Phase-5a local fallback: wrote ${filesWritten.length} prompt artifacts (degraded)`,
|
|
171
95
|
};
|
|
172
96
|
}
|
|
173
|
-
|
|
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(
|
|
200
|
-
lines.push(
|
|
201
|
-
lines.push(
|
|
202
|
-
lines.push('
|
|
203
|
-
lines.push(
|
|
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(
|
|
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(
|
|
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('
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
if (decisionMemo) {
|
|
227
|
-
lines.push('## Decision Memo (rationale, truncated)');
|
|
117
|
+
if (query) {
|
|
118
|
+
lines.push('## Brief');
|
|
228
119
|
lines.push('');
|
|
229
|
-
lines.push(
|
|
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('##
|
|
124
|
+
lines.push('## Executive Summary');
|
|
271
125
|
lines.push('');
|
|
272
|
-
lines.push(
|
|
126
|
+
lines.push(execSummary.trim());
|
|
273
127
|
lines.push('');
|
|
274
128
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
332
|
-
lines.push('
|
|
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(
|
|
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
|
-
|
|
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(
|
|
355
|
-
lines.push('');
|
|
356
|
-
lines.push(
|
|
357
|
-
lines.push('');
|
|
358
|
-
lines.push('
|
|
359
|
-
lines.push('');
|
|
360
|
-
|
|
361
|
-
|
|
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
|