@warmdrift/kgauto-compiler 2.0.0-alpha.20 → 2.0.0-alpha.22

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/index.mjs CHANGED
@@ -740,14 +740,160 @@ function setNestedField(obj, path, value) {
740
740
  cursor[parts[parts.length - 1]] = value;
741
741
  }
742
742
 
743
+ // src/brain-query.ts
744
+ var FRESH_SNAPSHOT = {
745
+ data: null,
746
+ expiresAt: 0,
747
+ refreshing: false,
748
+ warned: false
749
+ };
750
+ var snapshot = { ...FRESH_SNAPSHOT };
751
+ var runtime;
752
+ function configureBrainQuery(rt) {
753
+ runtime = rt;
754
+ snapshot = { ...FRESH_SNAPSHOT };
755
+ }
756
+ function createBrainQueryCache(opts) {
757
+ return () => {
758
+ const rt = runtime;
759
+ if (!rt || !rt.enabledTables.has(opts.table)) {
760
+ return opts.bundledFallback();
761
+ }
762
+ const now = Date.now();
763
+ const stale = snapshot.expiresAt <= now;
764
+ if (stale && !snapshot.refreshing) {
765
+ snapshot.refreshing = true;
766
+ void asyncRefresh(rt);
767
+ }
768
+ if (snapshot.data) {
769
+ const rows = snapshot.data[opts.table];
770
+ if (Array.isArray(rows) && rows.length > 0) {
771
+ try {
772
+ return opts.mapRows(rows);
773
+ } catch {
774
+ return opts.bundledFallback();
775
+ }
776
+ }
777
+ }
778
+ return opts.bundledFallback();
779
+ };
780
+ }
781
+ var pendingRefresh;
782
+ async function asyncRefresh(rt) {
783
+ const promise = doRefresh(rt);
784
+ pendingRefresh = promise;
785
+ try {
786
+ await promise;
787
+ } finally {
788
+ if (pendingRefresh === promise) pendingRefresh = void 0;
789
+ }
790
+ }
791
+ var DEFAULT_CONFIG_URL = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/config";
792
+ async function doRefresh(rt) {
793
+ const url = rt.configEndpoint ?? DEFAULT_CONFIG_URL;
794
+ try {
795
+ const res = await rt.fetchImpl(url, { method: "GET" });
796
+ if (!res.ok) {
797
+ throw new Error(`brain-query ${res.status}: ${res.statusText}`);
798
+ }
799
+ const body = await res.json();
800
+ if (runtime !== rt) return;
801
+ snapshot = {
802
+ data: body,
803
+ expiresAt: Date.now() + rt.ttlMs,
804
+ refreshing: false,
805
+ warned: snapshot.warned
806
+ };
807
+ } catch (err) {
808
+ if (runtime !== rt) return;
809
+ snapshot.refreshing = false;
810
+ snapshot.expiresAt = Date.now() + rt.ttlMs;
811
+ if (!snapshot.warned) {
812
+ snapshot.warned = true;
813
+ (rt.onError ?? defaultOnError)(err);
814
+ }
815
+ }
816
+ }
817
+ function defaultOnError(err) {
818
+ console.warn("[kgauto] brain-query failed (using bundled fallback):", err);
819
+ }
820
+ function isBrainQueryActiveFor(table) {
821
+ return runtime !== void 0 && runtime.enabledTables.has(table);
822
+ }
823
+
824
+ // src/archetype-perf-brain.ts
825
+ function isPerfRow(x) {
826
+ if (!x || typeof x !== "object") return false;
827
+ const r = x;
828
+ return typeof r.model_id === "string" && typeof r.archetype === "string" && typeof r.perf_score === "number";
829
+ }
830
+ function mapRowsToPerfMap(rows) {
831
+ const out = /* @__PURE__ */ new Map();
832
+ for (const row of rows) {
833
+ if (!isPerfRow(row)) continue;
834
+ const existing = out.get(row.model_id) ?? {};
835
+ existing[row.archetype] = row.perf_score;
836
+ out.set(row.model_id, existing);
837
+ }
838
+ return out;
839
+ }
840
+ function mapRowsToNMap(rows) {
841
+ const out = /* @__PURE__ */ new Map();
842
+ for (const row of rows) {
843
+ if (!isPerfRow(row)) continue;
844
+ if (typeof row.n !== "number") continue;
845
+ const existing = out.get(row.model_id) ?? {};
846
+ existing[row.archetype] = row.n;
847
+ out.set(row.model_id, existing);
848
+ }
849
+ return out;
850
+ }
851
+ function bundledArchetypePerf() {
852
+ const out = /* @__PURE__ */ new Map();
853
+ for (const profile of allProfiles()) {
854
+ if (profile.archetypePerf) out.set(profile.id, profile.archetypePerf);
855
+ }
856
+ return out;
857
+ }
858
+ function bundledArchetypePerfN() {
859
+ return /* @__PURE__ */ new Map();
860
+ }
861
+ var loadArchetypePerfFromBrain = createBrainQueryCache({
862
+ table: "kgauto_archetype_perf",
863
+ mapRows: mapRowsToPerfMap,
864
+ bundledFallback: bundledArchetypePerf
865
+ });
866
+ var loadArchetypePerfNFromBrain = createBrainQueryCache(
867
+ {
868
+ table: "kgauto_archetype_perf",
869
+ mapRows: mapRowsToNMap,
870
+ bundledFallback: bundledArchetypePerfN
871
+ }
872
+ );
873
+ var MEASURED_GROUNDING_MIN_N = 10;
874
+ function getArchetypePerfScore(modelId, archetype) {
875
+ const score = loadArchetypePerfFromBrain().get(modelId)?.[archetype] ?? 5;
876
+ const n = loadArchetypePerfNFromBrain().get(modelId)?.[archetype] ?? 0;
877
+ const grounding = n >= MEASURED_GROUNDING_MIN_N ? "measured" : "judgment";
878
+ return { score, n, grounding };
879
+ }
880
+
743
881
  // src/advisor.ts
