substrate-ai 0.21.3 → 0.21.5
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 +26 -8
- package/dist/{health-bhMCTYDO.js → health-BdYZpCP1.js} +2 -2
- package/dist/{health-Dnzblihr.js → health-hYMxKqAH.js} +2 -2
- package/dist/{interactive-prompt-BM5RaXYG.js → interactive-prompt-BvY2FKsl.js} +2 -2
- package/dist/{manifest-read-B3gE46DX.js → manifest-read-C0N7b9nH.js} +375 -212
- package/dist/modules/interactive-prompt/index.js +2 -2
- package/dist/{run-ZxFHQyE_.js → run-C7PLGWT0.js} +72 -13
- package/dist/{run-ChZFveqv.js → run-CHMwDPRx.js} +4 -4
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
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-hYMxKqAH.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-CpnLJuVw.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseJourneyDeferrals, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } 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_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, loadAcceptanceContractFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyDeferrals, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-C0N7b9nH.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-C7PLGWT0.js";
|
|
9
9
|
import "../errors-8tVEwG6v.js";
|
|
10
10
|
import "../routing-DFxoKHDt.js";
|
|
11
11
|
import { WorkGraphRepository } from "../work-graph-repository-DZyJv5pV.js";
|
|
12
12
|
import "../decisions-CzSIEeGP.js";
|
|
13
13
|
import "../decision-router-BAPpON_C.js";
|
|
14
|
-
import "../interactive-prompt-
|
|
14
|
+
import "../interactive-prompt-BvY2FKsl.js";
|
|
15
15
|
import "../recovery-engine-BKGBeBnW.js";
|
|
16
16
|
import "../version-manager-impl-qFBiO4Eh.js";
|
|
17
17
|
import { registerUpgradeCommand } from "../upgrade-BUSzXgnd.js";
|
|
@@ -7130,7 +7130,7 @@ async function runStatusAction(options) {
|
|
|
7130
7130
|
logger$15.debug({ err }, "Work graph query failed, continuing without work graph data");
|
|
7131
7131
|
}
|
|
7132
7132
|
if (run === void 0) {
|
|
7133
|
-
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-
|
|
7133
|
+
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-BdYZpCP1.js");
|
|
7134
7134
|
const substrateDirPath = join(projectRoot, ".substrate");
|
|
7135
7135
|
const processInfo = inspectProcessTree$1({
|
|
7136
7136
|
projectRoot,
|
|
@@ -8659,7 +8659,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
8659
8659
|
await initSchema(expAdapter);
|
|
8660
8660
|
const { runRunAction: runPipeline } = await import(
|
|
8661
8661
|
/* @vite-ignore */
|
|
8662
|
-
"../run-
|
|
8662
|
+
"../run-CHMwDPRx.js"
|
|
8663
8663
|
);
|
|
8664
8664
|
const runStoryFn = async (opts) => {
|
|
8665
8665
|
const exitCode = await runPipeline({
|
|
@@ -13474,15 +13474,33 @@ function registerAcceptanceCommand(program, version) {
|
|
|
13474
13474
|
const projectRoot = process.cwd();
|
|
13475
13475
|
const source = opts.ref !== void 0 ? `committed @ ${opts.ref}` : "working tree";
|
|
13476
13476
|
const result = opts.ref !== void 0 ? await loadJourneyRegistryFromTrustedTree(projectRoot, opts.ref) : await loadJourneyRegistryFromFile(projectRoot);
|
|
13477
|
+
let contract;
|
|
13478
|
+
if (opts.ref !== void 0) contract = await loadAcceptanceContractFromTrustedTree(projectRoot, opts.ref);
|
|
13479
|
+
else try {
|
|
13480
|
+
const profileContent = await readFile$1(join$1(projectRoot, ACCEPTANCE_CONTRACT_PROFILE_PATH), "utf-8");
|
|
13481
|
+
contract = parseAcceptanceContract(profileContent);
|
|
13482
|
+
} catch {
|
|
13483
|
+
contract = { status: "absent" };
|
|
13484
|
+
}
|
|
13477
13485
|
if (opts.outputFormat === "json") {
|
|
13478
13486
|
const output = buildJsonOutput("substrate acceptance validate", {
|
|
13479
13487
|
source,
|
|
13480
|
-
...result
|
|
13488
|
+
...result,
|
|
13489
|
+
contract: { status: contract.status }
|
|
13481
13490
|
}, version);
|
|
13482
13491
|
process.stdout.write(JSON.stringify(output, null, 2) + "\n");
|
|
13483
13492
|
process.exit(result.status === "ok" ? ACCEPTANCE_EXIT_SUCCESS : ACCEPTANCE_EXIT_ERROR);
|
|
13484
13493
|
}
|
|
13485
|
-
|
|
13494
|
+
const exitCode = renderHuman(result, source);
|
|
13495
|
+
if (contract.status === "ok") {
|
|
13496
|
+
const surfaces = Object.keys(contract.contract.surfaces).join(", ");
|
|
13497
|
+
process.stdout.write(`contract: OK — surfaces declared: ${surfaces}\n`);
|
|
13498
|
+
} else if (contract.status === "invalid") {
|
|
13499
|
+
process.stdout.write(`contract: INVALID (${ACCEPTANCE_CONTRACT_PROFILE_PATH} acceptance: block):\n`);
|
|
13500
|
+
for (const issue of contract.issues) process.stdout.write(` ${issue.path}: ${issue.message}\n`);
|
|
13501
|
+
} else if (contract.status === "absent") process.stdout.write(`contract: ABSENT — no acceptance: block in ${ACCEPTANCE_CONTRACT_PROFILE_PATH}. Claimed journeys can never be walked (acceptance-unrunnable in blocking mode).
|
|
13502
|
+
`);
|
|
13503
|
+
process.exit(exitCode);
|
|
13486
13504
|
});
|
|
13487
13505
|
acceptanceCmd.command("defer <journeyId>").description("Record an operator deferral for a journey — the coverage audit reports it `deferred` instead of unclaimed/unwalked. Writes to the working tree; COMMIT the file for the audit (trusted tree) to honor it.").requiredOption("--reason <text>", "why this journey is deferred (the operator ack is the point)").action(async (journeyId, opts) => {
|
|
13488
13506
|
const projectRoot = process.cwd();
|
|
@@ -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-hYMxKqAH.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./dist-CpnLJuVw.js";
|
|
4
|
-
import "./manifest-read-
|
|
4
|
+
import "./manifest-read-C0N7b9nH.js";
|
|
5
5
|
import "./work-graph-repository-DZyJv5pV.js";
|
|
6
6
|
import "./decisions-CzSIEeGP.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-CpnLJuVw.js";
|
|
3
|
-
import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-
|
|
3
|
+
import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-C0N7b9nH.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-hYMxKqAH.js.map
|
|
@@ -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-C0N7b9nH.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-BvY2FKsl.js.map
|
|
@@ -8,9 +8,10 @@ import { YAMLException, load } from "js-yaml";
|
|
|
8
8
|
import { existsSync, promises, readFileSync, readdirSync, statSync } from "node:fs";
|
|
9
9
|
import { execSync, spawn } from "node:child_process";
|
|
10
10
|
import * as path$2 from "node:path";
|
|
11
|
-
import { basename as basename$1, delimiter, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "node:path";
|
|
11
|
+
import { basename as basename$1, delimiter, dirname as dirname$1, join as join$1, relative, resolve as resolve$1 } from "node:path";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
12
13
|
import { z } from "zod";
|
|
13
|
-
import { mkdir as mkdir$1, open, readFile as readFile$1, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
|
|
14
|
+
import { mkdir as mkdir$1, open, readFile as readFile$1, readdir as readdir$1, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
|
|
14
15
|
import * as fs from "fs";
|
|
15
16
|
import { createRequire } from "node:module";
|
|
16
17
|
import { fileURLToPath } from "node:url";
|
|
@@ -2612,13 +2613,13 @@ var ContaminationCheck = class {
|
|
|
2612
2613
|
//#region packages/sdlc/dist/verification/checks/test-mutation-check.js
|
|
2613
2614
|
/** Heuristic: is this path a test file? Covers the JS/TS/Python/Go idioms. */
|
|
2614
2615
|
function isTestPath(file) {
|
|
2615
|
-
const norm = file.replace(/\\/g, "/").toLowerCase();
|
|
2616
|
-
const base = norm.split("/").pop() ?? "";
|
|
2617
|
-
if (/(^|\/)(__tests__|tests?)\//.test(norm)) return true;
|
|
2616
|
+
const norm$1 = file.replace(/\\/g, "/").toLowerCase();
|
|
2617
|
+
const base = norm$1.split("/").pop() ?? "";
|
|
2618
|
+
if (/(^|\/)(__tests__|tests?)\//.test(norm$1)) return true;
|
|
2618
2619
|
if (/\.(test|spec)\.[a-z]+$/.test(base)) return true;
|
|
2619
2620
|
if (/^test_.*\.py$/.test(base) || /_test\.(py|go)$/.test(base)) return true;
|
|
2620
2621
|
if (base === "conftest.py") return true;
|
|
2621
|
-
if (/(^|\/)(fixtures|factories|testsupport|test-support|test_support|__mocks__|__fixtures__)\//.test(norm)) return true;
|
|
2622
|
+
if (/(^|\/)(fixtures|factories|testsupport|test-support|test_support|__mocks__|__fixtures__)\//.test(norm$1)) return true;
|
|
2622
2623
|
return false;
|
|
2623
2624
|
}
|
|
2624
2625
|
var TestMutationCheck = class {
|
|
@@ -2648,6 +2649,351 @@ var TestMutationCheck = class {
|
|
|
2648
2649
|
}
|
|
2649
2650
|
};
|
|
2650
2651
|
|
|
2652
|
+
//#endregion
|
|
2653
|
+
//#region packages/sdlc/dist/acceptance/registry.js
|
|
2654
|
+
/** Repo-relative path of the registry — the single canonical location. */
|
|
2655
|
+
const JOURNEY_REGISTRY_PATH = ".substrate/acceptance/journeys.yaml";
|
|
2656
|
+
const JourneySurfaceSchema = z.enum([
|
|
2657
|
+
"email",
|
|
2658
|
+
"cli",
|
|
2659
|
+
"file",
|
|
2660
|
+
"web"
|
|
2661
|
+
]);
|
|
2662
|
+
const JourneyEndStateSchema = z.object({
|
|
2663
|
+
id: z.string().min(1, "end-state id must be a non-empty string"),
|
|
2664
|
+
given: z.string().min(1, "given must be a non-empty string"),
|
|
2665
|
+
walk: z.string().min(1, "walk must be a non-empty string"),
|
|
2666
|
+
then: z.string().min(1, "then must be a non-empty string")
|
|
2667
|
+
});
|
|
2668
|
+
const JourneySchema = z.object({
|
|
2669
|
+
id: z.string().min(1, "journey id must be a non-empty string"),
|
|
2670
|
+
title: z.string().min(1, "title must be a non-empty string"),
|
|
2671
|
+
criticality: z.enum(["critical", "standard"]),
|
|
2672
|
+
surfaces: z.array(JourneySurfaceSchema).min(1, "a journey must declare at least one surface"),
|
|
2673
|
+
epic: z.number().int().positive().optional(),
|
|
2674
|
+
end_states: z.array(JourneyEndStateSchema).min(1, "a journey must declare at least one end_state — a journey with none is unjudgeable")
|
|
2675
|
+
});
|
|
2676
|
+
const JourneyRegistrySchema = z.object({
|
|
2677
|
+
version: z.number().int().positive("version must be a positive integer"),
|
|
2678
|
+
journeys: z.array(JourneySchema)
|
|
2679
|
+
}).superRefine((registry, ctx) => {
|
|
2680
|
+
const seenJourneyIds = new Map();
|
|
2681
|
+
registry.journeys.forEach((journey, i) => {
|
|
2682
|
+
const firstIndex = seenJourneyIds.get(journey.id);
|
|
2683
|
+
if (firstIndex !== void 0) ctx.addIssue({
|
|
2684
|
+
code: "custom",
|
|
2685
|
+
path: [
|
|
2686
|
+
"journeys",
|
|
2687
|
+
i,
|
|
2688
|
+
"id"
|
|
2689
|
+
],
|
|
2690
|
+
message: `duplicate journey id "${journey.id}" (first declared at journeys[${firstIndex}])`
|
|
2691
|
+
});
|
|
2692
|
+
else seenJourneyIds.set(journey.id, i);
|
|
2693
|
+
const seenEndStateIds = new Map();
|
|
2694
|
+
journey.end_states.forEach((endState, j) => {
|
|
2695
|
+
const firstEs = seenEndStateIds.get(endState.id);
|
|
2696
|
+
if (firstEs !== void 0) ctx.addIssue({
|
|
2697
|
+
code: "custom",
|
|
2698
|
+
path: [
|
|
2699
|
+
"journeys",
|
|
2700
|
+
i,
|
|
2701
|
+
"end_states",
|
|
2702
|
+
j,
|
|
2703
|
+
"id"
|
|
2704
|
+
],
|
|
2705
|
+
message: `duplicate end-state id "${endState.id}" in journey "${journey.id}" (first declared at end_states[${firstEs}])`
|
|
2706
|
+
});
|
|
2707
|
+
else seenEndStateIds.set(endState.id, j);
|
|
2708
|
+
});
|
|
2709
|
+
});
|
|
2710
|
+
});
|
|
2711
|
+
function zodErrorToValidationIssues(error) {
|
|
2712
|
+
return error.issues.map((issue) => ({
|
|
2713
|
+
path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
|
|
2714
|
+
message: issue.message
|
|
2715
|
+
}));
|
|
2716
|
+
}
|
|
2717
|
+
/**
|
|
2718
|
+
* Parse and validate registry YAML content.
|
|
2719
|
+
*
|
|
2720
|
+
* Never throws: malformed YAML, non-object documents, and schema violations
|
|
2721
|
+
* all come back as named, pathed issues.
|
|
2722
|
+
*/
|
|
2723
|
+
function parseJourneyRegistry(yamlContent) {
|
|
2724
|
+
let doc;
|
|
2725
|
+
try {
|
|
2726
|
+
doc = load(yamlContent);
|
|
2727
|
+
} catch (err) {
|
|
2728
|
+
const message = err instanceof YAMLException ? err.message : String(err);
|
|
2729
|
+
return {
|
|
2730
|
+
ok: false,
|
|
2731
|
+
issues: [{
|
|
2732
|
+
path: "(root)",
|
|
2733
|
+
message: `malformed YAML: ${message}`
|
|
2734
|
+
}]
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
if (doc === null || doc === void 0) return {
|
|
2738
|
+
ok: false,
|
|
2739
|
+
issues: [{
|
|
2740
|
+
path: "(root)",
|
|
2741
|
+
message: "registry file is empty"
|
|
2742
|
+
}]
|
|
2743
|
+
};
|
|
2744
|
+
const result = JourneyRegistrySchema.safeParse(doc);
|
|
2745
|
+
if (!result.success) return {
|
|
2746
|
+
ok: false,
|
|
2747
|
+
issues: zodErrorToValidationIssues(result.error)
|
|
2748
|
+
};
|
|
2749
|
+
return {
|
|
2750
|
+
ok: true,
|
|
2751
|
+
registry: result.data
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
//#endregion
|
|
2756
|
+
//#region packages/sdlc/dist/acceptance/coverage.js
|
|
2757
|
+
/**
|
|
2758
|
+
* Compute the coverage state of every journey audited at this scope.
|
|
2759
|
+
*
|
|
2760
|
+
* - `{epic: n}` audits journeys declaring `epic: n`.
|
|
2761
|
+
* - `{final: true}` audits the FULL registry (epicless journeys have no
|
|
2762
|
+
* earlier audit point; epic-scoped ones are re-audited — idempotent).
|
|
2763
|
+
*
|
|
2764
|
+
* State precedence: deferred > walked-fail > walked-pass > unwalked/unclaimed.
|
|
2765
|
+
* An operator deferral wins over everything (explicit scope decision); a fail
|
|
2766
|
+
* verdict wins over a pass (any failing end-state fails the journey).
|
|
2767
|
+
*/
|
|
2768
|
+
function computeJourneyCoverage(input) {
|
|
2769
|
+
const { registry, claims, verdicts, deferredJourneyIds, scope } = input;
|
|
2770
|
+
const audited = registry.journeys.filter((j) => "final" in scope ? true : j.epic === scope.epic);
|
|
2771
|
+
const claimsByJourney = new Map();
|
|
2772
|
+
for (const claim of claims) {
|
|
2773
|
+
const owners = claimsByJourney.get(claim.journeyId) ?? [];
|
|
2774
|
+
if (!owners.includes(claim.storyKey)) owners.push(claim.storyKey);
|
|
2775
|
+
claimsByJourney.set(claim.journeyId, owners);
|
|
2776
|
+
}
|
|
2777
|
+
const deferred = new Set(deferredJourneyIds);
|
|
2778
|
+
const verdictByJourney = new Map();
|
|
2779
|
+
for (const v of verdicts) {
|
|
2780
|
+
const existing = verdictByJourney.get(v.journeyId);
|
|
2781
|
+
verdictByJourney.set(v.journeyId, existing === "fail" ? "fail" : v.verdict);
|
|
2782
|
+
}
|
|
2783
|
+
return audited.map((journey) => {
|
|
2784
|
+
const ownerStories = claimsByJourney.get(journey.id) ?? [];
|
|
2785
|
+
let state;
|
|
2786
|
+
if (deferred.has(journey.id)) state = "deferred";
|
|
2787
|
+
else {
|
|
2788
|
+
const verdict = verdictByJourney.get(journey.id);
|
|
2789
|
+
if (verdict === "fail") state = "walked-fail";
|
|
2790
|
+
else if (verdict === "pass") state = "walked-pass";
|
|
2791
|
+
else state = ownerStories.length > 0 ? "unwalked" : "unclaimed";
|
|
2792
|
+
}
|
|
2793
|
+
return {
|
|
2794
|
+
journeyId: journey.id,
|
|
2795
|
+
title: journey.title,
|
|
2796
|
+
criticality: journey.criticality,
|
|
2797
|
+
...journey.epic !== void 0 ? { epic: journey.epic } : {},
|
|
2798
|
+
state,
|
|
2799
|
+
ownerStories
|
|
2800
|
+
};
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
/** Aggregate counts for the `acceptance:coverage` event payload. */
|
|
2804
|
+
function summarizeCoverage(entries) {
|
|
2805
|
+
const summary = {
|
|
2806
|
+
"walked-pass": 0,
|
|
2807
|
+
"walked-fail": 0,
|
|
2808
|
+
deferred: 0,
|
|
2809
|
+
unclaimed: 0,
|
|
2810
|
+
unwalked: 0
|
|
2811
|
+
};
|
|
2812
|
+
for (const entry of entries) summary[entry.state] += 1;
|
|
2813
|
+
return summary;
|
|
2814
|
+
}
|
|
2815
|
+
/** Repo-relative path of the operator deferral file. */
|
|
2816
|
+
const JOURNEY_DEFERRALS_PATH = ".substrate/acceptance/deferrals.yaml";
|
|
2817
|
+
const JourneyDeferralSchema = z.object({
|
|
2818
|
+
journey: z.string().min(1),
|
|
2819
|
+
reason: z.string().min(1, "a deferral must carry an operator reason"),
|
|
2820
|
+
deferred_at: z.string().optional()
|
|
2821
|
+
});
|
|
2822
|
+
const JourneyDeferralsFileSchema = z.object({ deferrals: z.array(JourneyDeferralSchema) });
|
|
2823
|
+
/** Parse deferrals YAML. Never throws; malformed content comes back as issues. */
|
|
2824
|
+
function parseJourneyDeferrals(yamlContent) {
|
|
2825
|
+
let doc;
|
|
2826
|
+
try {
|
|
2827
|
+
doc = load(yamlContent);
|
|
2828
|
+
} catch (err) {
|
|
2829
|
+
const message = err instanceof YAMLException ? err.message : String(err);
|
|
2830
|
+
return {
|
|
2831
|
+
ok: false,
|
|
2832
|
+
issues: [{
|
|
2833
|
+
path: "(root)",
|
|
2834
|
+
message: `malformed YAML: ${message}`
|
|
2835
|
+
}]
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
if (doc === null || doc === void 0) return {
|
|
2839
|
+
ok: true,
|
|
2840
|
+
deferrals: []
|
|
2841
|
+
};
|
|
2842
|
+
const result = JourneyDeferralsFileSchema.safeParse(doc);
|
|
2843
|
+
if (!result.success) return {
|
|
2844
|
+
ok: false,
|
|
2845
|
+
issues: result.error.issues.map((issue) => ({
|
|
2846
|
+
path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
|
|
2847
|
+
message: issue.message
|
|
2848
|
+
}))
|
|
2849
|
+
};
|
|
2850
|
+
return {
|
|
2851
|
+
ok: true,
|
|
2852
|
+
deferrals: result.data.deferrals
|
|
2853
|
+
};
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
//#endregion
|
|
2857
|
+
//#region packages/sdlc/dist/acceptance/contract.js
|
|
2858
|
+
/** The acceptance contract lives inside the project profile. */
|
|
2859
|
+
const ACCEPTANCE_CONTRACT_PROFILE_PATH = ".substrate/project-profile.yaml";
|
|
2860
|
+
const RenderSurfaceSchema = z.object({ render: z.string().min(1) }).strict();
|
|
2861
|
+
const WebSurfaceSchema = z.object({
|
|
2862
|
+
serve: z.string().min(1),
|
|
2863
|
+
ready: z.string().optional()
|
|
2864
|
+
}).strict();
|
|
2865
|
+
const AcceptanceContractSchema = z.object({
|
|
2866
|
+
fixtures: z.string().optional(),
|
|
2867
|
+
surfaces: z.object({
|
|
2868
|
+
email: RenderSurfaceSchema.optional(),
|
|
2869
|
+
cli: RenderSurfaceSchema.optional(),
|
|
2870
|
+
file: RenderSurfaceSchema.optional(),
|
|
2871
|
+
web: WebSurfaceSchema.optional()
|
|
2872
|
+
}).strict()
|
|
2873
|
+
}).strict();
|
|
2874
|
+
/**
|
|
2875
|
+
* Extract + validate the `acceptance:` block from project-profile YAML
|
|
2876
|
+
* content. `absent` when the profile has no block (legal — the coverage
|
|
2877
|
+
* audit escalates registry-present+contract-absent as acceptance-unrunnable
|
|
2878
|
+
* in blocking mode; pure accounting still works without one).
|
|
2879
|
+
*/
|
|
2880
|
+
function parseAcceptanceContract(profileYamlContent) {
|
|
2881
|
+
let doc;
|
|
2882
|
+
try {
|
|
2883
|
+
doc = load(profileYamlContent);
|
|
2884
|
+
} catch (err) {
|
|
2885
|
+
const message = err instanceof YAMLException ? err.message : String(err);
|
|
2886
|
+
return {
|
|
2887
|
+
status: "invalid",
|
|
2888
|
+
issues: [{
|
|
2889
|
+
path: "(root)",
|
|
2890
|
+
message: `malformed profile YAML: ${message}`
|
|
2891
|
+
}]
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
if (doc === null || doc === void 0 || typeof doc !== "object") return { status: "absent" };
|
|
2895
|
+
const block = doc["acceptance"];
|
|
2896
|
+
if (block === void 0 || block === null) return { status: "absent" };
|
|
2897
|
+
const result = AcceptanceContractSchema.safeParse(block);
|
|
2898
|
+
if (!result.success) return {
|
|
2899
|
+
status: "invalid",
|
|
2900
|
+
issues: result.error.issues.map((issue) => ({
|
|
2901
|
+
path: issue.path.length > 0 ? `acceptance.${issue.path.map(String).join(".")}` : "acceptance",
|
|
2902
|
+
message: issue.message
|
|
2903
|
+
}))
|
|
2904
|
+
};
|
|
2905
|
+
return {
|
|
2906
|
+
status: "ok",
|
|
2907
|
+
contract: result.data
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
//#endregion
|
|
2912
|
+
//#region packages/sdlc/dist/verification/checks/acceptance-spec-check.js
|
|
2913
|
+
async function readWorktreeCopy(workingDir, relPath) {
|
|
2914
|
+
try {
|
|
2915
|
+
return await readFile$1(join$1(workingDir, relPath), "utf-8");
|
|
2916
|
+
} catch {
|
|
2917
|
+
return null;
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
const norm = (s) => s === null ? null : s.replace(/\r\n/g, "\n").trim();
|
|
2921
|
+
/** Compare only the acceptance BLOCK of the profile (other profile keys are ContaminationCheck/H7 territory). */
|
|
2922
|
+
function acceptanceBlockFingerprint(profileContent) {
|
|
2923
|
+
if (profileContent === null) return "absent";
|
|
2924
|
+
const parsed = parseAcceptanceContract(profileContent);
|
|
2925
|
+
if (parsed.status === "absent") return "absent";
|
|
2926
|
+
if (parsed.status === "invalid") return "invalid:" + JSON.stringify(parsed.issues);
|
|
2927
|
+
return JSON.stringify(parsed.contract);
|
|
2928
|
+
}
|
|
2929
|
+
var AcceptanceSpecCheck = class {
|
|
2930
|
+
name = "acceptance-spec";
|
|
2931
|
+
tier = "A";
|
|
2932
|
+
async run(context) {
|
|
2933
|
+
const start = Date.now();
|
|
2934
|
+
const guard = context.acceptanceSpecGuard;
|
|
2935
|
+
if (guard === void 0) return {
|
|
2936
|
+
status: "pass",
|
|
2937
|
+
details: "no acceptance spec guard in context (acceptance not configured or non-worktree dispatch)",
|
|
2938
|
+
duration_ms: Date.now() - start,
|
|
2939
|
+
findings: []
|
|
2940
|
+
};
|
|
2941
|
+
const findings = [];
|
|
2942
|
+
const rawSpecs = [{
|
|
2943
|
+
path: JOURNEY_REGISTRY_PATH,
|
|
2944
|
+
trusted: guard.journeysTrusted
|
|
2945
|
+
}, {
|
|
2946
|
+
path: JOURNEY_DEFERRALS_PATH,
|
|
2947
|
+
trusted: guard.deferralsTrusted
|
|
2948
|
+
}];
|
|
2949
|
+
for (const spec of rawSpecs) {
|
|
2950
|
+
const worktree = await readWorktreeCopy(context.workingDir, spec.path);
|
|
2951
|
+
const trustedNorm = norm(spec.trusted);
|
|
2952
|
+
const worktreeNorm = norm(worktree);
|
|
2953
|
+
if (trustedNorm === worktreeNorm) continue;
|
|
2954
|
+
const shape = trustedNorm === null ? "INTRODUCED in the story worktree (acceptance specs are planning/operator-authored, never story output)" : worktreeNorm === null ? "DELETED in the story worktree" : "DIVERGES from the trusted copy";
|
|
2955
|
+
findings.push({
|
|
2956
|
+
category: "acceptance-spec-tampered",
|
|
2957
|
+
severity: "error",
|
|
2958
|
+
message: `${spec.path} ${shape}. The acceptance gate reads the trusted tree, so this edit cannot fool the current audit — but merging it would change every FUTURE audit. Revert it or make the change through planning (operator commit outside a story).`
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
const worktreeProfile = await readWorktreeCopy(context.workingDir, ACCEPTANCE_CONTRACT_PROFILE_PATH);
|
|
2962
|
+
const trustedFp = acceptanceBlockFingerprint(guard.profileTrusted);
|
|
2963
|
+
const worktreeFp = acceptanceBlockFingerprint(worktreeProfile);
|
|
2964
|
+
if (trustedFp !== worktreeFp) findings.push({
|
|
2965
|
+
category: "acceptance-spec-tampered",
|
|
2966
|
+
severity: "error",
|
|
2967
|
+
message: `the acceptance: contract block in ${ACCEPTANCE_CONTRACT_PROFILE_PATH} differs between the story worktree and the trusted tree (render-command laundering shape). Revert the worktree edit.`
|
|
2968
|
+
});
|
|
2969
|
+
if (guard.fixturesPath !== void 0) {
|
|
2970
|
+
const prefix = guard.fixturesPath.replace(/\\/g, "/").replace(/\/+$/, "") + "/";
|
|
2971
|
+
const touched = (context.changedFiles ?? []).filter((f) => {
|
|
2972
|
+
const n = f.replace(/\\/g, "/");
|
|
2973
|
+
return n.startsWith(prefix) || n === prefix.slice(0, -1);
|
|
2974
|
+
});
|
|
2975
|
+
if (touched.length > 0) findings.push({
|
|
2976
|
+
category: "acceptance-fixture-mutation",
|
|
2977
|
+
severity: "warn",
|
|
2978
|
+
message: `story modified ${String(touched.length)} file(s) under the declared acceptance fixtures path (${guard.fixturesPath}): ${touched.slice(0, 10).join(", ")}` + (touched.length > 10 ? ` (+${String(touched.length - 10)} more)` : "") + `. The judge grounds verdicts in these fixtures — review whether the change tilts the walk.`
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
if (findings.length === 0) return {
|
|
2982
|
+
status: "pass",
|
|
2983
|
+
details: "acceptance specs match the trusted tree; no fixture mutations",
|
|
2984
|
+
duration_ms: Date.now() - start,
|
|
2985
|
+
findings: []
|
|
2986
|
+
};
|
|
2987
|
+
const hasError = findings.some((f) => f.severity === "error");
|
|
2988
|
+
return {
|
|
2989
|
+
status: hasError ? "fail" : "warn",
|
|
2990
|
+
details: renderFindings(findings),
|
|
2991
|
+
duration_ms: Date.now() - start,
|
|
2992
|
+
findings
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
};
|
|
2996
|
+
|
|
2651
2997
|
//#endregion
|
|
2652
2998
|
//#region packages/sdlc/dist/verification/probes/types.js
|
|
2653
2999
|
/**
|
|
@@ -4603,6 +4949,7 @@ function createDefaultVerificationPipeline(bus, config) {
|
|
|
4603
4949
|
new TestSuiteCheck(),
|
|
4604
4950
|
new ContaminationCheck(),
|
|
4605
4951
|
new TestMutationCheck(),
|
|
4952
|
+
new AcceptanceSpecCheck(),
|
|
4606
4953
|
new RuntimeProbeCheck(),
|
|
4607
4954
|
new SourceAcFidelityCheck(),
|
|
4608
4955
|
new SourceAcShelloutCheck(),
|
|
@@ -4977,210 +5324,6 @@ async function runAcTraceabilityCheck(input) {
|
|
|
4977
5324
|
};
|
|
4978
5325
|
}
|
|
4979
5326
|
|
|
4980
|
-
//#endregion
|
|
4981
|
-
//#region packages/sdlc/dist/acceptance/registry.js
|
|
4982
|
-
/** Repo-relative path of the registry — the single canonical location. */
|
|
4983
|
-
const JOURNEY_REGISTRY_PATH = ".substrate/acceptance/journeys.yaml";
|
|
4984
|
-
const JourneySurfaceSchema = z.enum([
|
|
4985
|
-
"email",
|
|
4986
|
-
"cli",
|
|
4987
|
-
"file",
|
|
4988
|
-
"web"
|
|
4989
|
-
]);
|
|
4990
|
-
const JourneyEndStateSchema = z.object({
|
|
4991
|
-
id: z.string().min(1, "end-state id must be a non-empty string"),
|
|
4992
|
-
given: z.string().min(1, "given must be a non-empty string"),
|
|
4993
|
-
walk: z.string().min(1, "walk must be a non-empty string"),
|
|
4994
|
-
then: z.string().min(1, "then must be a non-empty string")
|
|
4995
|
-
});
|
|
4996
|
-
const JourneySchema = z.object({
|
|
4997
|
-
id: z.string().min(1, "journey id must be a non-empty string"),
|
|
4998
|
-
title: z.string().min(1, "title must be a non-empty string"),
|
|
4999
|
-
criticality: z.enum(["critical", "standard"]),
|
|
5000
|
-
surfaces: z.array(JourneySurfaceSchema).min(1, "a journey must declare at least one surface"),
|
|
5001
|
-
epic: z.number().int().positive().optional(),
|
|
5002
|
-
end_states: z.array(JourneyEndStateSchema).min(1, "a journey must declare at least one end_state — a journey with none is unjudgeable")
|
|
5003
|
-
});
|
|
5004
|
-
const JourneyRegistrySchema = z.object({
|
|
5005
|
-
version: z.number().int().positive("version must be a positive integer"),
|
|
5006
|
-
journeys: z.array(JourneySchema)
|
|
5007
|
-
}).superRefine((registry, ctx) => {
|
|
5008
|
-
const seenJourneyIds = new Map();
|
|
5009
|
-
registry.journeys.forEach((journey, i) => {
|
|
5010
|
-
const firstIndex = seenJourneyIds.get(journey.id);
|
|
5011
|
-
if (firstIndex !== void 0) ctx.addIssue({
|
|
5012
|
-
code: "custom",
|
|
5013
|
-
path: [
|
|
5014
|
-
"journeys",
|
|
5015
|
-
i,
|
|
5016
|
-
"id"
|
|
5017
|
-
],
|
|
5018
|
-
message: `duplicate journey id "${journey.id}" (first declared at journeys[${firstIndex}])`
|
|
5019
|
-
});
|
|
5020
|
-
else seenJourneyIds.set(journey.id, i);
|
|
5021
|
-
const seenEndStateIds = new Map();
|
|
5022
|
-
journey.end_states.forEach((endState, j) => {
|
|
5023
|
-
const firstEs = seenEndStateIds.get(endState.id);
|
|
5024
|
-
if (firstEs !== void 0) ctx.addIssue({
|
|
5025
|
-
code: "custom",
|
|
5026
|
-
path: [
|
|
5027
|
-
"journeys",
|
|
5028
|
-
i,
|
|
5029
|
-
"end_states",
|
|
5030
|
-
j,
|
|
5031
|
-
"id"
|
|
5032
|
-
],
|
|
5033
|
-
message: `duplicate end-state id "${endState.id}" in journey "${journey.id}" (first declared at end_states[${firstEs}])`
|
|
5034
|
-
});
|
|
5035
|
-
else seenEndStateIds.set(endState.id, j);
|
|
5036
|
-
});
|
|
5037
|
-
});
|
|
5038
|
-
});
|
|
5039
|
-
function zodErrorToValidationIssues(error) {
|
|
5040
|
-
return error.issues.map((issue) => ({
|
|
5041
|
-
path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
|
|
5042
|
-
message: issue.message
|
|
5043
|
-
}));
|
|
5044
|
-
}
|
|
5045
|
-
/**
|
|
5046
|
-
* Parse and validate registry YAML content.
|
|
5047
|
-
*
|
|
5048
|
-
* Never throws: malformed YAML, non-object documents, and schema violations
|
|
5049
|
-
* all come back as named, pathed issues.
|
|
5050
|
-
*/
|
|
5051
|
-
function parseJourneyRegistry(yamlContent) {
|
|
5052
|
-
let doc;
|
|
5053
|
-
try {
|
|
5054
|
-
doc = load(yamlContent);
|
|
5055
|
-
} catch (err) {
|
|
5056
|
-
const message = err instanceof YAMLException ? err.message : String(err);
|
|
5057
|
-
return {
|
|
5058
|
-
ok: false,
|
|
5059
|
-
issues: [{
|
|
5060
|
-
path: "(root)",
|
|
5061
|
-
message: `malformed YAML: ${message}`
|
|
5062
|
-
}]
|
|
5063
|
-
};
|
|
5064
|
-
}
|
|
5065
|
-
if (doc === null || doc === void 0) return {
|
|
5066
|
-
ok: false,
|
|
5067
|
-
issues: [{
|
|
5068
|
-
path: "(root)",
|
|
5069
|
-
message: "registry file is empty"
|
|
5070
|
-
}]
|
|
5071
|
-
};
|
|
5072
|
-
const result = JourneyRegistrySchema.safeParse(doc);
|
|
5073
|
-
if (!result.success) return {
|
|
5074
|
-
ok: false,
|
|
5075
|
-
issues: zodErrorToValidationIssues(result.error)
|
|
5076
|
-
};
|
|
5077
|
-
return {
|
|
5078
|
-
ok: true,
|
|
5079
|
-
registry: result.data
|
|
5080
|
-
};
|
|
5081
|
-
}
|
|
5082
|
-
|
|
5083
|
-
//#endregion
|
|
5084
|
-
//#region packages/sdlc/dist/acceptance/coverage.js
|
|
5085
|
-
/**
|
|
5086
|
-
* Compute the coverage state of every journey audited at this scope.
|
|
5087
|
-
*
|
|
5088
|
-
* - `{epic: n}` audits journeys declaring `epic: n`.
|
|
5089
|
-
* - `{final: true}` audits the FULL registry (epicless journeys have no
|
|
5090
|
-
* earlier audit point; epic-scoped ones are re-audited — idempotent).
|
|
5091
|
-
*
|
|
5092
|
-
* State precedence: deferred > walked-fail > walked-pass > unwalked/unclaimed.
|
|
5093
|
-
* An operator deferral wins over everything (explicit scope decision); a fail
|
|
5094
|
-
* verdict wins over a pass (any failing end-state fails the journey).
|
|
5095
|
-
*/
|
|
5096
|
-
function computeJourneyCoverage(input) {
|
|
5097
|
-
const { registry, claims, verdicts, deferredJourneyIds, scope } = input;
|
|
5098
|
-
const audited = registry.journeys.filter((j) => "final" in scope ? true : j.epic === scope.epic);
|
|
5099
|
-
const claimsByJourney = new Map();
|
|
5100
|
-
for (const claim of claims) {
|
|
5101
|
-
const owners = claimsByJourney.get(claim.journeyId) ?? [];
|
|
5102
|
-
if (!owners.includes(claim.storyKey)) owners.push(claim.storyKey);
|
|
5103
|
-
claimsByJourney.set(claim.journeyId, owners);
|
|
5104
|
-
}
|
|
5105
|
-
const deferred = new Set(deferredJourneyIds);
|
|
5106
|
-
const verdictByJourney = new Map();
|
|
5107
|
-
for (const v of verdicts) {
|
|
5108
|
-
const existing = verdictByJourney.get(v.journeyId);
|
|
5109
|
-
verdictByJourney.set(v.journeyId, existing === "fail" ? "fail" : v.verdict);
|
|
5110
|
-
}
|
|
5111
|
-
return audited.map((journey) => {
|
|
5112
|
-
const ownerStories = claimsByJourney.get(journey.id) ?? [];
|
|
5113
|
-
let state;
|
|
5114
|
-
if (deferred.has(journey.id)) state = "deferred";
|
|
5115
|
-
else {
|
|
5116
|
-
const verdict = verdictByJourney.get(journey.id);
|
|
5117
|
-
if (verdict === "fail") state = "walked-fail";
|
|
5118
|
-
else if (verdict === "pass") state = "walked-pass";
|
|
5119
|
-
else state = ownerStories.length > 0 ? "unwalked" : "unclaimed";
|
|
5120
|
-
}
|
|
5121
|
-
return {
|
|
5122
|
-
journeyId: journey.id,
|
|
5123
|
-
title: journey.title,
|
|
5124
|
-
criticality: journey.criticality,
|
|
5125
|
-
...journey.epic !== void 0 ? { epic: journey.epic } : {},
|
|
5126
|
-
state,
|
|
5127
|
-
ownerStories
|
|
5128
|
-
};
|
|
5129
|
-
});
|
|
5130
|
-
}
|
|
5131
|
-
/** Aggregate counts for the `acceptance:coverage` event payload. */
|
|
5132
|
-
function summarizeCoverage(entries) {
|
|
5133
|
-
const summary = {
|
|
5134
|
-
"walked-pass": 0,
|
|
5135
|
-
"walked-fail": 0,
|
|
5136
|
-
deferred: 0,
|
|
5137
|
-
unclaimed: 0,
|
|
5138
|
-
unwalked: 0
|
|
5139
|
-
};
|
|
5140
|
-
for (const entry of entries) summary[entry.state] += 1;
|
|
5141
|
-
return summary;
|
|
5142
|
-
}
|
|
5143
|
-
/** Repo-relative path of the operator deferral file. */
|
|
5144
|
-
const JOURNEY_DEFERRALS_PATH = ".substrate/acceptance/deferrals.yaml";
|
|
5145
|
-
const JourneyDeferralSchema = z.object({
|
|
5146
|
-
journey: z.string().min(1),
|
|
5147
|
-
reason: z.string().min(1, "a deferral must carry an operator reason"),
|
|
5148
|
-
deferred_at: z.string().optional()
|
|
5149
|
-
});
|
|
5150
|
-
const JourneyDeferralsFileSchema = z.object({ deferrals: z.array(JourneyDeferralSchema) });
|
|
5151
|
-
/** Parse deferrals YAML. Never throws; malformed content comes back as issues. */
|
|
5152
|
-
function parseJourneyDeferrals(yamlContent) {
|
|
5153
|
-
let doc;
|
|
5154
|
-
try {
|
|
5155
|
-
doc = load(yamlContent);
|
|
5156
|
-
} catch (err) {
|
|
5157
|
-
const message = err instanceof YAMLException ? err.message : String(err);
|
|
5158
|
-
return {
|
|
5159
|
-
ok: false,
|
|
5160
|
-
issues: [{
|
|
5161
|
-
path: "(root)",
|
|
5162
|
-
message: `malformed YAML: ${message}`
|
|
5163
|
-
}]
|
|
5164
|
-
};
|
|
5165
|
-
}
|
|
5166
|
-
if (doc === null || doc === void 0) return {
|
|
5167
|
-
ok: true,
|
|
5168
|
-
deferrals: []
|
|
5169
|
-
};
|
|
5170
|
-
const result = JourneyDeferralsFileSchema.safeParse(doc);
|
|
5171
|
-
if (!result.success) return {
|
|
5172
|
-
ok: false,
|
|
5173
|
-
issues: result.error.issues.map((issue) => ({
|
|
5174
|
-
path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
|
|
5175
|
-
message: issue.message
|
|
5176
|
-
}))
|
|
5177
|
-
};
|
|
5178
|
-
return {
|
|
5179
|
-
ok: true,
|
|
5180
|
-
deferrals: result.data.deferrals
|
|
5181
|
-
};
|
|
5182
|
-
}
|
|
5183
|
-
|
|
5184
5327
|
//#endregion
|
|
5185
5328
|
//#region packages/sdlc/dist/acceptance/loader.js
|
|
5186
5329
|
/** stderr shapes that mean "the path is not in the tree at this ref" (absent, not an error). */
|
|
@@ -5286,6 +5429,26 @@ async function loadJourneyDeferralsFromTrustedTree(repoRoot, ref = "HEAD") {
|
|
|
5286
5429
|
};
|
|
5287
5430
|
}
|
|
5288
5431
|
/**
|
|
5432
|
+
* Load the acceptance contract (the `acceptance:` block of the project
|
|
5433
|
+
* profile) from the trusted tree at `ref` (A1.1). Same H7 posture as the
|
|
5434
|
+
* registry: the agent-writable worktree copy of the profile is never read.
|
|
5435
|
+
*/
|
|
5436
|
+
async function loadAcceptanceContractFromTrustedTree(repoRoot, ref = "HEAD") {
|
|
5437
|
+
const result = await runGitShow(repoRoot, ref, ACCEPTANCE_CONTRACT_PROFILE_PATH);
|
|
5438
|
+
if (result.spawnError !== void 0) return {
|
|
5439
|
+
status: "error",
|
|
5440
|
+
message: `git show could not be spawned: ${result.spawnError}`
|
|
5441
|
+
};
|
|
5442
|
+
if (result.code !== 0) {
|
|
5443
|
+
if (GIT_SHOW_ABSENT_PATTERNS.some((p) => p.test(result.stderr))) return { status: "absent" };
|
|
5444
|
+
return {
|
|
5445
|
+
status: "error",
|
|
5446
|
+
message: `git show ${ref}:${ACCEPTANCE_CONTRACT_PROFILE_PATH} failed (exit ${String(result.code)}): ${result.stderr.trim()}`
|
|
5447
|
+
};
|
|
5448
|
+
}
|
|
5449
|
+
return parseAcceptanceContract(result.stdout);
|
|
5450
|
+
}
|
|
5451
|
+
/**
|
|
5289
5452
|
* Filesystem read for OPERATOR LINT ONLY (`substrate acceptance validate`).
|
|
5290
5453
|
* Gate/judge code paths must use `loadJourneyRegistryFromTrustedTree`.
|
|
5291
5454
|
*/
|
|
@@ -6746,5 +6909,5 @@ async function resolveRunManifest(dbRoot, runId) {
|
|
|
6746
6909
|
}
|
|
6747
6910
|
|
|
6748
6911
|
//#endregion
|
|
6749
|
-
export { FindingsInjector, JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, RuntimeProbeListSchema, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseJourneyDeferrals, parseRuntimeProbes, parseStoryFrontmatter, readCurrentRunId, renderFindings, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage };
|
|
6750
|
-
//# sourceMappingURL=manifest-read-
|
|
6912
|
+
export { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_DEFERRALS_PATH, JOURNEY_REGISTRY_PATH, RunManifest, RuntimeProbeListSchema, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyDeferrals, parseRuntimeProbes, parseStoryFrontmatter, readCurrentRunId, renderFindings, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage };
|
|
6913
|
+
//# sourceMappingURL=manifest-read-C0N7b9nH.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../../logger-KeHncl-f.js";
|
|
2
2
|
import "../../dist-CpnLJuVw.js";
|
|
3
|
-
import "../../manifest-read-
|
|
4
|
-
import { runInteractivePrompt } from "../../interactive-prompt-
|
|
3
|
+
import "../../manifest-read-C0N7b9nH.js";
|
|
4
|
+
import { runInteractivePrompt } from "../../interactive-prompt-BvY2FKsl.js";
|
|
5
5
|
|
|
6
6
|
export { runInteractivePrompt };
|
|
@@ -1,11 +1,11 @@
|
|
|
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-hYMxKqAH.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-CpnLJuVw.js";
|
|
5
|
-
import { FindingsInjector, JOURNEY_DEFERRALS_PATH, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-
|
|
5
|
+
import { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_DEFERRALS_PATH, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-C0N7b9nH.js";
|
|
6
6
|
import { WorkGraphRepository, detectCycles } from "./work-graph-repository-DZyJv5pV.js";
|
|
7
7
|
import { deriveExitCode, routeDecision } from "./decision-router-BAPpON_C.js";
|
|
8
|
-
import { runInteractivePrompt } from "./interactive-prompt-
|
|
8
|
+
import { runInteractivePrompt } from "./interactive-prompt-BvY2FKsl.js";
|
|
9
9
|
import { runRecoveryEngine } from "./recovery-engine-BKGBeBnW.js";
|
|
10
10
|
import { basename, dirname, extname, join } from "path";
|
|
11
11
|
import { access, readFile, readdir, stat } from "fs/promises";
|
|
@@ -983,7 +983,7 @@ const PIPELINE_EVENT_METADATA = [
|
|
|
983
983
|
{
|
|
984
984
|
name: "reason",
|
|
985
985
|
type: "string",
|
|
986
|
-
description: "Escalation reason. Common values: review-cycles-exhausted (default review-loop max hit); create-story-no-file (create-story phase did not write a story artifact); dev-story-no-commit (substrate auto-commit found no committable changes — agent produced nothing or all changes were outside the worktree); dev-story-commit-failed (substrate auto-commit failed — typically a pre-commit hook rejected the commit; stderr captured in issues); merge-to-main-error (unexpected error in the merge-to-main phase); merge-conflict-detected (story branch could not be merged due to conflicts); parent-tree-dirtied-by-run (uncommitted parent changes intersect the story diff — merge refused, H3.3); ff-only-merge-not-possible (base moved and merge_strategy is ff-only — set finalization.merge_strategy: three-way or integrate manually, H3.3); epic-gate-failed (finalization.epic_gate_command exited non-zero before the last story of an epic integrated, H3.4); story-file-missing (story artifact gone from working tree AND branch HEAD — check wip/feat commits on the story branch, H5.5); undisclosed-files-in-merge (a committed implementation file was never in the dev agent's files_modified, so no review cycle inspected it — inspect the branch, then re-dispatch with accurate files_modified or merge manually, H7); journey-unclaimed (acceptance.mode: blocking — a registered journey has NO story claiming it at epic close; wire it or defer via `substrate acceptance defer`, A0.3); journey-unwalked (acceptance.mode: blocking — a claimed journey was never walked by the acceptance gate at epic close, A0.3). v0.20.87+."
|
|
986
|
+
description: "Escalation reason. Common values: review-cycles-exhausted (default review-loop max hit); create-story-no-file (create-story phase did not write a story artifact); dev-story-no-commit (substrate auto-commit found no committable changes — agent produced nothing or all changes were outside the worktree); dev-story-commit-failed (substrate auto-commit failed — typically a pre-commit hook rejected the commit; stderr captured in issues); merge-to-main-error (unexpected error in the merge-to-main phase); merge-conflict-detected (story branch could not be merged due to conflicts); parent-tree-dirtied-by-run (uncommitted parent changes intersect the story diff — merge refused, H3.3); ff-only-merge-not-possible (base moved and merge_strategy is ff-only — set finalization.merge_strategy: three-way or integrate manually, H3.3); epic-gate-failed (finalization.epic_gate_command exited non-zero before the last story of an epic integrated, H3.4); story-file-missing (story artifact gone from working tree AND branch HEAD — check wip/feat commits on the story branch, H5.5); undisclosed-files-in-merge (a committed implementation file was never in the dev agent's files_modified, so no review cycle inspected it — inspect the branch, then re-dispatch with accurate files_modified or merge manually, H7); journey-unclaimed (acceptance.mode: blocking — a registered journey has NO story claiming it at epic close; wire it or defer via `substrate acceptance defer`, A0.3); journey-unwalked (acceptance.mode: blocking — a claimed journey was never walked by the acceptance gate at epic close, A0.3); acceptance-unrunnable (acceptance.mode: blocking — a journey registry exists but the committed acceptance contract/registry is absent or invalid, so claimed journeys can never be walked; declare an acceptance: block in the project profile, A1.1). v0.20.87+."
|
|
987
987
|
},
|
|
988
988
|
{
|
|
989
989
|
name: "cycles",
|
|
@@ -12202,6 +12202,28 @@ function assembleVerificationContext(opts) {
|
|
|
12202
12202
|
const profileBuildCommand = readProfileKey(trustedDir, "buildCommand");
|
|
12203
12203
|
const profileTestCommand = readProfileKey(trustedDir, "testCommand");
|
|
12204
12204
|
const trustedLanguages = readProfileLanguagesLocal(trustedDir);
|
|
12205
|
+
let acceptanceSpecGuard;
|
|
12206
|
+
if (opts.trustedProfileDir !== void 0) {
|
|
12207
|
+
const readOrNull = (rel) => {
|
|
12208
|
+
try {
|
|
12209
|
+
const content = readFileSync(join$1(trustedDir, rel), "utf-8");
|
|
12210
|
+
return content.trim().length > 0 ? content : null;
|
|
12211
|
+
} catch {
|
|
12212
|
+
return null;
|
|
12213
|
+
}
|
|
12214
|
+
};
|
|
12215
|
+
const journeysTrusted = readOrNull(".substrate/acceptance/journeys.yaml");
|
|
12216
|
+
if (journeysTrusted !== null) {
|
|
12217
|
+
const profileTrusted = readOrNull(".substrate/project-profile.yaml");
|
|
12218
|
+
const fixturesPath = readAcceptanceFixturesPathLocal(profileTrusted);
|
|
12219
|
+
acceptanceSpecGuard = {
|
|
12220
|
+
journeysTrusted,
|
|
12221
|
+
deferralsTrusted: readOrNull(".substrate/acceptance/deferrals.yaml"),
|
|
12222
|
+
profileTrusted,
|
|
12223
|
+
...fixturesPath !== void 0 ? { fixturesPath } : {}
|
|
12224
|
+
};
|
|
12225
|
+
}
|
|
12226
|
+
}
|
|
12205
12227
|
return {
|
|
12206
12228
|
storyKey: opts.storyKey,
|
|
12207
12229
|
workingDir: opts.workingDir,
|
|
@@ -12217,10 +12239,32 @@ function assembleVerificationContext(opts) {
|
|
|
12217
12239
|
...opts.modifiedTrackedFiles !== void 0 ? { modifiedTrackedFiles: opts.modifiedTrackedFiles } : {},
|
|
12218
12240
|
...profileBuildCommand !== void 0 ? { buildCommand: profileBuildCommand } : {},
|
|
12219
12241
|
...profileTestCommand !== void 0 ? { testCommand: profileTestCommand } : {},
|
|
12220
|
-
...trustedLanguages.length > 0 ? { trustedLanguages } : {}
|
|
12242
|
+
...trustedLanguages.length > 0 ? { trustedLanguages } : {},
|
|
12243
|
+
...acceptanceSpecGuard !== void 0 ? { acceptanceSpecGuard } : {}
|
|
12221
12244
|
};
|
|
12222
12245
|
}
|
|
12223
12246
|
/**
|
|
12247
|
+
* A1.3: extract `fixtures:` from the `acceptance:` block of profile content.
|
|
12248
|
+
* Line-based (no yaml dependency, no sdlc value import) — tracks entry/exit
|
|
12249
|
+
* of the top-level acceptance block by indentation.
|
|
12250
|
+
*/
|
|
12251
|
+
function readAcceptanceFixturesPathLocal(profileContent) {
|
|
12252
|
+
if (profileContent === null) return void 0;
|
|
12253
|
+
let inAcceptance = false;
|
|
12254
|
+
for (const line of profileContent.split("\n")) {
|
|
12255
|
+
if (/^acceptance:\s*$/.test(line)) {
|
|
12256
|
+
inAcceptance = true;
|
|
12257
|
+
continue;
|
|
12258
|
+
}
|
|
12259
|
+
if (inAcceptance && /^\S/.test(line)) inAcceptance = false;
|
|
12260
|
+
if (inAcceptance) {
|
|
12261
|
+
const m = /^\s+fixtures:\s*['"]?([^'"\n#]+?)['"]?\s*$/.exec(line);
|
|
12262
|
+
if (m?.[1] !== void 0) return m[1].trim();
|
|
12263
|
+
}
|
|
12264
|
+
}
|
|
12265
|
+
return void 0;
|
|
12266
|
+
}
|
|
12267
|
+
/**
|
|
12224
12268
|
* Read a single `<key>: value` line from `.substrate/project-profile.yaml`
|
|
12225
12269
|
* under `workingDir` (H1.2). Line-based parse — no yaml dependency.
|
|
12226
12270
|
*/
|
|
@@ -13957,10 +14001,19 @@ function createImplementationOrchestrator(deps) {
|
|
|
13957
14001
|
if (mode === "off" || projectRoot === void 0) return void 0;
|
|
13958
14002
|
const registryLoad = await loadJourneyRegistryFromTrustedTree(projectRoot);
|
|
13959
14003
|
if (registryLoad.status === "absent") return void 0;
|
|
14004
|
+
if (registryLoad.status === "invalid") return {
|
|
14005
|
+
entries: [],
|
|
14006
|
+
unrunnable: "journey registry is INVALID: " + registryLoad.issues.map((i) => `${i.path}: ${i.message}`).join("; ") + " — fix it (substrate acceptance validate) or the audit cannot run"
|
|
14007
|
+
};
|
|
13960
14008
|
if (registryLoad.status !== "ok") {
|
|
13961
|
-
logger$27.warn({ detail: registryLoad.
|
|
14009
|
+
logger$27.warn({ detail: registryLoad.message }, "A0.3: journey registry read failed — coverage audit skipped (environmental)");
|
|
13962
14010
|
return void 0;
|
|
13963
14011
|
}
|
|
14012
|
+
let unrunnable;
|
|
14013
|
+
const contractLoad = await loadAcceptanceContractFromTrustedTree(projectRoot);
|
|
14014
|
+
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.`;
|
|
14015
|
+
else if (contractLoad.status === "invalid") unrunnable = "acceptance: contract block is INVALID: " + contractLoad.issues.map((i) => `${i.path}: ${i.message}`).join("; ");
|
|
14016
|
+
else if (contractLoad.status === "error") logger$27.warn({ detail: contractLoad.message }, "A1.1: acceptance contract read failed (environmental) — treating as absent for this audit");
|
|
13964
14017
|
const deferralsLoad = await loadJourneyDeferralsFromTrustedTree(projectRoot);
|
|
13965
14018
|
if (deferralsLoad.status !== "ok") logger$27.warn({ detail: deferralsLoad.status === "invalid" ? deferralsLoad.issues : deferralsLoad.message }, `A0.3: ${JOURNEY_DEFERRALS_PATH} unreadable/invalid — treating as no deferrals`);
|
|
13966
14019
|
const deferredJourneyIds = deferralsLoad.status === "ok" ? deferralsLoad.deferrals.map((d) => d.journey) : [];
|
|
@@ -13983,8 +14036,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
13983
14036
|
entries,
|
|
13984
14037
|
summary: summarizeCoverage(entries)
|
|
13985
14038
|
});
|
|
14039
|
+
if (unrunnable !== void 0) logger$27.warn({ scope: scopeLabel }, `A1.1: acceptance gate unrunnable — ${unrunnable}`);
|
|
13986
14040
|
if (opts?.persist === true && runManifest !== null) await runManifest.update({ journeys: entries }).catch((err) => logger$27.warn({ err }, "A0.3: manifest journeys ledger write failed — pipeline continues"));
|
|
13987
|
-
return
|
|
14041
|
+
return unrunnable !== void 0 ? {
|
|
14042
|
+
entries,
|
|
14043
|
+
unrunnable
|
|
14044
|
+
} : { entries };
|
|
13988
14045
|
}
|
|
13989
14046
|
function getStallThresholdMs(phase) {
|
|
13990
14047
|
return phase === "IN_DEV" ? DEV_STORY_STALL_THRESHOLD_MS : DEFAULT_STALL_THRESHOLD_MS;
|
|
@@ -16379,17 +16436,19 @@ function createImplementationOrchestrator(deps) {
|
|
|
16379
16436
|
const isLastOfEpicA = [..._stories.entries()].filter(([key]) => key !== storyKey && epicOfA(key) === epicIdA).every(([, st]) => TERMINAL_A.includes(st.phase));
|
|
16380
16437
|
const epicNum = Number(epicIdA);
|
|
16381
16438
|
if (isLastOfEpicA && Number.isInteger(epicNum)) {
|
|
16382
|
-
const
|
|
16383
|
-
const violations = (entries ?? []).filter((e) => e.state === "unclaimed" || e.state === "unwalked");
|
|
16384
|
-
if (violations.length > 0) {
|
|
16439
|
+
const audit = await auditJourneyCoverage({ epic: epicNum });
|
|
16440
|
+
const violations = (audit?.entries ?? []).filter((e) => e.state === "unclaimed" || e.state === "unwalked");
|
|
16441
|
+
if (violations.length > 0 || audit?.unrunnable !== void 0) {
|
|
16385
16442
|
const issueLines = violations.map((v) => `journey ${v.journeyId} [${v.criticality}] "${v.title}" is ${v.state}` + (v.ownerStories.length > 0 ? ` (claimed by ${v.ownerStories.join(", ")} but never walked)` : " — NO story claims it"));
|
|
16443
|
+
if (audit?.unrunnable !== void 0) issueLines.push(audit.unrunnable);
|
|
16386
16444
|
if (acceptanceModeCfg === "blocking") {
|
|
16387
|
-
const verdict = violations.some((v) => v.state === "unclaimed") ? "journey-unclaimed" : "journey-unwalked";
|
|
16445
|
+
const verdict = violations.some((v) => v.state === "unclaimed") ? "journey-unclaimed" : audit?.unrunnable !== void 0 ? "acceptance-unrunnable" : "journey-unwalked";
|
|
16388
16446
|
logger$27.error({
|
|
16389
16447
|
storyKey,
|
|
16390
16448
|
epicId: epicIdA,
|
|
16449
|
+
verdict,
|
|
16391
16450
|
journeys: violations.map((v) => v.journeyId)
|
|
16392
|
-
}, "A0.3: journey coverage violation at epic close — blocking finalization; branch preserved");
|
|
16451
|
+
}, "A0.3/A1.1: journey coverage violation at epic close — blocking finalization; branch preserved");
|
|
16393
16452
|
updateStory(storyKey, {
|
|
16394
16453
|
phase: "ESCALATED",
|
|
16395
16454
|
error: verdict,
|
|
@@ -48303,4 +48362,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
|
|
|
48303
48362
|
|
|
48304
48363
|
//#endregion
|
|
48305
48364
|
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 };
|
|
48306
|
-
//# sourceMappingURL=run-
|
|
48365
|
+
//# sourceMappingURL=run-C7PLGWT0.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import "./health-
|
|
1
|
+
import "./health-hYMxKqAH.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./helpers-CElYrONe.js";
|
|
4
4
|
import "./dist-CpnLJuVw.js";
|
|
5
|
-
import "./manifest-read-
|
|
6
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-
|
|
5
|
+
import "./manifest-read-C0N7b9nH.js";
|
|
6
|
+
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-C7PLGWT0.js";
|
|
7
7
|
import "./routing-DFxoKHDt.js";
|
|
8
8
|
import "./work-graph-repository-DZyJv5pV.js";
|
|
9
9
|
import "./decisions-CzSIEeGP.js";
|
|
10
10
|
import "./decision-router-BAPpON_C.js";
|
|
11
|
-
import "./interactive-prompt-
|
|
11
|
+
import "./interactive-prompt-BvY2FKsl.js";
|
|
12
12
|
import "./recovery-engine-BKGBeBnW.js";
|
|
13
13
|
|
|
14
14
|
export { runRunAction };
|