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 +156 -9
- package/dist/{health-BxH_n5cd.js → health-C1m6-7WH.js} +2 -2
- package/dist/{health-B1Rk7RXw.js → health-CI8pIygU.js} +2 -2
- package/dist/index.d.ts +32 -1
- package/dist/{interactive-prompt-GixkO5-6.js → interactive-prompt-BWdH9Lb9.js} +2 -2
- package/dist/{manifest-read-BX_tMdib.js → manifest-read-3cF8yP3_.js} +233 -2
- package/dist/modules/interactive-prompt/index.js +2 -2
- package/dist/{run-DcUXpWwu.js → run-BeYZ5L6d.js} +81 -4
- package/dist/{run-BnUAxdws.js → run-NlTM7HwK.js} +4 -4
- package/package.json +1 -1
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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: {
|
|
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)}…)\
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
4
|
-
import { runInteractivePrompt } from "../../interactive-prompt-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
48438
|
+
//# sourceMappingURL=run-BeYZ5L6d.js.map
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import "./health-
|
|
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-
|
|
6
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-
|
|
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-
|
|
12
|
+
import "./interactive-prompt-BWdH9Lb9.js";
|
|
13
13
|
import "./recovery-engine-dtLHyV4M.js";
|
|
14
14
|
|
|
15
15
|
export { runRunAction };
|