substrate-ai 0.21.15 → 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-kr5GC1SN.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, 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";
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-B5KE69I6.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";
@@ -7137,7 +7137,7 @@ async function runStatusAction(options) {
7137
7137
  logger$16.debug({ err }, "Work graph query failed, continuing without work graph data");
7138
7138
  }
7139
7139
  if (run === void 0) {
7140
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-CvsH53bv.js");
7140
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-C1m6-7WH.js");
7141
7141
  const substrateDirPath = join(projectRoot, ".substrate");
7142
7142
  const processInfo = inspectProcessTree$1({
7143
7143
  projectRoot,
@@ -8666,7 +8666,7 @@ async function runSupervisorAction(options, deps = {}) {
8666
8666
  await initSchema(expAdapter);
8667
8667
  const { runRunAction: runPipeline } = await import(
8668
8668
  /* @vite-ignore */
8669
- "../run-UilZoIOh.js"
8669
+ "../run-NlTM7HwK.js"
8670
8670
  );
8671
8671
  const runStoryFn = async (opts) => {
8672
8672
  const exitCode = await runPipeline({
@@ -13661,17 +13661,49 @@ function registerAcceptanceCommand(program, version, registry) {
13661
13661
  } catch {
13662
13662
  contract = { status: "absent" };
13663
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
+ }
13664
13678
  if (opts.outputFormat === "json") {
13665
13679
  const output = buildJsonOutput("substrate acceptance validate", {
13666
13680
  source,
13667
13681
  ...result,
13668
13682
  contract: { status: contract.status },
13669
- 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
+ }
13670
13687
  }, version);
13671
13688
  process.stdout.write(JSON.stringify(output, null, 2) + "\n");
13672
13689
  process.exit(result.status === "ok" ? ACCEPTANCE_EXIT_SUCCESS : ACCEPTANCE_EXIT_ERROR);
13673
13690
  }
13674
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
+ }
13675
13707
  if (contract.status === "ok") {
13676
13708
  const surfaces = Object.keys(contract.contract.surfaces).join(", ");
13677
13709
  process.stdout.write(`contract: OK — surfaces declared: ${surfaces}\n`);
@@ -1,7 +1,7 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-kr5GC1SN.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-CcK_LIaI.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-CcK_LIaI.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-kr5GC1SN.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-CcK_LIaI.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-B5KE69I6.js.map
183
+ //# sourceMappingURL=interactive-prompt-BWdH9Lb9.js.map
@@ -5552,7 +5552,12 @@ function ratifyCandidate(candidate, options) {
5552
5552
  }
5553
5553
  function endStatesEqual(a, b) {
5554
5554
  if (a.length !== b.length) return false;
5555
- const key = (es) => `${es.id}${es.given}${es.walk}${es.then}`;
5555
+ const key = (es) => JSON.stringify([
5556
+ es.id,
5557
+ es.given,
5558
+ es.walk,
5559
+ es.then
5560
+ ]);
5556
5561
  const aKeys = new Set(a.map(key));
5557
5562
  return b.every((es) => aKeys.has(key(es)));
5558
5563
  }
@@ -5590,6 +5595,52 @@ function diffJourneySets(current, candidate) {
5590
5595
  unchanged
5591
5596
  };
5592
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
+ }
5593
5644
  /** Render a diff for humans (derive/ratify CLI output). */
5594
5645
  function renderRegistryDiff(diff) {
5595
5646
  const lines = [];
@@ -5725,6 +5776,31 @@ async function loadAcceptanceContractFromTrustedTree(repoRoot, ref = "HEAD") {
5725
5776
  return parseAcceptanceContract(result.stdout);
5726
5777
  }
5727
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
+ /**
5728
5804
  * Filesystem read for OPERATOR LINT ONLY (`substrate acceptance validate`).
5729
5805
  * Gate/judge code paths must use `loadJourneyRegistryFromTrustedTree`.
5730
5806
  */
@@ -7675,5 +7751,5 @@ async function resolveRunManifest(dbRoot, runId) {
7675
7751
  }
7676
7752
 
7677
7753
  //#endregion
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
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-CcK_LIaI.js";
4
- import { runInteractivePrompt } from "../../interactive-prompt-B5KE69I6.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-kr5GC1SN.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-CcK_LIaI.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-B5KE69I6.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-DR_D61vF.js.map
48438
+ //# sourceMappingURL=run-BeYZ5L6d.js.map
@@ -1,15 +1,15 @@
1
- import "./health-kr5GC1SN.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-CcK_LIaI.js";
6
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DR_D61vF.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-B5KE69I6.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.15",
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",