substrate-ai 0.20.142 → 0.20.144

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1,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-DTJaiJOd.js";
2
+ import { FileKvStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-0kOtC07t.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, 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-DiNK6QOD.js";
6
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DHHryElL.js";
6
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-CUcRdKFK.js";
7
7
  import "../adapter-registry-DIcrxjH8.js";
8
- import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-BgZ6mR5R.js";
8
+ import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-DPN4jjTc.js";
9
9
  import "../errors-B21JUhcc.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-OMlqP7Lm.js";
14
+ import "../interactive-prompt-DTLnCbk2.js";
15
15
  import "../recovery-engine-BKGBeBnW.js";
16
16
  import "../version-manager-impl-qFBiO4Eh.js";
17
17
  import { registerUpgradeCommand } from "../upgrade-DB7KzD9c.js";
@@ -7052,7 +7052,7 @@ async function runStatusAction(options) {
7052
7052
  logger$15.debug({ err }, "Work graph query failed, continuing without work graph data");
7053
7053
  }
7054
7054
  if (run === void 0) {
7055
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-Cf5RjwHi.js");
7055
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-P6IZuE0b.js");
7056
7056
  const substrateDirPath = join(projectRoot, ".substrate");
7057
7057
  const processInfo = inspectProcessTree$1({
7058
7058
  projectRoot,
@@ -8581,7 +8581,7 @@ async function runSupervisorAction(options, deps = {}) {
8581
8581
  await initSchema(expAdapter);
8582
8582
  const { runRunAction: runPipeline } = await import(
8583
8583
  /* @vite-ignore */
8584
- "../run-DStT56J1.js"
8584
+ "../run-B5KqcL9T.js"
8585
8585
  );
8586
8586
  const runStoryFn = async (opts) => {
8587
8587
  const exitCode = await runPipeline({
@@ -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-DiNK6QOD.js";
3
- import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-BgZ6mR5R.js";
3
+ import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-DPN4jjTc.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-DTJaiJOd.js.map
1003
+ //# sourceMappingURL=health-0kOtC07t.js.map
@@ -1,7 +1,7 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-DTJaiJOd.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-0kOtC07t.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./dist-DiNK6QOD.js";
4
- import "./manifest-read-BgZ6mR5R.js";
4
+ import "./manifest-read-DPN4jjTc.js";
5
5
  import "./work-graph-repository-DZyJv5pV.js";
6
6
  import "./decisions-CzSIEeGP.js";
7
7
 
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { readCurrentRunId, resolveMainRepoRoot } from "./manifest-read-BgZ6mR5R.js";
2
+ import { readCurrentRunId, resolveMainRepoRoot } from "./manifest-read-DPN4jjTc.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-OMlqP7Lm.js.map
183
+ //# sourceMappingURL=interactive-prompt-DTLnCbk2.js.map
@@ -8,7 +8,7 @@ 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, 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, resolve as resolve$1 } from "node:path";
12
12
  import { z } from "zod";
13
13
  import { mkdir as mkdir$1, open, readFile as readFile$1, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
14
14
  import * as fs from "fs";
@@ -2357,6 +2357,166 @@ var TestSuiteCheck = class {
2357
2357
  }
2358
2358
  };
2359
2359
 
2360
+ //#endregion
2361
+ //#region packages/sdlc/dist/verification/checks/contamination-check.js
2362
+ /** Map of language → source extensions used for foreign-language detection. */
2363
+ const LANGUAGE_EXTENSIONS = {
2364
+ typescript: [
2365
+ ".ts",
2366
+ ".tsx",
2367
+ ".mts",
2368
+ ".cts"
2369
+ ],
2370
+ javascript: [
2371
+ ".js",
2372
+ ".jsx",
2373
+ ".mjs",
2374
+ ".cjs"
2375
+ ],
2376
+ python: [".py"],
2377
+ go: [".go"],
2378
+ rust: [".rs"],
2379
+ java: [".java"],
2380
+ kotlin: [".kt", ".kts"]
2381
+ };
2382
+ /** JS-family toolchain manifests whose appearance flips build detection. */
2383
+ const JS_TOOLCHAIN_MANIFESTS = [
2384
+ "package.json",
2385
+ "tsconfig.json",
2386
+ "package-lock.json",
2387
+ "pnpm-lock.yaml",
2388
+ "yarn.lock",
2389
+ "bun.lockb",
2390
+ "vite.config.ts",
2391
+ "vite.config.js"
2392
+ ];
2393
+ /** Droppings that must never appear in a story diff, regardless of language. */
2394
+ const ALWAYS_DENY_SEGMENTS = [
2395
+ "node_modules",
2396
+ ".venv",
2397
+ "__pycache__"
2398
+ ];
2399
+ /**
2400
+ * Collect every `language: <x>` declaration in the profile (single-project
2401
+ * `project.language` plus monorepo `packages[].language`). Line-based parse —
2402
+ * no yaml dependency. Returns [] when the profile is absent/unreadable.
2403
+ */
2404
+ function readProfileLanguages(workingDir) {
2405
+ const profilePath = join$1(workingDir, ".substrate", "project-profile.yaml");
2406
+ if (!existsSync(profilePath)) return [];
2407
+ try {
2408
+ const content = readFileSync(profilePath, "utf-8");
2409
+ const langs = new Set();
2410
+ for (const m of content.matchAll(/^\s*(?:-\s+)?language:\s*['"]?([a-z]+)['"]?\s*$/gm)) if (m[1] !== void 0) langs.add(m[1]);
2411
+ return [...langs];
2412
+ } catch {
2413
+ return [];
2414
+ }
2415
+ }
2416
+ /** Language of a file per LANGUAGE_EXTENSIONS, or undefined for neutral files. */
2417
+ function fileLanguage(file) {
2418
+ const lower = file.toLowerCase();
2419
+ for (const [lang, exts] of Object.entries(LANGUAGE_EXTENSIONS)) if (exts.some((e) => lower.endsWith(e))) return lang;
2420
+ return void 0;
2421
+ }
2422
+ /**
2423
+ * Pure classification of a changed-file list against the project's declared
2424
+ * languages. Exported for unit testing.
2425
+ */
2426
+ function classifyContamination(changedFiles, allowedLanguages) {
2427
+ const allowJs = allowedLanguages.includes("typescript") || allowedLanguages.includes("javascript");
2428
+ const foreignSourceFiles = [];
2429
+ const foreignToolchainManifests = [];
2430
+ const droppings = [];
2431
+ for (const raw of changedFiles) {
2432
+ const file = raw.replace(/\\/g, "/").replace(/^\.\//, "");
2433
+ const segments = file.split("/");
2434
+ if (segments.some((s) => ALWAYS_DENY_SEGMENTS.includes(s))) {
2435
+ droppings.push(file);
2436
+ continue;
2437
+ }
2438
+ if (!allowJs && segments.includes("dist")) {
2439
+ droppings.push(file);
2440
+ continue;
2441
+ }
2442
+ const base = segments[segments.length - 1] ?? "";
2443
+ if (!allowJs && JS_TOOLCHAIN_MANIFESTS.includes(base)) {
2444
+ foreignToolchainManifests.push(file);
2445
+ continue;
2446
+ }
2447
+ const lang = fileLanguage(file);
2448
+ if (lang !== void 0 && !allowedLanguages.includes(lang)) {
2449
+ if (allowJs && (lang === "typescript" || lang === "javascript")) continue;
2450
+ foreignSourceFiles.push({
2451
+ file,
2452
+ language: lang
2453
+ });
2454
+ }
2455
+ }
2456
+ return {
2457
+ foreignSourceFiles,
2458
+ foreignToolchainManifests,
2459
+ droppings
2460
+ };
2461
+ }
2462
+ var ContaminationCheck = class {
2463
+ name = "scope-contamination";
2464
+ tier = "A";
2465
+ async run(context) {
2466
+ const start = Date.now();
2467
+ const changedFiles = context.changedFiles ?? [];
2468
+ if (changedFiles.length === 0) return {
2469
+ status: "pass",
2470
+ details: "no changed files to inspect",
2471
+ duration_ms: Date.now() - start,
2472
+ findings: []
2473
+ };
2474
+ const allowedLanguages = readProfileLanguages(context.workingDir);
2475
+ if (allowedLanguages.length === 0) {
2476
+ const findings$1 = [{
2477
+ category: "contamination-skip",
2478
+ severity: "warn",
2479
+ message: `no project profile with declared languages at ${context.workingDir} — cannot check for foreign-toolchain contamination (run substrate init to generate one)`
2480
+ }];
2481
+ return {
2482
+ status: "warn",
2483
+ details: renderFindings(findings$1),
2484
+ duration_ms: Date.now() - start,
2485
+ findings: findings$1
2486
+ };
2487
+ }
2488
+ const verdict = classifyContamination(changedFiles, allowedLanguages);
2489
+ const findings = [];
2490
+ if (verdict.droppings.length > 0) findings.push({
2491
+ category: "contamination-droppings",
2492
+ severity: "error",
2493
+ message: `story diff contains build/dependency droppings that must never be committed: ${verdict.droppings.slice(0, 10).join(", ")}` + (verdict.droppings.length > 10 ? ` (+${String(verdict.droppings.length - 10)} more)` : "")
2494
+ });
2495
+ if (verdict.foreignToolchainManifests.length > 0) findings.push({
2496
+ category: "contamination-toolchain",
2497
+ severity: "error",
2498
+ message: `story introduces a JS toolchain on a ${allowedLanguages.join("/")} project: ${verdict.foreignToolchainManifests.join(", ")}. This is the exact trigger that flips build detection to npm and masks real story outcomes (field finding #12).`
2499
+ });
2500
+ if (verdict.foreignSourceFiles.length > 0) findings.push({
2501
+ category: "contamination-language",
2502
+ severity: "error",
2503
+ message: `story writes source files in language(s) the project does not use (declared: ${allowedLanguages.join(", ")}): ` + verdict.foreignSourceFiles.slice(0, 10).map((f) => `${f.file} [${f.language}]`).join(", ")
2504
+ });
2505
+ if (findings.length === 0) return {
2506
+ status: "pass",
2507
+ details: `no contamination across ${String(changedFiles.length)} changed file(s)`,
2508
+ duration_ms: Date.now() - start,
2509
+ findings: []
2510
+ };
2511
+ return {
2512
+ status: "fail",
2513
+ details: renderFindings(findings),
2514
+ duration_ms: Date.now() - start,
2515
+ findings
2516
+ };
2517
+ }
2518
+ };
2519
+
2360
2520
  //#endregion
2361
2521
  //#region packages/sdlc/dist/verification/probes/types.js
2362
2522
  /**
@@ -2554,6 +2714,35 @@ function parseRuntimeProbes(storyContent) {
2554
2714
 
2555
2715
  //#endregion
2556
2716
  //#region packages/sdlc/dist/verification/probes/executor.js
2717
+ /**
2718
+ * H1.3 (hardening program, field finding #6): shape the probe environment so
2719
+ * probe commands run in the PROJECT'S environment, not the orchestrator's.
2720
+ *
2721
+ * The field failure: probe `registry-rejects-undeclared-source` ran bare
2722
+ * `python` from the inherited PATH — outside the project venv — and died with
2723
+ * `ModuleNotFoundError: No module named 'structlog'` even though the behavior
2724
+ * it tested passed in-env. That single false negative flipped an
2725
+ * LGTM_WITH_NOTES story to VERIFICATION_FAILED and destabilized the rest of
2726
+ * the run.
2727
+ *
2728
+ * When the working dir carries a project-local env (`.venv/bin` — created by
2729
+ * uv, venv, virtualenv alike), prepend it to PATH and set VIRTUAL_ENV so bare
2730
+ * `python`/`pytest`/console-script invocations resolve inside the project.
2731
+ * PATH prepending (rather than command rewriting) is quoting-hazard-free and
2732
+ * tool-agnostic. POSIX layout only (`bin/`) — matches substrate's supported
2733
+ * platforms; extend for `Scripts/` if Windows dispatch ever lands.
2734
+ *
2735
+ * Pure given (cwd, baseEnv) + exported for testing.
2736
+ */
2737
+ function buildProbeEnv(cwd, baseEnv = process.env) {
2738
+ const venvBin = join$1(cwd, ".venv", "bin");
2739
+ if (!existsSync(venvBin)) return baseEnv;
2740
+ return {
2741
+ ...baseEnv,
2742
+ VIRTUAL_ENV: join$1(cwd, ".venv"),
2743
+ PATH: `${venvBin}${delimiter}${baseEnv.PATH ?? ""}`
2744
+ };
2745
+ }
2557
2746
  /** Return the last N bytes of a UTF-8 string (sliced by length for simplicity). */
2558
2747
  function tail(text, bytes = PROBE_TAIL_BYTES) {
2559
2748
  return text.length <= bytes ? text : text.slice(text.length - bytes);
@@ -3042,7 +3231,13 @@ function probesInvokeProductionTrigger(probes) {
3042
3231
  for (const probe of probes) for (const pattern of TRIGGER_COMMAND_PATTERNS) if (pattern.test(probe.command)) return true;
3043
3232
  return false;
3044
3233
  }
3045
- const defaultExecutors = { host: (probe, cwd) => executeProbeOnHost(probe, { cwd: cwd ?? process.cwd() }) };
3234
+ const defaultExecutors = { host: (probe, cwd) => {
3235
+ const effectiveCwd = cwd ?? process.cwd();
3236
+ return executeProbeOnHost(probe, {
3237
+ cwd: effectiveCwd,
3238
+ env: buildProbeEnv(effectiveCwd)
3239
+ });
3240
+ } };
3046
3241
  var RuntimeProbeCheck = class {
3047
3242
  name = "runtime-probes";
3048
3243
  tier = "A";
@@ -4257,6 +4452,7 @@ function createDefaultVerificationPipeline(bus, config) {
4257
4452
  new AcceptanceCriteriaEvidenceCheck(),
4258
4453
  new BuildCheck(),
4259
4454
  new TestSuiteCheck(),
4455
+ new ContaminationCheck(),
4260
4456
  new RuntimeProbeCheck(),
4261
4457
  new SourceAcFidelityCheck(),
4262
4458
  new SourceAcShelloutCheck(),
@@ -6040,4 +6236,4 @@ async function resolveRunManifest(dbRoot, runId) {
6040
6236
 
6041
6237
  //#endregion
6042
6238
  export { FindingsInjector, RunManifest, RuntimeProbeListSchema, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, readCurrentRunId, renderFindings, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runStaleVerificationRecovery };
6043
- //# sourceMappingURL=manifest-read-BgZ6mR5R.js.map
6239
+ //# sourceMappingURL=manifest-read-DPN4jjTc.js.map
@@ -1,6 +1,6 @@
1
1
  import "../../logger-KeHncl-f.js";
2
2
  import "../../dist-DiNK6QOD.js";
3
- import "../../manifest-read-BgZ6mR5R.js";
4
- import { runInteractivePrompt } from "../../interactive-prompt-OMlqP7Lm.js";
3
+ import "../../manifest-read-DPN4jjTc.js";
4
+ import { runInteractivePrompt } from "../../interactive-prompt-DTLnCbk2.js";
5
5
 
6
6
  export { runInteractivePrompt };
@@ -1,14 +1,14 @@
1
- import "./health-DTJaiJOd.js";
1
+ import "./health-0kOtC07t.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
4
  import "./dist-DiNK6QOD.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DHHryElL.js";
6
- import "./manifest-read-BgZ6mR5R.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-CUcRdKFK.js";
6
+ import "./manifest-read-DPN4jjTc.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-OMlqP7Lm.js";
11
+ import "./interactive-prompt-DTLnCbk2.js";
12
12
  import "./recovery-engine-BKGBeBnW.js";
13
13
 
14
14
  export { runRunAction };
@@ -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-DTJaiJOd.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-0kOtC07t.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, 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, createPipelineRun, createRequirement, createStderrLogger, 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-DiNK6QOD.js";
5
- import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-BgZ6mR5R.js";
5
+ import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-DPN4jjTc.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-OMlqP7Lm.js";
8
+ import { runInteractivePrompt } from "./interactive-prompt-DTLnCbk2.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";
@@ -7542,6 +7542,12 @@ const logger$20 = createLogger("compiled-workflows:git-helpers");
7542
7542
  * @returns Structured result for the orchestrator to inspect
7543
7543
  */
7544
7544
  async function commitDevStoryOutput(storyKey, storyTitle, filesModified, workingDir) {
7545
+ const COMMIT_DENY_SEGMENTS = [
7546
+ "node_modules",
7547
+ ".venv",
7548
+ "__pycache__",
7549
+ ".substrate-worktrees"
7550
+ ];
7545
7551
  const insideWorktree = [];
7546
7552
  for (const p of filesModified) {
7547
7553
  const abs = isAbsolute(p) ? p : resolve$1(workingDir, p);
@@ -7554,6 +7560,14 @@ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, working
7554
7560
  }, "commitDevStoryOutput: filtered out path outside worktree");
7555
7561
  continue;
7556
7562
  }
7563
+ const segments = rel.replace(/\\/g, "/").split("/");
7564
+ if (segments.some((s$1) => COMMIT_DENY_SEGMENTS.includes(s$1))) {
7565
+ logger$20.warn({
7566
+ path: rel,
7567
+ storyKey
7568
+ }, "commitDevStoryOutput: denylisted dependency/artifact path excluded from substrate commit");
7569
+ continue;
7570
+ }
7557
7571
  insideWorktree.push(rel);
7558
7572
  }
7559
7573
  if (insideWorktree.length === 0) return {
@@ -12619,6 +12633,7 @@ function assembleVerificationContext(opts) {
12619
12633
  outputTokenCount: opts.outputTokenCount,
12620
12634
  sourceEpicContent: opts.sourceEpicContent,
12621
12635
  runId: opts.runId,
12636
+ ...opts.changedFiles !== void 0 ? { changedFiles: opts.changedFiles } : {},
12622
12637
  ...profileBuildCommand !== void 0 ? { buildCommand: profileBuildCommand } : {},
12623
12638
  ...profileTestCommand !== void 0 ? { testCommand: profileTestCommand } : {}
12624
12639
  };
@@ -13490,6 +13505,34 @@ function summarizeEscalationIssues(issues, cap = 4e3) {
13490
13505
  * the opaque verdict. Best-effort: a probe failure yields an empty list (never
13491
13506
  * blocks escalation). Exported for unit testing.
13492
13507
  */
13508
+ /**
13509
+ * H1.4 (hardening program, field finding #13): classify a story's ground-truth
13510
+ * git diff into implementation vs. pipeline-artifact changes.
13511
+ *
13512
+ * The field failure: story 2-3 returned status=complete with "239 tests pass"
13513
+ * while its branch contained ONLY the create-story spec file — zero source,
13514
+ * zero tests (the 239 were the pre-existing suite; true but vacuous). The
13515
+ * zero-diff gate never fired because the spec .md IS a diff entry.
13516
+ *
13517
+ * A file counts as implementation when it lives outside substrate's own
13518
+ * artifact trees (`_bmad-output/`, `.substrate/`). Story specs, planning
13519
+ * artifacts, and manifest state are pipeline bookkeeping — a "successful"
13520
+ * dev pass whose diff is bookkeeping-only produced no implementation.
13521
+ *
13522
+ * Pure + exported for unit testing.
13523
+ */
13524
+ function classifyImplementationDiff(files) {
13525
+ const isArtifact = (f$1) => {
13526
+ const norm = f$1.replace(/\\/g, "/").replace(/^\.\//, "");
13527
+ return norm.startsWith("_bmad-output/") || norm.startsWith(".substrate/");
13528
+ };
13529
+ const artifactOnly = files.filter(isArtifact);
13530
+ const hasImplementation = files.some((f$1) => !isArtifact(f$1));
13531
+ return {
13532
+ hasImplementation,
13533
+ artifactOnly
13534
+ };
13535
+ }
13493
13536
  function detectWorkOutsideWorktree(effectiveProjectRoot, projectRoot, checkDiff) {
13494
13537
  const inWorktreeMode = effectiveProjectRoot !== void 0 && projectRoot !== void 0 && effectiveProjectRoot !== projectRoot;
13495
13538
  if (!inWorktreeMode) return [];
@@ -15700,6 +15743,31 @@ function createImplementationOrchestrator(deps) {
15700
15743
  }
15701
15744
  }
15702
15745
  }
15746
+ if (devStoryWasSuccess && gitDiffFiles !== void 0 && gitDiffFiles.length > 0) {
15747
+ const implClassification = classifyImplementationDiff(gitDiffFiles);
15748
+ if (!implClassification.hasImplementation) {
15749
+ logger$27.warn({
15750
+ storyKey,
15751
+ artifactFiles: implClassification.artifactOnly.slice(0, 10)
15752
+ }, "dev-story reported success but the diff contains only pipeline artifacts — no implementation was produced");
15753
+ endPhase(storyKey, "dev-story", devStoryModel);
15754
+ updateStory(storyKey, {
15755
+ phase: "ESCALATED",
15756
+ error: "no-implementation",
15757
+ completedAt: new Date().toISOString()
15758
+ });
15759
+ await writeStoryMetricsBestEffort(storyKey, "escalated", 0);
15760
+ await emitEscalation({
15761
+ storyKey,
15762
+ lastVerdict: "no-implementation",
15763
+ reviewCycles: 0,
15764
+ issues: [`dev-story reported COMPLETE but every changed file is a pipeline artifact (${implClassification.artifactOnly.slice(0, 10).join(", ")}) — no source or test files were produced. Self-reported test results on such a story are vacuous (they exercise the pre-existing suite).`],
15765
+ escalationReason: "no-implementation"
15766
+ });
15767
+ await persistState();
15768
+ return;
15769
+ }
15770
+ }
15703
15771
  let _devOutputCommitHookFailure;
15704
15772
  const _commitFirstEligible = !noWorktree && _worktreeManager !== void 0 && effectiveProjectRoot !== void 0 && effectiveProjectRoot !== projectRoot;
15705
15773
  if (_commitFirstEligible && effectiveProjectRoot !== void 0) {
@@ -16056,6 +16124,7 @@ function createImplementationOrchestrator(deps) {
16056
16124
  devStoryResult: devStorySignals,
16057
16125
  outputTokenCount: devOutputTokenCount,
16058
16126
  sourceEpicContent,
16127
+ ...gitDiffFiles !== void 0 ? { changedFiles: gitDiffFiles } : {},
16059
16128
  runId: config.pipelineRunId
16060
16129
  });
16061
16130
  const verifSummary = await verificationPipeline.run(verifContext, "A");
@@ -29968,7 +30037,7 @@ var require_uri_all = __commonJS({ "node_modules/uri-js/dist/es5/uri.all.js"(exp
29968
30037
  var damp = 700;
29969
30038
  var initialBias = 72;
29970
30039
  var initialN = 128;
29971
- var delimiter = "-";
30040
+ var delimiter$1 = "-";
29972
30041
  /** Regular expressions */
29973
30042
  var regexPunycode = /^xn--/;
29974
30043
  var regexNonASCII = /[^\0-\x7E]/;
@@ -30123,7 +30192,7 @@ var require_uri_all = __commonJS({ "node_modules/uri-js/dist/es5/uri.all.js"(exp
30123
30192
  var i = 0;
30124
30193
  var n$1 = initialN;
30125
30194
  var bias = initialBias;
30126
- var basic = input.lastIndexOf(delimiter);
30195
+ var basic = input.lastIndexOf(delimiter$1);
30127
30196
  if (basic < 0) basic = 0;
30128
30197
  for (var j$1 = 0; j$1 < basic; ++j$1) {
30129
30198
  if (input.charCodeAt(j$1) >= 128) error$1("not-basic");
@@ -30185,7 +30254,7 @@ var require_uri_all = __commonJS({ "node_modules/uri-js/dist/es5/uri.all.js"(exp
30185
30254
  }
30186
30255
  var basicLength = output.length;
30187
30256
  var handledCPCount = basicLength;
30188
- if (basicLength) output.push(delimiter);
30257
+ if (basicLength) output.push(delimiter$1);
30189
30258
  while (handledCPCount < inputLength) {
30190
30259
  var m = maxInt;
30191
30260
  var _iteratorNormalCompletion2 = true;
@@ -48068,4 +48137,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
48068
48137
 
48069
48138
  //#endregion
48070
48139
  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, createGitWorktreeManager, 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 };
48071
- //# sourceMappingURL=run-DHHryElL.js.map
48140
+ //# sourceMappingURL=run-CUcRdKFK.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.142",
3
+ "version": "0.20.144",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -8,6 +8,10 @@ You are a **probe-author agent**. Your sole responsibility is to author `## Runt
8
8
 
9
9
  ## Context
10
10
 
11
+ ### Project Environment
12
+
13
+ {{project_env}}
14
+
11
15
  ### Rendered Acceptance Criteria (Story Artifact)
12
16
 
13
17
  The following is the story's rendered AC section, as produced by the create-story agent: