substrate-ai 0.20.15 → 0.20.17

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
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDING_COUNTS, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts } from "../health-hNQ-z9nd.js";
2
+ import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDING_COUNTS, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts } from "../health-ZGa9E0D2.js";
3
3
  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--9oBsXVf.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-xQLHet2Y.js";
8
8
  import "../errors-1uLGqnvr.js";
9
9
  import "../routing-CcBOCuC9.js";
10
10
  import "../decisions-C0pz9Clx.js";
@@ -25,7 +25,7 @@ import { randomUUID } from "node:crypto";
25
25
  import { z } from "zod";
26
26
  import * as fs from "node:fs/promises";
27
27
  import { access as access$1, readFile as readFile$1, readdir as readdir$1 } from "node:fs/promises";
28
- import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
28
+ import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
29
29
  import { homedir } from "os";
30
30
  import { createRequire } from "node:module";
31
31
  import { fileURLToPath as fileURLToPath$1 } from "node:url";
@@ -3667,7 +3667,7 @@ async function runStatusAction(options) {
3667
3667
  logger$12.debug({ err }, "Work graph query failed, continuing without work graph data");
3668
3668
  }
3669
3669
  if (run === void 0) {
3670
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-B4_mAeh7.js");
3670
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-CeVz5k99.js");
3671
3671
  const substrateDirPath = join(projectRoot, ".substrate");
3672
3672
  const processInfo = inspectProcessTree$1({
3673
3673
  projectRoot,
@@ -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-CG-mUym3.js"
5201
+ "../run-CZW8qqr5.js"
5202
5202
  );
5203
5203
  const runStoryFn = async (opts) => {
5204
5204
  const exitCode = await runPipeline({
@@ -6801,7 +6801,7 @@ async function runMonitorStatusAction(options) {
6801
6801
  const { earliest: earliestDate, latest: latestDate } = monitorDb.getTaskMetricsDateRange();
6802
6802
  let dbSizeBytes = 0;
6803
6803
  try {
6804
- dbSizeBytes = statSync(dbPath).size;
6804
+ dbSizeBytes = statSync$1(dbPath).size;
6805
6805
  } catch {}
6806
6806
  const statusData = {
6807
6807
  total_tasks: totalTasks,
@@ -1,4 +1,4 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-hNQ-z9nd.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-ZGa9E0D2.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./dist-CqtWS9wF.js";
4
4
  import "./decisions-C0pz9Clx.js";
@@ -5,9 +5,9 @@ import { dirname, join } from "path";
5
5
  import { readFile } from "fs/promises";
6
6
  import { EventEmitter } from "node:events";
7
7
  import { YAMLException, load } from "js-yaml";
8
- import { existsSync, promises, readFileSync } from "node:fs";
8
+ import { existsSync, promises, readFileSync, readdirSync, statSync } from "node:fs";
9
9
  import { spawn, spawnSync } from "node:child_process";
10
- import { dirname as dirname$1, join as join$1, resolve as resolve$1 } from "node:path";
10
+ import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "node:path";
11
11
  import { z } from "zod";
12
12
  import { mkdir as mkdir$1, open, readFile as readFile$1, unlink, writeFile as writeFile$1 } from "node:fs/promises";
13
13
  import { existsSync as existsSync$1 } from "fs";
@@ -3767,6 +3767,86 @@ var RuntimeProbeCheck = class {
3767
3767
  //#endregion
3768
3768
  //#region packages/sdlc/dist/verification/source-ac-fidelity-check.js
3769
3769
  /**
3770
+ * Directory names that should never be searched when doing the basename-glob
3771
+ * fallback for a relative path clause. Prevents the check from spending time
3772
+ * in the node_modules tree (which frequently has files whose basenames
3773
+ * collide with project source) and from descending into build or VCS output.
3774
+ */
3775
+ const SKIP_DIRS = new Set([
3776
+ "node_modules",
3777
+ ".git",
3778
+ "dist",
3779
+ "build",
3780
+ ".substrate",
3781
+ "_bmad-output",
3782
+ "coverage",
3783
+ ".next",
3784
+ ".cache"
3785
+ ]);
3786
+ /** Max depth for the basename walk. Prevents pathological traversal. */
3787
+ const MAX_WALK_DEPTH = 8;
3788
+ /**
3789
+ * Return true if `base` (a filename like `discover.ts`) exists somewhere under
3790
+ * `root` within MAX_WALK_DEPTH levels, skipping SKIP_DIRS. The walk is
3791
+ * synchronous and bounded; finding a single match exits early.
3792
+ */
3793
+ function existsAnywhereUnderRoot(root, base) {
3794
+ const stack = [{
3795
+ path: root,
3796
+ depth: 0
3797
+ }];
3798
+ while (stack.length > 0) {
3799
+ const { path: path$1, depth } = stack.pop();
3800
+ if (depth > MAX_WALK_DEPTH) continue;
3801
+ let entries;
3802
+ try {
3803
+ entries = readdirSync(path$1);
3804
+ } catch {
3805
+ continue;
3806
+ }
3807
+ for (const entry of entries) {
3808
+ if (SKIP_DIRS.has(entry)) continue;
3809
+ if (entry === base) return true;
3810
+ const full = join$1(path$1, entry);
3811
+ try {
3812
+ const s = statSync(full);
3813
+ if (s.isDirectory()) stack.push({
3814
+ path: full,
3815
+ depth: depth + 1
3816
+ });
3817
+ } catch {
3818
+ continue;
3819
+ }
3820
+ }
3821
+ }
3822
+ return false;
3823
+ }
3824
+ /**
3825
+ * Check whether a path clause extracted from the source AC is satisfied by
3826
+ * the actual code under `workingDir`. Story 58-9c: handles relative paths
3827
+ * (e.g., `./discover.ts`) that the v0.20.15 literal `join(workingDir, path)`
3828
+ * check mis-resolved.
3829
+ *
3830
+ * Resolution strategy (in order):
3831
+ * 1. Literal `workingDir/path` — handles absolute paths and dot-stripped relatives.
3832
+ * 2. If the original started with `./`, strip the prefix and retry step 1.
3833
+ * 3. Basename search under workingDir — finds paths that live in an
3834
+ * unstated directory context (common for relative imports in ACs).
3835
+ *
3836
+ * Any hit is treated as "code satisfies" (stylistic drift → warn). No hit
3837
+ * means architectural drift → error.
3838
+ */
3839
+ function pathSatisfiedByCode(workingDir, pathClause) {
3840
+ const raw = pathClause.replace(/^`/, "").replace(/`$/, "");
3841
+ if (existsSync(join$1(workingDir, raw))) return true;
3842
+ if (raw.startsWith("./")) {
3843
+ if (existsSync(join$1(workingDir, raw.slice(2)))) return true;
3844
+ }
3845
+ const isLikelyRelative = raw.startsWith("./") || !raw.includes("/");
3846
+ if (isLikelyRelative) return existsAnywhereUnderRoot(workingDir, basename$1(raw));
3847
+ return false;
3848
+ }
3849
+ /**
3770
3850
  * Extract the story's section from the full epic content.
3771
3851
  *
3772
3852
  * Uses the same heading pattern as `isImplicitlyCovered` in the monolith:
@@ -3856,8 +3936,7 @@ var SourceAcFidelityCheck = class {
3856
3936
  } else if (!storyContent.includes(clause.text)) {
3857
3937
  const truncated = clause.text.length > 120 ? clause.text.slice(0, 120) : clause.text;
3858
3938
  if (clause.type === "path") {
3859
- const pathOnly = clause.text.replace(/^`/, "").replace(/`$/, "");
3860
- const existsInCode = existsSync(join$1(context.workingDir, pathOnly));
3939
+ const existsInCode = pathSatisfiedByCode(context.workingDir, clause.text);
3861
3940
  findings.push({
3862
3941
  category: "source-ac-drift",
3863
3942
  severity: existsInCode ? "warn" : "error",
@@ -5543,4 +5622,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
5543
5622
 
5544
5623
  //#endregion
5545
5624
  export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDING_COUNTS, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, createStateStore, detectCycles, extractTargetFilesFromStoryContent, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, registerHealthCommand, renderFindings, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, runHealthAction, validateStoryKey };
5546
- //# sourceMappingURL=health-hNQ-z9nd.js.map
5625
+ //# sourceMappingURL=health-ZGa9E0D2.js.map
@@ -1,8 +1,8 @@
1
- import "./health-hNQ-z9nd.js";
1
+ 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--9oBsXVf.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-xQLHet2Y.js";
6
6
  import "./routing-CcBOCuC9.js";
7
7
  import "./decisions-C0pz9Clx.js";
8
8
 
@@ -1,4 +1,4 @@
1
- import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-hNQ-z9nd.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-ZGa9E0D2.js";
2
2
  import { createLogger } from "./logger-KeHncl-f.js";
3
3
  import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
4
4
  import { ADVISORY_NOTES, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-CqtWS9wF.js";
@@ -7,7 +7,7 @@ import { access, readFile, readdir, stat } from "fs/promises";
7
7
  import { EventEmitter } from "node:events";
8
8
  import yaml from "js-yaml";
9
9
  import * as actualFS from "node:fs";
10
- import { accessSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, unlinkSync, unwatchFile, watchFile, writeFileSync } from "node:fs";
10
+ import { accessSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, unwatchFile, watchFile, writeFileSync } from "node:fs";
11
11
  import { exec, execFile, execFileSync, execSync, spawn } from "node:child_process";
12
12
  import path, { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, posix, resolve as resolve$1, win32 } from "node:path";
13
13
  import { tmpdir } from "node:os";
@@ -12034,7 +12034,8 @@ function createImplementationOrchestrator(deps) {
12034
12034
  const artifactsDir = projectRoot ? join$1(projectRoot, "_bmad-output", "implementation-artifacts") : void 0;
12035
12035
  if (artifactsDir && existsSync(artifactsDir)) try {
12036
12036
  const files = readdirSync(artifactsDir);
12037
- const match$2 = files.find((f$1) => f$1.startsWith(`${storyKey}-`) && f$1.endsWith(".md"));
12037
+ const STALE_SUFFIX = /\.stale-\d+\.md$/;
12038
+ const match$2 = files.find((f$1) => f$1.startsWith(`${storyKey}-`) && f$1.endsWith(".md") && !STALE_SUFFIX.test(f$1));
12038
12039
  if (match$2) {
12039
12040
  const candidatePath = join$1(artifactsDir, match$2);
12040
12041
  const validation = await isValidStoryFile(candidatePath);
@@ -12089,6 +12090,20 @@ function createImplementationOrchestrator(deps) {
12089
12090
  }
12090
12091
  });
12091
12092
  await persistState();
12093
+ } else try {
12094
+ const ts = Date.now();
12095
+ const staleName = match$2.replace(/\.md$/, `.stale-${ts}.md`);
12096
+ const stalePath = join$1(artifactsDir, staleName);
12097
+ renameSync(candidatePath, stalePath);
12098
+ logger$24.info({
12099
+ storyKey,
12100
+ staleName
12101
+ }, `[orchestrator] story ${storyKey}: renamed drifted artifact to ${staleName} before re-dispatch`);
12102
+ } catch (renameErr) {
12103
+ logger$24.warn({
12104
+ storyKey,
12105
+ err: renameErr
12106
+ }, "Failed to rename stale artifact before create-story re-dispatch; relying on 58-9d fraud-guard");
12092
12107
  }
12093
12108
  }
12094
12109
  }
@@ -12114,6 +12129,7 @@ function createImplementationOrchestrator(deps) {
12114
12129
  }
12115
12130
  if (storyFilePath === void 0) try {
12116
12131
  incrementDispatches(storyKey);
12132
+ const dispatchStartMs = Date.now();
12117
12133
  const createResult = await runCreateStory({
12118
12134
  db,
12119
12135
  pack,
@@ -12186,6 +12202,68 @@ function createImplementationOrchestrator(deps) {
12186
12202
  await persistState();
12187
12203
  return;
12188
12204
  }
12205
+ if (projectRoot !== void 0) {
12206
+ const expectedArtifactsDir = join$1(projectRoot, "_bmad-output", "implementation-artifacts");
12207
+ const claimedPath = createResult.story_file;
12208
+ if (claimedPath.startsWith(expectedArtifactsDir)) try {
12209
+ if (!existsSync(claimedPath)) {
12210
+ const outputTokens = createResult.tokenUsage?.output ?? 0;
12211
+ const errMsg = `create-story claimed success (story_file: ${claimedPath}) but the file does not exist on disk (output tokens: ${outputTokens})`;
12212
+ logger$24.error({
12213
+ storyKey,
12214
+ claimedPath,
12215
+ outputTokens
12216
+ }, errMsg);
12217
+ updateStory(storyKey, {
12218
+ phase: "ESCALATED",
12219
+ error: errMsg,
12220
+ completedAt: new Date().toISOString()
12221
+ });
12222
+ await writeStoryMetricsBestEffort(storyKey, "failed", 0);
12223
+ await emitEscalation({
12224
+ storyKey,
12225
+ lastVerdict: "create-story-fraud-success",
12226
+ reviewCycles: 0,
12227
+ issues: [errMsg]
12228
+ });
12229
+ await persistState();
12230
+ return;
12231
+ }
12232
+ const claimedStat = statSync(claimedPath);
12233
+ if (claimedStat.mtimeMs < dispatchStartMs) {
12234
+ const outputTokens = createResult.tokenUsage?.output ?? 0;
12235
+ const mtimeISO = new Date(claimedStat.mtimeMs).toISOString();
12236
+ const dispatchStartISO = new Date(dispatchStartMs).toISOString();
12237
+ const errMsg = `create-story claimed success but did not rewrite ${claimedPath} during this dispatch (file mtime ${mtimeISO} predates dispatch start ${dispatchStartISO}; output tokens: ${outputTokens})`;
12238
+ logger$24.error({
12239
+ storyKey,
12240
+ claimedPath,
12241
+ mtimeISO,
12242
+ dispatchStartISO,
12243
+ outputTokens
12244
+ }, errMsg);
12245
+ updateStory(storyKey, {
12246
+ phase: "ESCALATED",
12247
+ error: errMsg,
12248
+ completedAt: new Date().toISOString()
12249
+ });
12250
+ await writeStoryMetricsBestEffort(storyKey, "failed", 0);
12251
+ await emitEscalation({
12252
+ storyKey,
12253
+ lastVerdict: "create-story-fraud-success",
12254
+ reviewCycles: 0,
12255
+ issues: [errMsg]
12256
+ });
12257
+ await persistState();
12258
+ return;
12259
+ }
12260
+ } catch (verifyErr) {
12261
+ logger$24.warn({
12262
+ storyKey,
12263
+ err: verifyErr
12264
+ }, "create-story post-dispatch file verification threw; proceeding with claimed path");
12265
+ }
12266
+ }
12189
12267
  storyFilePath = createResult.story_file;
12190
12268
  if (createResult.story_title) try {
12191
12269
  const epicId = storyKey.split("-")[0] ?? storyKey;
@@ -14369,8 +14447,7 @@ function createImplementationOrchestrator(deps) {
14369
14447
  let escalated = 0;
14370
14448
  let failed = 0;
14371
14449
  for (const s$1 of _stories.values()) if (s$1.phase === "COMPLETE") completed++;
14372
- else if (s$1.phase === "ESCALATED") if (s$1.error !== void 0) failed++;
14373
- else escalated++;
14450
+ else if (s$1.phase === "ESCALATED") escalated++;
14374
14451
  else if (s$1.phase === "VERIFICATION_FAILED") failed++;
14375
14452
  eventBus.emit("orchestrator:complete", {
14376
14453
  totalStories: storyKeys.length,
@@ -43372,8 +43449,7 @@ async function runRunAction(options) {
43372
43449
  const failedKeys = [];
43373
43450
  const escalatedKeys = [];
43374
43451
  for (const [key, s$1] of Object.entries(status.stories)) if (s$1.phase === "COMPLETE") succeededKeys.push(key);
43375
- else if (s$1.phase === "ESCALATED") if (s$1.error !== void 0) failedKeys.push(key);
43376
- else escalatedKeys.push(key);
43452
+ else if (s$1.phase === "ESCALATED") escalatedKeys.push(key);
43377
43453
  else failedKeys.push(key);
43378
43454
  try {
43379
43455
  const runEndMs = Date.now();
@@ -43406,7 +43482,7 @@ async function runRunAction(options) {
43406
43482
  }
43407
43483
  try {
43408
43484
  const runsDir = join(dbDir, "runs");
43409
- const terminalStatus = failedKeys.length > 0 ? "failed" : "completed";
43485
+ const terminalStatus = failedKeys.length > 0 || escalatedKeys.length > 0 ? "failed" : "completed";
43410
43486
  await RunManifest.open(pipelineRun.id, runsDir).update({ run_status: terminalStatus });
43411
43487
  } catch {}
43412
43488
  if (progressRenderer !== void 0) progressRenderer.render({
@@ -43817,8 +43893,7 @@ async function runFullPipeline(options) {
43817
43893
  const implStatus = await orchestrator.run(storyKeys);
43818
43894
  if (outputFormat === "human") process.stdout.write("[IMPLEMENTATION] Complete\n");
43819
43895
  for (const [key, s$1] of Object.entries(implStatus.stories)) if (s$1.phase === "COMPLETE") fpSucceededKeys.push(key);
43820
- else if (s$1.phase === "ESCALATED") if (s$1.error !== void 0) fpFailedKeys.push(key);
43821
- else fpEscalatedKeys.push(key);
43896
+ else if (s$1.phase === "ESCALATED") fpEscalatedKeys.push(key);
43822
43897
  else fpFailedKeys.push(key);
43823
43898
  }
43824
43899
  if (fullPipelineNdjsonEmitter !== void 0) fullPipelineNdjsonEmitter.emit({
@@ -43977,4 +44052,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
43977
44052
 
43978
44053
  //#endregion
43979
44054
  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 };
43980
- //# sourceMappingURL=run--9oBsXVf.js.map
44055
+ //# sourceMappingURL=run-xQLHet2Y.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.15",
3
+ "version": "0.20.17",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",