substrate-ai 0.21.14 → 0.21.16

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-CI8pIygU.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, checkRegistryStaleness, clearGateDemotion, computePrecision, computeRecall, demoteGate, diffJourneySets, isProjectContainedPath, loadAcceptanceContractFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyCandidate, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, ratifyCandidate, readAcceptanceMetrics, readCurrentRunId, readGateState, readTrustedFileContent, recordCanary, recordOverride, renderRegistryDiff, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary } from "../manifest-read-3cF8yP3_.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-BeYZ5L6d.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-BWdH9Lb9.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-C1m6-7WH.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-NlTM7HwK.js"
8669
8670
  );
8670
8671
  const runStoryFn = async (opts) => {
8671
8672
  const exitCode = await runPipeline({
@@ -13660,17 +13661,49 @@ function registerAcceptanceCommand(program, version, registry) {
13660
13661
  } catch {
13661
13662
  contract = { status: "absent" };
13662
13663
  }
13664
+ let staleness;
13665
+ if (result.status === "ok" && result.registry.provenance !== void 0) {
13666
+ const derivedFrom = result.registry.provenance.derived_from;
13667
+ let sourceContent;
13668
+ if (isProjectContainedPath(derivedFrom)) if (opts.ref !== void 0) {
13669
+ const read = await readTrustedFileContent(projectRoot, opts.ref, derivedFrom);
13670
+ sourceContent = read.status === "ok" ? read.content : void 0;
13671
+ } else try {
13672
+ sourceContent = await readFile$1(join$1(projectRoot, derivedFrom), "utf-8");
13673
+ } catch {
13674
+ sourceContent = void 0;
13675
+ }
13676
+ staleness = checkRegistryStaleness(result.registry, sourceContent);
13677
+ }
13663
13678
  if (opts.outputFormat === "json") {
13664
13679
  const output = buildJsonOutput("substrate acceptance validate", {
13665
13680
  source,
13666
13681
  ...result,
13667
13682
  contract: { status: contract.status },
13668
- provenance: { status: result.status === "ok" && result.registry.provenance !== void 0 ? "present" : "absent" }
13683
+ provenance: {
13684
+ status: result.status === "ok" && result.registry.provenance !== void 0 ? "present" : "absent",
13685
+ ...staleness !== void 0 ? { staleness: staleness.status } : {}
13686
+ }
13669
13687
  }, version);
13670
13688
  process.stdout.write(JSON.stringify(output, null, 2) + "\n");
13671
13689
  process.exit(result.status === "ok" ? ACCEPTANCE_EXIT_SUCCESS : ACCEPTANCE_EXIT_ERROR);
13672
13690
  }
13673
13691
  const exitCode = renderHuman(result, source);
13692
+ if (staleness !== void 0) switch (staleness.status) {
13693
+ case "fresh":
13694
+ process.stdout.write(`staleness: FRESH — ${staleness.derivedFrom} unchanged since ratification\n`);
13695
+ break;
13696
+ case "stale":
13697
+ process.stdout.write(`registry-stale (advisory): ${staleness.derivedFrom} changed since ratification (recorded sha256 ${staleness.recordedSha.slice(0, 12)}…, current ${staleness.currentSha.slice(0, 12)}…) — re-run \`substrate acceptance derive --prd ${staleness.derivedFrom} --force\` and review the diff\n`);
13698
+ break;
13699
+ case "source-missing":
13700
+ process.stdout.write(`registry-source-missing (advisory): ${staleness.derivedFrom} (recorded in provenance) not found — the staleness baseline cannot be verified\n`);
13701
+ break;
13702
+ case "source-escapes-project":
13703
+ process.stdout.write(`registry-source-escapes-project (advisory): provenance derived_from "${staleness.derivedFrom}" resolves outside the project — refusing to read it\n`);
13704
+ break;
13705
+ case "no-provenance": break;
13706
+ }
13674
13707
  if (contract.status === "ok") {
13675
13708
  const surfaces = Object.keys(contract.contract.surfaces).join(", ");
13676
13709
  process.stdout.write(`contract: OK — surfaces declared: ${surfaces}\n`);
@@ -13909,7 +13942,121 @@ function registerAcceptanceCommand(program, version, registry) {
13909
13942
  }
13910
13943
  const needsElaboration = result.journeys.filter((j) => j.end_states.length === 0);
13911
13944
  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.
13945
+ derived from ${prdRel} (sha256 ${sourceSha.slice(0, 12)}…)\n`);
13946
+ if (existingRegistryYaml !== void 0) {
13947
+ const parsedExisting = parseJourneyRegistry(existingRegistryYaml);
13948
+ if (parsedExisting.ok) process.stdout.write(`delta vs ratified registry v${String(parsedExisting.registry.version)}:\n${renderRegistryDiff(diffJourneySets(parsedExisting.registry.journeys, result.journeys))}\n`);
13949
+ }
13950
+ 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");
13951
+ process.exit(ACCEPTANCE_EXIT_SUCCESS);
13952
+ });
13953
+ 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) => {
13954
+ const projectRoot = process.cwd();
13955
+ const candidatePath = join$1(projectRoot, JOURNEY_CANDIDATE_PATH);
13956
+ let candidateContent;
13957
+ try {
13958
+ candidateContent = await readFile$1(candidatePath, "utf-8");
13959
+ } catch {
13960
+ process.stdout.write(`acceptance ratify: no candidate at ${JOURNEY_CANDIDATE_PATH} — run \`substrate acceptance derive --prd <path>\` first\n`);
13961
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13962
+ return;
13963
+ }
13964
+ const parsedCandidate = parseJourneyCandidate(candidateContent);
13965
+ if (!parsedCandidate.ok) {
13966
+ process.stdout.write(`acceptance ratify: candidate invalid:\n${parsedCandidate.issues.map((i) => ` ${i.path}: ${i.message}`).join("\n")}\n`);
13967
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13968
+ return;
13969
+ }
13970
+ const candidate = parsedCandidate.candidate;
13971
+ const excludes = [];
13972
+ for (const spec of opts.exclude) {
13973
+ const sep = spec.indexOf(":");
13974
+ const id = sep >= 0 ? spec.slice(0, sep).trim() : spec.trim();
13975
+ const reason = sep >= 0 ? spec.slice(sep + 1).trim() : "";
13976
+ if (reason === "") {
13977
+ process.stdout.write(`acceptance ratify: --exclude "${spec}" has no reason — use "ID: reason" (reasonless exclusions are unauditable)\n`);
13978
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13979
+ return;
13980
+ }
13981
+ excludes.push({
13982
+ candidate: id,
13983
+ reason
13984
+ });
13985
+ }
13986
+ const epicAssignments = {};
13987
+ for (const spec of opts.epic) {
13988
+ const sep = spec.indexOf("=");
13989
+ const id = sep >= 0 ? spec.slice(0, sep).trim() : "";
13990
+ const n = sep >= 0 ? Number(spec.slice(sep + 1).trim()) : NaN;
13991
+ if (id === "" || !Number.isInteger(n) || n <= 0) {
13992
+ process.stdout.write(`acceptance ratify: --epic "${spec}" must be "JOURNEY-ID=<positive integer>"\n`);
13993
+ process.exit(ACCEPTANCE_EXIT_ERROR);
13994
+ return;
13995
+ }
13996
+ epicAssignments[id] = n;
13997
+ }
13998
+ let existingRegistry;
13999
+ try {
14000
+ const existingContent = await readFile$1(join$1(projectRoot, JOURNEY_REGISTRY_PATH), "utf-8");
14001
+ const parsedExisting = parseJourneyRegistry(existingContent);
14002
+ if (!parsedExisting.ok) {
14003
+ 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`);
14004
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14005
+ return;
14006
+ }
14007
+ existingRegistry = parsedExisting.registry;
14008
+ } catch {
14009
+ existingRegistry = void 0;
14010
+ }
14011
+ let sourceContent;
14012
+ try {
14013
+ sourceContent = await readFile$1(join$1(projectRoot, candidate.derived_from), "utf-8");
14014
+ } catch (err) {
14015
+ process.stdout.write(`acceptance ratify: cannot read source ${candidate.derived_from} (recorded in the candidate): ${String(err)}\n`);
14016
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14017
+ return;
14018
+ }
14019
+ const result = ratifyCandidate(candidate, {
14020
+ excludes,
14021
+ ratifiedBy: opts.ratifiedBy,
14022
+ sourceContent,
14023
+ now: new Date().toISOString(),
14024
+ ...existingRegistry !== void 0 ? { existingRegistry } : {},
14025
+ epicAssignments
14026
+ });
14027
+ if (!result.ok) {
14028
+ 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");
14029
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14030
+ return;
14031
+ }
14032
+ const reg = result.registry;
14033
+ 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("") : ""));
14034
+ if (existingRegistry !== void 0) process.stdout.write(`delta vs v${String(existingRegistry.version)}:\n${renderRegistryDiff(diffJourneySets(existingRegistry.journeys, candidate.journeys))}\n`);
14035
+ for (const w of result.warnings) process.stdout.write(`WARNING: ${w}\n`);
14036
+ if (!opts.yes) {
14037
+ const rl = createInterface$2({
14038
+ input: process.stdin,
14039
+ output: process.stderr
14040
+ });
14041
+ const answer = await rl.question("ratify? [y/N] ");
14042
+ rl.close();
14043
+ if (answer.trim().toLowerCase() !== "y") {
14044
+ process.stdout.write("aborted — candidate left in place\n");
14045
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14046
+ return;
14047
+ }
14048
+ }
14049
+ const registryHeader = "# Journey registry — ratified via `substrate acceptance ratify`.\n# The acceptance gate reads THIS file from the trusted tree. COMMIT it.\n";
14050
+ try {
14051
+ await mkdir$1(dirname$1(join$1(projectRoot, JOURNEY_REGISTRY_PATH)), { recursive: true });
14052
+ await writeFile$1(join$1(projectRoot, JOURNEY_REGISTRY_PATH), registryHeader + dump(reg, { lineWidth: 120 }), "utf-8");
14053
+ await unlink$1(candidatePath);
14054
+ } catch (err) {
14055
+ process.stdout.write(`acceptance ratify: write failed: ${String(err)}\n`);
14056
+ process.exit(ACCEPTANCE_EXIT_ERROR);
14057
+ return;
14058
+ }
14059
+ 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
14060
  `);
13914
14061
  process.exit(ACCEPTANCE_EXIT_SUCCESS);
13915
14062
  });
@@ -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-CI8pIygU.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-3cF8yP3_.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-3cF8yP3_.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-CI8pIygU.js.map
package/dist/index.d.ts CHANGED
@@ -260,6 +260,25 @@ interface AcceptanceVerdictEvent {
260
260
  excerpt: string;
261
261
  }[];
262
262
  }
