substrate-ai 0.20.48 → 0.20.50

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,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorMetrics } from "../health-BV-rzjf7.js";
2
+ import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorMetrics } from "../health-sQ1X_5_6.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, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-VcMmfo2w.js";
6
6
  import "../adapter-registry-DXLMTmfD.js";
7
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, validateStopAfterFromConflict } from "../run-Cdu2K3tg.js";
7
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, validateStopAfterFromConflict } from "../run-CFRXRuRO.js";
8
8
  import "../errors-CogpxBUg.js";
9
9
  import "../routing-CcBOCuC9.js";
10
10
  import "../decisions-C0pz9Clx.js";
@@ -3667,7 +3667,7 @@ async function runStatusAction(options) {
3667
3667
  logger$13.debug({ err }, "Work graph query failed, continuing without work graph data");
3668
3668
  }
3669
3669
  if (run === void 0) {
3670
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-DQrsmYTt.js");
3670
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-BQ5dj53s.js");
3671
3671
  const substrateDirPath = join(projectRoot, ".substrate");
3672
3672
  const processInfo = inspectProcessTree$1({
3673
3673
  projectRoot,
@@ -5204,7 +5204,7 @@ async function runSupervisorAction(options, deps = {}) {
5204
5204
  await initSchema(expAdapter);
5205
5205
  const { runRunAction: runPipeline } = await import(
5206
5206
  /* @vite-ignore */
5207
- "../run-syUfEHEq.js"
5207
+ "../run-C6jy25us.js"
5208
5208
  );
5209
5209
  const runStoryFn = async (opts) => {
5210
5210
  const exitCode = await runPipeline({
@@ -1,4 +1,4 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-BV-rzjf7.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-sQ1X_5_6.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./dist-VcMmfo2w.js";
4
4
  import "./decisions-C0pz9Clx.js";
@@ -4135,6 +4135,101 @@ function detectsEventDrivenAC(sourceEpicContent) {
4135
4135
  return false;
4136
4136
  }
4137
4137
  /**
4138
+ * Source-AC keywords that signal a state-integrating implementation. The six
4139
+ * categories — subprocess, filesystem, git, database, network, registry —
4140
+ * mirror the behavioral-signal enumeration in the create-story.md prompt
4141
+ * (Phase 1, v0.20.42, obs_2026-05-01_017 hotfix).
4142
+ *
4143
+ * Code identifiers are case-sensitive (e.g., `execSync(`, `Dolt`).
4144
+ * Natural-language phrases are case-insensitive (e.g., "reads from disk").
4145
+ *
4146
+ * Used by `detectsStateIntegratingAC` to gate probe-author dispatch for
4147
+ * state-integrating stories whose ACs do NOT use event-driven phrasing
4148
+ * (hooks, timers, signals, webhooks). Coexists with `EVENT_DRIVEN_KEYWORDS`:
4149
+ * ACs matching both heuristics trigger a single probe-author dispatch.
4150
+ */
4151
+ const STATE_INTEGRATING_KEYWORDS = [
4152
+ /\bexecSync\(/,
4153
+ /\bspawn\(/,
4154
+ /\bexec\(/,
4155
+ /\bchild_process\b/,
4156
+ /\bspawns\b/i,
4157
+ /\binvokes?\b/i,
4158
+ /\bfs\.read/,
4159
+ /\bfs\.write/,
4160
+ /\breadFile\b/,
4161
+ /\bwriteFile\b/,
4162
+ /\bpath\.join\b/,
4163
+ /\bhomedir\(\)/,
4164
+ /\bos\.homedir\(\)/,
4165
+ /\breads?\s+from\s+disk\b/i,
4166
+ /\bwrites?\s+to\s+disk\b/i,
4167
+ /\bscans?\s+(?:the\s+)?filesystem\b/i,
4168
+ /\bgit\s+log\b/,
4169
+ /\bgit\s+push\b/,
4170
+ /\bgit\s+pull\b/,
4171
+ /\bgit\s+merge\b/,
4172
+ /\bqueries?\s+git\b/i,
4173
+ /\bruns?\s+git\b/i,
4174
+ /\bDolt\b/,
4175
+ /\bmysql\b/i,
4176
+ /\bpg\b/,
4177
+ /\bsqlite\b/i,
4178
+ /\bINSERT\b/,
4179
+ /\bSELECT\b/,
4180
+ /\bqueries?\s+the\s+database\b/i,
4181
+ /\bwrites?\s+to\s+[Dd]olt\b/,
4182
+ /\bfetch\(/,
4183
+ /\baxios\b/i,
4184
+ /\bhttp\.get\(/,
4185
+ /\bhttps\.get\(/,
4186
+ /\bfetches?\b/i,
4187
+ /\bPOSTs?\s+to\b/i,
4188
+ /\bcalls?\s+the\s+API\b/i,
4189
+ /\bqueries?\s+(?:the\s+)?registry\b/i,
4190
+ /\bscans?\s+(?:the\s+)?registry\b/i
4191
+ ];
4192
+ /** Phrases that indicate a keyword match is in a mock/stub context (not real state). */
4193
+ const MOCK_QUALIFIER_PHRASES = [
4194
+ "mocks the",
4195
+ "stubs the",
4196
+ "mock ",
4197
+ "stub "
4198
+ ];
4199
+ /**
4200
+ * Returns true when a line contains a mock/stub qualifier, indicating the
4201
+ * keyword match is in a test-double context rather than production state.
4202
+ */
4203
+ function lineHasMockQualifier(line) {
4204
+ const lower = line.toLowerCase();
4205
+ return MOCK_QUALIFIER_PHRASES.some((phrase) => lower.includes(phrase));
4206
+ }
4207
+ /**
4208
+ * Returns true if the source AC text mentions a state-integrating operation:
4209
+ * subprocess, filesystem, git, database, network, or registry interaction.
4210
+ *
4211
+ * Exported for use by probe-author-integration.ts (Story 65-1) so the
4212
+ * orchestrator can gate probe-author dispatch on the same heuristic.
4213
+ *
4214
+ * Mock guard (AC #4): scans each matching line for mock/stub qualifiers
4215
+ * ("mocks the", "stubs the", "mock ", "stub "). If every match is in a
4216
+ * mock context, returns false — ground truth is whether the production
4217
+ * code path hits real state. If any match is NOT in a mock context,
4218
+ * returns true.
4219
+ *
4220
+ * Coexists with `detectsEventDrivenAC` (Story 60-11): when an AC matches
4221
+ * both heuristics, the orchestrator dispatches probe-author once (dispatch
4222
+ * gate uses `||`). No double-dispatch.
4223
+ */
4224
+ function detectsStateIntegratingAC(sourceContent) {
4225
+ const lines = sourceContent.split("\n");
4226
+ for (const line of lines) {
4227
+ const hasKeyword = STATE_INTEGRATING_KEYWORDS.some((p) => p.test(line));
4228
+ if (hasKeyword && !lineHasMockQualifier(line)) return true;
4229
+ }
4230
+ return false;
4231
+ }
4232
+ /**
4138
4233
  * Returns true if any probe's command line invokes a known production trigger.
4139
4234
  */
4140
4235
  function probesInvokeProductionTrigger(probes) {
@@ -6779,5 +6874,5 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
6779
6874
  }
6780
6875
 
6781
6876
  //#endregion
6782
- export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, __commonJS, __require, __toESM, aggregateProbeAuthorMetrics, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, createStateStore, detectCycles, detectsEventDrivenAC, extractTargetFilesFromStoryContent, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, renderFindings, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorMetrics, runHealthAction, validateStoryKey };
6783
- //# sourceMappingURL=health-BV-rzjf7.js.map
6877
+ export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, __commonJS, __require, __toESM, aggregateProbeAuthorMetrics, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, createStateStore, detectCycles, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, renderFindings, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorMetrics, runHealthAction, validateStoryKey };
6878
+ //# sourceMappingURL=health-sQ1X_5_6.js.map
@@ -1,8 +1,8 @@
1
- import "./health-BV-rzjf7.js";
1
+ import "./health-sQ1X_5_6.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
4
  import "./dist-VcMmfo2w.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-Cdu2K3tg.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-CFRXRuRO.js";
6
6
  import "./routing-CcBOCuC9.js";
7
7
  import "./decisions-C0pz9Clx.js";
8
8
 
@@ -1,4 +1,4 @@
1
- import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-BV-rzjf7.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-sQ1X_5_6.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, 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, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-VcMmfo2w.js";
@@ -8412,8 +8412,11 @@ const TIMEOUT_RETRY_MULTIPLIER = 1.5;
8412
8412
  /**
8413
8413
  * Execute the probe-author integration phase.
8414
8414
  *
8415
- * Gate 1 — Event-driven AC check: calls `detectsEventDrivenAC(epicContent)`.
8416
- * Skip if the source AC does not describe a hook, timer, signal, or webhook.
8415
+ * Gate 1 — Event-driven or state-integrating AC check: calls
8416
+ * `detectsEventDrivenAC(epicContent)` and `detectsStateIntegratingAC(epicContent)`
8417
+ * (Story 65-1). Skip if the source AC describes neither an event-driven
8418
+ * mechanism (hook, timer, signal, webhook) nor a state-integrating operation
8419
+ * (subprocess, filesystem, git, database, network, registry).
8417
8420
  *
8418
8421
  * Gate 2 — Idempotency check: reads storyFilePath and checks for an existing
8419
8422
  * `## Runtime Probes` section. Skip if present (probes already authored).
@@ -8440,8 +8443,8 @@ async function runProbeAuthor(deps, params) {
8440
8443
  input: 0,
8441
8444
  output: 0
8442
8445
  };
8443
- if (bypassGates !== true && !detectsEventDrivenAC(epicContent)) {
8444
- logger$14.debug({ storyKey }, "probe-author: source AC not event-driven — skipping");
8446
+ if (bypassGates !== true && !detectsEventDrivenAC(epicContent) && !detectsStateIntegratingAC(epicContent)) {
8447
+ logger$14.debug({ storyKey }, "probe-author: source AC neither event-driven nor state-integrating — skipping");
8445
8448
  emitEvent?.("probe-author:skipped", {
8446
8449
  storyKey,
8447
8450
  runId: pipelineRunId,
@@ -13443,7 +13446,7 @@ function createImplementationOrchestrator(deps) {
13443
13446
  const section = extractStorySection(epicFull, storyKey);
13444
13447
  probeAuthorEpicContent = section ?? epicFull;
13445
13448
  } catch {}
13446
- if (detectsEventDrivenAC(probeAuthorEpicContent)) {
13449
+ if (detectsEventDrivenAC(probeAuthorEpicContent) || detectsStateIntegratingAC(probeAuthorEpicContent)) {
13447
13450
  let artifactHasProbes = false;
13448
13451
  try {
13449
13452
  const artifactContent = readFileSync(storyFilePath, "utf-8");
@@ -45366,4 +45369,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
45366
45369
 
45367
45370
  //#endregion
45368
45371
  export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, validateStopAfterFromConflict, wireNdjsonEmitter };
45369
- //# sourceMappingURL=run-Cdu2K3tg.js.map
45372
+ //# sourceMappingURL=run-CFRXRuRO.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.48",
3
+ "version": "0.20.50",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,312 @@
1
+ ##
2
+ # Probe-Author State-Integrating Defect Corpus
3
+ #
4
+ # Version: v1 (2026-05-03)
5
+ # Substrate version when corpus authored: v0.20.49
6
+ #
7
+ # Purpose: Oracle for the state-integrating eval harness
8
+ # (Story 65-3, scripts/eval-probe-author-state-integrating.mjs).
9
+ # Each entry documents a defect class where the broken implementation
10
+ # reads/writes/queries external state incorrectly. The eval dispatches
11
+ # probe-author against each entry's source_ac and asserts that the
12
+ # authored probe's shape matches the entry's signature regexes.
13
+ #
14
+ # Schema (each applicable_entries item):
15
+ # id — unique kebab-label
16
+ # story_key — optional; reference only
17
+ # description — one-line human label
18
+ # source_ac — AC text sent to probe-author
19
+ # broken_implementation — what the broken impl does
20
+ # real_state_condition — the real-state condition that breaks it
21
+ # signature — non-empty list of regex strings; ALL must
22
+ # match JSON.stringify(probe) for ANY probe
23
+ # mock_authored_probes — ≥1 probe; used in --dry-run mode
24
+ ##
25
+
26
+ applicable_entries:
27
+ - id: entry-1-obs017-git-log-wrong-cwd
28
+ story_key: '2-4'
29
+ description: git log called with cwd=fleetRoot instead of per-project directory
30
+ source_ac: |
31
+ For each project repository in the fleet, the morning briefing generator
32
+ reads the most recent 10 commits authored in the last 24 hours using
33
+ `git log --since=24h --format="%H %s" --no-merges`. Attribution must be
34
+ per-project: commits from repository A must not appear in the briefing
35
+ for repository B. The implementation invokes `git log` with the correct
36
+ `cwd` set to each project's root directory.
37
+ broken_implementation: |
38
+ fetchGitLog() calls `execSync('git log ...', { cwd: fleetRoot })` where
39
+ fleetRoot is the top-level directory containing all project subdirectories.
40
+ All commits from all repos are attributed to every project, causing
41
+ cross-project commit leakage.
42
+ real_state_condition: |
43
+ Two or more git repositories exist as sibling directories under a common
44
+ parent. Each repo has distinct commits. The broken implementation returns
45
+ all commits regardless of which project directory is requested.
46
+ signature:
47
+ - 'git\s+log'
48
+ - 'alpha|beta|fleet|project.?[AB]|repo.?[12]|tmpdir|mkdtemp'
49
+ mock_authored_probes:
50
+ - name: per-project-git-log-attribution
51
+ sandbox: host
52
+ command: |
53
+ # Create two sibling repos with distinct commits
54
+ PARENT=$(mktemp -d)
55
+ mkdir -p "$PARENT/repo-alpha" "$PARENT/repo-beta"
56
+ cd "$PARENT/repo-alpha" && git init && git config user.email "t@t" && git config user.name "T"
57
+ echo "alpha" > a.txt && git add . && git commit -m "alpha commit"
58
+ cd "$PARENT/repo-beta" && git init && git config user.email "t@t" && git config user.name "T"
59
+ echo "beta" > b.txt && git add . && git commit -m "beta commit"
60
+ # Probe: verify git log is called per-project, not for the fleet root
61
+ # Run git log for repo-alpha and confirm only alpha commits appear
62
+ OUTPUT=$(cd "$PARENT/repo-alpha" && git log --format="%s" 2>&1)
63
+ echo "$OUTPUT"
64
+ echo "$OUTPUT" | grep -q "alpha commit" && echo "alpha-found" || echo "alpha-missing"
65
+ echo "$OUTPUT" | grep -q "beta commit" && echo "beta-found" || echo "beta-missing"
66
+ expect_stdout_regex:
67
+ - 'alpha-found'
68
+ expect_stdout_no_regex:
69
+ - 'beta-found'
70
+
71
+ - id: entry-2-subprocess-synthesized-vs-real
72
+ story_key: '2-5'
73
+ description: npm outdated called with mocked input instead of real subprocess
74
+ source_ac: |
75
+ The dependency staleness checker invokes `npm outdated --json` as a real
76
+ subprocess in the project directory. The output JSON is parsed to identify
77
+ packages where the `current` version is behind `wanted` or `latest`. The
78
+ implementation must NOT use cached or synthetic data; it must invoke npm
79
+ as an external process each time.
80
+ broken_implementation: |
81
+ runDependencyCheck() returns a hardcoded JSON fixture `{ "lodash": { "current":
82
+ "4.17.20", "wanted": "4.17.21", "latest": "4.17.21" } }` instead of
83
+ spawning a real npm process. Tests pass but the feature silently shows
84
+ stale data in production.
85
+ real_state_condition: |
86
+ A real npm project directory with a package.json exists on disk. The
87
+ real npm outdated output differs from the hardcoded fixture (either
88
+ empty or different packages).
89
+ signature:
90
+ - 'npm\s+outdated'
91
+ - 'current|wanted|latest|outdated'
92
+ mock_authored_probes:
93
+ - name: npm-outdated-real-subprocess
94
+ sandbox: host
95
+ command: |
96
+ # Create a minimal npm project
97
+ TMPDIR=$(mktemp -d)
98
+ cd "$TMPDIR"
99
+ echo '{"name":"probe-test","version":"1.0.0","dependencies":{}}' > package.json
100
+ npm install --silent
101
+ # Run the implementation — it must invoke npm outdated, not return a fixture
102
+ node dist/cli/index.js dependency-check --project "$TMPDIR" --output json
103
+ expect_stdout_regex:
104
+ - '\{|\[|dependencies|outdated|packages'
105
+ expect_stdout_no_regex:
106
+ - 'fixture|mock|synthetic|hardcoded'
107
+
108
+ - id: entry-3-tilde-path-not-expanded
109
+ story_key: '2-6'
110
+ description: fs.readFileSync called with literal tilde path instead of expanded home directory
111
+ source_ac: |
112
+ The configuration reader reads the user's config file at `~/.config/myapp/config.json`.
113
+ The path must be expanded to the actual home directory before reading. The implementation
114
+ uses `os.homedir()` or equivalent to resolve `~` to the absolute path. A literal
115
+ `~` in the path passed to `fs.readFileSync` is not a valid filesystem path on Linux/macOS.
116
+ broken_implementation: |
117
+ configReader() calls `fs.readFileSync('~/.config/myapp/config.json', 'utf8')`.
118
+ The literal tilde is not expanded by Node.js's fs module, causing ENOENT
119
+ on every read even when the config file exists at the real path.
120
+ real_state_condition: |
121
+ The config file exists at the real expanded path (e.g., /home/user/.config/myapp/config.json)
122
+ but does NOT exist at the literal path `~/.config/myapp/config.json`. The broken
123
+ implementation throws ENOENT while the correct implementation reads successfully.
124
+ signature:
125
+ - 'HOME|homedir\(\)|\$HOME|home.*dir'
126
+ - '\.config|config\.json|tilde|~'
127
+ mock_authored_probes:
128
+ - name: config-path-tilde-expansion
129
+ sandbox: host
130
+ command: |
131
+ # Ensure config file exists at real expanded path
132
+ REAL_CONFIG="$HOME/.config/myapp/config.json"
133
+ mkdir -p "$(dirname "$REAL_CONFIG")"
134
+ echo '{"setting":"value"}' > "$REAL_CONFIG"
135
+ # Implementation must read it successfully
136
+ node dist/cli/index.js config read
137
+ expect_stdout_regex:
138
+ - 'setting|value|config'
139
+ expect_stdout_no_regex:
140
+ - 'ENOENT|no such file|tilde'
141
+
142
+ - id: entry-4-db-mocked-vs-real
143
+ story_key: '2-7'
144
+ description: DB query returns canned response instead of real Dolt wg_stories state
145
+ source_ac: |
146
+ The sprint planning report queries the `wg_stories` Dolt table for all
147
+ stories with `status = 'PLANNED'` in the current sprint. The query must
148
+ execute against the live Dolt database; the result count must reflect
149
+ the actual number of planned stories. Using an in-memory mock or
150
+ hardcoded fixture is not acceptable.
151
+ broken_implementation: |
152
+ queryPlannedStories() returns a hardcoded array `[{ id: 'fake-1', status:
153
+ 'PLANNED', sprint: 1 }]` without connecting to Dolt. The sprint planning
154
+ report always shows 1 planned story regardless of actual database state.
155
+ real_state_condition: |
156
+ The Dolt database has 0 or ≥2 planned stories. The broken implementation
157
+ always returns exactly 1, masking the real state.
158
+ signature:
159
+ - 'dolt|mysql|wg_stories|planned.stories'
160
+ - 'PLANNED|status.*planned|count|rowCount'
161
+ mock_authored_probes:
162
+ - name: wg-stories-planned-count-from-db
163
+ sandbox: host
164
+ command: |
165
+ # Query the real Dolt database for planned stories
166
+ node dist/cli/index.js status --output-format json | \
167
+ node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); \
168
+ console.log(JSON.stringify({planned: (d.stories||[]).filter(s=>s.status==='PLANNED').length}))"
169
+ expect_stdout_regex:
170
+ - 'planned'
171
+ expect_stdout_no_regex:
172
+ - 'mock|fixture|fake|hardcoded'
173
+
174
+ - id: entry-5-network-mocked-vs-real
175
+ story_key: '2-8'
176
+ description: npm registry fetch intercepted by test double instead of real network call
177
+ source_ac: |
178
+ The version checker fetches the latest published version of a package from
179
+ the npm registry using `npm view <package> version` or `https://registry.npmjs.org/<package>/latest`.
180
+ The fetch must reach the real npm registry; intercepted or cached responses
181
+ are not acceptable. The result is compared against the locally installed version.
182
+ broken_implementation: |
183
+ getLatestVersion() returns a hardcoded version string `"1.2.3"` without
184
+ making any network request. The comparison always uses stale data, masking
185
+ cases where the registry has a newer version.
186
+ real_state_condition: |
187
+ The real npm registry has a version for the package that may differ from
188
+ the hardcoded `"1.2.3"`. The broken implementation always returns `"1.2.3"`.
189
+ signature:
190
+ - 'npm\s+view|registry\.npmjs|npm.*version'
191
+ - 'latest|version|registry|current'
192
+ mock_authored_probes:
193
+ - name: npm-registry-fetch-real-version
194
+ sandbox: host
195
+ command: |
196
+ # Verify the version checker reaches the real registry
197
+ node dist/cli/index.js check-version --package js-yaml --output json
198
+ expect_stdout_regex:
199
+ - 'version|latest|current'
200
+ expect_stdout_no_regex:
201
+ - '1\.2\.3|hardcoded|mock|fixture'
202
+
203
+ - id: entry-6-registry-scan-single-vs-multi
204
+ story_key: '2-9'
205
+ description: registry scan passes on single-package workspace but fails on multi-package monorepo
206
+ source_ac: |
207
+ The workspace version-constraint scanner reads all `package.json` files in
208
+ a monorepo workspace and reports packages where the declared version in one
209
+ workspace package conflicts with the version declared in another. The scanner
210
+ must handle workspaces with ≥2 packages. A single-package workspace is not
211
+ a valid test fixture for cross-package constraint detection.
212
+ broken_implementation: |
213
+ scanVersionConstraints() only reads the root `package.json` and ignores
214
+ sub-package `package.json` files. It passes on single-package workspaces
215
+ but misses cross-package conflicts in real multi-package monorepos.
216
+ real_state_condition: |
217
+ A workspace with ≥2 packages exists, where package A declares `"lodash": "^4.17.0"`
218
+ and package B declares `"lodash": "^3.10.0"`. The broken implementation
219
+ reports no conflicts; the correct implementation reports the constraint mismatch.
220
+ signature:
221
+ - 'mktemp|tmpdir|tmp.*dir'
222
+ - 'package\.json|workspace|monorepo|packages'
223
+ mock_authored_probes:
224
+ - name: multi-package-version-constraint-scan
225
+ sandbox: host
226
+ command: |
227
+ # Create a two-package monorepo fixture
228
+ ROOT=$(mktemp -d)
229
+ mkdir -p "$ROOT/packages/pkg-a" "$ROOT/packages/pkg-b"
230
+ echo '{"name":"root","workspaces":["packages/*"]}' > "$ROOT/package.json"
231
+ echo '{"name":"pkg-a","dependencies":{"lodash":"^4.17.0"}}' > "$ROOT/packages/pkg-a/package.json"
232
+ echo '{"name":"pkg-b","dependencies":{"lodash":"^3.10.0"}}' > "$ROOT/packages/pkg-b/package.json"
233
+ node dist/cli/index.js scan-constraints --root "$ROOT" --output json
234
+ expect_stdout_regex:
235
+ - 'conflict|mismatch|lodash|constraint'
236
+ expect_stdout_no_regex:
237
+ - 'no conflicts|clean|ok'
238
+
239
+ - id: entry-7-git-op-empty-vs-real-repo
240
+ story_key: '2-10'
241
+ description: git tag/describe returns empty on empty repo but silently passes
242
+ source_ac: |
243
+ The release versioner reads the latest git tag from the repository using
244
+ `git tag --sort=-version:refname` or `git describe --tags --abbrev=0`.
245
+ The result must be a non-empty string representing the most recent version tag.
246
+ On a repository with no tags, the implementation must return an explicit error
247
+ or default value, not an empty string silently treated as a valid version.
248
+ broken_implementation: |
249
+ getLatestTag() runs `git tag` in the repo and returns the first line of output.
250
+ On a fresh repository with no tags, `git tag` returns empty output, and the
251
+ function returns an empty string `""` which is used as a version string
252
+ without validation, causing downstream failures.
253
+ real_state_condition: |
254
+ A git repository with ≥1 annotated or lightweight tag exists. The probe
255
+ must assert that the output is a non-empty version string matching a semver
256
+ pattern (e.g., `v1.0.0` or `1.0.0`).
257
+ signature:
258
+ - 'git\s+tag|git\s+describe'
259
+ - 'v\d+\.\d+|semver|non.?empty|tag.*version|version.*tag'
260
+ mock_authored_probes:
261
+ - name: git-tag-non-empty-assertion
262
+ sandbox: host
263
+ command: |
264
+ # Create a git repo with a real tag
265
+ REPO=$(mktemp -d)
266
+ cd "$REPO" && git init && git config user.email "t@t" && git config user.name "T"
267
+ echo "init" > README.md && git add . && git commit -m "initial"
268
+ git tag v1.0.0
269
+ # Run the versioner — must return the tag, not empty
270
+ node dist/cli/index.js get-version --repo "$REPO"
271
+ expect_stdout_regex:
272
+ - 'v1\.0\.0|1\.0\.0'
273
+ expect_stdout_no_regex:
274
+ - '^$|empty|undefined|null'
275
+
276
+ - id: entry-8-spawn-swallows-nonzero-exit
277
+ story_key: '2-11'
278
+ description: spawn invocation ignores non-zero exit code from tsc, masking TypeScript errors
279
+ source_ac: |
280
+ The TypeScript validation step runs `tsc --noEmit` to check for compile
281
+ errors. If `tsc` exits with a non-zero exit code, the validation must
282
+ report failure. The implementation must not swallow the exit code; a
283
+ TypeScript compile error in the project must cause the validation to
284
+ return a failure result, not a success result.
285
+ broken_implementation: |
286
+ runTscCheck() spawns `tsc --noEmit` but wraps the call in a try/catch
287
+ that catches ENOENT and sets result.success=true on any other error
288
+ (including non-zero exit). TypeScript compile errors are silently
289
+ treated as validation success.
290
+ real_state_condition: |
291
+ A TypeScript file with a deliberate type error (e.g., `const x: number = "string"`)
292
+ exists. The broken implementation reports success; the correct implementation
293
+ reports failure with the tsc error output.
294
+ signature:
295
+ - 'tsc'
296
+ - 'exit.*code|exitCode|nonzero|non.zero|status.*[^0]|process\.exit'
297
+ mock_authored_probes:
298
+ - name: tsc-nonzero-exit-detected
299
+ sandbox: host
300
+ command: |
301
+ # Create a TS file with a deliberate type error
302
+ TMPDIR=$(mktemp -d)
303
+ echo '{"compilerOptions":{"strict":true,"noEmit":true}}' > "$TMPDIR/tsconfig.json"
304
+ echo 'const x: number = "this is a string error";' > "$TMPDIR/bad.ts"
305
+ # Run the TypeScript validation — must detect and report failure
306
+ node dist/cli/index.js validate-ts --project "$TMPDIR" --output json; true
307
+ expect_stdout_regex:
308
+ - 'error|fail|invalid|type.*error|tsc.*error'
309
+ expect_stdout_no_regex:
310
+ - '"success":true|"valid":true|"passed":true'
311
+
312
+ excluded_entries: []