substrate-ai 0.20.19 → 0.20.21
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/cli/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createLogger } from "../logger-KeHncl-f.js";
|
|
|
4
4
|
import { createEventBus } from "../helpers-CElYrONe.js";
|
|
5
5
|
import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-CqtWS9wF.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-
|
|
7
|
+
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-DrJWCS63.js";
|
|
8
8
|
import "../errors-1uLGqnvr.js";
|
|
9
9
|
import "../routing-CcBOCuC9.js";
|
|
10
10
|
import "../decisions-C0pz9Clx.js";
|
|
@@ -5198,7 +5198,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
5198
5198
|
await initSchema(expAdapter);
|
|
5199
5199
|
const { runRunAction: runPipeline } = await import(
|
|
5200
5200
|
/* @vite-ignore */
|
|
5201
|
-
"../run-
|
|
5201
|
+
"../run-C46Xfny6.js"
|
|
5202
5202
|
);
|
|
5203
5203
|
const runStoryFn = async (opts) => {
|
|
5204
5204
|
const exitCode = await runPipeline({
|
|
@@ -2,7 +2,7 @@ import "./health-ZGa9E0D2.js";
|
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./helpers-CElYrONe.js";
|
|
4
4
|
import "./dist-CqtWS9wF.js";
|
|
5
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-
|
|
5
|
+
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-DrJWCS63.js";
|
|
6
6
|
import "./routing-CcBOCuC9.js";
|
|
7
7
|
import "./decisions-C0pz9Clx.js";
|
|
8
8
|
|
|
@@ -5708,7 +5708,7 @@ function hashSourceAcSection(section) {
|
|
|
5708
5708
|
* @returns Promise resolving to CreateStoryResult
|
|
5709
5709
|
*/
|
|
5710
5710
|
async function runCreateStory(deps, params) {
|
|
5711
|
-
const { epicId, storyKey, pipelineRunId, source_ac_hash } = params;
|
|
5711
|
+
const { epicId, storyKey, pipelineRunId, source_ac_hash, priorDriftFeedback } = params;
|
|
5712
5712
|
logger$18.debug({
|
|
5713
5713
|
epicId,
|
|
5714
5714
|
storyKey,
|
|
@@ -5797,7 +5797,16 @@ async function runCreateStory(deps, params) {
|
|
|
5797
5797
|
name: "source_ac_hash",
|
|
5798
5798
|
content: effectiveSourceAcHash,
|
|
5799
5799
|
priority: "required"
|
|
5800
|
-
}] : []
|
|
5800
|
+
}] : [],
|
|
5801
|
+
...priorDriftFeedback !== void 0 && priorDriftFeedback.length > 0 ? [{
|
|
5802
|
+
name: "prior_drift_feedback",
|
|
5803
|
+
content: priorDriftFeedback,
|
|
5804
|
+
priority: "required"
|
|
5805
|
+
}] : [{
|
|
5806
|
+
name: "prior_drift_feedback",
|
|
5807
|
+
content: "",
|
|
5808
|
+
priority: "optional"
|
|
5809
|
+
}]
|
|
5801
5810
|
], TOKEN_CEILING);
|
|
5802
5811
|
logger$18.debug({
|
|
5803
5812
|
tokenCount,
|
|
@@ -5958,6 +5967,70 @@ function extractStorySection(shardContent, storyKey) {
|
|
|
5958
5967
|
return section.length > 0 ? section : null;
|
|
5959
5968
|
}
|
|
5960
5969
|
/**
|
|
5970
|
+
* Story 59-3: extract the list of named filesystem paths and filenames from
|
|
5971
|
+
* source AC text. Looks for backtick-wrapped strings that contain a path
|
|
5972
|
+
* separator OR end with a recognized source-file extension. The result is
|
|
5973
|
+
* a deduped list of names the source AC declares as part of the story's
|
|
5974
|
+
* artifact contract.
|
|
5975
|
+
*
|
|
5976
|
+
* Used by the orchestrator's pre-dev fidelity gate to detect create-story
|
|
5977
|
+
* output drift: if the agent produced a story file that doesn't reference
|
|
5978
|
+
* the source AC's named files (`adjacency-store.ts`, `wikilink-parser.ts`,
|
|
5979
|
+
* etc.) the gate fires and the orchestrator renames-to-stale + retries.
|
|
5980
|
+
*
|
|
5981
|
+
* Heuristic chosen over LLM-based fidelity check because deterministic,
|
|
5982
|
+
* fast, and the LLM-based source-ac-fidelity check still runs at
|
|
5983
|
+
* verification phase as a backstop for nuanced drift this gate can't see.
|
|
5984
|
+
*/
|
|
5985
|
+
function extractNamedPathsFromSource(shardContent) {
|
|
5986
|
+
const paths = new Set();
|
|
5987
|
+
const backtickPattern = /`([^`\n]+)`/g;
|
|
5988
|
+
const extensionPattern = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|md|json|sql|sh|toml|yaml|yml|html|css|scss|svelte)$/i;
|
|
5989
|
+
let match$2;
|
|
5990
|
+
while ((match$2 = backtickPattern.exec(shardContent)) !== null) {
|
|
5991
|
+
const candidate = match$2[1]?.trim();
|
|
5992
|
+
if (candidate === void 0 || candidate.length === 0) continue;
|
|
5993
|
+
if (candidate.includes(" ")) continue;
|
|
5994
|
+
if (!candidate.includes("/") && !extensionPattern.test(candidate)) continue;
|
|
5995
|
+
paths.add(candidate);
|
|
5996
|
+
}
|
|
5997
|
+
return Array.from(paths);
|
|
5998
|
+
}
|
|
5999
|
+
/**
|
|
6000
|
+
* Story 59-3: compute fidelity between a generated story file and the
|
|
6001
|
+
* named paths in the source AC. Drift is the fraction of source-AC paths
|
|
6002
|
+
* that do NOT appear anywhere in the story file content.
|
|
6003
|
+
*
|
|
6004
|
+
* Substring-match (not exact) — a source AC path
|
|
6005
|
+
* `packages/memory/src/graph/adjacency-store.ts` matches a story-file
|
|
6006
|
+
* mention of just the basename `adjacency-store.ts`. This is intentional:
|
|
6007
|
+
* stories sometimes shorten paths in prose while still preserving the
|
|
6008
|
+
* named file. Full-path or basename — both count as present. The drift
|
|
6009
|
+
* case we're catching (Run 9's WikilinkResolver substituting for
|
|
6010
|
+
* adjacency-store) has neither full nor basename present.
|
|
6011
|
+
*
|
|
6012
|
+
* Empty namedPaths list returns drift=0 (cannot drift from nothing).
|
|
6013
|
+
*/
|
|
6014
|
+
function computeStoryFileFidelity(storyFileContent, namedPaths) {
|
|
6015
|
+
if (namedPaths.length === 0) return {
|
|
6016
|
+
missing: [],
|
|
6017
|
+
present: [],
|
|
6018
|
+
drift: 0
|
|
6019
|
+
};
|
|
6020
|
+
const missing = [];
|
|
6021
|
+
const present = [];
|
|
6022
|
+
for (const path$3 of namedPaths) {
|
|
6023
|
+
const basename$2 = path$3.includes("/") ? path$3.slice(path$3.lastIndexOf("/") + 1) : path$3;
|
|
6024
|
+
if (storyFileContent.includes(path$3) || storyFileContent.includes(basename$2)) present.push(path$3);
|
|
6025
|
+
else missing.push(path$3);
|
|
6026
|
+
}
|
|
6027
|
+
return {
|
|
6028
|
+
missing,
|
|
6029
|
+
present,
|
|
6030
|
+
drift: missing.length / namedPaths.length
|
|
6031
|
+
};
|
|
6032
|
+
}
|
|
6033
|
+
/**
|
|
5961
6034
|
* Retrieve the epic shard from the pre-fetched implementation decisions.
|
|
5962
6035
|
*
|
|
5963
6036
|
* Lookup order (post-37-0 schema):
|
|
@@ -8784,6 +8857,7 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
8784
8857
|
}
|
|
8785
8858
|
const shards = parseEpicShards(content);
|
|
8786
8859
|
let count = 0;
|
|
8860
|
+
const seenKeys = new Set();
|
|
8787
8861
|
for (const shard of shards) {
|
|
8788
8862
|
const subsections = parseStorySubsections(shard.epicId, shard.content);
|
|
8789
8863
|
for (const subsection of subsections) {
|
|
@@ -8794,6 +8868,15 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
8794
8868
|
truncatedLength: MAX_EPIC_SHARD_CHARS,
|
|
8795
8869
|
droppedChars: subsection.content.length - MAX_EPIC_SHARD_CHARS
|
|
8796
8870
|
}, `Epic shard for ${subsection.key} exceeded ${MAX_EPIC_SHARD_CHARS}-char cap and was truncated; tail content lost from decisions store. Consider splitting the story or raising MAX_EPIC_SHARD_CHARS.`);
|
|
8871
|
+
if (seenKeys.has(subsection.key)) {
|
|
8872
|
+
logger$11.warn({
|
|
8873
|
+
epicId: shard.epicId,
|
|
8874
|
+
storyKey: subsection.key,
|
|
8875
|
+
droppedContentLength: subsection.content.length
|
|
8876
|
+
}, `Epic shard parser produced duplicate key '${subsection.key}' (parser regression?); skipping additional insert. First entry retained.`);
|
|
8877
|
+
continue;
|
|
8878
|
+
}
|
|
8879
|
+
seenKeys.add(subsection.key);
|
|
8797
8880
|
await createDecision(db, {
|
|
8798
8881
|
pipeline_run_id: null,
|
|
8799
8882
|
phase: "implementation",
|
|
@@ -8915,9 +8998,9 @@ function parseEpicShards(content) {
|
|
|
8915
8998
|
* Parse an epic section's content into per-story subsections.
|
|
8916
8999
|
*
|
|
8917
9000
|
* Matches story headings using three patterns:
|
|
8918
|
-
* - Markdown headings: #{2,6} Story \d+[-._ ]\d+ (e.g., ### Story 37-1
|
|
8919
|
-
* - Bold: **Story \d+[-._ ]\d
|
|
8920
|
-
* - Bare key: \d+[-._ ]\d
|
|
9001
|
+
* - Markdown headings: #{2,6} Story \d+[-._ ]\d+[a-z]* (e.g., ### Story 37-1, ### Story 1.1, ### Story 1.11a)
|
|
9002
|
+
* - Bold: **Story \d+[-._ ]\d+[a-z]*** (e.g., **Story 37-1**)
|
|
9003
|
+
* - Bare key: \d+[-._ ]\d+[a-z]*:\s (e.g., 37-1a: Title)
|
|
8921
9004
|
*
|
|
8922
9005
|
* Each subsection spans from its heading to the next matching heading or EOF.
|
|
8923
9006
|
*
|
|
@@ -8934,16 +9017,28 @@ function parseEpicShards(content) {
|
|
|
8934
9017
|
* Epic 58-5 already made `extractStorySection` separator-agnostic for the
|
|
8935
9018
|
* same reason; this matches that precedent at the seed-time parser.
|
|
8936
9019
|
*
|
|
8937
|
-
*
|
|
8938
|
-
*
|
|
8939
|
-
*
|
|
8940
|
-
*
|
|
9020
|
+
* Story 59-2: alpha-suffix capture. BMAD-template projects subdivide stories
|
|
9021
|
+
* with letter suffixes (`### Story 1.11a`, `### Story 1.11b`, …) when an
|
|
9022
|
+
* original 1.11 ships broken and gets split for clarity. Strata's epics.md
|
|
9023
|
+
* uses this convention with 5 substories (1.11, 1.11a-d). 58-17's regex
|
|
9024
|
+
* `\d+[-._ ]\d+` truncated capture at the digit boundary, normalizing all
|
|
9025
|
+
* 5 to canonical key `1-11` and inserting 5 duplicate-key rows in the
|
|
9026
|
+
* decisions store (no UNIQUE constraint enforces uniqueness — strata
|
|
9027
|
+
* obs_2026-04-25_010). Trailing `[a-z]*` captures alpha suffixes of any
|
|
9028
|
+
* length; the `i` flag on the storyPattern (needed for `Story` heading
|
|
9029
|
+
* case variation) means uppercase is also accepted, so a stray `1.11A`
|
|
9030
|
+
* heading captures cleanly to key `1-11A` rather than truncating.
|
|
9031
|
+
*
|
|
9032
|
+
* Captured storyKey is normalized to canonical dash-form (`1.1` → `1-1`,
|
|
9033
|
+
* `1.11a` → `1-11a`) so decision keys are consistent regardless of the
|
|
9034
|
+
* source heading style. The separator-replace `[._ ] → -` does not touch
|
|
9035
|
+
* `[a-z]`, so trailing alpha is preserved through normalization.
|
|
8941
9036
|
*
|
|
8942
9037
|
* AC3: If no story headings are found, returns a single per-epic fallback entry
|
|
8943
9038
|
* keyed by epicId — preserving backward-compatible behaviour for unstructured epics.
|
|
8944
9039
|
*/
|
|
8945
9040
|
function parseStorySubsections(epicId, epicContent) {
|
|
8946
|
-
const storyPattern = /(?:^#{2,6}\s+Story\s+(\d+[-._ ]\d+)|^\*\*Story\s+(\d+[-._ ]\d+)\*\*|^(\d+[-._ ]\d+):\s)/gim;
|
|
9041
|
+
const storyPattern = /(?:^#{2,6}\s+Story\s+(\d+[-._ ]\d+[a-z]*)|^\*\*Story\s+(\d+[-._ ]\d+[a-z]*)\*\*|^(\d+[-._ ]\d+[a-z]*):\s)/gim;
|
|
8947
9042
|
const matches = [];
|
|
8948
9043
|
let match$2;
|
|
8949
9044
|
while ((match$2 = storyPattern.exec(epicContent)) !== null) {
|
|
@@ -11307,6 +11402,9 @@ async function autoIngestEpicsDependencies(db, projectRoot) {
|
|
|
11307
11402
|
};
|
|
11308
11403
|
}
|
|
11309
11404
|
const TITLE_OVERLAP_WARNING_THRESHOLD = .3;
|
|
11405
|
+
const FIDELITY_DRIFT_THRESHOLD = .5;
|
|
11406
|
+
const MIN_NAMED_PATHS_FOR_FIDELITY_GATE = 3;
|
|
11407
|
+
const MAX_FIDELITY_RETRIES = 2;
|
|
11310
11408
|
/**
|
|
11311
11409
|
* Map a terminal StoryPhase to the corresponding PerStoryStatus for run-manifest writes.
|
|
11312
11410
|
* Returns 'dispatched' for in-progress phases (used as a safe default).
|
|
@@ -12166,66 +12264,235 @@ function createImplementationOrchestrator(deps) {
|
|
|
12166
12264
|
await persistState();
|
|
12167
12265
|
return;
|
|
12168
12266
|
}
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
});
|
|
12187
|
-
endPhase(storyKey, "create-story");
|
|
12188
|
-
eventBus.emit("orchestrator:story-phase-complete", {
|
|
12189
|
-
storyKey,
|
|
12190
|
-
phase: "IN_STORY_CREATION",
|
|
12191
|
-
result: createResult
|
|
12192
|
-
});
|
|
12193
|
-
if (config.pipelineRunId !== void 0 && createResult.tokenUsage !== void 0) Promise.resolve().then(() => addTokenUsage(db, config.pipelineRunId, {
|
|
12194
|
-
phase: "create-story",
|
|
12195
|
-
agent: "create-story",
|
|
12196
|
-
input_tokens: createResult.tokenUsage.input,
|
|
12197
|
-
output_tokens: createResult.tokenUsage.output,
|
|
12198
|
-
cost_usd: estimateDispatchCost(createResult.tokenUsage.input, createResult.tokenUsage.output),
|
|
12199
|
-
metadata: JSON.stringify({ storyKey })
|
|
12200
|
-
})).catch((tokenErr) => logger$24.warn({
|
|
12201
|
-
storyKey,
|
|
12202
|
-
err: tokenErr
|
|
12203
|
-
}, "Failed to record create-story token usage"));
|
|
12204
|
-
await persistState();
|
|
12205
|
-
if (createResult.result === "failed") {
|
|
12206
|
-
const errMsg = createResult.error ?? "create-story failed";
|
|
12207
|
-
const stderrSnippet = errMsg.includes("--- stderr ---") ? errMsg.slice(errMsg.indexOf("--- stderr ---") + 15, errMsg.indexOf("--- stderr ---") + 515) : errMsg.slice(0, 500);
|
|
12208
|
-
logger$24.error({
|
|
12267
|
+
let fidelityRetries = 0;
|
|
12268
|
+
let priorDriftFeedback;
|
|
12269
|
+
while (storyFilePath === void 0) {
|
|
12270
|
+
try {
|
|
12271
|
+
incrementDispatches(storyKey);
|
|
12272
|
+
const dispatchStartMs = Date.now();
|
|
12273
|
+
const createResult = await runCreateStory({
|
|
12274
|
+
db,
|
|
12275
|
+
pack,
|
|
12276
|
+
contextCompiler,
|
|
12277
|
+
dispatcher,
|
|
12278
|
+
projectRoot,
|
|
12279
|
+
tokenCeilings,
|
|
12280
|
+
otlpEndpoint: _otlpEndpoint,
|
|
12281
|
+
agentId
|
|
12282
|
+
}, {
|
|
12283
|
+
epicId: storyKey.split("-")[0] ?? storyKey,
|
|
12209
12284
|
storyKey,
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
phase: "ESCALATED",
|
|
12214
|
-
error: errMsg,
|
|
12215
|
-
completedAt: new Date().toISOString()
|
|
12285
|
+
pipelineRunId: config.pipelineRunId,
|
|
12286
|
+
source_ac_hash: sourceAcHash,
|
|
12287
|
+
...priorDriftFeedback !== void 0 ? { priorDriftFeedback } : {}
|
|
12216
12288
|
});
|
|
12217
|
-
|
|
12218
|
-
|
|
12289
|
+
endPhase(storyKey, "create-story");
|
|
12290
|
+
eventBus.emit("orchestrator:story-phase-complete", {
|
|
12219
12291
|
storyKey,
|
|
12220
|
-
|
|
12221
|
-
|
|
12222
|
-
issues: [errMsg]
|
|
12292
|
+
phase: "IN_STORY_CREATION",
|
|
12293
|
+
result: createResult
|
|
12223
12294
|
});
|
|
12295
|
+
if (config.pipelineRunId !== void 0 && createResult.tokenUsage !== void 0) Promise.resolve().then(() => addTokenUsage(db, config.pipelineRunId, {
|
|
12296
|
+
phase: "create-story",
|
|
12297
|
+
agent: "create-story",
|
|
12298
|
+
input_tokens: createResult.tokenUsage.input,
|
|
12299
|
+
output_tokens: createResult.tokenUsage.output,
|
|
12300
|
+
cost_usd: estimateDispatchCost(createResult.tokenUsage.input, createResult.tokenUsage.output),
|
|
12301
|
+
metadata: JSON.stringify({ storyKey })
|
|
12302
|
+
})).catch((tokenErr) => logger$24.warn({
|
|
12303
|
+
storyKey,
|
|
12304
|
+
err: tokenErr
|
|
12305
|
+
}, "Failed to record create-story token usage"));
|
|
12224
12306
|
await persistState();
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12307
|
+
if (createResult.result === "failed") {
|
|
12308
|
+
const errMsg = createResult.error ?? "create-story failed";
|
|
12309
|
+
const stderrSnippet = errMsg.includes("--- stderr ---") ? errMsg.slice(errMsg.indexOf("--- stderr ---") + 15, errMsg.indexOf("--- stderr ---") + 515) : errMsg.slice(0, 500);
|
|
12310
|
+
logger$24.error({
|
|
12311
|
+
storyKey,
|
|
12312
|
+
stderrSnippet
|
|
12313
|
+
}, `Create-story failed: ${stderrSnippet.split("\n")[0]}`);
|
|
12314
|
+
updateStory(storyKey, {
|
|
12315
|
+
phase: "ESCALATED",
|
|
12316
|
+
error: errMsg,
|
|
12317
|
+
completedAt: new Date().toISOString()
|
|
12318
|
+
});
|
|
12319
|
+
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12320
|
+
await emitEscalation({
|
|
12321
|
+
storyKey,
|
|
12322
|
+
lastVerdict: "create-story-failed",
|
|
12323
|
+
reviewCycles: 0,
|
|
12324
|
+
issues: [errMsg]
|
|
12325
|
+
});
|
|
12326
|
+
await persistState();
|
|
12327
|
+
return;
|
|
12328
|
+
}
|
|
12329
|
+
if (createResult.story_file === void 0 || createResult.story_file === "") {
|
|
12330
|
+
const errMsg = "create-story succeeded but returned no story_file path";
|
|
12331
|
+
updateStory(storyKey, {
|
|
12332
|
+
phase: "ESCALATED",
|
|
12333
|
+
error: errMsg,
|
|
12334
|
+
completedAt: new Date().toISOString()
|
|
12335
|
+
});
|
|
12336
|
+
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12337
|
+
await emitEscalation({
|
|
12338
|
+
storyKey,
|
|
12339
|
+
lastVerdict: "create-story-no-file",
|
|
12340
|
+
reviewCycles: 0,
|
|
12341
|
+
issues: [errMsg]
|
|
12342
|
+
});
|
|
12343
|
+
await persistState();
|
|
12344
|
+
return;
|
|
12345
|
+
}
|
|
12346
|
+
if (projectRoot !== void 0) {
|
|
12347
|
+
const expectedArtifactsDir = join$1(projectRoot, "_bmad-output", "implementation-artifacts");
|
|
12348
|
+
const escapedExpectedDir = expectedArtifactsDir.replace("/_bmad-output/", "/\\_bmad-output/");
|
|
12349
|
+
let claimedPath = createResult.story_file;
|
|
12350
|
+
if (claimedPath.startsWith(escapedExpectedDir)) {
|
|
12351
|
+
claimedPath = claimedPath.replace("/\\_bmad-output/", "/_bmad-output/");
|
|
12352
|
+
logger$24.warn({
|
|
12353
|
+
storyKey,
|
|
12354
|
+
originalClaim: createResult.story_file,
|
|
12355
|
+
normalizedClaim: claimedPath
|
|
12356
|
+
}, "create-story claimed path contains backslash-escaped underscore; normalizing");
|
|
12357
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
12358
|
+
storyKey,
|
|
12359
|
+
msg: `create-story claim path was backslash-escaped; normalized to ${claimedPath}`
|
|
12360
|
+
});
|
|
12361
|
+
}
|
|
12362
|
+
if (claimedPath.startsWith(expectedArtifactsDir)) try {
|
|
12363
|
+
let actualPath = null;
|
|
12364
|
+
if (existsSync(claimedPath)) actualPath = claimedPath;
|
|
12365
|
+
else {
|
|
12366
|
+
const escapedVariant = claimedPath.replace("/_bmad-output/", "/\\_bmad-output/");
|
|
12367
|
+
if (escapedVariant !== claimedPath && existsSync(escapedVariant)) try {
|
|
12368
|
+
renameSync(escapedVariant, claimedPath);
|
|
12369
|
+
actualPath = claimedPath;
|
|
12370
|
+
logger$24.warn({
|
|
12371
|
+
storyKey,
|
|
12372
|
+
escapedVariant,
|
|
12373
|
+
canonicalPath: claimedPath
|
|
12374
|
+
}, "create-story wrote artifact to backslash-escaped path; moved to canonical location");
|
|
12375
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
12376
|
+
storyKey,
|
|
12377
|
+
msg: `create-story wrote to backslash-escaped path ${escapedVariant}; corrected to ${claimedPath}`
|
|
12378
|
+
});
|
|
12379
|
+
} catch (renameErr) {
|
|
12380
|
+
actualPath = escapedVariant;
|
|
12381
|
+
logger$24.warn({
|
|
12382
|
+
storyKey,
|
|
12383
|
+
escapedVariant,
|
|
12384
|
+
canonicalPath: claimedPath,
|
|
12385
|
+
err: renameErr
|
|
12386
|
+
}, "create-story wrote to backslash-escaped path; rename to canonical failed; treating as success at escaped location");
|
|
12387
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
12388
|
+
storyKey,
|
|
12389
|
+
msg: `create-story wrote to backslash-escaped path ${escapedVariant}; rename to canonical failed`
|
|
12390
|
+
});
|
|
12391
|
+
}
|
|
12392
|
+
}
|
|
12393
|
+
if (actualPath === null) {
|
|
12394
|
+
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
12395
|
+
const errMsg = `create-story claimed success (story_file: ${createResult.story_file}) but the file does not exist on disk (output tokens: ${outputTokens})`;
|
|
12396
|
+
logger$24.error({
|
|
12397
|
+
storyKey,
|
|
12398
|
+
claimedPath: createResult.story_file,
|
|
12399
|
+
outputTokens
|
|
12400
|
+
}, errMsg);
|
|
12401
|
+
updateStory(storyKey, {
|
|
12402
|
+
phase: "ESCALATED",
|
|
12403
|
+
error: errMsg,
|
|
12404
|
+
completedAt: new Date().toISOString()
|
|
12405
|
+
});
|
|
12406
|
+
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12407
|
+
await emitEscalation({
|
|
12408
|
+
storyKey,
|
|
12409
|
+
lastVerdict: "create-story-fraud-success",
|
|
12410
|
+
reviewCycles: 0,
|
|
12411
|
+
issues: [errMsg]
|
|
12412
|
+
});
|
|
12413
|
+
await persistState();
|
|
12414
|
+
return;
|
|
12415
|
+
}
|
|
12416
|
+
if (actualPath !== createResult.story_file) createResult.story_file = actualPath;
|
|
12417
|
+
const claimedStat = statSync(actualPath);
|
|
12418
|
+
if (claimedStat.mtimeMs < dispatchStartMs) {
|
|
12419
|
+
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
12420
|
+
const mtimeISO = new Date(claimedStat.mtimeMs).toISOString();
|
|
12421
|
+
const dispatchStartISO = new Date(dispatchStartMs).toISOString();
|
|
12422
|
+
const errMsg = `create-story claimed success but did not rewrite ${actualPath} during this dispatch (file mtime ${mtimeISO} predates dispatch start ${dispatchStartISO}; output tokens: ${outputTokens})`;
|
|
12423
|
+
logger$24.error({
|
|
12424
|
+
storyKey,
|
|
12425
|
+
claimedPath: actualPath,
|
|
12426
|
+
mtimeISO,
|
|
12427
|
+
dispatchStartISO,
|
|
12428
|
+
outputTokens
|
|
12429
|
+
}, errMsg);
|
|
12430
|
+
updateStory(storyKey, {
|
|
12431
|
+
phase: "ESCALATED",
|
|
12432
|
+
error: errMsg,
|
|
12433
|
+
completedAt: new Date().toISOString()
|
|
12434
|
+
});
|
|
12435
|
+
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12436
|
+
await emitEscalation({
|
|
12437
|
+
storyKey,
|
|
12438
|
+
lastVerdict: "create-story-fraud-success",
|
|
12439
|
+
reviewCycles: 0,
|
|
12440
|
+
issues: [errMsg]
|
|
12441
|
+
});
|
|
12442
|
+
await persistState();
|
|
12443
|
+
return;
|
|
12444
|
+
}
|
|
12445
|
+
} catch (verifyErr) {
|
|
12446
|
+
logger$24.warn({
|
|
12447
|
+
storyKey,
|
|
12448
|
+
err: verifyErr
|
|
12449
|
+
}, "create-story post-dispatch file verification threw; proceeding with claimed path");
|
|
12450
|
+
}
|
|
12451
|
+
}
|
|
12452
|
+
storyFilePath = createResult.story_file;
|
|
12453
|
+
if (createResult.story_title) try {
|
|
12454
|
+
const epicId = storyKey.split("-")[0] ?? storyKey;
|
|
12455
|
+
const implDecisions = await getDecisionsByPhase(db, "implementation");
|
|
12456
|
+
let shardContent;
|
|
12457
|
+
const perStoryShard = implDecisions.find((d) => d.category === "epic-shard" && d.key === storyKey);
|
|
12458
|
+
if (perStoryShard?.value) shardContent = perStoryShard.value;
|
|
12459
|
+
else {
|
|
12460
|
+
const epicShard = implDecisions.find((d) => d.category === "epic-shard" && d.key === epicId);
|
|
12461
|
+
if (epicShard?.value) shardContent = extractStorySection(epicShard.value, storyKey) ?? epicShard.value;
|
|
12462
|
+
}
|
|
12463
|
+
if (shardContent) {
|
|
12464
|
+
const expectedTitle = extractExpectedStoryTitle(shardContent, storyKey);
|
|
12465
|
+
if (expectedTitle) {
|
|
12466
|
+
const overlap = computeTitleOverlap(expectedTitle, createResult.story_title);
|
|
12467
|
+
if (overlap < TITLE_OVERLAP_WARNING_THRESHOLD) {
|
|
12468
|
+
const msg = `Story title mismatch: expected "${expectedTitle}" but got "${createResult.story_title}" (word overlap: ${Math.round(overlap * 100)}%). This may indicate the create-story agent received truncated context.`;
|
|
12469
|
+
logger$24.warn({
|
|
12470
|
+
storyKey,
|
|
12471
|
+
expectedTitle,
|
|
12472
|
+
generatedTitle: createResult.story_title,
|
|
12473
|
+
overlap
|
|
12474
|
+
}, msg);
|
|
12475
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
12476
|
+
storyKey,
|
|
12477
|
+
msg
|
|
12478
|
+
});
|
|
12479
|
+
} else logger$24.debug({
|
|
12480
|
+
storyKey,
|
|
12481
|
+
expectedTitle,
|
|
12482
|
+
generatedTitle: createResult.story_title,
|
|
12483
|
+
overlap
|
|
12484
|
+
}, "Story title validation passed");
|
|
12485
|
+
}
|
|
12486
|
+
}
|
|
12487
|
+
} catch (titleValidationErr) {
|
|
12488
|
+
logger$24.debug({
|
|
12489
|
+
storyKey,
|
|
12490
|
+
err: titleValidationErr
|
|
12491
|
+
}, "Story title validation skipped due to error");
|
|
12492
|
+
}
|
|
12493
|
+
} catch (err) {
|
|
12494
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
12495
|
+
endPhase(storyKey, "create-story");
|
|
12229
12496
|
updateStory(storyKey, {
|
|
12230
12497
|
phase: "ESCALATED",
|
|
12231
12498
|
error: errMsg,
|
|
@@ -12234,133 +12501,106 @@ function createImplementationOrchestrator(deps) {
|
|
|
12234
12501
|
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12235
12502
|
await emitEscalation({
|
|
12236
12503
|
storyKey,
|
|
12237
|
-
lastVerdict: "create-story-
|
|
12504
|
+
lastVerdict: "create-story-exception",
|
|
12238
12505
|
reviewCycles: 0,
|
|
12239
12506
|
issues: [errMsg]
|
|
12240
12507
|
});
|
|
12241
12508
|
await persistState();
|
|
12242
12509
|
return;
|
|
12243
12510
|
}
|
|
12244
|
-
if (projectRoot !== void 0) {
|
|
12245
|
-
const expectedArtifactsDir = join$1(projectRoot, "_bmad-output", "implementation-artifacts");
|
|
12246
|
-
const claimedPath = createResult.story_file;
|
|
12247
|
-
if (claimedPath.startsWith(expectedArtifactsDir)) try {
|
|
12248
|
-
if (!existsSync(claimedPath)) {
|
|
12249
|
-
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
12250
|
-
const errMsg = `create-story claimed success (story_file: ${claimedPath}) but the file does not exist on disk (output tokens: ${outputTokens})`;
|
|
12251
|
-
logger$24.error({
|
|
12252
|
-
storyKey,
|
|
12253
|
-
claimedPath,
|
|
12254
|
-
outputTokens
|
|
12255
|
-
}, errMsg);
|
|
12256
|
-
updateStory(storyKey, {
|
|
12257
|
-
phase: "ESCALATED",
|
|
12258
|
-
error: errMsg,
|
|
12259
|
-
completedAt: new Date().toISOString()
|
|
12260
|
-
});
|
|
12261
|
-
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12262
|
-
await emitEscalation({
|
|
12263
|
-
storyKey,
|
|
12264
|
-
lastVerdict: "create-story-fraud-success",
|
|
12265
|
-
reviewCycles: 0,
|
|
12266
|
-
issues: [errMsg]
|
|
12267
|
-
});
|
|
12268
|
-
await persistState();
|
|
12269
|
-
return;
|
|
12270
|
-
}
|
|
12271
|
-
const claimedStat = statSync(claimedPath);
|
|
12272
|
-
if (claimedStat.mtimeMs < dispatchStartMs) {
|
|
12273
|
-
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
12274
|
-
const mtimeISO = new Date(claimedStat.mtimeMs).toISOString();
|
|
12275
|
-
const dispatchStartISO = new Date(dispatchStartMs).toISOString();
|
|
12276
|
-
const errMsg = `create-story claimed success but did not rewrite ${claimedPath} during this dispatch (file mtime ${mtimeISO} predates dispatch start ${dispatchStartISO}; output tokens: ${outputTokens})`;
|
|
12277
|
-
logger$24.error({
|
|
12278
|
-
storyKey,
|
|
12279
|
-
claimedPath,
|
|
12280
|
-
mtimeISO,
|
|
12281
|
-
dispatchStartISO,
|
|
12282
|
-
outputTokens
|
|
12283
|
-
}, errMsg);
|
|
12284
|
-
updateStory(storyKey, {
|
|
12285
|
-
phase: "ESCALATED",
|
|
12286
|
-
error: errMsg,
|
|
12287
|
-
completedAt: new Date().toISOString()
|
|
12288
|
-
});
|
|
12289
|
-
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12290
|
-
await emitEscalation({
|
|
12291
|
-
storyKey,
|
|
12292
|
-
lastVerdict: "create-story-fraud-success",
|
|
12293
|
-
reviewCycles: 0,
|
|
12294
|
-
issues: [errMsg]
|
|
12295
|
-
});
|
|
12296
|
-
await persistState();
|
|
12297
|
-
return;
|
|
12298
|
-
}
|
|
12299
|
-
} catch (verifyErr) {
|
|
12300
|
-
logger$24.warn({
|
|
12301
|
-
storyKey,
|
|
12302
|
-
err: verifyErr
|
|
12303
|
-
}, "create-story post-dispatch file verification threw; proceeding with claimed path");
|
|
12304
|
-
}
|
|
12305
|
-
}
|
|
12306
|
-
storyFilePath = createResult.story_file;
|
|
12307
|
-
if (createResult.story_title) try {
|
|
12511
|
+
if (storyFilePath !== void 0 && projectRoot !== void 0) try {
|
|
12308
12512
|
const epicId = storyKey.split("-")[0] ?? storyKey;
|
|
12309
|
-
const
|
|
12310
|
-
let
|
|
12311
|
-
const
|
|
12312
|
-
if (
|
|
12513
|
+
const fidelityImplDecisions = await getDecisionsByPhase(db, "implementation");
|
|
12514
|
+
let fidelitySourceContent;
|
|
12515
|
+
const fidelityPerStoryShard = fidelityImplDecisions.find((d) => d.category === "epic-shard" && d.key === storyKey);
|
|
12516
|
+
if (fidelityPerStoryShard?.value) fidelitySourceContent = fidelityPerStoryShard.value;
|
|
12313
12517
|
else {
|
|
12314
|
-
const
|
|
12315
|
-
if (
|
|
12316
|
-
}
|
|
12317
|
-
if (
|
|
12318
|
-
const
|
|
12319
|
-
if (
|
|
12320
|
-
const
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
logger$24.warn({
|
|
12324
|
-
storyKey,
|
|
12325
|
-
expectedTitle,
|
|
12326
|
-
generatedTitle: createResult.story_title,
|
|
12327
|
-
overlap
|
|
12328
|
-
}, msg);
|
|
12329
|
-
eventBus.emit("orchestrator:story-warn", {
|
|
12330
|
-
storyKey,
|
|
12331
|
-
msg
|
|
12332
|
-
});
|
|
12333
|
-
} else logger$24.debug({
|
|
12518
|
+
const epicShardForFidelity = fidelityImplDecisions.find((d) => d.category === "epic-shard" && d.key === epicId);
|
|
12519
|
+
if (epicShardForFidelity?.value) fidelitySourceContent = extractStorySection(epicShardForFidelity.value, storyKey) ?? void 0;
|
|
12520
|
+
}
|
|
12521
|
+
if (fidelitySourceContent !== void 0) {
|
|
12522
|
+
const namedPaths = extractNamedPathsFromSource(fidelitySourceContent);
|
|
12523
|
+
if (namedPaths.length >= MIN_NAMED_PATHS_FOR_FIDELITY_GATE) {
|
|
12524
|
+
const storyContentForFidelity = await readFile$1(storyFilePath, "utf-8");
|
|
12525
|
+
const fidelity = computeStoryFileFidelity(storyContentForFidelity, namedPaths);
|
|
12526
|
+
logger$24.debug({
|
|
12334
12527
|
storyKey,
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12528
|
+
drift: fidelity.drift,
|
|
12529
|
+
missing: fidelity.missing,
|
|
12530
|
+
presentCount: fidelity.present.length,
|
|
12531
|
+
namedPathsCount: namedPaths.length
|
|
12532
|
+
}, "create-story output fidelity check");
|
|
12533
|
+
if (fidelity.drift > FIDELITY_DRIFT_THRESHOLD) {
|
|
12534
|
+
fidelityRetries++;
|
|
12535
|
+
if (fidelityRetries <= MAX_FIDELITY_RETRIES) {
|
|
12536
|
+
const stalePath = storyFilePath.replace(/\.md$/, `.stale-${Date.now()}.md`);
|
|
12537
|
+
try {
|
|
12538
|
+
renameSync(storyFilePath, stalePath);
|
|
12539
|
+
const driftPct = Math.round(fidelity.drift * 100);
|
|
12540
|
+
logger$24.warn({
|
|
12541
|
+
storyKey,
|
|
12542
|
+
drift: fidelity.drift,
|
|
12543
|
+
missing: fidelity.missing,
|
|
12544
|
+
retries: fidelityRetries,
|
|
12545
|
+
stalePath
|
|
12546
|
+
}, `create-story output drifted from source AC (${driftPct}% of ${namedPaths.length} named paths missing); renamed to ${stalePath} and retrying (${fidelityRetries}/${MAX_FIDELITY_RETRIES})`);
|
|
12547
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
12548
|
+
storyKey,
|
|
12549
|
+
msg: `create-story drift detected (${fidelity.missing.length}/${namedPaths.length} named paths missing); retry ${fidelityRetries}/${MAX_FIDELITY_RETRIES}`
|
|
12550
|
+
});
|
|
12551
|
+
priorDriftFeedback = [
|
|
12552
|
+
`### Prior Dispatch Drift Detected (retry ${fidelityRetries}/${MAX_FIDELITY_RETRIES})`,
|
|
12553
|
+
"",
|
|
12554
|
+
`A previous create-story dispatch for this story produced an artifact that omitted ${fidelity.missing.length} of ${namedPaths.length} named files/paths from the source AC. The previous artifact has been moved to \`${stalePath}\` and you are being re-dispatched to produce a corrected artifact.`,
|
|
12555
|
+
"",
|
|
12556
|
+
"**Named paths from the source AC that were missing in the prior dispatch:**",
|
|
12557
|
+
"",
|
|
12558
|
+
...fidelity.missing.map((p) => `- \`${p}\``),
|
|
12559
|
+
"",
|
|
12560
|
+
"These names appear in the Epic Scope above and are part of the source AC contract. Preserve them verbatim in your rendered artifact (file lists, paths, named identifiers in Tasks/Subtasks). Do not substitute alternative names from training priors. If the source AC says `adjacency-store.ts`, the rendered story file says `adjacency-store.ts` — not `LinkStore`, `AdjacencyManager`, or any other re-conceptualization."
|
|
12561
|
+
].join("\n");
|
|
12562
|
+
storyFilePath = void 0;
|
|
12563
|
+
continue;
|
|
12564
|
+
} catch (renameErr) {
|
|
12565
|
+
logger$24.warn({
|
|
12566
|
+
storyKey,
|
|
12567
|
+
err: renameErr,
|
|
12568
|
+
stalePath
|
|
12569
|
+
}, "failed to rename drifting artifact for retry; proceeding with current artifact");
|
|
12570
|
+
}
|
|
12571
|
+
} else {
|
|
12572
|
+
const errMsg = `create-story output drifted from source AC after ${MAX_FIDELITY_RETRIES} retries; ${fidelity.missing.length} of ${namedPaths.length} named paths missing: ` + fidelity.missing.join(", ");
|
|
12573
|
+
logger$24.error({
|
|
12574
|
+
storyKey,
|
|
12575
|
+
drift: fidelity.drift,
|
|
12576
|
+
missing: fidelity.missing,
|
|
12577
|
+
namedPaths
|
|
12578
|
+
}, errMsg);
|
|
12579
|
+
endPhase(storyKey, "create-story");
|
|
12580
|
+
updateStory(storyKey, {
|
|
12581
|
+
phase: "ESCALATED",
|
|
12582
|
+
error: errMsg,
|
|
12583
|
+
completedAt: new Date().toISOString()
|
|
12584
|
+
});
|
|
12585
|
+
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12586
|
+
await emitEscalation({
|
|
12587
|
+
storyKey,
|
|
12588
|
+
lastVerdict: "create-story-source-ac-drift",
|
|
12589
|
+
reviewCycles: 0,
|
|
12590
|
+
issues: [errMsg]
|
|
12591
|
+
});
|
|
12592
|
+
await persistState();
|
|
12593
|
+
return;
|
|
12594
|
+
}
|
|
12595
|
+
}
|
|
12339
12596
|
}
|
|
12340
12597
|
}
|
|
12341
|
-
} catch (
|
|
12342
|
-
logger$24.
|
|
12598
|
+
} catch (fidelityErr) {
|
|
12599
|
+
logger$24.warn({
|
|
12343
12600
|
storyKey,
|
|
12344
|
-
err:
|
|
12345
|
-
}, "
|
|
12601
|
+
err: fidelityErr
|
|
12602
|
+
}, "fidelity gate threw; proceeding without retry");
|
|
12346
12603
|
}
|
|
12347
|
-
} catch (err) {
|
|
12348
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
12349
|
-
endPhase(storyKey, "create-story");
|
|
12350
|
-
updateStory(storyKey, {
|
|
12351
|
-
phase: "ESCALATED",
|
|
12352
|
-
error: errMsg,
|
|
12353
|
-
completedAt: new Date().toISOString()
|
|
12354
|
-
});
|
|
12355
|
-
await writeStoryMetricsBestEffort(storyKey, "failed", 0);
|
|
12356
|
-
await emitEscalation({
|
|
12357
|
-
storyKey,
|
|
12358
|
-
lastVerdict: "create-story-exception",
|
|
12359
|
-
reviewCycles: 0,
|
|
12360
|
-
issues: [errMsg]
|
|
12361
|
-
});
|
|
12362
|
-
await persistState();
|
|
12363
|
-
return;
|
|
12364
12604
|
}
|
|
12365
12605
|
if (storyFilePath) try {
|
|
12366
12606
|
const storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
@@ -44091,4 +44331,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
44091
44331
|
|
|
44092
44332
|
//#endregion
|
|
44093
44333
|
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
44094
|
-
//# sourceMappingURL=run-
|
|
44334
|
+
//# sourceMappingURL=run-DrJWCS63.js.map
|
package/package.json
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
### Story Definition (from Solutioning Phase)
|
|
20
20
|
{{story_definition}}
|
|
21
21
|
|
|
22
|
+
{{prior_drift_feedback}}
|
|
23
|
+
|
|
22
24
|
---
|
|
23
25
|
|
|
24
26
|
## Mission
|
|
@@ -72,6 +74,7 @@ Do NOT write a partial story file. Do NOT paraphrase surrounding context. Do NOT
|
|
|
72
74
|
- Dev Notes with file paths, import patterns, testing requirements
|
|
73
75
|
6. **Apply the scope cap** — see Scope Cap Guidance below
|
|
74
76
|
7. **Write the story file** to: `_bmad-output/implementation-artifacts/{{story_key}}-<kebab-title>.md`
|
|
77
|
+
- Pass this path to your file-writing tool **literally as written** — do NOT markdown-escape the underscore as `\_bmad-output`. The leading underscore is part of the directory name, not a markdown italic delimiter.
|
|
75
78
|
- Do NOT add a `Status:` field to the story file — story status is managed exclusively by the Dolt work graph (`wg_stories` table)
|
|
76
79
|
- Dev Agent Record section must be present but left blank (to be filled by dev agent)
|
|
77
80
|
|