263
+ /**
264
+ * RP2.1 (registry-provenance): the registry's provenance `derived_from`
265
+ * source no longer hashes to the recorded ratification baseline (`stale`),
266
+ * cannot be found (`source-missing`), or records an escaping path
267
+ * (`source-escapes-project`). ADVISORY — the run continues; the signal means
268
+ * the PRD moved after ratification and the registry may no longer cover the
269
+ * vision. Resolution: `substrate acceptance derive` + review the diff +
270
+ * re-ratify.
271
+ */
272
+ interface AcceptanceRegistryStaleEvent {
273
+ type: 'acceptance:registry-stale';
274
+ ts: string;
275
+ /** Audit boundary that detected it: `epic-<n>` or `final` */
276
+ scope: string;
277
+ status: 'stale' | 'source-missing' | 'source-escapes-project';
278
+ derived_from: string;
279
+ recorded_sha?: string;
280
+ current_sha?: string;
281
+ }
263
282
  /** A6.1: canary self-test — did the gate catch a planted (reverted-wiring) regression? */
264
283
  interface AcceptanceCanaryEvent {
265
284
  type: 'acceptance:canary';
@@ -904,7 +923,7 @@ interface PipelineMergeConflictDetectedEvent {
904
923
  * }
905
924
  * ```
906
925
  */
907
- type PipelineEvent = PipelineStartEvent | PipelineCompleteEvent | PipelinePreFlightFailureEvent | PipelineProfileStaleEvent | PipelineContractMismatchEvent | PipelineContractVerificationSummaryEvent | StoryPhaseEvent | StoryDoneEvent | StoryCommittedEvent | StoryMergedEvent | StoryFinalizedEvent | AcceptanceCoverageEvent | AcceptanceStartedEvent | AcceptanceRenderedEvent | AcceptanceVerdictEvent | AcceptanceCanaryEvent | StoryEscalationEvent | StoryWarnEvent | StoryLogEvent | PipelineHeartbeatEvent | StoryStallEvent | StoryZeroDiffEscalationEvent | StoryBuildVerificationFailedEvent | StoryBuildVerificationPassedEvent | StoryInterfaceChangeWarningEvent | StoryMetricsEvent | SupervisorPollEvent | SupervisorKillEvent | SupervisorRestartEvent | SupervisorAbortEvent | SupervisorSummaryEvent | SupervisorAnalysisCompleteEvent | SupervisorAnalysisErrorEvent | SupervisorExperimentStartEvent | SupervisorExperimentSkipEvent | SupervisorExperimentRecommendationsEvent | SupervisorExperimentCompleteEvent | SupervisorExperimentErrorEvent | RoutingModelSelectedEvent | PipelinePhaseStartEvent | PipelinePhaseCompleteEvent | StoryAutoApprovedEvent | VerificationCheckCompleteEvent | VerificationStoryCompleteEvent | CostWarningEvent | CostCeilingReachedEvent | DecisionHaltSkippedNonInteractiveEvent | PipelineMergeConflictDetectedEvent; //#endregion
926
+ type PipelineEvent = PipelineStartEvent | PipelineCompleteEvent | PipelinePreFlightFailureEvent | PipelineProfileStaleEvent | PipelineContractMismatchEvent | PipelineContractVerificationSummaryEvent | StoryPhaseEvent | StoryDoneEvent | StoryCommittedEvent | StoryMergedEvent | StoryFinalizedEvent | AcceptanceCoverageEvent | AcceptanceStartedEvent | AcceptanceRenderedEvent | AcceptanceVerdictEvent | AcceptanceCanaryEvent | AcceptanceRegistryStaleEvent | StoryEscalationEvent | StoryWarnEvent | StoryLogEvent | PipelineHeartbeatEvent | StoryStallEvent | StoryZeroDiffEscalationEvent | StoryBuildVerificationFailedEvent | StoryBuildVerificationPassedEvent | StoryInterfaceChangeWarningEvent | StoryMetricsEvent | SupervisorPollEvent | SupervisorKillEvent | SupervisorRestartEvent | SupervisorAbortEvent | SupervisorSummaryEvent | SupervisorAnalysisCompleteEvent | SupervisorAnalysisErrorEvent | SupervisorExperimentStartEvent | SupervisorExperimentSkipEvent | SupervisorExperimentRecommendationsEvent | SupervisorExperimentCompleteEvent | SupervisorExperimentErrorEvent | RoutingModelSelectedEvent | PipelinePhaseStartEvent | PipelinePhaseCompleteEvent | StoryAutoApprovedEvent | VerificationCheckCompleteEvent | VerificationStoryCompleteEvent | CostWarningEvent | CostCeilingReachedEvent | DecisionHaltSkippedNonInteractiveEvent | PipelineMergeConflictDetectedEvent; //#endregion
908
927
  //#region src/core/errors.d.ts
909
928
 
910
929
  /**
@@ -1607,6 +1626,18 @@ interface OrchestratorEvents {
1607
1626
  }[];
1608
1627
  summary: Record<string, number>;
1609
1628
  };
1629
+ /**
1630
+ * RP2.1 (registry-provenance): the registry's `derived_from` source no
1631
+ * longer hashes to the recorded ratification baseline (or cannot be read).
1632
+ * ADVISORY — mapped to the NDJSON `acceptance:registry-stale` event.
1633
+ */
1634
+ 'orchestrator:acceptance-registry-stale': {
1635
+ scope: string;
1636
+ status: 'stale' | 'source-missing' | 'source-escapes-project';
1637
+ derivedFrom: string;
1638
+ recordedSha?: string;
1639
+ currentSha?: string;
1640
+ };
1610
1641
  /** A story has been escalated after exceeding max review cycles */
1611
1642
  'orchestrator:story-escalated': {
1612
1643
  storyKey: string;
@@ -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-3cF8yP3_.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-BWdH9Lb9.js.map
@@ -5444,6 +5444,212 @@ 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) => JSON.stringify([
5556
+ es.id,
5557
+ es.given,
5558
+ es.walk,
5559
+ es.then
5560
+ ]);
5561
+ const aKeys = new Set(a.map(key));
5562
+ return b.every((es) => aKeys.has(key(es)));
5563
+ }
5564
+ /**
5565
+ * Diff the current registry's journeys against a candidate's. Field-level on
5566
+ * the shared ids so a semantic change (criticality flip, end-state rewrite,
5567
+ * surface add) can never render as a no-op; ordering and the candidate-only
5568
+ * criticality_rationale are deliberately ignored (not semantic).
5569
+ */
5570
+ function diffJourneySets(current, candidate) {
5571
+ const currentById = new Map(current.map((j) => [j.id, j]));
5572
+ const candidateById = new Map(candidate.map((j) => [j.id, j]));
5573
+ const added = candidate.filter((j) => !currentById.has(j.id)).map((j) => j.id);
5574
+ const removed = current.filter((j) => !candidateById.has(j.id)).map((j) => j.id);
5575
+ const changed = [];
5576
+ const unchanged = [];
5577
+ for (const [id, cur] of currentById) {
5578
+ const cand = candidateById.get(id);
5579
+ if (cand === void 0) continue;
5580
+ const fields = [];
5581
+ if (cur.title !== cand.title) fields.push("title");
5582
+ if (cur.criticality !== cand.criticality) fields.push("criticality");
5583
+ if ([...cur.surfaces].sort().join(",") !== [...cand.surfaces].sort().join(",")) fields.push("surfaces");
5584
+ if (!endStatesEqual(cur.end_states, cand.end_states)) fields.push("end_states");
5585
+ if (fields.length > 0) changed.push({
5586
+ id,
5587
+ fields
5588
+ });
5589
+ else unchanged.push(id);
5590
+ }
5591
+ return {
5592
+ added,
5593
+ removed,
5594
+ changed,
5595
+ unchanged
5596
+ };
5597
+ }
5598
+ /**
5599
+ * A provenance `derived_from` must resolve INSIDE the project: relative, no
5600
+ * traversal, no absolute/drive/scheme forms. The staleness check re-reads
5601
+ * this recorded path — an escaping path would let a hostile provenance block
5602
+ * point the re-hash at content outside the repo (RP5 catalog item 5).
5603
+ */
5604
+ function isProjectContainedPath(relPath) {
5605
+ if (relPath === "" || relPath.startsWith("/") || relPath.startsWith("\\")) return false;
5606
+ if (/^[a-zA-Z]:[\\/]/.test(relPath)) return false;
5607
+ if (/^[a-z][a-z0-9+.-]*:/i.test(relPath)) return false;
5608
+ const segments = relPath.split(/[\\/]/);
5609
+ return !segments.includes("..");
5610
+ }
5611
+ /**
5612
+ * Compare the recorded `source_sha256` against the CURRENT content of
5613
+ * `derived_from`. Pure: the caller supplies the content (fs for operator
5614
+ * lint, trusted-tree `git show` for the orchestrator) — pass `undefined`
5615
+ * when the source could not be read.
5616
+ *
5617
+ * ADVISORY by construction: every status is information for the operator;
5618
+ * nothing here blocks. Registry rot must be LOUD, not fatal.
5619
+ */
5620
+ function checkRegistryStaleness(registry, sourceContent) {
5621
+ const prov = registry.provenance;
5622
+ if (prov === void 0) return { status: "no-provenance" };
5623
+ if (!isProjectContainedPath(prov.derived_from)) return {
5624
+ status: "source-escapes-project",
5625
+ derivedFrom: prov.derived_from
5626
+ };
5627
+ if (sourceContent === void 0) return {
5628
+ status: "source-missing",
5629
+ derivedFrom: prov.derived_from
5630
+ };
5631
+ const currentSha = createHash("sha256").update(sourceContent, "utf-8").digest("hex");
5632
+ if (currentSha === prov.source_sha256) return {
5633
+ status: "fresh",
5634
+ sha: currentSha,
5635
+ derivedFrom: prov.derived_from
5636
+ };
5637
+ return {
5638
+ status: "stale",
5639
+ recordedSha: prov.source_sha256,
5640
+ currentSha,
5641
+ derivedFrom: prov.derived_from
5642
+ };
5643
+ }
5644
+ /** Render a diff for humans (derive/ratify CLI output). */
5645
+ function renderRegistryDiff(diff) {
5646
+ const lines = [];
5647
+ for (const id of diff.added) lines.push(` + ${id} (new journey)`);
5648
+ for (const id of diff.removed) lines.push(` - ${id} (REMOVED — was in the ratified registry; removal needs a hard look)`);
5649
+ for (const c of diff.changed) lines.push(` ~ ${c.id} (changed: ${c.fields.join(", ")})`);
5650
+ for (const id of diff.unchanged) lines.push(` = ${id} (unchanged)`);
5651
+ return lines.join("\n");
5652
+ }
5447
5653
 
5448
5654
  //#endregion
5449
5655
  //#region packages/sdlc/dist/acceptance/loader.js
@@ -5570,6 +5776,31 @@ async function loadAcceptanceContractFromTrustedTree(repoRoot, ref = "HEAD") {
5570
5776
  return parseAcceptanceContract(result.stdout);
5571
5777
  }
5572
5778
  /**
5779
+ * Read an arbitrary project-relative file from the trusted tree at `ref`
5780
+ * (RP2.1: the staleness check re-hashes `provenance.derived_from` against
5781
+ * the same snapshot the registry was loaded from). Callers must containment-
5782
+ * check the path first (`isProjectContainedPath`) — git itself rejects
5783
+ * escaping specs, but the check belongs before the spawn.
5784
+ */
5785
+ async function readTrustedFileContent(repoRoot, ref, relPath) {
5786
+ const result = await runGitShow(repoRoot, ref, relPath);
5787
+ if (result.spawnError !== void 0) return {
5788
+ status: "error",
5789
+ message: `git show could not be spawned: ${result.spawnError}`
5790
+ };
5791
+ if (result.code !== 0) {
5792
+ if (GIT_SHOW_ABSENT_PATTERNS.some((p) => p.test(result.stderr))) return { status: "absent" };
5793
+ return {
5794
+ status: "error",
5795
+ message: `git show ${ref}:${relPath} failed (exit ${String(result.code)}): ${result.stderr.trim()}`
5796
+ };
5797
+ }
5798
+ return {
5799
+ status: "ok",
5800
+ content: result.stdout
5801
+ };
5802
+ }
5803
+ /**
5573
5804
  * Filesystem read for OPERATOR LINT ONLY (`substrate acceptance validate`).
5574
5805
  * Gate/judge code paths must use `loadJourneyRegistryFromTrustedTree`.
5575
5806
  */
@@ -7520,5 +7751,5 @@ async function resolveRunManifest(dbRoot, runId) {
7520
7751
  }
7521
7752
 
7522
7753
  //#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
7754
+ 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, checkRegistryStaleness, clearGateDemotion, computeJourneyCoverage, computePrecision, computeRecall, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, demoteGate, detectsEventDrivenAC, detectsStateIntegratingAC, diffJourneySets, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, isProjectContainedPath, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyCandidate, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, parseStoryFrontmatter, ratifyCandidate, readAcceptanceMetrics, readCurrentRunId, readGateState, readTrustedFileContent, recordCanary, recordCriticalFail, recordOverride, renderFindings, renderRegistryDiff, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary, runStaleVerificationRecovery, summarizeCoverage };
7755
+ //# sourceMappingURL=manifest-read-3cF8yP3_.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-3cF8yP3_.js";
4
+ import { runInteractivePrompt } from "../../interactive-prompt-BWdH9Lb9.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-CI8pIygU.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, checkRegistryStaleness, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, isProjectContainedPath, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, readTrustedFileContent, recordCriticalFail, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-3cF8yP3_.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-BWdH9Lb9.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";
@@ -1091,6 +1091,45 @@ const PIPELINE_EVENT_METADATA = [
1091
1091
  }
1092
1092
  ]
1093
1093
  },
1094
+ {
1095
+ type: "acceptance:registry-stale",
1096
+ description: "Registry staleness advisory (RP2.1): the registry's provenance source no longer hashes to its ratification baseline (stale), is unreadable (source-missing), or escapes the project (source-escapes-project). Run continues; re-derive + re-ratify to resolve.",
1097
+ when: "At coverage-audit boundaries when a provenance-bearing registry's source diverged.",
1098
+ fields: [
1099
+ {
1100
+ name: "ts",
1101
+ type: "string",
1102
+ description: "Timestamp."
1103
+ },
1104
+ {
1105
+ name: "scope",
1106
+ type: "string",
1107
+ description: "epic-<n> or final."
1108
+ },
1109
+ {
1110
+ name: "status",
1111
+ type: "string",
1112
+ description: "stale | source-missing | source-escapes-project."
1113
+ },
1114
+ {
1115
+ name: "derived_from",
1116
+ type: "string",
1117
+ description: "Recorded source path."
1118
+ },
1119
+ {
1120
+ name: "recorded_sha",
1121
+ type: "string",
1122
+ description: "Baseline sha256 (stale only).",
1123
+ optional: true
1124
+ },
1125
+ {
1126
+ name: "current_sha",
1127
+ type: "string",
1128
+ description: "Current sha256 (stale only).",
1129
+ optional: true
1130
+ }
1131
+ ]
1132
+ },
1094
1133
  {
1095
1134
  type: "story:escalation",
1096
1135
  description: "Story escalated — either max review cycles exceeded or a precondition for SHIP_IT was not met.",
@@ -13836,6 +13875,33 @@ function createImplementationOrchestrator(deps) {
13836
13875
  logger$26.warn({ detail: registryLoad.message }, "A0.3: journey registry read failed — coverage audit skipped (environmental)");
13837
13876
  return void 0;
13838
13877
  }
13878
+ {
13879
+ const prov = registryLoad.registry.provenance;
13880
+ if (prov !== void 0) {
13881
+ let sourceContent;
13882
+ if (isProjectContainedPath(prov.derived_from)) {
13883
+ const read = await readTrustedFileContent(projectRoot, _runStartSha ?? "HEAD", prov.derived_from);
13884
+ sourceContent = read.status === "ok" ? read.content : void 0;
13885
+ }
13886
+ const staleness = checkRegistryStaleness(registryLoad.registry, sourceContent);
13887
+ if (staleness.status === "stale" || staleness.status === "source-missing" || staleness.status === "source-escapes-project") {
13888
+ const scopeLabelStale = "final" in scope ? "final" : `epic-${String(scope.epic)}`;
13889
+ logger$26.warn({
13890
+ staleness,
13891
+ scope: scopeLabelStale
13892
+ }, `RP2.1: registry-stale advisory (${staleness.status}) — the registry's source document diverged from its ratification baseline; re-run \`substrate acceptance derive\` and review the diff`);
13893
+ eventBus.emit("orchestrator:acceptance-registry-stale", {
13894
+ scope: scopeLabelStale,
13895
+ status: staleness.status,
13896
+ derivedFrom: staleness.derivedFrom,
13897
+ ...staleness.status === "stale" ? {
13898
+ recordedSha: staleness.recordedSha,
13899
+ currentSha: staleness.currentSha
13900
+ } : {}
13901
+ });
13902
+ }
13903
+ }
13904
+ }
13839
13905
  let unrunnable;
