substrate-ai 0.20.47 → 0.20.48

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
@@ -4,7 +4,7 @@ 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-BYMVrlGZ.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";
8
8
  import "../errors-CogpxBUg.js";
9
9
  import "../routing-CcBOCuC9.js";
10
10
  import "../decisions-C0pz9Clx.js";
@@ -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-Dwru4oKj.js"
5207
+ "../run-syUfEHEq.js"
5208
5208
  );
5209
5209
  const runStoryFn = async (opts) => {
5210
5210
  const exitCode = await runPipeline({
@@ -6082,6 +6082,61 @@ const WORD_TO_NUMBER = {
6082
6082
  nine: 9,
6083
6083
  ten: 10
6084
6084
  };
6085
+ /**
6086
+ * obs_2026-05-03_021: nouns that genuinely end in `-s` in their singular form
6087
+ * — must NOT be lemma-stripped (would yield `proces`, `statu`, `busines`).
6088
+ * The list is the conservative set of common engineering vocabulary; broader
6089
+ * coverage can be added as new false-strips surface.
6090
+ */
6091
+ const LEMMA_STOPLIST = new Set([
6092
+ "process",
6093
+ "status",
6094
+ "class",
6095
+ "access",
6096
+ "success",
6097
+ "address",
6098
+ "business",
6099
+ "analysis",
6100
+ "basis",
6101
+ "crisis",
6102
+ "thesis",
6103
+ "axis",
6104
+ "series",
6105
+ "species"
6106
+ ]);
6107
+ /**
6108
+ * obs_2026-05-03_021: collapse plural ↔ singular noun forms to a shared
6109
+ * lemma so that the source AC's plural ("functions") and the rendered story's
6110
+ * singular code-form (`'function'`) compare on the same key.
6111
+ *
6112
+ * Strata Story 1-11b's failure shape was a canonical TS/JS rendering: source
6113
+ * AC says "X and Y are both **functions**" (prose plural), rendered story
6114
+ * expresses the same constraint as `typeof X === 'function' && typeof Y === 'function'`
6115
+ * (singular literal in backticks). The pre-fix heuristic counted plural
6116
+ * forms only, saw source=2, rendered=0, escalated as drift after 2 retries.
6117
+ *
6118
+ * Rules (priority order):
6119
+ * - Stoplist hit → return as-is (preserves `process`, `status`, etc.)
6120
+ * - `-ies` suffix (≥5 chars) → strip + 'y' (categories → category)
6121
+ * - `-es` suffix (≥5 chars) where stem ends in s/x/z/ch/sh → strip 'es' (classes → class, boxes → box, watches → watch)
6122
+ * - `-s` suffix (≥4 chars) → strip (functions → function, tools → tool)
6123
+ * - otherwise return as-is
6124
+ */
6125
+ function lemmatizeNoun(noun) {
6126
+ const lower = noun.toLowerCase();
6127
+ if (LEMMA_STOPLIST.has(lower)) return lower;
6128
+ if (lower.length >= 5 && lower.endsWith("ies")) return lower.slice(0, -3) + "y";
6129
+ if (lower.length >= 5 && lower.endsWith("ches")) {
6130
+ if (lower.endsWith("tches")) return lower.slice(0, -2);
6131
+ return lower.slice(0, -1);
6132
+ }
6133
+ if (lower.length >= 5 && lower.endsWith("es")) {
6134
+ const stem = lower.slice(0, -2);
6135
+ if (/[sxz]$/.test(stem) || /sh$/.test(stem)) return stem;
6136
+ }
6137
+ if (lower.length >= 4 && lower.endsWith("s")) return lower.slice(0, -1);
6138
+ return lower;
6139
+ }
6085
6140
  function extractBehavioralAssertions(content) {
6086
6141
  if (content.length === 0) return {
6087
6142
  whenClauseCount: 0,
@@ -6113,13 +6168,33 @@ function extractBehavioralAssertions(content) {
6113
6168
  }
6114
6169
  if (noun.length < 3) continue;
6115
6170
  const phrase = `${determiner} ${numStr || (determiner === "both" ? "" : "")} ${noun}`.trim().replace(/\s+/g, " ");
6116
- const dedupKey = `${count}|${noun}`;
6171
+ const lemma = lemmatizeNoun(noun);
6172
+ const dedupKey = `${count}|${lemma}`;
6117
6173
  if (seen.has(dedupKey)) continue;
6118
6174
  seen.add(dedupKey);
6119
6175
  numericQuantifiers.push({
6120
6176
  phrase,
6121
6177
  count,
6122
- noun
6178
+ noun: lemma
6179
+ });
6180
+ }
6181
+ const backtickLiteralPattern = /`[^`]*?'([a-z][a-z_-]+)'[^`]*?`/gi;
6182
+ const backtickCounts = new Map();
6183
+ let blMatch;
6184
+ while ((blMatch = backtickLiteralPattern.exec(content)) !== null) {
6185
+ const rawNoun = blMatch[1]?.toLowerCase() ?? "";
6186
+ if (rawNoun.length < 3) continue;
6187
+ const lemma = lemmatizeNoun(rawNoun);
6188
+ backtickCounts.set(lemma, (backtickCounts.get(lemma) ?? 0) + 1);
6189
+ }
6190
+ for (const [lemma, count] of backtickCounts) {
6191
+ const dedupKey = `${count}|${lemma}`;
6192
+ if (seen.has(dedupKey)) continue;
6193
+ seen.add(dedupKey);
6194
+ numericQuantifiers.push({
6195
+ phrase: `<backtick-literal-occurrences>`,
6196
+ count,
6197
+ noun: lemma
6123
6198
  });
6124
6199
  }
6125
6200
  return {
@@ -6128,6 +6203,14 @@ function extractBehavioralAssertions(content) {
6128
6203
  numericQuantifiers
6129
6204
  };
6130
6205
  }
6206
+ /**
6207
+ * obs_2026-05-03_021: hard-fail threshold for numeric-quantifier drift.
6208
+ * When `renderedCount / sourceCount ≤ 0.5`, the drop is large enough to
6209
+ * indicate genuine clause reduction (strata 1-10 was 4→2 = 0.5; the
6210
+ * boundary is inclusive). Above 0.5, the gap is within plausible
6211
+ * lemma/code-rendering variance and demoted to warn.
6212
+ */
6213
+ const NUMERIC_HARD_FAIL_RATIO = .5;
6131
6214
  function computeClauseFidelity(storyFileContent, sourceContent) {
6132
6215
  const sourceSignals = extractBehavioralAssertions(sourceContent);
6133
6216
  const renderedSignals = extractBehavioralAssertions(storyFileContent);
@@ -6141,13 +6224,19 @@ function computeClauseFidelity(storyFileContent, sourceContent) {
6141
6224
  const numericMismatches = [];
6142
6225
  for (const [noun, sourceCnt] of sourceNounCounts.entries()) {
6143
6226
  const renderedCnt = renderedNounCounts.get(noun) ?? 0;
6144
- if (renderedCnt < sourceCnt) numericMismatches.push({
6145
- noun,
6146
- sourceCount: sourceCnt,
6147
- renderedCount: renderedCnt
6148
- });
6227
+ if (renderedCnt < sourceCnt) {
6228
+ const ratio = sourceCnt === 0 ? 1 : renderedCnt / sourceCnt;
6229
+ const severity = ratio <= NUMERIC_HARD_FAIL_RATIO ? "error" : "warn";
6230
+ numericMismatches.push({
6231
+ noun,
6232
+ sourceCount: sourceCnt,
6233
+ renderedCount: renderedCnt,
6234
+ severity
6235
+ });
6236
+ }
6149
6237
  }
6150
- const numericDriftComponent = numericMismatches.length > 0 ? 1 : 0;
6238
+ const hasNumericHardFail = numericMismatches.some((m) => m.severity === "error");
6239
+ const numericDriftComponent = hasNumericHardFail ? 1 : 0;
6151
6240
  const CLAUSE_RATIO_FLOOR = .7;
6152
6241
  const clauseDriftComponent = clauseRatio >= CLAUSE_RATIO_FLOOR ? 0 : Math.min(1, (CLAUSE_RATIO_FLOOR - clauseRatio) / CLAUSE_RATIO_FLOOR);
6153
6242
  const drift = Math.max(numericDriftComponent, clauseDriftComponent);
@@ -13214,7 +13303,7 @@ function createImplementationOrchestrator(deps) {
13214
13303
  renameSync(storyFilePath, stalePath);
13215
13304
  const driftPct = Math.round(overallDrift * 100);
13216
13305
  const pathMissing = pathFidelity?.missing ?? [];
13217
- const numericMismatches = clauseFidelity.numericMismatches;
13306
+ const numericMismatches = clauseFidelity.numericMismatches.filter((m) => m.severity === "error");
13218
13307
  const reasons = [];
13219
13308
  if (pathMissing.length > 0) reasons.push(`${pathMissing.length} named path(s) missing`);
13220
13309
  if (numericMismatches.length > 0) reasons.push(`${numericMismatches.length} numeric quantifier mismatch(es) (e.g., "${numericMismatches[0].noun}" source=${numericMismatches[0].sourceCount} rendered=${numericMismatches[0].renderedCount})`);
@@ -13270,7 +13359,7 @@ function createImplementationOrchestrator(deps) {
13270
13359
  }
13271
13360
  } else {
13272
13361
  const pathMissing = pathFidelity?.missing ?? [];
13273
- const numericMismatches = clauseFidelity.numericMismatches;
13362
+ const numericMismatches = clauseFidelity.numericMismatches.filter((m) => m.severity === "error");
13274
13363
  const reasons = [];
13275
13364
  if (pathMissing.length > 0) reasons.push(`paths missing: ${pathMissing.join(", ")}`);
13276
13365
  if (numericMismatches.length > 0) reasons.push(`numeric mismatches: ${numericMismatches.map((m) => `${m.noun} (source=${m.sourceCount}, rendered=${m.renderedCount})`).join("; ")}`);
@@ -45277,4 +45366,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
45277
45366
 
45278
45367
  //#endregion
45279
45368
  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 };
45280
- //# sourceMappingURL=run-BYMVrlGZ.js.map
45369
+ //# sourceMappingURL=run-Cdu2K3tg.js.map
@@ -2,7 +2,7 @@ import "./health-BV-rzjf7.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-BYMVrlGZ.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-Cdu2K3tg.js";
6
6
  import "./routing-CcBOCuC9.js";
7
7
  import "./decisions-C0pz9Clx.js";
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.47",
3
+ "version": "0.20.48",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",