substrate-ai 0.20.32 → 0.20.33

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.
@@ -0,0 +1,4 @@
1
+ import { AdapterRegistry } from "./dist-BnMsd9hC.js";
2
+ import "./adapter-registry-DXLMTmfD.js";
3
+
4
+ export { AdapterRegistry };
package/dist/cli/index.js CHANGED
@@ -1,15 +1,15 @@
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-DJ4z2uWN.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-Cz4RTHNh.js";
3
3
  import { createLogger } from "../logger-KeHncl-f.js";
4
4
  import { createEventBus } from "../helpers-CElYrONe.js";
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";
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-DGyWCmcu.js";
8
- import "../errors-1uLGqnvr.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";
8
+ import "../errors-DSGhhrgv.js";
9
9
  import "../routing-CcBOCuC9.js";
10
10
  import "../decisions-C0pz9Clx.js";
11
11
  import "../version-manager-impl-BmOWu8ml.js";
12
- import { registerUpgradeCommand } from "../upgrade-k15NGTno.js";
12
+ import { registerUpgradeCommand } from "../upgrade-D3NuTkSL.js";
13
13
  import { Command } from "commander";
14
14
  import { fileURLToPath } from "url";
15
15
  import { dirname, join, resolve } from "path";
@@ -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-DLqMd9uN.js");
3670
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-B6AMpmJB.js");
3671
3671
  const substrateDirPath = join(projectRoot, ".substrate");