744
- function runAdvisor(ir, result, profile, policy) {
882
+ var QUALITY_FLOOR_FOR_RECOMMENDATION = 6;
883
+ var TIER_DOWN_COST_RATIO = 0.5;
884
+ var COST_MISMATCHED_CHOSEN_SCORE_CEILING = 7;
885
+ function runAdvisor(ir, result, profile, policy, phase2) {
745
886
  const out = [];
746
887
  out.push(...detectCachingOff(ir, profile));
747
888
  out.push(...detectSingleChunkSystem(ir, profile));
748
889
  out.push(...detectToolBloat(ir, result));
749
890
  out.push(...detectHistoryUncached(ir, profile));
750
891
  out.push(...detectSingleModelArray(ir, policy));
892
+ if (policy?.posture !== "locked") {
893
+ out.push(...detectCostMismatchedArchetype(ir, profile, phase2));
894
+ out.push(...detectModelStaleEvidence(ir, profile));
895
+ out.push(...detectTierDown(ir, profile, phase2));
896
+ }
751
897
  return out;
752
898
  }
753
899
  function detectCachingOff(ir, profile) {
@@ -833,6 +979,91 @@ function detectSingleModelArray(ir, policy) {
833
979
  }
834
980
  ];
835
981
  }
982
+ function detectCostMismatchedArchetype(ir, profile, phase2) {
983
+ if (!phase2 || phase2.fallbackChain.length === 0) return [];
984
+ if (!phase2.profileResolver) return [];
985
+ const archetype = ir.intent.archetype;
986
+ const chosenScore = getArchetypePerfScore(profile.id, archetype);
987
+ const chosenHasRoomToGrow = chosenScore.grounding === "judgment" || chosenScore.score < COST_MISMATCHED_CHOSEN_SCORE_CEILING;
988
+ if (!chosenHasRoomToGrow) return [];
989
+ let bestAlt = null;
990
+ for (const altId of phase2.fallbackChain) {
991
+ const altProfile = phase2.profileResolver(altId);
992
+ if (!altProfile) continue;
993
+ if (altProfile.id === profile.id) continue;
994
+ const altScore = getArchetypePerfScore(altProfile.id, archetype);
995
+ if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
996
+ if (altScore.score < chosenScore.score) continue;
997
+ if (altProfile.costInputPer1m >= profile.costInputPer1m) continue;
998
+ if (!bestAlt || altScore.score > bestAlt.score.score || altScore.score === bestAlt.score.score && altProfile.costInputPer1m < bestAlt.profile.costInputPer1m) {
999
+ bestAlt = { id: altId, profile: altProfile, score: altScore };
1000
+ }
1001
+ }
1002
+ if (!bestAlt) return [];
1003
+ const tierDownWouldFire = bestAlt.score.grounding === "measured" && bestAlt.profile.costInputPer1m <= profile.costInputPer1m * TIER_DOWN_COST_RATIO;
1004
+ if (tierDownWouldFire) return [];
1005
+ const chosenGrounding = chosenScore.grounding === "judgment" ? `archetypePerf.${archetype}=judgment` : `archetypePerf.${archetype}=${chosenScore.score}`;
1006
+ const altGrounding = bestAlt.score.grounding === "measured" ? `archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}` : `archetypePerf.${archetype}=${bestAlt.score.score}, judgment`;
1007
+ return [
1008
+ {
1009
+ level: "warn",
1010
+ code: "cost-mismatched-archetype",
1011
+ message: `Cost-mismatched-archetype: target=${profile.id} (${chosenGrounding}) selected for ${archetype}. Alternative ${bestAlt.id} (${altGrounding}) is cheaper ($${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} per 1M) at equal-or-better quality.`,
1012
+ suggestion: `Consider declaring \`${bestAlt.id}\` as the primary model for this archetype, or relax to posture='open' to let kgauto select among the chain. If the chosen model is required for compliance/brand reasons, set \`policy.posture = 'locked'\` to silence this rule.`,
1013
+ recommendationType: profile.provider === bestAlt.profile.provider ? "tier-down" : "model-swap",
1014
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1015
+ }
1016
+ ];
1017
+ }
1018
+ function detectModelStaleEvidence(ir, profile) {
1019
+ if (!isBrainQueryActiveFor("kgauto_archetype_perf")) return [];
1020
+ const archetype = ir.intent.archetype;
1021
+ const chosen = getArchetypePerfScore(profile.id, archetype);
1022
+ if (chosen.grounding !== "judgment") return [];
1023
+ return [
1024
+ {
1025
+ level: "info",
1026
+ code: "model-stale-evidence",
1027
+ message: `Model-stale-evidence: target=${profile.id} archetype=${archetype} is judgment-grounded (n=${chosen.n}) despite brain-query mode being active. Measurement substrate is wired but the brain hasn't accumulated >=10 outcomes for this (model, archetype) tuple yet \u2014 routing decisions remain pre-measured for this slot.`,
1028
+ suggestion: "Verify that `record()` is being called on every call() outcome with the appropriate `actualModel` and `mutationsApplied` fields. Once the brain accumulates n>=10 rows on this tuple, the score promotes from judgment to measured automatically (5-min SWR cache). No code change required from your side \u2014 this is the substrate signaling the gap.",
1029
+ recommendationType: "prompt-fix",
1030
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1031
+ }
1032
+ ];
1033
+ }
1034
+ function detectTierDown(ir, profile, phase2) {
1035
+ if (!phase2 || phase2.fallbackChain.length === 0) return [];
1036
+ if (!phase2.profileResolver) return [];
1037
+ const archetype = ir.intent.archetype;
1038
+ const chosenScore = getArchetypePerfScore(profile.id, archetype);
1039
+ const chosenCost = profile.costInputPer1m;
1040
+ let bestAlt = null;
1041
+ for (const altId of phase2.fallbackChain) {
1042
+ const altProfile = phase2.profileResolver(altId);
1043
+ if (!altProfile) continue;
1044
+ if (altProfile.id === profile.id) continue;
1045
+ const altScore = getArchetypePerfScore(altProfile.id, archetype);
1046
+ if (altScore.grounding !== "measured") continue;
1047
+ if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
1048
+ if (altScore.score < chosenScore.score) continue;
1049
+ if (altProfile.costInputPer1m > chosenCost * TIER_DOWN_COST_RATIO) continue;
1050
+ if (!bestAlt || altProfile.costInputPer1m < bestAlt.profile.costInputPer1m || altProfile.costInputPer1m === bestAlt.profile.costInputPer1m && altScore.score > bestAlt.score.score) {
1051
+ bestAlt = { id: altId, profile: altProfile, score: altScore };
1052
+ }
1053
+ }
1054
+ if (!bestAlt) return [];
1055
+ const chosenDesc = chosenScore.grounding === "measured" ? `archetypePerf.${archetype}=${chosenScore.score} (measured, n=${chosenScore.n})` : `archetypePerf.${archetype}=${chosenScore.score} (${chosenScore.grounding})`;
1056
+ return [
1057
+ {
1058
+ level: "warn",
1059
+ code: "tier-down",
1060
+ message: `Tier-down: target=${profile.id} (${chosenDesc}) selected for ${archetype}. Brain shows ${bestAlt.id} delivers equal-or-better quality (archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}) at $${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} per 1M vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} \u2014 a measured tier-down opportunity.`,
1061
+ suggestion: `Move \`${bestAlt.id}\` to primary for this archetype. The brain has n=${bestAlt.score.n} measured outcomes backing the recommendation; this is data, not opinion. If posture='locked' is required (compliance/brand promise), set it explicitly to silence this rule.`,
1062
+ recommendationType: "tier-down",
1063
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1064
+ }
1065
+ ];
1066
+ }
836
1067
 
