substrate-ai 0.20.33 → 0.20.35

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-Cz4RTHNh.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-CnV6ndAb.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-BnMsd9hC.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-BLaHTh1C.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-B7O3HgSR.js";
8
8
  import "../errors-DSGhhrgv.js";
9
9
  import "../routing-CcBOCuC9.js";
10
10
  import "../decisions-C0pz9Clx.js";
@@ -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-B6AMpmJB.js");
3670
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-Bqzqu6zC.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-C-mxCkwh.js"
5201
+ "../run-VgLqFM7X.js"
5202
5202
  );
5203
5203
  const runStoryFn = async (opts) => {
5204
5204
  const exitCode = await runPipeline({
@@ -1,4 +1,4 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-Cz4RTHNh.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-CnV6ndAb.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./dist-BnMsd9hC.js";
4
4
  import "./decisions-C0pz9Clx.js";
@@ -3831,6 +3831,40 @@ function tail(text, bytes = PROBE_TAIL_BYTES) {
3831
3831
  * way a typo in one author's probe surfaces as a deterministic finding,
3832
3832
  * not a pipeline crash that masks the rest of the run.
3833
3833
  */
3834
+ /**
3835
+ * Story 63-2: canonical error-envelope shapes that signal the tool
3836
+ * responded with a structured error despite exiting 0. Detected
3837
+ * regardless of whether the author declared an assertion — defense-in-depth
3838
+ * against under-test probes that count tool advertisement but don't check
3839
+ * response shape (the obs_012 REOPENED class).
3840
+ *
3841
+ * Patterns are matched against the FULL captured stdout (not the tailed
3842
+ * excerpt) so error envelopes deeper than `PROBE_TAIL_BYTES` aren't
3843
+ * missed when a probe runs multiple sub-commands and the error surfaces
3844
+ * partway through.
3845
+ *
3846
+ * Match keys are JSON-shape only (case-sensitive); we do not try to
3847
+ * detect prose-form errors ("ERROR:" log lines) because those produce
3848
+ * far too many false positives — many tools log informational warnings
3849
+ * to stdout that contain the word "error".
3850
+ */
3851
+ const ERROR_SHAPE_PATTERNS = [{
3852
+ pattern: /"isError"\s*:\s*true\b/,
3853
+ description: "\"isError\": true (MCP / Anthropic tool error envelope)"
3854
+ }, {
3855
+ pattern: /"status"\s*:\s*"error"/,
3856
+ description: "\"status\": \"error\" (REST / RPC error envelope)"
3857
+ }];
3858
+ /**
3859
+ * Story 63-2: scan stdout for canonical error-envelope shapes. Returns
3860
+ * an array of human-readable descriptions of detected patterns; empty
3861
+ * array when the response shape looks clean.
3862
+ */
3863
+ function detectErrorShapeIndicators(stdout) {
3864
+ const indicators = [];
3865
+ for (const { pattern, description } of ERROR_SHAPE_PATTERNS) if (pattern.test(stdout)) indicators.push(description);
3866
+ return indicators;
3867
+ }
3834
3868
  function evaluateStdoutAssertions(probe, stdout) {
3835
3869
  const failures = [];
3836
3870
  for (const pattern of probe.expect_stdout_no_regex ?? []) {
@@ -3931,11 +3965,18 @@ function executeProbeOnHost(probe, options = {}) {
3931
3965
  const duration = Date.now() - start;
3932
3966
  let outcome = code === 0 ? "pass" : "fail";
3933
3967
  let assertionFailures;
3968
+ let errorShapeIndicators;
3934
3969
  if (outcome === "pass") {
3935
3970
  const failures = evaluateStdoutAssertions(probe, stdout);
3936
3971
  if (failures.length > 0) {
3937
3972
  outcome = "fail";
3938
3973
  assertionFailures = failures;
3974
+ } else {
3975
+ const indicators = detectErrorShapeIndicators(stdout);
3976
+ if (indicators.length > 0) {
3977
+ outcome = "fail";
3978
+ errorShapeIndicators = indicators;
3979
+ }
3939
3980
  }
3940
3981
  }
3941
3982
  finalize({
@@ -3945,7 +3986,8 @@ function executeProbeOnHost(probe, options = {}) {
3945
3986
  stdoutTail: tail(stdout),
3946
3987
  stderrTail: tail(stderr),
3947
3988
  durationMs: duration,
3948
- ...assertionFailures !== void 0 ? { assertionFailures } : {}
3989
+ ...assertionFailures !== void 0 ? { assertionFailures } : {},
3990
+ ...errorShapeIndicators !== void 0 ? { errorShapeIndicators } : {}
3949
3991
  });
3950
3992
  });
3951
3993
  });
@@ -3966,6 +4008,16 @@ const CATEGORY_TIMEOUT = "runtime-probe-timeout";
3966
4008
  */
3967
4009
  const CATEGORY_ASSERTION_FAIL = "runtime-probe-assertion-fail";
3968
4010
  /**
4011
+ * Story 63-2: command exited 0 and no author-declared assertion tripped,
4012
+ * but the captured stdout contains a canonical error-envelope shape
4013
+ * (`"isError": true`, `"status": "error"`). Defense-in-depth against
4014
+ * under-test probes that count tool advertisement without checking
4015
+ * response shape — the structural fix for obs_2026-04-25_012 (REOPENED).
4016
+ * Distinct from CATEGORY_ASSERTION_FAIL because the author DIDN'T declare
4017
+ * an assertion; the executor caught the error envelope automatically.
4018
+ */
4019
+ const CATEGORY_ERROR_RESPONSE = "runtime-probe-error-response";
4020
+ /**
3969
4021
  * Story 60-11: source AC describes an event-driven mechanism (hook, timer,
3970
4022
  * signal, webhook) but no probe's command invokes a known production-trigger
3971
4023
  * pattern. Strata Run 13 (Story 1-12, 2026-04-26): vault conflict hook
@@ -4103,11 +4155,12 @@ var RuntimeProbeCheck = class {
4103
4155
  }
4104
4156
  const result = await this._executors.host(probe);
4105
4157
  if (result.outcome === "pass") continue;
4106
- const category = result.outcome === "timeout" ? CATEGORY_TIMEOUT : result.assertionFailures !== void 0 ? CATEGORY_ASSERTION_FAIL : CATEGORY_FAIL;
4158
+ const category = result.outcome === "timeout" ? CATEGORY_TIMEOUT : result.assertionFailures !== void 0 ? CATEGORY_ASSERTION_FAIL : result.errorShapeIndicators !== void 0 ? CATEGORY_ERROR_RESPONSE : CATEGORY_FAIL;
4107
4159
  const descriptor = probe.description ? ` (${probe.description})` : "";
4108
4160
  let message;
4109
4161
  if (result.outcome === "timeout") message = `probe "${probe.name}"${descriptor} timed out after ${result.durationMs}ms`;
4110
4162
  else if (result.assertionFailures !== void 0) message = `probe "${probe.name}"${descriptor} exit 0 but stdout assertion failed: ` + result.assertionFailures.join("; ");
4163
+ else if (result.errorShapeIndicators !== void 0) message = `probe "${probe.name}"${descriptor} exit 0 but response contained error envelope: ` + result.errorShapeIndicators.join("; ") + " — the tool returned an error-shaped JSON response despite a clean exit code. This is structural evidence the implementation didn't actually work; add an explicit `expect_stdout_no_regex` assertion to make the failure surface earlier in author-controlled form.";
4111
4164
  else message = `probe "${probe.name}"${descriptor} failed with exit ${result.exitCode ?? "unknown"}`;
4112
4165
  findings.push({
4113
4166
  category,
@@ -6291,4 +6344,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
6291
6344
 
6292
6345
  //#endregion
6293
6346
  export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, 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, detectsEventDrivenAC, extractTargetFilesFromStoryContent, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, registerHealthCommand, renderFindings, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, runHealthAction, validateStoryKey };
6294
- //# sourceMappingURL=health-Cz4RTHNh.js.map
6347
+ //# sourceMappingURL=health-CnV6ndAb.js.map
@@ -1,4 +1,4 @@
1
- import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-Cz4RTHNh.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-CnV6ndAb.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-BnMsd9hC.js";
@@ -14171,6 +14171,79 @@ function createImplementationOrchestrator(deps) {
14171
14171
  let schemaValidationRetries = 0;
14172
14172
  let previousIterationWasMalformed = false;
14173
14173
  const MAX_SCHEMA_VALIDATION_RETRIES = 3;
14174
+ async function runVerificationAndComplete(args) {
14175
+ const { recordedVerdict, finalReviewCycles, reviewResult, autoApprove } = args;
14176
+ endPhase(storyKey, "code-review");
14177
+ if (config.skipVerification !== true) {
14178
+ const latestReviewSignals = reviewResult != null ? {
14179
+ dispatchFailed: reviewResult.dispatchFailed,
14180
+ error: reviewResult.error,
14181
+ rawOutput: reviewResult.rawOutput
14182
+ } : void 0;
14183
+ let sourceEpicContent;
14184
+ const epicsPath = findEpicFileForStory(projectRoot ?? process.cwd(), storyKey);
14185
+ if (epicsPath) try {
14186
+ const epicFull = readFileSync(epicsPath, "utf-8");
14187
+ const section = extractStorySection(epicFull, storyKey);
14188
+ if (section) sourceEpicContent = section;
14189
+ } catch {}
14190
+ await persistDevStorySignals(storyKey, devStorySignals, runManifest);
14191
+ const verifContext = assembleVerificationContext({
14192
+ storyKey,
14193
+ workingDir: projectRoot ?? process.cwd(),
14194
+ reviewResult: latestReviewSignals,
14195
+ storyContent: storyContentForVerification,
14196
+ devStoryResult: devStorySignals,
14197
+ outputTokenCount: devOutputTokenCount,
14198
+ sourceEpicContent
14199
+ });
14200
+ const verifSummary = await verificationPipeline.run(verifContext, "A");
14201
+ verificationStore.set(storyKey, verifSummary);
14202
+ await persistVerificationResult(storyKey, verifSummary, runManifest);
14203
+ if (verifSummary.status === "fail") {
14204
+ updateStory(storyKey, {
14205
+ phase: "VERIFICATION_FAILED",
14206
+ completedAt: new Date().toISOString()
14207
+ });
14208
+ persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
14209
+ err,
14210
+ storyKey
14211
+ }, "StateStore write failed after verification-failed"));
14212
+ await writeStoryMetricsBestEffort(storyKey, "verification-failed", finalReviewCycles);
14213
+ await persistState();
14214
+ return "verification-failed";
14215
+ }
14216
+ }
14217
+ if (autoApprove !== void 0) eventBus.emit("story:auto-approved", {
14218
+ storyKey,
14219
+ verdict: recordedVerdict,
14220
+ reviewCycles: finalReviewCycles,
14221
+ maxReviewCycles: config.maxReviewCycles,
14222
+ issueCount: autoApprove.issueCount,
14223
+ reason: autoApprove.reason
14224
+ });
14225
+ const completeUpdate = {
14226
+ phase: "COMPLETE",
14227
+ completedAt: new Date().toISOString()
14228
+ };
14229
+ if (autoApprove !== void 0) completeUpdate.reviewCycles = finalReviewCycles;
14230
+ if (autoApprove?.downgradeLastVerdict !== void 0) completeUpdate.lastVerdict = autoApprove.downgradeLastVerdict;
14231
+ updateStory(storyKey, completeUpdate);
14232
+ if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
14233
+ if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
14234
+ storyKey,
14235
+ category: "verification-result-missing"
14236
+ }, "post-COMPLETE invariant: verification_result absent in manifest");
14237
+ }).catch(() => {});
14238
+ await writeStoryMetricsBestEffort(storyKey, recordedVerdict, finalReviewCycles);
14239
+ await writeStoryOutcomeBestEffort(storyKey, "complete", finalReviewCycles);
14240
+ eventBus.emit("orchestrator:story-complete", {
14241
+ storyKey,
14242
+ reviewCycles: finalReviewCycles
14243
+ });
14244
+ await persistState();
14245
+ return "completed";
14246
+ }
14174
14247
  while (keepReviewing) {
14175
14248
  await waitIfPaused();
14176
14249
  if (_state !== "RUNNING") return;
@@ -14457,65 +14530,13 @@ function createImplementationOrchestrator(deps) {
14457
14530
  return;
14458
14531
  }
14459
14532
  if (verdict === "SHIP_IT" || verdict === "LGTM_WITH_NOTES") {
14460
- endPhase(storyKey, "code-review");
14461
- if (config.skipVerification !== true) {
14462
- const latestReviewSignals = reviewResult != null ? {
14463
- dispatchFailed: reviewResult.dispatchFailed,
14464
- error: reviewResult.error,
14465
- rawOutput: reviewResult.rawOutput
14466
- } : void 0;
14467
- let sourceEpicContent;
14468
- const epicsPath1 = findEpicFileForStory(projectRoot ?? process.cwd(), storyKey);
14469
- if (epicsPath1) try {
14470
- const epicFull = readFileSync(epicsPath1, "utf-8");
14471
- const section = extractStorySection(epicFull, storyKey);
14472
- if (section) sourceEpicContent = section;
14473
- } catch {}
14474
- await persistDevStorySignals(storyKey, devStorySignals, runManifest);
14475
- const verifContext = assembleVerificationContext({
14476
- storyKey,
14477
- workingDir: projectRoot ?? process.cwd(),
14478
- reviewResult: latestReviewSignals,
14479
- storyContent: storyContentForVerification,
14480
- devStoryResult: devStorySignals,
14481
- outputTokenCount: devOutputTokenCount,
14482
- sourceEpicContent
14483
- });
14484
- const verifSummary = await verificationPipeline.run(verifContext, "A");
14485
- verificationStore.set(storyKey, verifSummary);
14486
- await persistVerificationResult(storyKey, verifSummary, runManifest);
14487
- if (verifSummary.status === "fail") {
14488
- updateStory(storyKey, {
14489
- phase: "VERIFICATION_FAILED",
14490
- completedAt: new Date().toISOString()
14491
- });
14492
- persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
14493
- err,
14494
- storyKey
14495
- }, "StateStore write failed after verification-failed"));
14496
- await writeStoryMetricsBestEffort(storyKey, "verification-failed", reviewCycles);
14497
- await persistState();
14498
- return;
14499
- }
14500
- }
14501
- updateStory(storyKey, {
14502
- phase: "COMPLETE",
14503
- completedAt: new Date().toISOString()
14504
- });
14505
- if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
14506
- if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
14507
- storyKey,
14508
- category: "verification-result-missing"
14509
- }, "post-COMPLETE invariant: verification_result absent in manifest");
14510
- }).catch(() => {});
14511
14533
  const completedReviewCycles = reviewCycles + 1;
14512
- await writeStoryMetricsBestEffort(storyKey, verdict, completedReviewCycles);
14513
- await writeStoryOutcomeBestEffort(storyKey, "complete", completedReviewCycles);
14514
- eventBus.emit("orchestrator:story-complete", {
14515
- storyKey,
14516
- reviewCycles: completedReviewCycles
14534
+ const outcome = await runVerificationAndComplete({
14535
+ recordedVerdict: verdict,
14536
+ finalReviewCycles: completedReviewCycles,
14537
+ reviewResult
14517
14538
  });
14518
- await persistState();
14539
+ if (outcome === "verification-failed") return;
14519
14540
  if (verdict === "LGTM_WITH_NOTES" && reviewResult.notes && config.pipelineRunId) try {
14520
14541
  await createDecision(db, {
14521
14542
  pipeline_run_id: config.pipelineRunId,
@@ -14730,73 +14751,16 @@ function createImplementationOrchestrator(deps) {
14730
14751
  err
14731
14752
  }, "Auto-approve fix dispatch failed — approving anyway (issues were minor)");
14732
14753
  }
14733
- endPhase(storyKey, "code-review");
14734
- if (config.skipVerification !== true) {
14735
- const latestReviewSignals = reviewResult != null ? {
14736
- dispatchFailed: reviewResult.dispatchFailed,
14737
- error: reviewResult.error,
14738
- rawOutput: reviewResult.rawOutput
14739
- } : void 0;
14740
- let sourceEpicContent2;
14741
- const epicsPath2 = findEpicFileForStory(projectRoot ?? process.cwd(), storyKey);
14742
- if (epicsPath2) try {
14743
- const epicFull2 = readFileSync(epicsPath2, "utf-8");
14744
- const section2 = extractStorySection(epicFull2, storyKey);
14745
- if (section2) sourceEpicContent2 = section2;
14746
- } catch {}
14747
- await persistDevStorySignals(storyKey, devStorySignals, runManifest);
14748
- const verifContext = assembleVerificationContext({
14749
- storyKey,
14750
- workingDir: projectRoot ?? process.cwd(),
14751
- reviewResult: latestReviewSignals,
14752
- storyContent: storyContentForVerification,
14753
- devStoryResult: devStorySignals,
14754
- outputTokenCount: devOutputTokenCount,
14755
- sourceEpicContent: sourceEpicContent2
14756
- });
14757
- const verifSummary = await verificationPipeline.run(verifContext, "A");
14758
- verificationStore.set(storyKey, verifSummary);
14759
- await persistVerificationResult(storyKey, verifSummary, runManifest);
14760
- if (verifSummary.status === "fail") {
14761
- updateStory(storyKey, {
14762
- phase: "VERIFICATION_FAILED",
14763
- completedAt: new Date().toISOString()
14764
- });
14765
- persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
14766
- err,
14767
- storyKey
14768
- }, "StateStore write failed after verification-failed"));
14769
- await writeStoryMetricsBestEffort(storyKey, "verification-failed", finalReviewCycles);
14770
- await persistState();
14771
- return;
14754
+ const outcome = await runVerificationAndComplete({
14755
+ recordedVerdict: verdict,
14756
+ finalReviewCycles,
14757
+ reviewResult,
14758
+ autoApprove: {
14759
+ issueCount: issueList.length,
14760
+ reason: `Review cycles exhausted (${finalReviewCycles}/${config.maxReviewCycles}) with only minor issues — auto-approving`
14772
14761
  }
14773
- }
14774
- eventBus.emit("story:auto-approved", {
14775
- storyKey,
14776
- verdict,
14777
- reviewCycles: finalReviewCycles,
14778
- maxReviewCycles: config.maxReviewCycles,
14779
- issueCount: issueList.length,
14780
- reason: `Review cycles exhausted (${finalReviewCycles}/${config.maxReviewCycles}) with only minor issues — auto-approving`
14781
- });
14782
- updateStory(storyKey, {
14783
- phase: "COMPLETE",
14784
- reviewCycles: finalReviewCycles,
14785
- completedAt: new Date().toISOString()
14786
- });
14787
- if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
14788
- if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
14789
- storyKey,
14790
- category: "verification-result-missing"
14791
- }, "post-COMPLETE invariant: verification_result absent in manifest");
14792
- }).catch(() => {});
14793
- await writeStoryMetricsBestEffort(storyKey, verdict, finalReviewCycles);
14794
- await writeStoryOutcomeBestEffort(storyKey, "complete", finalReviewCycles);
14795
- eventBus.emit("orchestrator:story-complete", {
14796
- storyKey,
14797
- reviewCycles: finalReviewCycles
14798
14762
  });
14799
- await persistState();
14763
+ if (outcome === "verification-failed") return;
14800
14764
  keepReviewing = false;
14801
14765
  return;
14802
14766
  }
@@ -14995,74 +14959,17 @@ function createImplementationOrchestrator(deps) {
14995
14959
  reviewCycles: finalReviewCycles,
14996
14960
  issueCount: issueList.length
14997
14961
  }, "Minor-fixes dispatch timed out — auto-approving as LGTM_WITH_NOTES (original findings retained as warnings)");
14998
- endPhase(storyKey, "code-review");
14999
- if (config.skipVerification !== true) {
15000
- const latestReviewSignals = reviewResult != null ? {
15001
- dispatchFailed: reviewResult.dispatchFailed,
15002
- error: reviewResult.error,
15003
- rawOutput: reviewResult.rawOutput
15004
- } : void 0;
15005
- let sourceEpicContent3;
15006
- const epicsPath3 = findEpicFileForStory(projectRoot ?? process.cwd(), storyKey);
15007
- if (epicsPath3) try {
15008
- const epicFull3 = readFileSync(epicsPath3, "utf-8");
15009
- const section3 = extractStorySection(epicFull3, storyKey);
15010
- if (section3) sourceEpicContent3 = section3;
15011
- } catch {}
15012
- await persistDevStorySignals(storyKey, devStorySignals, runManifest);
15013
- const verifContext = assembleVerificationContext({
15014
- storyKey,
15015
- workingDir: projectRoot ?? process.cwd(),
15016
- reviewResult: latestReviewSignals,
15017
- storyContent: storyContentForVerification,
15018
- devStoryResult: devStorySignals,
15019
- outputTokenCount: devOutputTokenCount,
15020
- sourceEpicContent: sourceEpicContent3
15021
- });
15022
- const verifSummary = await verificationPipeline.run(verifContext, "A");
15023
- verificationStore.set(storyKey, verifSummary);
15024
- await persistVerificationResult(storyKey, verifSummary, runManifest);
15025
- if (verifSummary.status === "fail") {
15026
- updateStory(storyKey, {
15027
- phase: "VERIFICATION_FAILED",
15028
- completedAt: new Date().toISOString()
15029
- });
15030
- persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
15031
- err,
15032
- storyKey
15033
- }, "StateStore write failed after verification-failed"));
15034
- await writeStoryMetricsBestEffort(storyKey, "verification-failed", finalReviewCycles);
15035
- await persistState();
15036
- return;
14962
+ const outcome = await runVerificationAndComplete({
14963
+ recordedVerdict: downgradedVerdict,
14964
+ finalReviewCycles,
14965
+ reviewResult,
14966
+ autoApprove: {
14967
+ issueCount: issueList.length,
14968
+ reason: `Minor-fixes dispatch timed out (cycle ${finalReviewCycles}) auto-approving as LGTM_WITH_NOTES with original findings retained as warnings`,
14969
+ downgradeLastVerdict: downgradedVerdict
15037
14970
  }
15038
- }
15039
- eventBus.emit("story:auto-approved", {
15040
- storyKey,
15041
- verdict: downgradedVerdict,
15042
- reviewCycles: finalReviewCycles,
15043
- maxReviewCycles: config.maxReviewCycles,
15044
- issueCount: issueList.length,
15045
- reason: `Minor-fixes dispatch timed out (cycle ${finalReviewCycles}) — auto-approving as LGTM_WITH_NOTES with original findings retained as warnings`
15046
- });
15047
- updateStory(storyKey, {
15048
- phase: "COMPLETE",
15049
- reviewCycles: finalReviewCycles,
15050
- lastVerdict: downgradedVerdict,
15051
- completedAt: new Date().toISOString()
15052
14971
  });
15053
- if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
15054
- if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
15055
- storyKey,
15056
- category: "verification-result-missing"
15057
- }, "post-COMPLETE invariant: verification_result absent in manifest");
15058
- }).catch(() => {});
15059
- await writeStoryMetricsBestEffort(storyKey, downgradedVerdict, finalReviewCycles);
15060
- await writeStoryOutcomeBestEffort(storyKey, "complete", finalReviewCycles);
15061
- eventBus.emit("orchestrator:story-complete", {
15062
- storyKey,
15063
- reviewCycles: finalReviewCycles
15064
- });
15065
- await persistState();
14972
+ if (outcome === "verification-failed") return;
15066
14973
  keepReviewing = false;
15067
14974
  return;
15068
14975
  }
@@ -45201,4 +45108,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
45201
45108
 
45202
45109
  //#endregion
45203
45110
  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 };
45204
- //# sourceMappingURL=run-BLaHTh1C.js.map
45111
+ //# sourceMappingURL=run-B7O3HgSR.js.map
@@ -1,8 +1,8 @@
1
- import "./health-Cz4RTHNh.js";
1
+ import "./health-CnV6ndAb.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
4
  import "./dist-BnMsd9hC.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-BLaHTh1C.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-B7O3HgSR.js";
6
6
  import "./routing-CcBOCuC9.js";
7
7
  import "./decisions-C0pz9Clx.js";
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.33",
3
+ "version": "0.20.35",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",