3672
3672
  const processInfo = inspectProcessTree$1({
3673
3673
  projectRoot,
@@ -4617,7 +4617,7 @@ function defaultSupervisorDeps() {
4617
4617
  if (cached === null) {
4618
4618
  const { AdapterRegistry: AR } = await import(
4619
4619
  /* @vite-ignore */
4620
- "../adapter-registry-N0Klnk7Y.js"
4620
+ "../adapter-registry-Cu2eLuau.js"
4621
4621
  );
4622
4622
  cached = new AR();
4623
4623
  await cached.discoverAndRegister();
@@ -5184,11 +5184,11 @@ async function runSupervisorAction(options, deps = {}) {
5184
5184
  try {
5185
5185
  const { createExperimenter } = await import(
5186
5186
  /* @vite-ignore */
5187
- "../experimenter-VEJHtfLh.js"
5187
+ "../experimenter-CN8PhRbv.js"
5188
5188
  );
5189
5189
  const { getLatestRun: getLatest } = await import(
5190
5190
  /* @vite-ignore */
5191
- "../decisions-7UJcRETq.js"
5191
+ "../decisions-DlPFWRDm.js"
5192
5192
  );
5193
5193
  const expAdapter = createDatabaseAdapter({
5194
5194
  backend: "auto",
@@ -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-D-OcJNtZ.js"
5201
+ "../run-C-mxCkwh.js"
5202
5202
  );
5203
5203
  const runStoryFn = async (opts) => {
5204
5204
  const exitCode = await runPipeline({
@@ -5730,7 +5730,7 @@ async function runMetricsAction(options) {
5730
5730
  const routingConfigPath = join(dbDir, "routing.yml");
5731
5731
  let routingConfig = null;
5732
5732
  if (existsSync$1(routingConfigPath)) try {
5733
- const { loadModelRoutingConfig } = await import("../routing-Ccpb_syA.js");
5733
+ const { loadModelRoutingConfig } = await import("../routing-sauIk945.js");
5734
5734
  routingConfig = loadModelRoutingConfig(routingConfigPath);
5735
5735
  } catch {}
5736
5736
  if (routingConfig === null) routingConfig = {
@@ -9003,8 +9003,8 @@ async function createProgram() {
9003
9003
  /** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
9004
9004
  function checkForUpdatesInBackground(currentVersion) {
9005
9005
  if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
9006
- import("../upgrade-CVaD7iUR.js").then(async () => {
9007
- const { createVersionManager } = await import("../version-manager-impl-CEiZEsmi.js");
9006
+ import("../upgrade-BXfinu5K.js").then(async () => {
9007
+ const { createVersionManager } = await import("../version-manager-impl-ChzfLw90.js");
9008
9008
  const vm = createVersionManager();
9009
9009
  const result = await vm.checkForUpdates();
9010
9010
  if (result.updateAvailable) {
@@ -1,4 +1,4 @@
1
- import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunningPipelineRuns, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./dist-CqtWS9wF.js";
1
+ import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunningPipelineRuns, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./dist-BnMsd9hC.js";
2
2
  import "./decisions-C0pz9Clx.js";
3
3
 
4
4
  export { getLatestRun };
@@ -283,7 +283,21 @@ function parseYamlResult(yamlText, schema) {
283
283
  error: `YAML parse error: ${message}`
284
284
  };
285
285
  }
286
- else return {
286
+ else if (message.includes("bad indentation of a mapping entry")) {
287
+ const recovered = attemptBlockScalarRecovery(yamlText, message);
288
+ if (recovered !== null) try {
289
+ raw = yaml.load(sanitizeYamlEscapes(recovered));
290
+ } catch {
291
+ return {
292
+ parsed: null,
293
+ error: `YAML parse error: ${message}`
294
+ };
295
+ }
296
+ else return {
297
+ parsed: null,
298
+ error: `YAML parse error: ${message}`
299
+ };
300
+ } else return {
287
301
  parsed: null,
288
302
  error: `YAML parse error: ${message}`
289
303
  };
@@ -307,6 +321,67 @@ function parseYamlResult(yamlText, schema) {
307
321
  };
308
322
  }
309
323
  /**
324
+ * Field names whose values are known free-form strings and may safely be
325
+ * rewritten as block scalars when the parser fails on an embedded colon.
326
+ * Other fields (numeric, enum, structural) stay strict.
327
+ *
328
+ * Allowlist intent: we only rescue the failure mode that obs_015 documents
329
+ * (reviewer-style agents quoting colons in description-shaped fields).
330
+ * Adding fields here loosens the recovery surface; do so only when an
331
+ * empirical case shows a new field needs the same protection.
332
+ */
333
+ const RECOVERABLE_BLOCK_SCALAR_FIELDS = new Set([
334
+ "description",
335
+ "message",
336
+ "error",
337
+ "notes",
338
+ "comment",
339
+ "finding",
340
+ "command",
341
+ "details",
342
+ "rationale",
343
+ "reason"
344
+ ]);
345
+ /**
346
+ * Attempt to rewrite a single `<field>: <value-with-colons>` line as a
347
+ * literal block scalar (`<field>: |-\n <value>`) so the YAML parser
348
+ * doesn't reinterpret the inner colons as mapping separators.
349
+ *
350
+ * Returns the rewritten YAML on success, or `null` when:
351
+ * - the error message doesn't carry a parseable position
352
+ * - no allowlisted field within a 4-line backward window matches
353
+ * - the matched value doesn't contain a colon (the trigger condition)
354
+ */
355
+ function attemptBlockScalarRecovery(yamlText, errorMessage) {
356
+ const positionMatch = errorMessage.match(/\((\d+):(\d+)\)/);
357
+ if (positionMatch === null) return null;
358
+ const lineNum = Number.parseInt(positionMatch[1] ?? "", 10);
359
+ if (!Number.isFinite(lineNum) || lineNum <= 0) return null;
360
+ const lineIdx = lineNum - 1;
361
+ const lines = yamlText.split("\n");
362
+ if (lineIdx >= lines.length) return null;
363
+ for (let i = lineIdx; i >= Math.max(0, lineIdx - 4); i -= 1) {
364
+ const line = lines[i] ?? "";
365
+ const m = line.match(/^(\s*-?\s*)([A-Za-z_][A-Za-z0-9_]*):\s+(\S.*?)\s*$/);
366
+ if (m === null) continue;
367
+ const fieldName = (m[2] ?? "").toLowerCase();
368
+ if (!RECOVERABLE_BLOCK_SCALAR_FIELDS.has(fieldName)) continue;
369
+ const value = m[3] ?? "";
370
+ if (!value.includes(":")) continue;
371
+ const prefix = m[1] ?? "";
372
+ const valueIndent = " ".repeat(prefix.length + 2);
373
+ const rewrittenKeyLine = `${prefix}${m[2]}: |-`;
374
+ const valueLines = value.split("\n").map((v) => `${valueIndent}${v}`);
375
+ return [
376
+ ...lines.slice(0, i),
377
+ rewrittenKeyLine,
378
+ ...valueLines,
379
+ ...lines.slice(i + 1)
380
+ ].join("\n");
381
+ }
382
+ return null;
383
+ }
384
+ /**
310
385
  * Valid YAML escape sequences in double-quoted strings (YAML 1.2 spec).
311
386
  * Any backslash followed by a character NOT in this set is invalid.
312
387
  */
@@ -10940,4 +11015,4 @@ async function callLLM(params) {
10940
11015
 
10941
11016
  //#endregion
10942
11017
  export { ADVISORY_NOTES, AdapterRegistry, AdtError, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, Categorizer, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, ConsumerAnalyzer, CostTrackerConfigSchema, DEFAULT_CONFIG, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, DoltNotInstalled, DoltQueryError, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, GeminiCLIAdapter, GlobalSettingsSchema, IngestionServer, LEARNING_FINDING, LogTurnAnalyzer, ModelRoutingConfigSchema, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProviderPolicySchema, ProvidersSchema, Recommender, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TASK_TYPE_PHASE_MAP, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryConfigSchema, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, VersionManagerImpl, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, callLLM, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDatabaseAdapter as createDatabaseAdapter$1, createDecision, createDoltClient, createExperimenter, createPipelineRun, createRequirement, createVersionManager, detectInterfaceChanges, determineVerdict, getActiveDecisions, getAllCostEntriesFiltered, getArtifactByTypeForRun, getArtifactsByRun, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getModelTier, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRequirements, listRunMetrics, loadModelRoutingConfig, loadParentRunDecisions, registerArtifact, resolvePromptFile, supersedeDecision, tagRunAsBaseline, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics };
10943
- //# sourceMappingURL=dist-CqtWS9wF.js.map
11018
+ //# sourceMappingURL=dist-BnMsd9hC.js.map
@@ -1,4 +1,4 @@
1
- import { AdtError } from "./dist-CqtWS9wF.js";
1
+ import { AdtError } from "./dist-BnMsd9hC.js";
2
2
 
3
3
  //#region src/core/errors.ts
4
4
  /** Error thrown when task configuration is invalid */
@@ -71,4 +71,4 @@ var TaskGraphIncompatibleFormatError = class extends AdtError {
71
71
 
72
72
  //#endregion
73
73
  export { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError };
74
- //# sourceMappingURL=errors-1uLGqnvr.js.map
74
+ //# sourceMappingURL=errors-DSGhhrgv.js.map
@@ -1,3 +1,3 @@
1
- import { buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, createExperimenter, determineVerdict, resolvePromptFile } from "./dist-CqtWS9wF.js";
1
+ import { buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, createExperimenter, determineVerdict, resolvePromptFile } from "./dist-BnMsd9hC.js";
2
2
 
3
3
  export { createExperimenter };
@@ -1,6 +1,6 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-DJ4z2uWN.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-Cz4RTHNh.js";
2
2
  import "./logger-KeHncl-f.js";
3
- import "./dist-CqtWS9wF.js";
3
+ import "./dist-BnMsd9hC.js";
4
4
  import "./decisions-C0pz9Clx.js";
5
5
 
6
6
  export { inspectProcessTree };
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { DoltClient, DoltQueryError, LEARNING_FINDING, createDatabaseAdapter$1 as createDatabaseAdapter, createDecision, getDecisionsByCategory, getLatestRun, getPipelineRunById, initSchema } from "./dist-CqtWS9wF.js";
2
+ import { DoltClient, DoltQueryError, LEARNING_FINDING, createDatabaseAdapter$1 as createDatabaseAdapter, createDecision, getDecisionsByCategory, getLatestRun, getPipelineRunById, initSchema } from "./dist-BnMsd9hC.js";
3
3
  import { createRequire } from "module";
4
4
  import { dirname, join } from "path";
5
5
  import { readFile } from "fs/promises";
@@ -6291,4 +6291,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
6291
6291
 
6292
6292
  //#endregion
6293
6293
  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-DJ4z2uWN.js.map
6294
+ //# sourceMappingURL=health-Cz4RTHNh.js.map
package/dist/index.d.ts CHANGED
@@ -2106,6 +2106,24 @@ interface OrchestratorEvents {
2106
2106
  storyKey: string;
2107
2107
  reason: string;
2108
2108
  };
2109
+ /**
2110
+ * Story 62-3: code-review agent emitted YAML output that failed schema
2111
+ * validation (typically a parse error from unquoted-colon-in-value or
2112
+ * unbalanced quotes — see obs_2026-04-27_015). Distinct from the generic
2113
+ * phantom-review path so operators can debug agent emission shape rather
2114
+ * than chase a crash/timeout phantom. Fires on each malformed-output
2115
+ * cycle; final escalation (after MAX_SCHEMA_VALIDATION_RETRIES exhausted)
2116
+ * surfaces via the standard `orchestrator:story-escalated` event with
2117
+ * `lastVerdict: 'code-review-output-malformed-budget-exceeded'`.
2118
+ */
2119
+ 'orchestrator:code-review-output-malformed': {
2120
+ storyKey: string;
2121
+ reviewCycles: number;
2122
+ attempt: number;
2123
+ maxAttempts: number;
2124
+ error: string;
2125
+ details?: string;
2126
+ };
2109
2127
  /** Implementation orchestrator has finished all stories */
2110
2128
  'orchestrator:complete': {
2111
2129
  totalStories: number;
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { childLogger, createLogger, logger } from "./logger-KeHncl-f.js";
2
2
  import { assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry } from "./helpers-CElYrONe.js";
3
- import { AdapterRegistry, AdtError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter } from "./dist-CqtWS9wF.js";
3
+ import { AdapterRegistry, AdtError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter } from "./dist-BnMsd9hC.js";
4
4
  import "./adapter-registry-DXLMTmfD.js";
5
- import { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-1uLGqnvr.js";
5
+ import { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-DSGhhrgv.js";
6
6
 
7
7
  //#region src/core/di.ts
8
8
  /**
@@ -1,4 +1,4 @@
1
- import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-CqtWS9wF.js";
1
+ import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-BnMsd9hC.js";
2
2
  import "./routing-CcBOCuC9.js";
3
3
 
4
4
  export { loadModelRoutingConfig };
@@ -1,7 +1,7 @@
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-DJ4z2uWN.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-Cz4RTHNh.js";
2
2
  import { createLogger } from "./logger-KeHncl-f.js";
3
3
  import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
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";
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";
5
5
  import { basename, dirname, extname, join } from "path";
6
6
  import { access, readFile, readdir, stat } from "fs/promises";
7
7
  import { EventEmitter } from "node:events";
@@ -14168,11 +14168,14 @@ function createImplementationOrchestrator(deps) {
14168
14168
  let keepReviewing = true;
14169
14169
  let timeoutRetried = false;
14170
14170
  let previousIssueList = [];
14171
+ let schemaValidationRetries = 0;
14172
+ let previousIterationWasMalformed = false;
14173
+ const MAX_SCHEMA_VALIDATION_RETRIES = 3;
14171
14174
  while (keepReviewing) {
14172
14175
  await waitIfPaused();
14173
14176
  if (_state !== "RUNNING") return;
14174
14177
  if (reviewCycles === 0) startPhase(storyKey, "code-review");
14175
- if (reviewCycles > 0) {
14178
+ if (reviewCycles > 0 && !previousIterationWasMalformed) {
14176
14179
  const currentRetries = _storyRetryCount.get(storyKey) ?? 0;
14177
14180
  const budget = config.retryBudget ?? 2;
14178
14181
  if (currentRetries >= budget) {
@@ -14197,6 +14200,7 @@ function createImplementationOrchestrator(deps) {
14197
14200
  }
14198
14201
  incrementRetryCount(storyKey);
14199
14202
  }
14203
+ previousIterationWasMalformed = false;
14200
14204
  updateStory(storyKey, {
14201
14205
  phase: "IN_REVIEW",
14202
14206
  reviewCycles
@@ -14316,6 +14320,48 @@ function createImplementationOrchestrator(deps) {
14316
14320
  }, "Failed to record code-review token usage"));
14317
14321
  }
14318
14322
  const isPhantomReview = reviewResult.dispatchFailed === true || reviewResult.verdict !== "SHIP_IT" && reviewResult.verdict !== "LGTM_WITH_NOTES" && (reviewResult.issue_list === void 0 || reviewResult.issue_list.length === 0) && reviewResult.error !== void 0;
14323
+ const isMalformedOutput = isPhantomReview && reviewResult.error === "schema_validation_failed";
14324
+ if (isMalformedOutput) {
14325
+ schemaValidationRetries++;
14326
+ eventBus.emit("orchestrator:code-review-output-malformed", {
14327
+ storyKey,
14328
+ reviewCycles,
14329
+ attempt: schemaValidationRetries,
14330
+ maxAttempts: MAX_SCHEMA_VALIDATION_RETRIES,
14331
+ error: reviewResult.error ?? "schema_validation_failed",
14332
+ ...reviewResult.details !== void 0 ? { details: reviewResult.details } : {}
14333
+ });
14334
+ if (schemaValidationRetries <= MAX_SCHEMA_VALIDATION_RETRIES) {
14335
+ logger$26.warn({
14336
+ storyKey,
14337
+ reviewCycles,
14338
+ attempt: schemaValidationRetries,
14339
+ error: reviewResult.error
14340
+ }, "Code-review output malformed (schema validation failed) — retrying review");
14341
+ previousIterationWasMalformed = true;
14342
+ continue;
14343
+ }
14344
+ logger$26.warn({
14345
+ storyKey,
14346
+ reviewCycles,
14347
+ schemaValidationRetries
14348
+ }, "Code-review output malformed across MAX_SCHEMA_VALIDATION_RETRIES attempts — escalating");
14349
+ endPhase(storyKey, "code-review");
14350
+ updateStory(storyKey, {
14351
+ phase: "ESCALATED",
14352
+ error: "code-review-output-malformed-budget-exceeded",
14353
+ completedAt: new Date().toISOString()
14354
+ });
14355
+ await writeStoryMetricsBestEffort(storyKey, "escalated", reviewCycles + 1);
14356
+ await emitEscalation({
14357
+ storyKey,
14358
+ lastVerdict: "code-review-output-malformed-budget-exceeded",
14359
+ reviewCycles: reviewCycles + 1,
14360
+ issues: [`Code-review agent output failed schema validation ${schemaValidationRetries} consecutive times. The output was malformed (likely YAML parse error from unquoted colons, unbalanced quotes, or invalid escapes), not absent. Inspect the rawOutput on the manifest entry for the agent's emission shape and update the prompt or yaml-parser fallbacks.`]
14361
+ });
14362
+ await persistState();
14363
+ return;
14364
+ }
14319
14365
  if (isPhantomReview && !timeoutRetried) {
14320
14366
  timeoutRetried = true;
14321
14367
  logger$26.warn({
@@ -45155,4 +45201,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
45155
45201
 
45156
45202
  //#endregion
45157
45203
  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 };
45158
- //# sourceMappingURL=run-DGyWCmcu.js.map
45204
+ //# sourceMappingURL=run-BLaHTh1C.js.map
@@ -1,8 +1,8 @@
1
- import "./health-DJ4z2uWN.js";
1
+ import "./health-Cz4RTHNh.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
- import "./dist-CqtWS9wF.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-DGyWCmcu.js";
4
+ import "./dist-BnMsd9hC.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-BLaHTh1C.js";
6
6
  import "./routing-CcBOCuC9.js";
7
7
  import "./decisions-C0pz9Clx.js";
8
8
 
@@ -1,5 +1,5 @@
1
- import "./dist-CqtWS9wF.js";
1
+ import "./dist-BnMsd9hC.js";
2
2
  import "./version-manager-impl-BmOWu8ml.js";
3
- import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-k15NGTno.js";
3
+ import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-D3NuTkSL.js";
4
4
 
5
5
  export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
@@ -1,4 +1,4 @@
1
- import { createVersionManager } from "./dist-CqtWS9wF.js";
1
+ import { createVersionManager } from "./dist-BnMsd9hC.js";
2
2
  import { execSync, spawn } from "child_process";
3
3
  import * as readline from "readline";
4
4
 
@@ -123,4 +123,4 @@ function registerUpgradeCommand(program) {
123
123
 
124
124
  //#endregion
125
125
  export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
126
- //# sourceMappingURL=upgrade-k15NGTno.js.map
126
+ //# sourceMappingURL=upgrade-D3NuTkSL.js.map
@@ -1,4 +1,4 @@
1
- import { VersionManagerImpl, createVersionManager } from "./dist-CqtWS9wF.js";
1
+ import { VersionManagerImpl, createVersionManager } from "./dist-BnMsd9hC.js";
2
2
  import "./version-manager-impl-BmOWu8ml.js";
3
3
 
4
4
  export { createVersionManager };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.32",
3
+ "version": "0.20.33",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -57,7 +57,40 @@ Adversarial code review. Find what's wrong. Validate story claims against actual
57
57
 
58
58
  ## Output Contract
59
59
 
60
- After completing the review, emit ONLY raw YAML — no markdown fences, no ``` wrappers, no other text:
60
+ After completing the review, emit ONLY raw YAML — no markdown fences, no ``` wrappers, no other text.
61
+
62
+ ### CRITICAL: Block-scalar form for free-form string fields
63
+
64
+ When a finding's `description`, `message`, `command`, `notes`, or any other free-form string field may contain a colon (`:`), a quoted shell snippet, a file path with extension (`scripts/install.sh:`, `src/foo.ts:`), or any other text that could be interpreted as a YAML key-value separator, you MUST emit it as a YAML block scalar (`field: |`) followed by indented content. Block scalars don't interpret `:` specially, so the value's content can't be misparsed as a nested mapping.
65
+
66
+ **Wrong** — unquoted scalar with internal colons (the YAML parser sees a key `description`, then sees `scripts/install.sh: copies ...` as a NEW key, fails with "bad indentation of a mapping entry"):
67
+
68
+ ```text
69
+ issue_list:
70
+ - severity: minor
71
+ description: scripts/install.sh: copies Quadlet via 'cp ${QUADLET_SRC} ${QUADLET_DEST}': copies file
72
+ file: scripts/install.sh
73
+ ```
74
+
75
+ **Right** — block scalar (`|`) preserves the value verbatim, colons and all:
76
+
77
+ ```yaml
78
+ issue_list:
79
+ - severity: minor
80
+ description: |
81
+ scripts/install.sh: copies Quadlet via 'cp ${QUADLET_SRC} ${QUADLET_DEST}': copies file
82
+ file: scripts/install.sh
83
+ ```
84
+
85
+ The `|` indicator is a literal block scalar (preserves newlines). Use `|-` if you want trailing newlines stripped. Either is safe.
86
+
87
+ Quoted scalars (`"..."` and `'...'`) ARE technically able to contain colons — but they're brittle: any embedded quote of the matching kind closes the scalar early, leaving the rest of the value exposed to the parser. Block scalars have no closing delimiter to worry about, so they're the safer default whenever a string might contain code.
88
+
89
+ **When in doubt — when a description quotes any code from the reviewed source — default to block-scalar form.** The cost is two extra characters; the benefit is that substrate's parser won't reject your output and trigger a false-positive escalation.
90
+
91
+ ### YAML format
92
+
93
+ After the rules above, emit raw YAML:
61
94
 
62
95
  ```yaml
63
96
  verdict: SHIP_IT
@@ -1,4 +0,0 @@
1
- import { AdapterRegistry } from "./dist-CqtWS9wF.js";
2
- import "./adapter-registry-DXLMTmfD.js";
3
-
4
- export { AdapterRegistry };