substrate-ai 0.20.32 → 0.20.34

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-CnV6ndAb.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-BQxm1Qix.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-Bqzqu6zC.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-B7jP4apv.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-CnV6ndAb.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";
@@ -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-DJ4z2uWN.js.map
6347
+ //# sourceMappingURL=health-CnV6ndAb.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,8 +1,8 @@
1
- import "./health-DJ4z2uWN.js";
1
+ import "./health-CnV6ndAb.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-BQxm1Qix.js";
6
6
  import "./routing-CcBOCuC9.js";
7
7
  import "./decisions-C0pz9Clx.js";
8
8
 
@@ -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-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
- 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-BQxm1Qix.js.map
@@ -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.34",
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 };