13840
13906
  const contractLoad = await loadAcceptanceContractFromTrustedTree(projectRoot, _runStartSha ?? "HEAD");
13841
13907
  if (contractLoad.status === "absent") unrunnable = `journey registry exists but the committed project profile has no acceptance: contract block (${ACCEPTANCE_CONTRACT_PROFILE_PATH}) — claimed journeys can never be walked. Declare render commands per surface.`;
@@ -46499,6 +46565,17 @@ function wireNdjsonEmitter(eventBus, ndjsonEmitter) {
46499
46565
  summary: payload.summary
46500
46566
  });
46501
46567
  });
46568
+ eventBus.on("orchestrator:acceptance-registry-stale", (payload) => {
46569
+ ndjsonEmitter.emit({
46570
+ type: "acceptance:registry-stale",
46571
+ ts: new Date().toISOString(),
46572
+ scope: payload.scope,
46573
+ status: payload.status,
46574
+ derived_from: payload.derivedFrom,
46575
+ ...payload.recordedSha !== void 0 ? { recorded_sha: payload.recordedSha } : {},
46576
+ ...payload.currentSha !== void 0 ? { current_sha: payload.currentSha } : {}
46577
+ });
46578
+ });
46502
46579
  eventBus.on("orchestrator:story-escalated", (payload) => {
46503
46580
  const rawIssues = Array.isArray(payload.issues) ? payload.issues : [];
46504
46581
  const issues = rawIssues.map((issue) => {
@@ -48358,4 +48435,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
48358
48435
 
48359
48436
  //#endregion
48360
48437
  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
48438
+ //# sourceMappingURL=run-BeYZ5L6d.js.map
@@ -1,15 +1,15 @@
1
- import "./health-B1Rk7RXw.js";
1
+ import "./health-CI8pIygU.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-3cF8yP3_.js";
6
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-BeYZ5L6d.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-BWdH9Lb9.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.16",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",