substrate-ai 0.21.4 → 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 +6 -6
- package/dist/{health-DklP4Se9.js → health-BdYZpCP1.js} +2 -2
- package/dist/{health-BUl3y64N.js → health-hYMxKqAH.js} +2 -2
- package/dist/{interactive-prompt-C4Is1QDB.js → interactive-prompt-BvY2FKsl.js} +2 -2
- package/dist/{manifest-read-DZDlSq_s.js → manifest-read-C0N7b9nH.js} +468 -381
- package/dist/modules/interactive-prompt/index.js +2 -2
- package/dist/{run-nSb1TD3o.js → run-C7PLGWT0.js} +49 -5
- package/dist/{run-CMXmzqoy.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 { 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-
|
|
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({
|
|
@@ -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
|
|
@@ -2613,13 +2613,13 @@ var ContaminationCheck = class {
|
|
|
2613
2613
|
//#region packages/sdlc/dist/verification/checks/test-mutation-check.js
|
|
2614
2614
|
/** Heuristic: is this path a test file? Covers the JS/TS/Python/Go idioms. */
|
|
2615
2615
|
function isTestPath(file) {
|
|
2616
|
-
const norm = file.replace(/\\/g, "/").toLowerCase();
|
|
2617
|
-
const base = norm.split("/").pop() ?? "";
|
|
2618
|
-
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;
|
|
2619
2619
|
if (/\.(test|spec)\.[a-z]+$/.test(base)) return true;
|
|
2620
2620
|
if (/^test_.*\.py$/.test(base) || /_test\.(py|go)$/.test(base)) return true;
|
|
2621
2621
|
if (base === "conftest.py") return true;
|
|
2622
|
-
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;
|
|
2623
2623
|
return false;
|
|
2624
2624
|
}
|
|
2625
2625
|
var TestMutationCheck = class {
|
|
@@ -2649,6 +2649,351 @@ var TestMutationCheck = class {
|
|
|
2649
2649
|
}
|
|
2650
2650
|
};
|
|
2651
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
|
+
|
|
2652
2997
|
//#endregion
|
|
2653
2998
|
//#region packages/sdlc/dist/verification/probes/types.js
|
|
2654
2999
|
/**
|
|
@@ -4604,6 +4949,7 @@ function createDefaultVerificationPipeline(bus, config) {
|
|
|
4604
4949
|
new TestSuiteCheck(),
|
|
4605
4950
|
new ContaminationCheck(),
|
|
4606
4951
|
new TestMutationCheck(),
|
|
4952
|
+
new AcceptanceSpecCheck(),
|
|
4607
4953
|
new RuntimeProbeCheck(),
|
|
4608
4954
|
new SourceAcFidelityCheck(),
|
|
4609
4955
|
new SourceAcShelloutCheck(),
|
|
@@ -4844,396 +5190,137 @@ function tokenize(s) {
|
|
|
4844
5190
|
return new Set(words);
|
|
4845
5191
|
}
|
|
4846
5192
|
/**
|
|
4847
|
-
* Compute Jaccard-based word overlap between two strings.
|
|
4848
|
-
* Returns 0 when either string has no tokens.
|
|
4849
|
-
*/
|
|
4850
|
-
function wordOverlap(a, b) {
|
|
4851
|
-
const setA = tokenize(a);
|
|
4852
|
-
const setB = tokenize(b);
|
|
4853
|
-
if (setA.size === 0 || setB.size === 0) return 0;
|
|
4854
|
-
let intersection = 0;
|
|
4855
|
-
for (const w of setA) if (setB.has(w)) intersection++;
|
|
4856
|
-
const union = new Set([...setA, ...setB]).size;
|
|
4857
|
-
return intersection / union;
|
|
4858
|
-
}
|
|
4859
|
-
/**
|
|
4860
|
-
* Extract numbered AC items from the `## Acceptance Criteria` section of a
|
|
4861
|
-
* story spec. Handles both plain `## Acceptance Criteria` headings and the
|
|
4862
|
-
* bold-wrapped variant `**Acceptance Criteria:**`.
|
|
4863
|
-
*
|
|
4864
|
-
* Stops scanning at the next `##` heading (or end-of-file).
|
|
4865
|
-
*
|
|
4866
|
-
* Returns an array of trimmed AC text strings (numbering stripped).
|
|
4867
|
-
*/
|
|
4868
|
-
function parseAcList(storyContent) {
|
|
4869
|
-
const lines = storyContent.split("\n");
|
|
4870
|
-
const items = [];
|
|
4871
|
-
let inAcSection = false;
|
|
4872
|
-
for (const line of lines) {
|
|
4873
|
-
if (/^##\s+Acceptance Criteria/i.test(line) || /\*\*Acceptance Criteria:\*\*/i.test(line)) {
|
|
4874
|
-
inAcSection = true;
|
|
4875
|
-
continue;
|
|
4876
|
-
}
|
|
4877
|
-
if (inAcSection && /^##\s/.test(line)) break;
|
|
4878
|
-
if (!inAcSection) continue;
|
|
4879
|
-
const numbered = line.match(/^\s*(?:\d+[.):]|AC\d+[.):])\s*(.+)/);
|
|
4880
|
-
if (numbered) {
|
|
4881
|
-
const text = (numbered[1] ?? "").trim();
|
|
4882
|
-
if (text.length > 0) items.push(text);
|
|
4883
|
-
}
|
|
4884
|
-
}
|
|
4885
|
-
return items;
|
|
4886
|
-
}
|
|
4887
|
-
const TEST_FILE_PATTERNS = [
|
|
4888
|
-
/\.test\.ts$/,
|
|
4889
|
-
/\.test\.js$/,
|
|
4890
|
-
/test/i
|
|
4891
|
-
];
|
|
4892
|
-
/** Returns true when the path matches a known test file pattern. */
|
|
4893
|
-
function isTestFile(path$3) {
|
|
4894
|
-
return TEST_FILE_PATTERNS.some((p) => p.test(path$3));
|
|
4895
|
-
}
|
|
4896
|
-
const TEST_DESC_RE = /(?:describe|it|test)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
4897
|
-
/**
|
|
4898
|
-
* Extract all string literals passed to `describe(`, `it(`, or `test(` in the
|
|
4899
|
-
* provided source text.
|
|
4900
|
-
*/
|
|
4901
|
-
function extractTestDescriptions(source) {
|
|
4902
|
-
const results = [];
|
|
4903
|
-
let m;
|
|
4904
|
-
TEST_DESC_RE.lastIndex = 0;
|
|
4905
|
-
while ((m = TEST_DESC_RE.exec(source)) !== null) {
|
|
4906
|
-
const desc = m[1];
|
|
4907
|
-
if (desc !== void 0 && desc.trim().length > 0) results.push(desc.trim());
|
|
4908
|
-
}
|
|
4909
|
-
return results;
|
|
4910
|
-
}
|
|
4911
|
-
/**
|
|
4912
|
-
* Run the AC-to-test traceability heuristic.
|
|
4913
|
-
*
|
|
4914
|
-
* Steps:
|
|
4915
|
-
* 1. Parse AC list from `input.storyContent`.
|
|
4916
|
-
* 2. Filter `input.filesModified` to test files.
|
|
4917
|
-
* 3. Read each test file and extract describe/it/test descriptions.
|
|
4918
|
-
* 4. For each AC × each test description, compute word-overlap score.
|
|
4919
|
-
* 5. A score ≥ 0.4 marks the AC as "matched".
|
|
4920
|
-
* 6. Return the matrix with `confidence: 'approximate'`.
|
|
4921
|
-
*
|
|
4922
|
-
* File I/O errors are silently ignored per file (the file is simply skipped).
|
|
4923
|
-
* When no test files are found, all ACs are "not matched" and a warning is emitted.
|
|
4924
|
-
*/
|
|
4925
|
-
async function runAcTraceabilityCheck(input) {
|
|
4926
|
-
const { storyKey, storyContent, filesModified } = input;
|
|
4927
|
-
const fileReader = input._readFile ?? ((p) => readFile(p, "utf-8"));
|
|
4928
|
-
const warnings = [];
|
|
4929
|
-
const acList = parseAcList(storyContent);
|
|
4930
|
-
const testFiles = filesModified.filter(isTestFile);
|
|
4931
|
-
if (testFiles.length === 0) {
|
|
4932
|
-
warnings.push(`No test files found in filesModified for story ${storyKey}. All ACs marked as unmatched.`);
|
|
4933
|
-
const matrix$1 = acList.map((acText) => ({
|
|
4934
|
-
acText,
|
|
4935
|
-
matched: false,
|
|
4936
|
-
testName: null,
|
|
4937
|
-
score: 0
|
|
4938
|
-
}));
|
|
4939
|
-
return {
|
|
4940
|
-
storyKey,
|
|
4941
|
-
matrix: matrix$1,
|
|
4942
|
-
confidence: "approximate",
|
|
4943
|
-
warnings
|
|
4944
|
-
};
|
|
4945
|
-
}
|
|
4946
|
-
const allTestDescriptions = [];
|
|
4947
|
-
for (const filePath of testFiles) try {
|
|
4948
|
-
const source = await fileReader(filePath);
|
|
4949
|
-
if (source != null) {
|
|
4950
|
-
const descs = extractTestDescriptions(source);
|
|
4951
|
-
allTestDescriptions.push(...descs);
|
|
4952
|
-
}
|
|
4953
|
-
} catch {}
|
|
4954
|
-
const MATCH_THRESHOLD = .4;
|
|
4955
|
-
const matrix = acList.map((acText) => {
|
|
4956
|
-
let bestScore = 0;
|
|
4957
|
-
let bestTestName = null;
|
|
4958
|
-
for (const desc of allTestDescriptions) {
|
|
4959
|
-
const score = wordOverlap(acText, desc);
|
|
4960
|
-
if (score > bestScore) {
|
|
4961
|
-
bestScore = score;
|
|
4962
|
-
bestTestName = desc;
|
|
4963
|
-
}
|
|
4964
|
-
}
|
|
4965
|
-
const matched = bestScore >= MATCH_THRESHOLD;
|
|
4966
|
-
return {
|
|
4967
|
-
acText,
|
|
4968
|
-
matched,
|
|
4969
|
-
testName: matched ? bestTestName : null,
|
|
4970
|
-
score: bestScore
|
|
4971
|
-
};
|
|
4972
|
-
});
|
|
4973
|
-
return {
|
|
4974
|
-
storyKey,
|
|
4975
|
-
matrix,
|
|
4976
|
-
confidence: "approximate",
|
|
4977
|
-
warnings
|
|
4978
|
-
};
|
|
4979
|
-
}
|
|
4980
|
-
|
|
4981
|
-
//#endregion
|
|
4982
|
-
//#region packages/sdlc/dist/acceptance/registry.js
|
|
4983
|
-
/** Repo-relative path of the registry — the single canonical location. */
|
|
4984
|
-
const JOURNEY_REGISTRY_PATH = ".substrate/acceptance/journeys.yaml";
|
|
4985
|
-
const JourneySurfaceSchema = z.enum([
|
|
4986
|
-
"email",
|
|
4987
|
-
"cli",
|
|
4988
|
-
"file",
|
|
4989
|
-
"web"
|
|
4990
|
-
]);
|
|
4991
|
-
const JourneyEndStateSchema = z.object({
|
|
4992
|
-
id: z.string().min(1, "end-state id must be a non-empty string"),
|
|
4993
|
-
given: z.string().min(1, "given must be a non-empty string"),
|
|
4994
|
-
walk: z.string().min(1, "walk must be a non-empty string"),
|
|
4995
|
-
then: z.string().min(1, "then must be a non-empty string")
|
|
4996
|
-
});
|
|
4997
|
-
const JourneySchema = z.object({
|
|
4998
|
-
id: z.string().min(1, "journey id must be a non-empty string"),
|
|
4999
|
-
title: z.string().min(1, "title must be a non-empty string"),
|
|
5000
|
-
criticality: z.enum(["critical", "standard"]),
|
|
5001
|
-
surfaces: z.array(JourneySurfaceSchema).min(1, "a journey must declare at least one surface"),
|
|
5002
|
-
epic: z.number().int().positive().optional(),
|
|
5003
|
-
end_states: z.array(JourneyEndStateSchema).min(1, "a journey must declare at least one end_state — a journey with none is unjudgeable")
|
|
5004
|
-
});
|
|
5005
|
-
const JourneyRegistrySchema = z.object({
|
|
5006
|
-
version: z.number().int().positive("version must be a positive integer"),
|
|
5007
|
-
journeys: z.array(JourneySchema)
|
|
5008
|
-
}).superRefine((registry, ctx) => {
|
|
5009
|
-
const seenJourneyIds = new Map();
|
|
5010
|
-
registry.journeys.forEach((journey, i) => {
|
|
5011
|
-
const firstIndex = seenJourneyIds.get(journey.id);
|
|
5012
|
-
if (firstIndex !== void 0) ctx.addIssue({
|
|
5013
|
-
code: "custom",
|
|
5014
|
-
path: [
|
|
5015
|
-
"journeys",
|
|
5016
|
-
i,
|
|
5017
|
-
"id"
|
|
5018
|
-
],
|
|
5019
|
-
message: `duplicate journey id "${journey.id}" (first declared at journeys[${firstIndex}])`
|
|
5020
|
-
});
|
|
5021
|
-
else seenJourneyIds.set(journey.id, i);
|
|
5022
|
-
const seenEndStateIds = new Map();
|
|
5023
|
-
journey.end_states.forEach((endState, j) => {
|
|
5024
|
-
const firstEs = seenEndStateIds.get(endState.id);
|
|
5025
|
-
if (firstEs !== void 0) ctx.addIssue({
|
|
5026
|
-
code: "custom",
|
|
5027
|
-
path: [
|
|
5028
|
-
"journeys",
|
|
5029
|
-
i,
|
|
5030
|
-
"end_states",
|
|
5031
|
-
j,
|
|
5032
|
-
"id"
|
|
5033
|
-
],
|
|
5034
|
-
message: `duplicate end-state id "${endState.id}" in journey "${journey.id}" (first declared at end_states[${firstEs}])`
|
|
5035
|
-
});
|
|
5036
|
-
else seenEndStateIds.set(endState.id, j);
|
|
5037
|
-
});
|
|
5038
|
-
});
|
|
5039
|
-
});
|
|
5040
|
-
function zodErrorToValidationIssues(error) {
|
|
5041
|
-
return error.issues.map((issue) => ({
|
|
5042
|
-
path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
|
|
5043
|
-
message: issue.message
|
|
5044
|
-
}));
|
|
5045
|
-
}
|
|
5046
|
-
/**
|
|
5047
|
-
* Parse and validate registry YAML content.
|
|
5048
|
-
*
|
|
5049
|
-
* Never throws: malformed YAML, non-object documents, and schema violations
|
|
5050
|
-
* all come back as named, pathed issues.
|
|
5051
|
-
*/
|
|
5052
|
-
function parseJourneyRegistry(yamlContent) {
|
|
5053
|
-
let doc;
|
|
5054
|
-
try {
|
|
5055
|
-
doc = load(yamlContent);
|
|
5056
|
-
} catch (err) {
|
|
5057
|
-
const message = err instanceof YAMLException ? err.message : String(err);
|
|
5058
|
-
return {
|
|
5059
|
-
ok: false,
|
|
5060
|
-
issues: [{
|
|
5061
|
-
path: "(root)",
|
|
5062
|
-
message: `malformed YAML: ${message}`
|
|
5063
|
-
}]
|
|
5064
|
-
};
|
|
5065
|
-
}
|
|
5066
|
-
if (doc === null || doc === void 0) return {
|
|
5067
|
-
ok: false,
|
|
5068
|
-
issues: [{
|
|
5069
|
-
path: "(root)",
|
|
5070
|
-
message: "registry file is empty"
|
|
5071
|
-
}]
|
|
5072
|
-
};
|
|
5073
|
-
const result = JourneyRegistrySchema.safeParse(doc);
|
|
5074
|
-
if (!result.success) return {
|
|
5075
|
-
ok: false,
|
|
5076
|
-
issues: zodErrorToValidationIssues(result.error)
|
|
5077
|
-
};
|
|
5078
|
-
return {
|
|
5079
|
-
ok: true,
|
|
5080
|
-
registry: result.data
|
|
5081
|
-
};
|
|
5082
|
-
}
|
|
5083
|
-
|
|
5084
|
-
//#endregion
|
|
5085
|
-
//#region packages/sdlc/dist/acceptance/coverage.js
|
|
5086
|
-
/**
|
|
5087
|
-
* Compute the coverage state of every journey audited at this scope.
|
|
5193
|
+
* Compute Jaccard-based word overlap between two strings.
|
|
5194
|
+
* Returns 0 when either string has no tokens.
|
|
5195
|
+
*/
|
|
5196
|
+
function wordOverlap(a, b) {
|
|
5197
|
+
const setA = tokenize(a);
|
|
5198
|
+
const setB = tokenize(b);
|
|
5199
|
+
if (setA.size === 0 || setB.size === 0) return 0;
|
|
5200
|
+
let intersection = 0;
|
|
5201
|
+
for (const w of setA) if (setB.has(w)) intersection++;
|
|
5202
|
+
const union = new Set([...setA, ...setB]).size;
|
|
5203
|
+
return intersection / union;
|
|
5204
|
+
}
|
|
5205
|
+
/**
|
|
5206
|
+
* Extract numbered AC items from the `## Acceptance Criteria` section of a
|
|
5207
|
+
* story spec. Handles both plain `## Acceptance Criteria` headings and the
|
|
5208
|
+
* bold-wrapped variant `**Acceptance Criteria:**`.
|
|
5088
5209
|
*
|
|
5089
|
-
*
|
|
5090
|
-
* - `{final: true}` audits the FULL registry (epicless journeys have no
|
|
5091
|
-
* earlier audit point; epic-scoped ones are re-audited — idempotent).
|
|
5210
|
+
* Stops scanning at the next `##` heading (or end-of-file).
|
|
5092
5211
|
*
|
|
5093
|
-
*
|
|
5094
|
-
* An operator deferral wins over everything (explicit scope decision); a fail
|
|
5095
|
-
* verdict wins over a pass (any failing end-state fails the journey).
|
|
5212
|
+
* Returns an array of trimmed AC text strings (numbering stripped).
|
|
5096
5213
|
*/
|
|
5097
|
-
function
|
|
5098
|
-
const
|
|
5099
|
-
const
|
|
5100
|
-
|
|
5101
|
-
for (const
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
}
|
|
5106
|
-
const deferred = new Set(deferredJourneyIds);
|
|
5107
|
-
const verdictByJourney = new Map();
|
|
5108
|
-
for (const v of verdicts) {
|
|
5109
|
-
const existing = verdictByJourney.get(v.journeyId);
|
|
5110
|
-
verdictByJourney.set(v.journeyId, existing === "fail" ? "fail" : v.verdict);
|
|
5111
|
-
}
|
|
5112
|
-
return audited.map((journey) => {
|
|
5113
|
-
const ownerStories = claimsByJourney.get(journey.id) ?? [];
|
|
5114
|
-
let state;
|
|
5115
|
-
if (deferred.has(journey.id)) state = "deferred";
|
|
5116
|
-
else {
|
|
5117
|
-
const verdict = verdictByJourney.get(journey.id);
|
|
5118
|
-
if (verdict === "fail") state = "walked-fail";
|
|
5119
|
-
else if (verdict === "pass") state = "walked-pass";
|
|
5120
|
-
else state = ownerStories.length > 0 ? "unwalked" : "unclaimed";
|
|
5214
|
+
function parseAcList(storyContent) {
|
|
5215
|
+
const lines = storyContent.split("\n");
|
|
5216
|
+
const items = [];
|
|
5217
|
+
let inAcSection = false;
|
|
5218
|
+
for (const line of lines) {
|
|
5219
|
+
if (/^##\s+Acceptance Criteria/i.test(line) || /\*\*Acceptance Criteria:\*\*/i.test(line)) {
|
|
5220
|
+
inAcSection = true;
|
|
5221
|
+
continue;
|
|
5121
5222
|
}
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5223
|
+
if (inAcSection && /^##\s/.test(line)) break;
|
|
5224
|
+
if (!inAcSection) continue;
|
|
5225
|
+
const numbered = line.match(/^\s*(?:\d+[.):]|AC\d+[.):])\s*(.+)/);
|
|
5226
|
+
if (numbered) {
|
|
5227
|
+
const text = (numbered[1] ?? "").trim();
|
|
5228
|
+
if (text.length > 0) items.push(text);
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
return items;
|
|
5131
5232
|
}
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
};
|
|
5141
|
-
for (const entry of entries) summary[entry.state] += 1;
|
|
5142
|
-
return summary;
|
|
5233
|
+
const TEST_FILE_PATTERNS = [
|
|
5234
|
+
/\.test\.ts$/,
|
|
5235
|
+
/\.test\.js$/,
|
|
5236
|
+
/test/i
|
|
5237
|
+
];
|
|
5238
|
+
/** Returns true when the path matches a known test file pattern. */
|
|
5239
|
+
function isTestFile(path$3) {
|
|
5240
|
+
return TEST_FILE_PATTERNS.some((p) => p.test(path$3));
|
|
5143
5241
|
}
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
doc = load(yamlContent);
|
|
5157
|
-
} catch (err) {
|
|
5158
|
-
const message = err instanceof YAMLException ? err.message : String(err);
|
|
5159
|
-
return {
|
|
5160
|
-
ok: false,
|
|
5161
|
-
issues: [{
|
|
5162
|
-
path: "(root)",
|
|
5163
|
-
message: `malformed YAML: ${message}`
|
|
5164
|
-
}]
|
|
5165
|
-
};
|
|
5242
|
+
const TEST_DESC_RE = /(?:describe|it|test)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
5243
|
+
/**
|
|
5244
|
+
* Extract all string literals passed to `describe(`, `it(`, or `test(` in the
|
|
5245
|
+
* provided source text.
|
|
5246
|
+
*/
|
|
5247
|
+
function extractTestDescriptions(source) {
|
|
5248
|
+
const results = [];
|
|
5249
|
+
let m;
|
|
5250
|
+
TEST_DESC_RE.lastIndex = 0;
|
|
5251
|
+
while ((m = TEST_DESC_RE.exec(source)) !== null) {
|
|
5252
|
+
const desc = m[1];
|
|
5253
|
+
if (desc !== void 0 && desc.trim().length > 0) results.push(desc.trim());
|
|
5166
5254
|
}
|
|
5167
|
-
|
|
5168
|
-
ok: true,
|
|
5169
|
-
deferrals: []
|
|
5170
|
-
};
|
|
5171
|
-
const result = JourneyDeferralsFileSchema.safeParse(doc);
|
|
5172
|
-
if (!result.success) return {
|
|
5173
|
-
ok: false,
|
|
5174
|
-
issues: result.error.issues.map((issue) => ({
|
|
5175
|
-
path: issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)",
|
|
5176
|
-
message: issue.message
|
|
5177
|
-
}))
|
|
5178
|
-
};
|
|
5179
|
-
return {
|
|
5180
|
-
ok: true,
|
|
5181
|
-
deferrals: result.data.deferrals
|
|
5182
|
-
};
|
|
5255
|
+
return results;
|
|
5183
5256
|
}
|
|
5184
|
-
|
|
5185
|
-
//#endregion
|
|
5186
|
-
//#region packages/sdlc/dist/acceptance/contract.js
|
|
5187
|
-
/** The acceptance contract lives inside the project profile. */
|
|
5188
|
-
const ACCEPTANCE_CONTRACT_PROFILE_PATH = ".substrate/project-profile.yaml";
|
|
5189
|
-
const RenderSurfaceSchema = z.object({ render: z.string().min(1) }).strict();
|
|
5190
|
-
const WebSurfaceSchema = z.object({
|
|
5191
|
-
serve: z.string().min(1),
|
|
5192
|
-
ready: z.string().optional()
|
|
5193
|
-
}).strict();
|
|
5194
|
-
const AcceptanceContractSchema = z.object({
|
|
5195
|
-
fixtures: z.string().optional(),
|
|
5196
|
-
surfaces: z.object({
|
|
5197
|
-
email: RenderSurfaceSchema.optional(),
|
|
5198
|
-
cli: RenderSurfaceSchema.optional(),
|
|
5199
|
-
file: RenderSurfaceSchema.optional(),
|
|
5200
|
-
web: WebSurfaceSchema.optional()
|
|
5201
|
-
}).strict()
|
|
5202
|
-
}).strict();
|
|
5203
5257
|
/**
|
|
5204
|
-
*
|
|
5205
|
-
*
|
|
5206
|
-
*
|
|
5207
|
-
*
|
|
5258
|
+
* Run the AC-to-test traceability heuristic.
|
|
5259
|
+
*
|
|
5260
|
+
* Steps:
|
|
5261
|
+
* 1. Parse AC list from `input.storyContent`.
|
|
5262
|
+
* 2. Filter `input.filesModified` to test files.
|
|
5263
|
+
* 3. Read each test file and extract describe/it/test descriptions.
|
|
5264
|
+
* 4. For each AC × each test description, compute word-overlap score.
|
|
5265
|
+
* 5. A score ≥ 0.4 marks the AC as "matched".
|
|
5266
|
+
* 6. Return the matrix with `confidence: 'approximate'`.
|
|
5267
|
+
*
|
|
5268
|
+
* File I/O errors are silently ignored per file (the file is simply skipped).
|
|
5269
|
+
* When no test files are found, all ACs are "not matched" and a warning is emitted.
|
|
5208
5270
|
*/
|
|
5209
|
-
function
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5271
|
+
async function runAcTraceabilityCheck(input) {
|
|
5272
|
+
const { storyKey, storyContent, filesModified } = input;
|
|
5273
|
+
const fileReader = input._readFile ?? ((p) => readFile(p, "utf-8"));
|
|
5274
|
+
const warnings = [];
|
|
5275
|
+
const acList = parseAcList(storyContent);
|
|
5276
|
+
const testFiles = filesModified.filter(isTestFile);
|
|
5277
|
+
if (testFiles.length === 0) {
|
|
5278
|
+
warnings.push(`No test files found in filesModified for story ${storyKey}. All ACs marked as unmatched.`);
|
|
5279
|
+
const matrix$1 = acList.map((acText) => ({
|
|
5280
|
+
acText,
|
|
5281
|
+
matched: false,
|
|
5282
|
+
testName: null,
|
|
5283
|
+
score: 0
|
|
5284
|
+
}));
|
|
5215
5285
|
return {
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
}]
|
|
5286
|
+
storyKey,
|
|
5287
|
+
matrix: matrix$1,
|
|
5288
|
+
confidence: "approximate",
|
|
5289
|
+
warnings
|
|
5221
5290
|
};
|
|
5222
5291
|
}
|
|
5223
|
-
|
|
5224
|
-
const
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5292
|
+
const allTestDescriptions = [];
|
|
5293
|
+
for (const filePath of testFiles) try {
|
|
5294
|
+
const source = await fileReader(filePath);
|
|
5295
|
+
if (source != null) {
|
|
5296
|
+
const descs = extractTestDescriptions(source);
|
|
5297
|
+
allTestDescriptions.push(...descs);
|
|
5298
|
+
}
|
|
5299
|
+
} catch {}
|
|
5300
|
+
const MATCH_THRESHOLD = .4;
|
|
5301
|
+
const matrix = acList.map((acText) => {
|
|
5302
|
+
let bestScore = 0;
|
|
5303
|
+
let bestTestName = null;
|
|
5304
|
+
for (const desc of allTestDescriptions) {
|
|
5305
|
+
const score = wordOverlap(acText, desc);
|
|
5306
|
+
if (score > bestScore) {
|
|
5307
|
+
bestScore = score;
|
|
5308
|
+
bestTestName = desc;
|
|
5309
|
+
}
|
|
5310
|
+
}
|
|
5311
|
+
const matched = bestScore >= MATCH_THRESHOLD;
|
|
5312
|
+
return {
|
|
5313
|
+
acText,
|
|
5314
|
+
matched,
|
|
5315
|
+
testName: matched ? bestTestName : null,
|
|
5316
|
+
score: bestScore
|
|
5317
|
+
};
|
|
5318
|
+
});
|
|
5234
5319
|
return {
|
|
5235
|
-
|
|
5236
|
-
|
|
5320
|
+
storyKey,
|
|
5321
|
+
matrix,
|
|
5322
|
+
confidence: "approximate",
|
|
5323
|
+
warnings
|
|
5237
5324
|
};
|
|
5238
5325
|
}
|
|
5239
5326
|
|
|
@@ -6823,4 +6910,4 @@ async function resolveRunManifest(dbRoot, runId) {
|
|
|
6823
6910
|
|
|
6824
6911
|
//#endregion
|
|
6825
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 };
|
|
6826
|
-
//# sourceMappingURL=manifest-read-
|
|
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 { 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-
|
|
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";
|
|
@@ -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
|
*/
|
|
@@ -48318,4 +48362,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
|
|
|
48318
48362
|
|
|
48319
48363
|
//#endregion
|
|
48320
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 };
|
|
48321
|
-
//# 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 };
|