substrate-ai 0.21.14 → 0.21.15

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,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import { FileKvStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-B1Rk7RXw.js";
2
+ import { FileKvStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-kr5GC1SN.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, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createGitWorktreeManager, createPipelineRun, createStderrLogger, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initWorkGraphSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, swallowDebug, tagRunAsBaseline, updatePipelineRun } from "../dist-BZGqn-XQ.js";
6
6
  import "../adapter-registry-DXLMTmfD.js";
7
- import { ACCEPTANCE_CONTRACT_PROFILE_PATH, JOURNEY_CANDIDATE_PATH, JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, clearGateDemotion, computePrecision, computeRecall, demoteGate, loadAcceptanceContractFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, readAcceptanceMetrics, readCurrentRunId, readGateState, recordCanary, recordOverride, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary } from "../manifest-read-BX_tMdib.js";
8
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DcUXpWwu.js";
7
+ import { ACCEPTANCE_CONTRACT_PROFILE_PATH, JOURNEY_CANDIDATE_PATH, JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, clearGateDemotion, computePrecision, computeRecall, demoteGate, diffJourneySets, loadAcceptanceContractFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyCandidate, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, ratifyCandidate, readAcceptanceMetrics, readCurrentRunId, readGateState, recordCanary, recordOverride, renderRegistryDiff, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary } from "../manifest-read-CcK_LIaI.js";
8
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DR_D61vF.js";
9
9
  import "../errors-xSeGw6pf.js";
10
10
  import { AcceptanceDeriveResultSchema, assemblePrompt, getTokenCeiling, runAcceptanceJudge } from "../acceptance-judge-lAv5EvYA.js";
11
11
  import "../routing-DZT5PN3N.js";
12
12
  import { WorkGraphRepository } from "../work-graph-repository-4cKsf8Lf.js";
13
13
  import "../decisions-BAaxpVD0.js";
14
14
  import "../decision-router-Dyby0fUf.js";
15
- import "../interactive-prompt-GixkO5-6.js";
15
+ import "../interactive-prompt-B5KE69I6.js";
16
16
  import "../recovery-engine-dtLHyV4M.js";
17
17
  import "../version-manager-impl-DMTw551Q.js";
18
18
  import { registerUpgradeCommand } from "../upgrade-CNGc12AV.js";
@@ -30,7 +30,7 @@ import { basename as basename$1, dirname as dirname$1, join as join$1, posix, re
30
30
  import { createHash, randomUUID } from "node:crypto";
31
31
  import { z } from "zod";
32
32
  import * as fs from "node:fs/promises";
33
- import { lstat, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$1, readlink, realpath, writeFile as writeFile$1 } from "node:fs/promises";
33
+ import { lstat, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$1, readlink, realpath, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
34
34
  import { chmodSync, cpSync, existsSync as existsSync$1, lstatSync, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdir as readdir$2, readdirSync as readdirSync$1, readlinkSync, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
35
35
  import { homedir } from "os";
36
36
  import { createRequire } from "node:module";
@@ -39,6 +39,7 @@ import * as readline from "node:readline";
39
39
  import { createInterface } from "node:readline";
40
40
  import { randomUUID as randomUUID$1 } from "crypto";
41
41
  import { createInterface as createInterface$1 } from "readline";
42
+ import { createInterface as createInterface$2 } from "node:readline/promises";
42
43
 
43
44
  //#region packages/core/dist/monitor/recommendation-engine.js
44
45
  var RecommendationEngine = class {
@@ -7136,7 +7137,7 @@ async function runStatusAction(options) {
7136
7137
  logger$16.debug({ err }, "Work graph query failed, continuing without work graph data");
7137
7138
  }
7138
7139
  if (run === void 0) {
7139
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-BxH_n5cd.js");
7140
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-CvsH53bv.js");
7140
7141
  const substrateDirPath = join(projectRoot, ".substrate");
7141
7142
  const processInfo = inspectProcessTree$1({
7142
7143
  projectRoot,
@@ -8665,7 +8666,7 @@ async function runSupervisorAction(options, deps = {}) {
8665
8666
  await initSchema(expAdapter);
8666
8667
  const { runRunAction: runPipeline } = await import(
8667
8668
  /* @vite-ignore */
8668
- "../run-BnUAxdws.js"
8669
+ "../run-UilZoIOh.js"
8669
8670
  );
8670
8671
  const runStoryFn = async (opts) => {
8671
8672
  const exitCode = await runPipeline({
@@ -13909,7 +13910,121 @@ function registerAcceptanceCommand(program, version, registry) {
13909
13910
  }
13910
13911
  const needsElaboration = result.journeys.filter((j) => j.end_states.length === 0);
13911
13912
  process.stdout.write(`candidate written: ${relative(projectRoot, outPath)}\n ${String(result.journeys.length)} journeys (${String(result.journeys.filter((j) => j.criticality === "critical").length)} critical), ${String(result.journeys.reduce((n, j) => n + j.end_states.length, 0))} end-states` + (needsElaboration.length > 0 ? `, ${String(needsElaboration.length)} journey(s) need end-state elaboration: ${needsElaboration.map((j) => j.id).join(", ")}` : "") + `
13912
- derived from ${prdRel} (sha256 ${sourceSha.slice(0, 12)}…)\nThis candidate is NOT authoritative and the gate ignores it. Review every journey against the PRD — a journey missing here is invisible to the whole acceptance machinery.
13913
+ derived from ${prdRel} (sha256 ${sourceSha.slice(0, 12)}…)\n`);
13914
+ if (existingRegistryYaml !== void 0) {
13915
+ const parsedExisting = parseJourneyRegistry(existingRegistryYaml);
13916
+ if (parsedExisting.ok) process.stdout.write(`delta vs ratified registry v${String(parsedExisting.registry.version)}:\n${renderRegistryDiff(diffJourneySets(parsedExisting.registry.journeys, result.journeys))}\n`);
13917
+ }
13918
+ process.stdout.write("This candidate is NOT authoritative and the gate ignores it. Review every journey against the PRD — a journey missing here is invisible to the whole acceptance machinery.\n");
13919
+ process.exit(ACCEPTANCE_EXIT_SUCCESS);
13920
+ });
13921
+ acceptanceCmd.command("ratify").description(`Promote ${JOURNEY_CANDIDATE_PATH} to ${JOURNEY_REGISTRY_PATH} with a recorded provenance block. Interactive confirm unless --yes. The candidate file is deleted on success.`).option("--exclude <spec>", "exclude a candidate journey: \"UJ-2: reason text\" (repeatable; reason mandatory)", (v, acc) => [...acc, v], []).option("--epic <spec>", "assign an epic at ratify time: \"UJ-1=2\" (repeatable; critical journeys require one)", (v, acc) => [...acc, v], []).option("--ratified-by <name>", "who is ratifying (recorded in provenance)", "operator").option("--yes", "skip the interactive confirmation", false).action(async (opts) => {
13922
+ const projectRoot = process.cwd();
13923
+ const candidatePath = join$1(projectRoot, JOURNEY_CANDIDATE_PATH);
13924
+ let candidateContent;
13925
+ try {
13926
+ candidateContent = await readFile$1(candidatePath, "utf-8");
13927
+ } catch {
13928
+ process.stdout.write(`acceptance ratify: no candidate at ${JOURNEY_CANDIDATE_PATH} — run \`substrate acceptance derive --prd <path>\` first\n`);
13929
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13930
+ return;
13931
+ }
13932
+ const parsedCandidate = parseJourneyCandidate(candidateContent);
13933
+ if (!parsedCandidate.ok) {
13934
+ process.stdout.write(`acceptance ratify: candidate invalid:\n${parsedCandidate.issues.map((i) => ` ${i.path}: ${i.message}`).join("\n")}\n`);
13935
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13936
+ return;
13937
+ }
13938
+ const candidate = parsedCandidate.candidate;
13939
+ const excludes = [];
13940
+ for (const spec of opts.exclude) {
13941
+ const sep = spec.indexOf(":");
13942
+ const id = sep >= 0 ? spec.slice(0, sep).trim() : spec.trim();
13943
+ const reason = sep >= 0 ? spec.slice(sep + 1).trim() : "";
13944
+ if (reason === "") {
13945
+ process.stdout.write(`acceptance ratify: --exclude "${spec}" has no reason — use "ID: reason" (reasonless exclusions are unauditable)\n`);
13946
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13947
+ return;
13948
+ }
13949
+ excludes.push({
13950
+ candidate: id,
13951
+ reason
13952
+ });
13953
+ }
13954
+ const epicAssignments = {};
13955
+ for (const spec of opts.epic) {
13956
+ const sep = spec.indexOf("=");
13957
+ const id = sep >= 0 ? spec.slice(0, sep).trim() : "";
13958
+ const n = sep >= 0 ? Number(spec.slice(sep + 1).trim()) : NaN;
13959
+ if (id === "" || !Number.isInteger(n) || n <= 0) {
13960
+ process.stdout.write(`acceptance ratify: --epic "${spec}" must be "JOURNEY-ID=<positive integer>"\n`);
13961
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13962
+ return;
13963
+ }
13964
+ epicAssignments[id] = n;
13965
+ }
13966
+ let existingRegistry;
13967
+ try {
13968
+ const existingContent = await readFile$1(join$1(projectRoot, JOURNEY_REGISTRY_PATH), "utf-8");
13969
+ const parsedExisting = parseJourneyRegistry(existingContent);
13970
+ if (!parsedExisting.ok) {
13971
+ process.stdout.write(`acceptance ratify: existing ${JOURNEY_REGISTRY_PATH} is INVALID — fix or remove it before re-ratifying:\n${parsedExisting.issues.map((i) => ` ${i.path}: ${i.message}`).join("\n")}\n`);
13972
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13973
+ return;
13974
+ }
13975
+ existingRegistry = parsedExisting.registry;
13976
+ } catch {
13977
+ existingRegistry = void 0;
13978
+ }
13979
+ let sourceContent;
13980
+ try {
13981
+ sourceContent = await readFile$1(join$1(projectRoot, candidate.derived_from), "utf-8");
13982
+ } catch (err) {
13983
+ process.stdout.write(`acceptance ratify: cannot read source ${candidate.derived_from} (recorded in the candidate): ${String(err)}\n`);
13984
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13985
+ return;
13986
+ }
13987
+ const result = ratifyCandidate(candidate, {
13988
+ excludes,
13989
+ ratifiedBy: opts.ratifiedBy,
13990
+ sourceContent,
13991
+ now: new Date().toISOString(),
13992
+ ...existingRegistry !== void 0 ? { existingRegistry } : {},
13993
+ epicAssignments
13994
+ });
13995
+ if (!result.ok) {
13996
+ process.stdout.write(`acceptance ratify: the candidate would not ratify into a VALID registry — edit ${JOURNEY_CANDIDATE_PATH} (it is editable by design), assign epics via --epic, or exclude journeys via --exclude:\n` + result.issues.map((i) => ` ${i.path}: ${i.message}`).join("\n") + "\n");
13997
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13998
+ return;
13999
+ }
14000
+ const reg = result.registry;
14001
+ process.stdout.write(`ratifying → ${JOURNEY_REGISTRY_PATH} v${String(reg.version)}${existingRegistry !== void 0 ? ` (replacing v${String(existingRegistry.version)})` : ""}\n` + reg.journeys.map((j) => ` ${j.id} [${j.criticality}${j.epic !== void 0 ? ` epic ${String(j.epic)}` : ""}] ${j.title} — ${String(j.end_states.length)} end-state(s)\n`).join("") + (reg.provenance?.excluded !== void 0 ? reg.provenance.excluded.map((e) => ` excluded: ${e.candidate} — ${e.reason}\n`).join("") : ""));
14002
+ if (existingRegistry !== void 0) process.stdout.write(`delta vs v${String(existingRegistry.version)}:\n${renderRegistryDiff(diffJourneySets(existingRegistry.journeys, candidate.journeys))}\n`);
14003
+ for (const w of result.warnings) process.stdout.write(`WARNING: ${w}\n`);
14004
+ if (!opts.yes) {
14005
+ const rl = createInterface$2({
14006
+ input: process.stdin,
14007
+ output: process.stderr
14008
+ });
14009
+ const answer = await rl.question("ratify? [y/N] ");
14010
+ rl.close();
14011
+ if (answer.trim().toLowerCase() !== "y") {
14012
+ process.stdout.write("aborted — candidate left in place\n");
14013
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14014
+ return;
14015
+ }
14016
+ }
14017
+ const registryHeader = "# Journey registry — ratified via `substrate acceptance ratify`.\n# The acceptance gate reads THIS file from the trusted tree. COMMIT it.\n";
14018
+ try {
14019
+ await mkdir$1(dirname$1(join$1(projectRoot, JOURNEY_REGISTRY_PATH)), { recursive: true });
14020
+ await writeFile$1(join$1(projectRoot, JOURNEY_REGISTRY_PATH), registryHeader + dump(reg, { lineWidth: 120 }), "utf-8");
14021
+ await unlink$1(candidatePath);
14022
+ } catch (err) {
14023
+ process.stdout.write(`acceptance ratify: write failed: ${String(err)}\n`);
14024
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14025
+ return;
14026
+ }
14027
+ process.stdout.write(`ratified: ${JOURNEY_REGISTRY_PATH} v${String(reg.version)} (provenance recorded, ratified_by: ${opts.ratifiedBy}; candidate deleted)\nCOMMIT the registry — the gate reads the trusted (committed) tree.
13913
14028
  `);
13914
14029
  process.exit(ACCEPTANCE_EXIT_SUCCESS);
13915
14030
  });
@@ -1,7 +1,7 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-B1Rk7RXw.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-kr5GC1SN.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./dist-BZGqn-XQ.js";
4
- import "./manifest-read-BX_tMdib.js";
4
+ import "./manifest-read-CcK_LIaI.js";
5
5
  import "./work-graph-repository-4cKsf8Lf.js";
6
6
  import "./decisions-BAaxpVD0.js";
7
7
 
@@ -1,6 +1,6 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
2
  import { DoltClient, DoltQueryError, createDatabaseAdapter$1 as createDatabaseAdapter, getLatestRun, getPipelineRunById, initSchema } from "./dist-BZGqn-XQ.js";
3
- import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-BX_tMdib.js";
3
+ import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-CcK_LIaI.js";
4
4
  import { createRequire } from "module";
5
5
  import { dirname, join } from "path";
6
6
  import { existsSync, readFileSync } from "node:fs";
@@ -1000,4 +1000,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
1000
1000
 
1001
1001
  //#endregion
1002
1002
  export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, runHealthAction, validateStoryKey };
1003
- //# sourceMappingURL=health-B1Rk7RXw.js.map
1003
+ //# sourceMappingURL=health-kr5GC1SN.js.map
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { readCurrentRunId, resolveMainRepoRoot } from "./manifest-read-BX_tMdib.js";
2
+ import { readCurrentRunId, resolveMainRepoRoot } from "./manifest-read-CcK_LIaI.js";
3
3
  import { join } from "node:path";
4
4
  import { mkdir, readFile, writeFile } from "node:fs/promises";
5
5
  import * as readline from "node:readline";
@@ -180,4 +180,4 @@ async function runInteractivePrompt(decisionContext) {
180
180
 
181
181
  //#endregion
182
182
  export { runInteractivePrompt };
183
- //# sourceMappingURL=interactive-prompt-GixkO5-6.js.map
183
+ //# sourceMappingURL=interactive-prompt-B5KE69I6.js.map
@@ -5444,6 +5444,161 @@ const JourneyCandidateSchema = z.object({
5444
5444
  else seen.set(journey.id, i);
5445
5445
  });
5446
5446
  });
5447
+ /** Parse + validate candidate YAML. Never throws (mirrors parseJourneyRegistry). */
5448
+ function parseJourneyCandidate(yamlContent) {
5449
+ let doc;
5450
+ try {
5451
+ doc = load(yamlContent);
5452
+ } catch (err) {
5453
+ const message = err instanceof YAMLException ? err.message : String(err);
5454
+ return {
5455
+ ok: false,
5456
+ issues: [{
5457
+ path: "(root)",
5458
+ message: `malformed YAML: ${message}`
5459
+ }]
5460
+ };
5461
+ }
5462
+ if (doc === null || doc === void 0) return {
5463
+ ok: false,
5464
+ issues: [{
5465
+ path: "(root)",
5466
+ message: "candidate file is empty"
5467
+ }]
5468
+ };
5469
+ const result = JourneyCandidateSchema.safeParse(doc);
5470
+ if (!result.success) return {
5471
+ ok: false,
5472
+ issues: result.error.issues.map((issue) => ({
5473
+ path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
5474
+ message: issue.message
5475
+ }))
5476
+ };
5477
+ return {
5478
+ ok: true,
5479
+ candidate: result.data
5480
+ };
5481
+ }
5482
+
5483
+ //#endregion
5484
+ //#region packages/sdlc/dist/acceptance/provenance.js
5485
+ function candidateToJourney(c, epicAssignments) {
5486
+ const epic = epicAssignments?.[c.id] ?? c.epic;
5487
+ return {
5488
+ id: c.id,
5489
+ title: c.title,
5490
+ criticality: c.criticality,
5491
+ surfaces: c.surfaces,
5492
+ ...epic !== void 0 ? { epic } : {},
5493
+ end_states: c.end_states
5494
+ };
5495
+ }
5496
+ /**
5497
+ * Build the ratified registry from a candidate. Pure — no fs, no prompts.
5498
+ *
5499
+ * Validation is the REGISTRY schema's (critical-needs-epic, non-empty
5500
+ * end_states, duplicate ids …): a candidate that would ratify into an
5501
+ * invalid registry comes back as issues for the operator to resolve by
5502
+ * editing the candidate (it is editable by design) or excluding journeys.
5503
+ */
5504
+ function ratifyCandidate(candidate, options) {
5505
+ const issues = [];
5506
+ const warnings = [];
5507
+ const candidateIds = new Set(candidate.journeys.map((j) => j.id));
5508
+ for (const ex of options.excludes) if (!candidateIds.has(ex.candidate)) issues.push({
5509
+ path: "excluded",
5510
+ message: `--exclude "${ex.candidate}" does not match any candidate journey id (known: ${[...candidateIds].join(", ")})`
5511
+ });
5512
+ if (issues.length > 0) return {
5513
+ ok: false,
5514
+ issues
5515
+ };
5516
+ const excludedIds = new Set(options.excludes.map((e) => e.candidate));
5517
+ const kept = candidate.journeys.filter((j) => !excludedIds.has(j.id));
5518
+ if (kept.length === 0) return {
5519
+ ok: false,
5520
+ issues: [{
5521
+ path: "journeys",
5522
+ message: "every candidate journey was excluded — nothing to ratify"
5523
+ }]
5524
+ };
5525
+ const carried = (options.existingRegistry?.provenance?.excluded ?? []).filter((prior) => !kept.some((j) => j.id === prior.candidate || j.title === prior.candidate) && !excludedIds.has(prior.candidate));
5526
+ const sourceShaNow = createHash("sha256").update(options.sourceContent, "utf-8").digest("hex");
5527
+ if (sourceShaNow !== candidate.source_sha256) warnings.push(`source ${candidate.derived_from} changed between derive (sha256 ${candidate.source_sha256.slice(0, 12)}…) and ratify (sha256 ${sourceShaNow.slice(0, 12)}…) — the provenance records the CURRENT content; consider re-deriving so the candidate reflects what you are ratifying against`);
5528
+ const registry = {
5529
+ version: options.existingRegistry !== void 0 ? options.existingRegistry.version + 1 : 1,
5530
+ journeys: kept.map((j) => candidateToJourney(j, options.epicAssignments)),
5531
+ provenance: {
5532
+ derived_from: candidate.derived_from,
5533
+ source_sha256: sourceShaNow,
5534
+ derived_at: options.now,
5535
+ ratified_by: options.ratifiedBy,
5536
+ ...options.excludes.length + carried.length > 0 ? { excluded: [...options.excludes, ...carried] } : {}
5537
+ }
5538
+ };
5539
+ const validated = JourneyRegistrySchema.safeParse(registry);
5540
+ if (!validated.success) return {
5541
+ ok: false,
5542
+ issues: validated.error.issues.map((issue) => ({
5543
+ path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
5544
+ message: issue.message
5545
+ }))
5546
+ };
5547
+ return {
5548
+ ok: true,
5549
+ registry: validated.data,
5550
+ warnings
5551
+ };
5552
+ }
5553
+ function endStatesEqual(a, b) {
5554
+ if (a.length !== b.length) return false;
5555
+ const key = (es) => `${es.id}${es.given}${es.walk}${es.then}`;
5556
+ const aKeys = new Set(a.map(key));
5557
+ return b.every((es) => aKeys.has(key(es)));
5558
+ }
5559
+ /**
5560
+ * Diff the current registry's journeys against a candidate's. Field-level on
5561
+ * the shared ids so a semantic change (criticality flip, end-state rewrite,
5562
+ * surface add) can never render as a no-op; ordering and the candidate-only
5563
+ * criticality_rationale are deliberately ignored (not semantic).
5564
+ */
5565
+ function diffJourneySets(current, candidate) {
5566
+ const currentById = new Map(current.map((j) => [j.id, j]));
5567
+ const candidateById = new Map(candidate.map((j) => [j.id, j]));
5568
+ const added = candidate.filter((j) => !currentById.has(j.id)).map((j) => j.id);
5569
+ const removed = current.filter((j) => !candidateById.has(j.id)).map((j) => j.id);
5570
+ const changed = [];
5571
+ const unchanged = [];
5572
+ for (const [id, cur] of currentById) {
5573
+ const cand = candidateById.get(id);
5574
+ if (cand === void 0) continue;
5575
+ const fields = [];
5576
+ if (cur.title !== cand.title) fields.push("title");
5577
+ if (cur.criticality !== cand.criticality) fields.push("criticality");
5578
+ if ([...cur.surfaces].sort().join(",") !== [...cand.surfaces].sort().join(",")) fields.push("surfaces");
5579
+ if (!endStatesEqual(cur.end_states, cand.end_states)) fields.push("end_states");
5580
+ if (fields.length > 0) changed.push({
5581
+ id,
5582
+ fields
5583
+ });
5584
+ else unchanged.push(id);
5585
+ }
5586
+ return {
5587
+ added,
5588
+ removed,
5589
+ changed,
5590
+ unchanged
5591
+ };
5592
+ }
5593
+ /** Render a diff for humans (derive/ratify CLI output). */
5594
+ function renderRegistryDiff(diff) {
5595
+ const lines = [];
5596
+ for (const id of diff.added) lines.push(` + ${id} (new journey)`);
5597
+ for (const id of diff.removed) lines.push(` - ${id} (REMOVED — was in the ratified registry; removal needs a hard look)`);
5598
+ for (const c of diff.changed) lines.push(` ~ ${c.id} (changed: ${c.fields.join(", ")})`);
5599
+ for (const id of diff.unchanged) lines.push(` = ${id} (unchanged)`);
5600
+ return lines.join("\n");
5601
+ }
5447
5602
 
5448
5603
  //#endregion
5449
5604
  //#region packages/sdlc/dist/acceptance/loader.js
@@ -7520,5 +7675,5 @@ async function resolveRunManifest(dbRoot, runId) {
7520
7675
  }
7521
7676
 
7522
7677
  //#endregion
7523
- export { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_CANDIDATE_PATH, JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, RuntimeProbeListSchema, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, applyConfigToGraph, clearGateDemotion, computeJourneyCoverage, computePrecision, computeRecall, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, demoteGate, detectsEventDrivenAC, detectsStateIntegratingAC, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, parseStoryFrontmatter, readAcceptanceMetrics, readCurrentRunId, readGateState, recordCanary, recordCriticalFail, recordOverride, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary, runStaleVerificationRecovery, summarizeCoverage };
7524
- //# sourceMappingURL=manifest-read-BX_tMdib.js.map
7678
+ export { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_CANDIDATE_PATH, JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, RuntimeProbeListSchema, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, applyConfigToGraph, clearGateDemotion, computeJourneyCoverage, computePrecision, computeRecall, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, demoteGate, detectsEventDrivenAC, detectsStateIntegratingAC, diffJourneySets, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyCandidate, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, parseStoryFrontmatter, ratifyCandidate, readAcceptanceMetrics, readCurrentRunId, readGateState, recordCanary, recordCriticalFail, recordOverride, renderFindings, renderRegistryDiff, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary, runStaleVerificationRecovery, summarizeCoverage };
7679
+ //# sourceMappingURL=manifest-read-CcK_LIaI.js.map
@@ -1,6 +1,6 @@
1
1
  import "../../logger-KeHncl-f.js";
2
2
  import "../../dist-BZGqn-XQ.js";
3
- import "../../manifest-read-BX_tMdib.js";
4
- import { runInteractivePrompt } from "../../interactive-prompt-GixkO5-6.js";
3
+ import "../../manifest-read-CcK_LIaI.js";
4
+ import { runInteractivePrompt } from "../../interactive-prompt-B5KE69I6.js";
5
5
 
6
6
  export { runInteractivePrompt };
@@ -1,12 +1,12 @@
1
- import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-B1Rk7RXw.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-kr5GC1SN.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, BRANCH_PREFIX, CLAUDE_AUTH_FAILURE_HINT, CODEX_SANDBOX_BLOCK_HINT, 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, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createGitWorktreeManager, createPipelineRun, createRequirement, detectClaudeAuthFailure, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-BZGqn-XQ.js";
5
- import { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_DEFERRALS_PATH, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, recordCriticalFail, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-BX_tMdib.js";
5
+ import { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_DEFERRALS_PATH, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, recordCriticalFail, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-CcK_LIaI.js";
6
6
  import { CodeReviewResultSchema, CreateStoryResultSchema, DevStoryResultSchema, ProbeAuthorResultSchema, TestExpansionResultSchema, TestPlanResultSchema, assemblePrompt, countTokens, getTokenCeiling, runAcceptanceJudge, truncateToTokens } from "./acceptance-judge-lAv5EvYA.js";
7
7
  import { WorkGraphRepository, detectCycles } from "./work-graph-repository-4cKsf8Lf.js";
8
8
  import { deriveExitCode, routeDecision } from "./decision-router-Dyby0fUf.js";
9
- import { runInteractivePrompt } from "./interactive-prompt-GixkO5-6.js";
9
+ import { runInteractivePrompt } from "./interactive-prompt-B5KE69I6.js";
10
10
  import { runRecoveryEngine } from "./recovery-engine-dtLHyV4M.js";
11
11
  import { basename, dirname, extname, join } from "path";
12
12
  import { access, readFile, readdir, stat } from "fs/promises";
@@ -48358,4 +48358,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
48358
48358
 
48359
48359
  //#endregion
48360
48360
  export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
48361
- //# sourceMappingURL=run-DcUXpWwu.js.map
48361
+ //# sourceMappingURL=run-DR_D61vF.js.map
@@ -1,15 +1,15 @@
1
- import "./health-B1Rk7RXw.js";
1
+ import "./health-kr5GC1SN.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
4
  import "./dist-BZGqn-XQ.js";
5
- import "./manifest-read-BX_tMdib.js";
6
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DcUXpWwu.js";
5
+ import "./manifest-read-CcK_LIaI.js";
6
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DR_D61vF.js";
7
7
  import "./acceptance-judge-lAv5EvYA.js";
8
8
  import "./routing-DZT5PN3N.js";
9
9
  import "./work-graph-repository-4cKsf8Lf.js";
10
10
  import "./decisions-BAaxpVD0.js";
11
11
  import "./decision-router-Dyby0fUf.js";
12
- import "./interactive-prompt-GixkO5-6.js";
12
+ import "./interactive-prompt-B5KE69I6.js";
13
13
  import "./recovery-engine-dtLHyV4M.js";
14
14
 
15
15
  export { runRunAction };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.21.14",
3
+ "version": "0.21.15",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",