837
1068
  // src/compile.ts
838
1069
  var counter = 0;
@@ -908,6 +1139,13 @@ function compile(ir, opts = {}) {
908
1139
  description: "ir.constraints.toolOrchestration='sequential' selected the DeepSeek-tier-0 hunt chain overlay (L-040 parallel-tool cliff doesn't apply at single-step granularity)."
909
1140
  });
910
1141
  }
1142
+ const phase2ProfileResolver = opts.profileResolver ? (id) => {
1143
+ try {
1144
+ return opts.profileResolver(id);
1145
+ } catch {
1146
+ return void 0;
1147
+ }
1148
+ } : tryGetProfile;
911
1149
  const advisories = runAdvisor(
912
1150
  ir,
913
1151
  {
@@ -917,7 +1155,11 @@ function compile(ir, opts = {}) {
917
1155
  diagnostics
918
1156
  },
919
1157
  profile,
920
- opts.policy
1158
+ opts.policy,
1159
+ {
1160
+ fallbackChain,
1161
+ profileResolver: phase2ProfileResolver
1162
+ }
921
1163
  );
922
1164
  return {
923
1165
  handle,
@@ -970,84 +1212,6 @@ function validateFinalFit(ir, profile, tokens) {
970
1212
  }
971
1213
  }
972
1214
 
973
- // src/brain-query.ts
974
- var FRESH_SNAPSHOT = {
975
- data: null,
976
- expiresAt: 0,
977
- refreshing: false,
978
- warned: false
979
- };
980
- var snapshot = { ...FRESH_SNAPSHOT };
981
- var runtime;
982
- function configureBrainQuery(rt) {
983
- runtime = rt;
984
- snapshot = { ...FRESH_SNAPSHOT };
985
- }
986
- function createBrainQueryCache(opts) {
987
- return () => {
988
- const rt = runtime;
989
- if (!rt || !rt.enabledTables.has(opts.table)) {
990
- return opts.bundledFallback();
991
- }
992
- const now = Date.now();
993
- const stale = snapshot.expiresAt <= now;
994
- if (stale && !snapshot.refreshing) {
995
- snapshot.refreshing = true;
996
- void asyncRefresh(rt);
997
- }
998
- if (snapshot.data) {
999
- const rows = snapshot.data[opts.table];
1000
- if (Array.isArray(rows) && rows.length > 0) {
1001
- try {
1002
- return opts.mapRows(rows);
1003
- } catch {
1004
- return opts.bundledFallback();
1005
- }
1006
- }
1007
- }
1008
- return opts.bundledFallback();
1009
- };
1010
- }
1011
- var pendingRefresh;
1012
- async function asyncRefresh(rt) {
1013
- const promise = doRefresh(rt);
1014
- pendingRefresh = promise;
1015
- try {
1016
- await promise;
1017
- } finally {
1018
- if (pendingRefresh === promise) pendingRefresh = void 0;
1019
- }
1020
- }
1021
- var DEFAULT_CONFIG_URL = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/config";
1022
- async function doRefresh(rt) {
1023
- const url = rt.configEndpoint ?? DEFAULT_CONFIG_URL;
1024
- try {
1025
- const res = await rt.fetchImpl(url, { method: "GET" });
1026
- if (!res.ok) {
1027
- throw new Error(`brain-query ${res.status}: ${res.statusText}`);
1028
- }
1029
- const body = await res.json();
1030
- if (runtime !== rt) return;
1031
- snapshot = {
1032
- data: body,
1033
- expiresAt: Date.now() + rt.ttlMs,
1034
- refreshing: false,
1035
- warned: snapshot.warned
1036
- };
1037
- } catch (err) {
1038
- if (runtime !== rt) return;
1039
- snapshot.refreshing = false;
1040
- snapshot.expiresAt = Date.now() + rt.ttlMs;
1041
- if (!snapshot.warned) {
1042
- snapshot.warned = true;
1043
- (rt.onError ?? defaultOnError)(err);
1044
- }
1045
- }
1046
- }
1047
- function defaultOnError(err) {
1048
- console.warn("[kgauto] brain-query failed (using bundled fallback):", err);
1049
- }
1050
-
1051
1215
  // src/pricing-brain.ts
1052
1216
  function isPricingRow(x) {
1053
1217
  if (!x || typeof x !== "object") return false;
@@ -1701,101 +1865,119 @@ var loadChainsFromBrain = createBrainQueryCache({
1701
1865
  });
1702
1866
 
1703
1867
  // src/fallback.ts
1704
- var STARTER_CHAINS = {
1868
+ var STARTER_CHAINS_GROUNDED = {
1705
1869
  // Reasoning floor — never degrade. Walk UP on 429 to Opus → cross-provider.
1706
- // alpha.16: gpt-5.5 appended as third-provider critique floor (frontier-tier,
1707
- // archetypePerf=9). Cross-provider-tail invariant has somewhere to land when
1708
- // both Anthropic + Google are unreachable (consumer adds only OpenAI key).
1709
1870
  critique: [
1710
- "claude-opus-4-7",
1711
- "claude-sonnet-4-6",
1712
- "gemini-2.5-pro",
1713
- "gpt-5.5"
1871
+ { id: "claude-opus-4-7", grounding: "judgment", reason: "Highest reasoning bar, no degradation tier \u2014 engineer pick, awaiting measured backing" },
1872
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Same-provider walk-down from Opus on 429" },
1873
+ { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor in similar quality bracket" },
1874
+ { id: "gpt-5.5", grounding: "judgment", reason: "alpha.16: third-provider frontier-tier floor (archetypePerf=9)" }
1714
1875
  ],
1715
- // Reasoning matters — Sonnet primary; walk UP to Opus on 429 (rare exception
1716
- // to "always cheaper"); cross-provider via Pro; DeepSeek Pro as tier 3 floor.
1876
+ // Reasoning matters — Sonnet primary; walk UP to Opus on 429.
1717
1877
  plan: [
1718
- "claude-sonnet-4-6",
1719
- "claude-opus-4-7",
1720
- "gemini-2.5-pro",
1721
- "deepseek-v4-pro"
1878
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Reasoning + cost balance \u2014 engineer pick" },
1879
+ { id: "claude-opus-4-7", grounding: "judgment", reason: 'Same-provider walk-UP on 429 (rare exception to "always cheaper")' },
1880
+ { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1881
+ { id: "deepseek-v4-pro", grounding: "judgment", reason: "Tier 3 cost floor \u2014 no brain evidence yet" }
1722
1882
  ],
1723
- // Quality + cost match. Walk Sonnet → Haiku same-provider, Pro cross,
1724
- // gpt-5.4-mini as third-provider tail (alpha.16 — closes the mono-Anthropic
1725
- // gap when consumer has only ANTHROPIC + OPENAI keys; archetypePerf=7).
1883
+ // Quality + cost match.
1726
1884
  generate: [
1727
- "claude-sonnet-4-6",
1728
- "claude-haiku-4-5",
1729
- "gemini-2.5-pro",
1730
- "gpt-5.4-mini"
1885
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality + cost match \u2014 engineer pick" },
1886
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down" },
1887
+ { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1888
+ { id: "gpt-5.4-mini", grounding: "judgment", reason: "alpha.16: third-provider tail (archetypePerf=7) \u2014 closes mono-Anthropic gap" }
1731
1889
  ],
1890
+ // ask::sonnet — STARTER_CHAINS calls this "Quality + cost match" but
1891
+ // tt-intel s78 prod data showed 27% empty rate. Labeled 'judgment' until
1892
+ // evidence either validates or refutes the placement.
1732
1893
  ask: [
1733
- "claude-sonnet-4-6",
1734
- "claude-haiku-4-5",
1735
- "gemini-2.5-pro",
1736
- "gpt-5.4-mini"
1894
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality + cost match \u2014 engineer pick. NOTE: tt-intel s78 prod showed 27% empty rate; placement awaits measurement validation" },
1895
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down" },
1896
+ { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1897
+ { id: "gpt-5.4-mini", grounding: "judgment", reason: "alpha.16: third-provider tail (archetypePerf=7)" }
1737
1898
  ],
1738
- // Structured-output archetype — Flash skipped (alpha.8 MAX_TOKENS cliff),
1739
- // DeepSeek skipped (no brain evidence). Floor at Haiku. alpha.16: gpt-5.4
1740
- // appended as third-provider extract floor (archetypePerf=8, native
1741
- // structured-output support).
1899
+ // Structured-output archetype — Flash skipped (alpha.8 MAX_TOKENS cliff,
1900
+ // capability-fact); DeepSeek skipped (no brain evidence).
1742
1901
  extract: [
1743
- "claude-sonnet-4-6",
1744
- "claude-haiku-4-5",
1745
- "gemini-2.5-pro",
1746
- "gpt-5.4"
1902
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Reliable structured-output anchor \u2014 engineer pick" },
1903
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down with native structured output" },
1904
+ { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor with structured-output support" },
1905
+ { id: "gpt-5.4", grounding: "capability-fact", reason: "alpha.16: third-provider floor \u2014 native structured-output capability (archetypePerf=8)" }
1747
1906
  ],
1748
1907
  // Forgiving archetype — Sonnet primary but Flash safely floors it.
1749
1908
  transform: [
1750
- "claude-sonnet-4-6",
1751
- "claude-haiku-4-5",
1752
- "gemini-2.5-pro",
1753
- "gemini-2.5-flash"
1909
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality anchor \u2014 engineer pick" },
1910
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down" },
1911
+ { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1912
+ { id: "gemini-2.5-flash", grounding: "judgment", reason: "Cost floor \u2014 forgiving archetype tolerates Flash" }
1754
1913
  ],
1755
- // Parallel-tool throughput champion (Flash, L-040). Tier 1 cross-provider
1756
- // Pro; tier 2 Sonnet (quality safety net for blocked-Flash case); tier 3
1757
- // Haiku (reduced tool budget — cliff at 16 fires). This is the
1758
- // `toolOrchestration: 'parallel'` (default) hunt chain. The sequential
1759
- // variant lives in STARTER_CHAINS_BY_MODE.hunt.sequential below — see
1760
- // alpha.20 E3 / interfaces/kgauto.md `sequential-agentic-hunt-mode`.
1914
+ // Parallel-tool throughput champion Flash leads on the L-040 cliff
1915
+ // (capability-fact: Flash 15-75 parallel calls/step vs DeepSeek 7-8).
1761
1916
  hunt: [
1762
- "gemini-2.5-flash",
1763
- "gemini-2.5-pro",
1764
- "claude-sonnet-4-6",
1765
- "claude-haiku-4-5"
1917
+ { id: "gemini-2.5-flash", grounding: "capability-fact", reason: "L-040 parallel-tool throughput champion (15-75 calls/step)" },
1918
+ { id: "gemini-2.5-pro", grounding: "capability-fact", reason: "Cross-provider tier 1 with strong parallel-tool support" },
1919
+ { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality safety net for blocked-Flash case" },
1920
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Reduced tool budget \u2014 cliff at 16 fires" }
1766
1921
  ],
1767
- // Cost-sensitive + tolerant. DeepSeek brain-evidence tier 1; Haiku tier 2
1768
- // for quality safety; Flash-Lite emergency floor (onboarded s22).
1922
+ // Cost-sensitive + tolerant. DeepSeek brain-evidence tier 1.
1769
1923
  summarize: [
1770
- "gemini-2.5-flash",
1771
- "deepseek-v4-flash",
1772
- "claude-haiku-4-5",
1773
- "gemini-2.5-flash-lite"
1924
+ { id: "gemini-2.5-flash", grounding: "judgment", reason: "Cost-sensitive primary \u2014 engineer pick" },
1925
+ { id: "deepseek-v4-flash", grounding: "measured", reason: "Brain-validated tier 1 for cost-sensitive summarize workloads", n: 169 },
1926
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Quality safety net" },
1927
+ { id: "gemini-2.5-flash-lite", grounding: "judgment", reason: "Emergency floor \u2014 onboarded s22, no brain evidence yet" }
1774
1928
  ],
1775
- // Brain-validated DeepSeek tier 1 (169 rows, 0% empty); Haiku tier 2;
1776
- // Flash-Lite floor for repeat-prompt workloads (cache-discount 10×).
1929
+ // Brain-validated DeepSeek tier 1 (169 rows, 0% empty rate).
1777
1930
  classify: [
1778
- "gemini-2.5-flash",
1779
- "deepseek-v4-flash",
1780
- "claude-haiku-4-5",
1781
- "gemini-2.5-flash-lite"
1931
+ { id: "gemini-2.5-flash", grounding: "judgment", reason: "Cost-sensitive primary \u2014 engineer pick" },
1932
+ { id: "deepseek-v4-flash", grounding: "measured", reason: "Brain-validated tier 1 (169 rows, 0% empty rate)", n: 169 },
1933
+ { id: "claude-haiku-4-5", grounding: "judgment", reason: "Quality safety net" },
1934
+ { id: "gemini-2.5-flash-lite", grounding: "judgment", reason: "Cache-discount 10\xD7 floor for repeat-prompt workloads" }
1782
1935
  ]
1783
1936
  };
1784
- var STARTER_CHAINS_BY_MODE = {
1937
+ var STARTER_CHAINS = (() => {
1938
+ const out = {};
1939
+ for (const [archetype, entries] of Object.entries(STARTER_CHAINS_GROUNDED)) {
1940
+ out[archetype] = entries.map((e) => e.id);
1941
+ }
1942
+ return out;
1943
+ })();
1944
+ var STARTER_CHAINS_BY_MODE_GROUNDED = {
1785
1945
  hunt: {
1786
1946
  sequential: [
1787
- // V4-Pro: cheap + good reasoning at single-step granularity; no
1788
- // L-040 cliff applies when consumer commits to sequential.
1789
- "deepseek-v4-pro",
1790
- // V4-Flash: cheapest viable; sibling-provider fallback.
1791
- "deepseek-v4-flash",
1792
- // Cross-provider safety net — Sonnet handles sequential agentic loops
1793
- // cleanly; Pro as third-provider tail when no DeepSeek key reachable.
1794
- "claude-sonnet-4-6",
1795
- "gemini-2.5-pro"
1947
+ {
1948
+ id: "deepseek-v4-pro",
1949
+ grounding: "judgment",
1950
+ reason: "alpha.20 E3: cheap + good reasoning at single-step granularity; L-040 cliff silenced when sequential \u2014 hypothesis not yet measured"
1951
+ },
1952
+ {
1953
+ id: "deepseek-v4-flash",
1954
+ grounding: "judgment",
1955
+ reason: "Cheapest viable; sibling-provider fallback"
1956
+ },
1957
+ {
1958
+ id: "claude-sonnet-4-6",
1959
+ grounding: "judgment",
1960
+ reason: "Cross-provider safety net \u2014 Sonnet handles sequential agentic loops cleanly"
1961
+ },
1962
+ {
1963
+ id: "gemini-2.5-pro",
1964
+ grounding: "judgment",
1965
+ reason: "Third-provider tail when no DeepSeek key reachable"
1966
+ }
1796
1967
  ]
1797
1968
  }
1798
1969
  };
1970
+ var STARTER_CHAINS_BY_MODE = (() => {
1971
+ const out = {};
1972
+ for (const [archetype, modes] of Object.entries(STARTER_CHAINS_BY_MODE_GROUNDED)) {
1973
+ if (modes?.sequential) {
1974
+ out[archetype] = {
1975
+ sequential: modes.sequential.map((e) => e.id)
1976
+ };
1977
+ }
1978
+ }
1979
+ return out;
1980
+ })();
1799
1981
  function resolveStarterForMode(archetype, toolOrchestration, allChains) {
1800
1982
  if (toolOrchestration === "sequential") {
1801
1983
  const overlay = STARTER_CHAINS_BY_MODE[archetype]?.sequential;
@@ -1857,6 +2039,114 @@ function getAllStarterChains() {
1857
2039
  }
1858
2040
  return out;
1859
2041
  }
2042
+ function getSequentialStarterChain(archetype) {
2043
+ const overlay = STARTER_CHAINS_BY_MODE[archetype]?.sequential;
2044
+ return overlay ? [...overlay] : void 0;
2045
+ }
2046
+ function copyEntry(e) {
2047
+ const out = { id: e.id, grounding: e.grounding };
2048
+ if (e.reason !== void 0) out.reason = e.reason;
2049
+ if (e.n !== void 0) out.n = e.n;
2050
+ return out;
2051
+ }
2052
+ function lookupStaticEntry(id, archetype) {
2053
+ const archetypeEntries = STARTER_CHAINS_GROUNDED[archetype];
2054
+ if (archetypeEntries) {
2055
+ const hit = archetypeEntries.find((e) => e.id === id);
2056
+ if (hit) return hit;
2057
+ }
2058
+ const seqOverlay = STARTER_CHAINS_BY_MODE_GROUNDED[archetype]?.sequential;
2059
+ if (seqOverlay) {
2060
+ const hit = seqOverlay.find((e) => e.id === id);
2061
+ if (hit) return hit;
2062
+ }
2063
+ return void 0;
2064
+ }
2065
+ function resolveGroundedChainForArchetype(archetype, toolOrchestration) {
2066
+ if (toolOrchestration === "sequential") {
2067
+ const overlay = STARTER_CHAINS_BY_MODE_GROUNDED[archetype]?.sequential;
2068
+ if (overlay) return overlay.map(copyEntry);
2069
+ }
2070
+ const allChains = loadChainsFromBrain();
2071
+ const ids = allChains[archetype];
2072
+ if (!ids) return void 0;
2073
+ return ids.map((id) => {
2074
+ const known = lookupStaticEntry(id, archetype);
2075
+ if (known) return copyEntry(known);
2076
+ return { id, grounding: "judgment" };
2077
+ });
2078
+ }
2079
+ function getDefaultFallbackChainWithGrounding(opts) {
2080
+ const {
2081
+ archetype,
2082
+ primary,
2083
+ maxDepth = 3,
2084
+ policy,
2085
+ reachability,
2086
+ toolOrchestration
2087
+ } = opts;
2088
+ if (maxDepth < 1) {
2089
+ throw new Error(
2090
+ `getDefaultFallbackChainWithGrounding: maxDepth must be >= 1, got ${maxDepth}`
2091
+ );
2092
+ }
2093
+ const starter = resolveGroundedChainForArchetype(archetype, toolOrchestration);
2094
+ if (!starter) {
2095
+ throw new Error(
2096
+ `getDefaultFallbackChainWithGrounding: unknown archetype "${archetype}". Known: ${Object.keys(STARTER_CHAINS_GROUNDED).join(", ")}`
2097
+ );
2098
+ }
2099
+ let chain;
2100
+ if (primary) {
2101
+ const primaryEntry = (() => {
2102
+ const inStarter = starter.find((e) => e.id === primary);
2103
+ if (inStarter) return copyEntry(inStarter);
2104
+ const knownAnywhere = lookupStaticEntry(primary, archetype);
2105
+ if (knownAnywhere) return { ...copyEntry(knownAnywhere), id: primary };
2106
+ return { id: primary, grounding: "judgment" };
2107
+ })();
2108
+ chain = [primaryEntry, ...starter.filter((e) => e.id !== primary)];
2109
+ } else {
2110
+ chain = [...starter];
2111
+ }
2112
+ if (policy?.blockedModels && policy.blockedModels.length > 0) {
2113
+ const blocked = new Set(policy.blockedModels);
2114
+ chain = chain.filter((e) => !blocked.has(e.id));
2115
+ }
2116
+ const seen = /* @__PURE__ */ new Set();
2117
+ const deduped = [];
2118
+ for (const e of chain) {
2119
+ if (!seen.has(e.id)) {
2120
+ seen.add(e.id);
2121
+ deduped.push(e);
2122
+ }
2123
+ }
2124
+ let filtered = deduped;
2125
+ if (reachability) {
2126
+ filtered = deduped.filter((e) => isModelReachable(e.id, reachability));
2127
+ }
2128
+ return filtered.slice(0, maxDepth);
2129
+ }
2130
+ function getStarterChainWithGrounding(archetype) {
2131
+ const entries = STARTER_CHAINS_GROUNDED[archetype];
2132
+ if (!entries) {
2133
+ throw new Error(
2134
+ `getStarterChainWithGrounding: unknown archetype "${archetype}"`
2135
+ );
2136
+ }
2137
+ return entries.map(copyEntry);
2138
+ }
2139
+ function getAllStarterChainsWithGrounding() {
2140
+ const out = {};
2141
+ for (const [archetype, entries] of Object.entries(STARTER_CHAINS_GROUNDED)) {
2142
+ out[archetype] = entries.map(copyEntry);
2143
+ }
2144
+ return out;
2145
+ }
2146
+ function getSequentialStarterChainWithGrounding(archetype) {
2147
+ const overlay = STARTER_CHAINS_BY_MODE_GROUNDED[archetype]?.sequential;
2148
+ return overlay ? overlay.map(copyEntry) : void 0;
2149
+ }
1860
2150
  function ensureCrossProviderTail(opts) {
1861
2151
  const { chain, archetype, apiKeys, envSource } = opts;
1862
2152
  if (chain.length < 1) return { chain };
@@ -2305,38 +2595,6 @@ function clamp(n) {
2305
2595
  return Math.max(0, Math.min(1, n));
2306
2596
  }
2307
2597
 
2308
- // src/archetype-perf-brain.ts
2309
- function isPerfRow(x) {
2310
- if (!x || typeof x !== "object") return false;
2311
- const r = x;
2312
- return typeof r.model_id === "string" && typeof r.archetype === "string" && typeof r.perf_score === "number";
2313
- }
2314
- function mapRowsToPerfMap(rows) {
2315
- const out = /* @__PURE__ */ new Map();
2316
- for (const row of rows) {
2317
- if (!isPerfRow(row)) continue;
2318
- const existing = out.get(row.model_id) ?? {};
2319
- existing[row.archetype] = row.perf_score;
2320
- out.set(row.model_id, existing);
2321
- }
2322
- return out;
2323
- }
2324
- function bundledArchetypePerf() {
2325
- const out = /* @__PURE__ */ new Map();
2326
- for (const profile of allProfiles()) {
2327
- if (profile.archetypePerf) out.set(profile.id, profile.archetypePerf);
2328
- }
2329
- return out;
2330
- }
2331
- var loadArchetypePerfFromBrain = createBrainQueryCache({
2332
- table: "kgauto_archetype_perf",
2333
- mapRows: mapRowsToPerfMap,
2334
- bundledFallback: bundledArchetypePerf
2335
- });
2336
- function getArchetypePerfScore(modelId, archetype) {
2337
- return loadArchetypePerfFromBrain().get(modelId)?.[archetype] ?? 5;
2338
- }
2339
-
2340
2598
  // src/models-brain.ts
2341
2599
  function isModelRow(x) {
2342
2600
  if (!x || typeof x !== "object") return false;
@@ -2468,6 +2726,7 @@ export {
2468
2726
  CallError,
2469
2727
  DIALECT_VERSION,
2470
2728
  INTENT_ARCHETYPES,
2729
+ MEASURED_GROUNDING_MIN_N,
2471
2730
  PROVIDER_ENV_KEYS,
2472
2731
  allProfiles,
2473
2732
  bucketContext,
@@ -2481,18 +2740,25 @@ export {
2481
2740
  countTokens,
2482
2741
  execute,
2483
2742
  getAllStarterChains,
2743
+ getAllStarterChainsWithGrounding,
2484
2744
  getArchetypePerfScore,
2485
2745
  getDefaultFallbackChain,
2746
+ getDefaultFallbackChainWithGrounding,
2486
2747
  getProfile,
2487
2748
  getReachabilityDiagnostic,
2749
+ getSequentialStarterChain,
2750
+ getSequentialStarterChainWithGrounding,
2488
2751
  getStarterChain,
2752
+ getStarterChainWithGrounding,
2489
2753
  hashShape,
2490
2754
  isArchetype,
2755
+ isBrainQueryActiveFor,
2491
2756
  isModelReachable,
2492
2757
  isProviderReachable,
2493
2758
  learningKey,
2494
2759
  loadAliasesFromBrain,
2495
2760
  loadArchetypePerfFromBrain,
2761
+ loadArchetypePerfNFromBrain,
2496
2762
  loadChainsFromBrain,
2497
2763
  loadModelsFromBrain,
2498
2764
  loadPricingFromBrain,