substrate-ai 0.21.9 → 0.21.11

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.
Files changed (37) hide show
  1. package/dist/acceptance-judge-CKNJdq03.js +4 -0
  2. package/dist/acceptance-judge-eIZZha1C.js +702 -0
  3. package/dist/adapter-registry-Z0RlAJY4.js +4 -0
  4. package/dist/cli/index.js +175 -22
  5. package/dist/{decision-router-BAPpON_C.js → decision-router-Dyby0fUf.js} +1 -1
  6. package/dist/{decisions-DMUwdH1O.js → decisions-Cst_r3kF.js} +2 -2
  7. package/dist/{dist-CO4BbTu3.js → dist-BZGqn-XQ.js} +5 -3
  8. package/dist/{errors-0OA2nge4.js → errors-xSeGw6pf.js} +2 -2
  9. package/dist/{experimenter-BTUtFcGu.js → experimenter-hnLiBgcQ.js} +1 -1
  10. package/dist/health--DIz8sJ9.js +8 -0
  11. package/dist/{health-BbgLm021.js → health-B867L-8I.js} +3 -3
  12. package/dist/{index-s7wBSfVT.d.ts → index-Be5MEp2y.d.ts} +2 -1
  13. package/dist/index.d.ts +13 -2
  14. package/dist/index.js +2 -2
  15. package/dist/{interactive-prompt-qTo2iuop.js → interactive-prompt-BvHUcoY4.js} +2 -2
  16. package/dist/{manifest-read-qsNEHEaF.js → manifest-read-BGzmmY01.js} +268 -5
  17. package/dist/modules/interactive-prompt/index.js +3 -3
  18. package/dist/{recovery-engine-BKGBeBnW.js → recovery-engine-dtLHyV4M.js} +2 -2
  19. package/dist/{routing-Bet3Iu2w.js → routing-BcnHtKAm.js} +2 -2
  20. package/dist/{run-nda59MmG.js → run-CoZ5kK6c.js} +617 -1169
  21. package/dist/run-G4HOt6-R.js +15 -0
  22. package/dist/src/modules/decision-router/index.js +1 -1
  23. package/dist/src/modules/recovery-engine/index.d.ts +1 -1
  24. package/dist/src/modules/recovery-engine/index.js +2 -2
  25. package/dist/{upgrade-Cryksfvg.js → upgrade-BoSsIewI.js} +3 -3
  26. package/dist/{upgrade-DGpQdA9A.js → upgrade-CNGc12AV.js} +2 -2
  27. package/dist/version-manager-impl-B9VDdCKb.js +4 -0
  28. package/dist/{work-graph-repository-DZyJv5pV.js → work-graph-repository-4cKsf8Lf.js} +1 -1
  29. package/package.json +1 -1
  30. package/packs/bmad/prompts/acceptance-judge.md +1 -1
  31. package/dist/adapter-registry-Cr9f2ICC.js +0 -4
  32. package/dist/health-CLo5vM7O.js +0 -8
  33. package/dist/run-DXJeZOid.js +0 -14
  34. package/dist/version-manager-impl-DSK9i3Xk.js +0 -4
  35. /package/dist/{decisions-CzSIEeGP.js → decisions-BAaxpVD0.js} +0 -0
  36. /package/dist/{routing-DFxoKHDt.js → routing-DZT5PN3N.js} +0 -0
  37. /package/dist/{version-manager-impl-qFBiO4Eh.js → version-manager-impl-DMTw551Q.js} +0 -0
@@ -1,17 +1,18 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { LEARNING_FINDING, createDecision, getDecisionsByCategory } from "./dist-CO4BbTu3.js";
2
+ import { LEARNING_FINDING, createDecision, getDecisionsByCategory } from "./dist-BZGqn-XQ.js";
3
3
  import * as path$1 from "path";
4
4
  import { join } from "path";
5
5
  import { readFile } from "fs/promises";
6
6
  import { EventEmitter } from "node:events";
7
7
  import { YAMLException, load } from "js-yaml";
8
- import { existsSync, promises, readFileSync, readdirSync, statSync } from "node:fs";
8
+ import { existsSync, mkdirSync, promises, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
9
9
  import { execSync, spawn } from "node:child_process";
10
10
  import * as path$2 from "node:path";
11
11
  import { basename as basename$1, delimiter, dirname as dirname$1, join as join$1, relative, resolve as resolve$1 } from "node:path";
12
+ import { tmpdir } from "node:os";
12
13
  import { createHash } from "node:crypto";
13
14
  import { z } from "zod";
14
- import { mkdir as mkdir$1, open, readFile as readFile$1, readdir as readdir$1, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
15
+ import { mkdir as mkdir$1, mkdtemp, open, readFile as readFile$1, readdir as readdir$1, rm, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
15
16
  import * as fs from "fs";
16
17
  import { createRequire } from "node:module";
17
18
  import { fileURLToPath } from "node:url";
@@ -2679,6 +2680,15 @@ const JourneyRegistrySchema = z.object({
2679
2680
  }).superRefine((registry, ctx) => {
2680
2681
  const seenJourneyIds = new Map();
2681
2682
  registry.journeys.forEach((journey, i) => {
2683
+ if (journey.criticality === "critical" && journey.epic === void 0) ctx.addIssue({
2684
+ code: "custom",
2685
+ path: [
2686
+ "journeys",
2687
+ i,
2688
+ "epic"
2689
+ ],
2690
+ message: `critical journey "${journey.id}" must declare an epic — it is the blocking-audit boundary; without it the journey is only reported at run end, never enforced`
2691
+ });
2682
2692
  const firstIndex = seenJourneyIds.get(journey.id);
2683
2693
  if (firstIndex !== void 0) ctx.addIssue({
2684
2694
  code: "custom",
@@ -5747,6 +5757,259 @@ ${rows}
5747
5757
  `;
5748
5758
  }
5749
5759
 
5760
+ //#endregion
5761
+ //#region packages/sdlc/dist/acceptance/gate-state.js
5762
+ /** Repo-relative path of the operator-local gate state. */
5763
+ const GATE_STATE_PATH = ".substrate/acceptance/gate-state.json";
5764
+ const GateStateSchema = z.object({
5765
+ demoted: z.boolean(),
5766
+ reason: z.string(),
5767
+ since: z.string(),
5768
+ detail: z.string().optional()
5769
+ });
5770
+ /** Read the demotion overlay. Absent/unreadable/invalid → not demoted. */
5771
+ function readGateState(projectRoot) {
5772
+ const path$3 = join$1(projectRoot, GATE_STATE_PATH);
5773
+ if (!existsSync(path$3)) return void 0;
5774
+ try {
5775
+ const parsed = GateStateSchema.safeParse(JSON.parse(readFileSync(path$3, "utf-8")));
5776
+ return parsed.success ? parsed.data : void 0;
5777
+ } catch {
5778
+ return void 0;
5779
+ }
5780
+ }
5781
+ /** Is the gate currently auto-demoted (blocking authority suspended)? */
5782
+ function isGateDemoted(projectRoot) {
5783
+ return readGateState(projectRoot)?.demoted === true;
5784
+ }
5785
+ /** Write the demotion overlay (canary miss / precision breach). Idempotent. */
5786
+ function demoteGate(projectRoot, reason, detail) {
5787
+ const state = {
5788
+ demoted: true,
5789
+ reason,
5790
+ since: new Date().toISOString(),
5791
+ ...detail !== void 0 ? { detail } : {}
5792
+ };
5793
+ const path$3 = join$1(projectRoot, GATE_STATE_PATH);
5794
+ mkdirSync(dirname$1(path$3), { recursive: true });
5795
+ writeFileSync(path$3, JSON.stringify(state, null, 2) + "\n", "utf-8");
5796
+ return state;
5797
+ }
5798
+ /** Operator clears the demotion (after diagnosing the miss/precision issue). */
5799
+ function clearGateDemotion(projectRoot) {
5800
+ const path$3 = join$1(projectRoot, GATE_STATE_PATH);
5801
+ if (!existsSync(path$3)) return false;
5802
+ rmSync(path$3, { force: true });
5803
+ return true;
5804
+ }
5805
+ /**
5806
+ * Resolve the EFFECTIVE acceptance mode: a demoted gate can never be
5807
+ * `blocking`, no matter what the config says. `off` stays off.
5808
+ */
5809
+ function effectiveAcceptanceMode(configured, projectRoot) {
5810
+ if (configured === "off") return "off";
5811
+ if (configured === "blocking" && isGateDemoted(projectRoot)) return "advisory";
5812
+ return configured;
5813
+ }
5814
+
5815
+ //#endregion
5816
+ //#region packages/sdlc/dist/acceptance/canary.js
5817
+ function git(args, cwd) {
5818
+ return new Promise((resolve$2) => {
5819
+ let stderr = "";
5820
+ const proc = spawn("git", args, {
5821
+ cwd,
5822
+ stdio: [
5823
+ "ignore",
5824
+ "ignore",
5825
+ "pipe"
5826
+ ]
5827
+ });
5828
+ proc.stderr?.on("data", (c) => stderr += c.toString("utf-8"));
5829
+ proc.on("error", (err) => resolve$2({
5830
+ code: null,
5831
+ stderr,
5832
+ spawnError: err.message
5833
+ }));
5834
+ proc.on("close", (code) => resolve$2({
5835
+ code,
5836
+ stderr
5837
+ }));
5838
+ });
5839
+ }
5840
+ /**
5841
+ * Run one canary. Clones the repo into a scratch dir, reverts the wiring
5842
+ * commit(s), renders the journey's non-web surfaces, judges, and reports
5843
+ * whether the verdict flipped away from all-PASS.
5844
+ *
5845
+ * `caught: false` with `inconclusive: false` is the alarming case — the gate
5846
+ * rated a de-wired journey as passing. Setup failures (revert conflict, render
5847
+ * error, judge error) are `inconclusive: true` and are NOT treated as misses
5848
+ * (they mean "couldn't test", not "gate is blind").
5849
+ */
5850
+ async function runCanary(opts) {
5851
+ const { repoRoot, journey, contract, wiringCommits, judge } = opts;
5852
+ const scratch = await mkdtemp(join$1(tmpdir(), "substrate-canary-"));
5853
+ try {
5854
+ const clone = await git([
5855
+ "clone",
5856
+ "--quiet",
5857
+ "--no-hardlinks",
5858
+ repoRoot,
5859
+ scratch
5860
+ ], tmpdir());
5861
+ if (clone.code !== 0) return {
5862
+ journeyId: journey.id,
5863
+ caught: false,
5864
+ inconclusive: true,
5865
+ detail: `clone failed: ${clone.stderr.trim() || clone.spawnError || "unknown"}`
5866
+ };
5867
+ await git([
5868
+ "config",
5869
+ "user.email",
5870
+ "canary@local"
5871
+ ], scratch);
5872
+ await git([
5873
+ "config",
5874
+ "user.name",
5875
+ "canary"
5876
+ ], scratch);
5877
+ for (const sha of wiringCommits) {
5878
+ const rev = await git([
5879
+ "revert",
5880
+ "--no-edit",
5881
+ sha
5882
+ ], scratch);
5883
+ if (rev.code !== 0) return {
5884
+ journeyId: journey.id,
5885
+ caught: false,
5886
+ inconclusive: true,
5887
+ detail: `git revert ${sha} failed (conflict?): ${rev.stderr.trim().slice(0, 300)}`
5888
+ };
5889
+ }
5890
+ const artifactsDir = join$1(scratch, ".canary-artifacts");
5891
+ const artifacts = [];
5892
+ for (const surface of journey.surfaces) {
5893
+ if (surface === "web") continue;
5894
+ if (contract.surfaces[surface] === void 0) continue;
5895
+ const res = await renderSurface({
5896
+ surface,
5897
+ contract,
5898
+ workingDirectory: scratch,
5899
+ artifactsDir: join$1(artifactsDir, surface)
5900
+ });
5901
+ if (res.status === "rendered") artifacts.push(...res.artifacts.map((a) => join$1(surface, a)));
5902
+ }
5903
+ if (artifacts.length === 0) return {
5904
+ journeyId: journey.id,
5905
+ caught: true,
5906
+ detail: "no surfaces rendered after reverting the wiring commit — journey is structurally unreachable (caught)"
5907
+ };
5908
+ const judged = await judge(journey, artifactsDir, artifacts);
5909
+ if (!judged.ok) return {
5910
+ journeyId: journey.id,
5911
+ caught: false,
5912
+ inconclusive: true,
5913
+ detail: `judge error: ${judged.error}`
5914
+ };
5915
+ const allPass = judged.verdicts.length > 0 && judged.verdicts.every((v) => v.verdict === "PASS");
5916
+ return {
5917
+ journeyId: journey.id,
5918
+ caught: !allPass,
5919
+ detail: allPass ? "MISS: judge still rated every end-state PASS after the wiring was reverted — the gate is blind to this journey" : `caught: verdict flipped to ${judged.verdicts.map((v) => `${v.end_state_id}=${v.verdict}`).join(", ")}`,
5920
+ postRevertVerdicts: judged.verdicts
5921
+ };
5922
+ } finally {
5923
+ await rm(scratch, {
5924
+ recursive: true,
5925
+ force: true
5926
+ }).catch(() => {});
5927
+ }
5928
+ }
5929
+
5930
+ //#endregion
5931
+ //#region packages/sdlc/dist/acceptance/precision.js
5932
+ const ACCEPTANCE_METRICS_PATH = ".substrate/acceptance/metrics.json";
5933
+ const AcceptanceMetricsSchema = z.object({
5934
+ total_fails: z.number().int().nonnegative().default(0),
5935
+ overrides: z.array(z.object({
5936
+ story: z.string(),
5937
+ reason: z.string(),
5938
+ at: z.string()
5939
+ })).default([]),
5940
+ canaries_planted: z.number().int().nonnegative().default(0),
5941
+ canaries_caught: z.number().int().nonnegative().default(0)
5942
+ });
5943
+ const EMPTY = {
5944
+ total_fails: 0,
5945
+ overrides: [],
5946
+ canaries_planted: 0,
5947
+ canaries_caught: 0
5948
+ };
5949
+ function readAcceptanceMetrics(projectRoot) {
5950
+ const path$3 = join$1(projectRoot, ACCEPTANCE_METRICS_PATH);
5951
+ if (!existsSync(path$3)) return { ...EMPTY };
5952
+ try {
5953
+ const parsed = AcceptanceMetricsSchema.safeParse(JSON.parse(readFileSync(path$3, "utf-8")));
5954
+ return parsed.success ? parsed.data : { ...EMPTY };
5955
+ } catch {
5956
+ return { ...EMPTY };
5957
+ }
5958
+ }
5959
+ function writeMetrics(projectRoot, m) {
5960
+ const path$3 = join$1(projectRoot, ACCEPTANCE_METRICS_PATH);
5961
+ mkdirSync(dirname$1(path$3), { recursive: true });
5962
+ writeFileSync(path$3, JSON.stringify(m, null, 2) + "\n", "utf-8");
5963
+ }
5964
+ /** Precision = confirmed-fails / total-fails. 1.0 when no fails yet (nothing to be wrong about). */
5965
+ function computePrecision(m) {
5966
+ if (m.total_fails === 0) return 1;
5967
+ const confirmed = Math.max(0, m.total_fails - m.overrides.length);
5968
+ return confirmed / m.total_fails;
5969
+ }
5970
+ /** Recall = caught / planted. 1.0 when no canaries run yet. */
5971
+ function computeRecall(m) {
5972
+ if (m.canaries_planted === 0) return 1;
5973
+ return m.canaries_caught / m.canaries_planted;
5974
+ }
5975
+ /** A6.2: the gate blocked a journey-critical FAIL — count it (precision denominator). */
5976
+ function recordCriticalFail(projectRoot) {
5977
+ const m = readAcceptanceMetrics(projectRoot);
5978
+ m.total_fails += 1;
5979
+ writeMetrics(projectRoot, m);
5980
+ }
5981
+ /** A6.1: record a canary outcome (recall). */
5982
+ function recordCanary(projectRoot, caught) {
5983
+ const m = readAcceptanceMetrics(projectRoot);
5984
+ m.canaries_planted += 1;
5985
+ if (caught) m.canaries_caught += 1;
5986
+ writeMetrics(projectRoot, m);
5987
+ }
5988
+ /**
5989
+ * A6.2 AC1: record an operator override of a FAIL verdict, then re-check the
5990
+ * precision floor. Below floor → auto-demote (AC2).
5991
+ */
5992
+ function recordOverride(projectRoot, story, reason, precisionFloor) {
5993
+ const m = readAcceptanceMetrics(projectRoot);
5994
+ m.overrides.push({
5995
+ story,
5996
+ reason,
5997
+ at: new Date().toISOString()
5998
+ });
5999
+ writeMetrics(projectRoot, m);
6000
+ const precision = computePrecision(m);
6001
+ let demoted = false;
6002
+ if (m.total_fails >= 3 && precision < precisionFloor) {
6003
+ demoteGate(projectRoot, "precision-floor", `verdict precision ${precision.toFixed(2)} < floor ${precisionFloor.toFixed(2)} (${m.overrides.length} overrides / ${String(m.total_fails)} blocks)`);
6004
+ demoted = true;
6005
+ }
6006
+ return {
6007
+ metrics: m,
6008
+ precision,
6009
+ demoted
6010
+ };
6011
+ }
6012
+
5750
6013
  //#endregion
5751
6014
  //#region packages/sdlc/dist/run-model/cli-flags.js
5752
6015
  /**
@@ -7191,5 +7454,5 @@ async function resolveRunManifest(dbRoot, runId) {
7191
7454
  }
7192
7455
 
7193
7456
  //#endregion
7194
- 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, parseJourneyRegistry, parseRuntimeProbes, parseStoryFrontmatter, readCurrentRunId, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage };
7195
- //# sourceMappingURL=manifest-read-qsNEHEaF.js.map
7457
+ 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, clearGateDemotion, computeJourneyCoverage, computePrecision, computeRecall, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, demoteGate, detectsEventDrivenAC, detectsStateIntegratingAC, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromFile, loadJourneyRegistryFromTrustedTree, parseAcceptanceContract, parseJourneyDeferrals, parseJourneyRegistry, parseRuntimeProbes, parseStoryFrontmatter, readAcceptanceMetrics, readCurrentRunId, readGateState, recordCanary, recordCriticalFail, recordOverride, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runCanary, runStaleVerificationRecovery, summarizeCoverage };
7458
+ //# sourceMappingURL=manifest-read-BGzmmY01.js.map
@@ -1,6 +1,6 @@
1
1
  import "../../logger-KeHncl-f.js";
2
- import "../../dist-CO4BbTu3.js";
3
- import "../../manifest-read-qsNEHEaF.js";
4
- import { runInteractivePrompt } from "../../interactive-prompt-qTo2iuop.js";
2
+ import "../../dist-BZGqn-XQ.js";
3
+ import "../../manifest-read-BGzmmY01.js";
4
+ import { runInteractivePrompt } from "../../interactive-prompt-BvHUcoY4.js";
5
5
 
6
6
  export { runInteractivePrompt };
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { WorkGraphRepository } from "./work-graph-repository-DZyJv5pV.js";
2
+ import { WorkGraphRepository } from "./work-graph-repository-4cKsf8Lf.js";
3
3
  import { randomUUID } from "node:crypto";
4
4
 
5
5
  //#region src/modules/recovery-engine/index.ts
@@ -278,4 +278,4 @@ function buildSuggestedAction(rootCause, storyKey) {
278
278
 
279
279
  //#endregion
280
280
  export { classifyRecoveryAction, runRecoveryEngine };
281
- //# sourceMappingURL=recovery-engine-BKGBeBnW.js.map
281
+ //# sourceMappingURL=recovery-engine-dtLHyV4M.js.map
@@ -1,4 +1,4 @@
1
- import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-CO4BbTu3.js";
2
- import "./routing-DFxoKHDt.js";
1
+ import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-BZGqn-XQ.js";
2
+ import "./routing-DZT5PN3N.js";
3
3
 
4
4
  export { loadModelRoutingConfig };