@warmdrift/kgauto-compiler 2.0.0-alpha.82 → 2.0.0-alpha.85

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.js CHANGED
@@ -23,9 +23,14 @@ __export(index_exports, {
23
23
  ABSOLUTE_FLOOR: () => ABSOLUTE_FLOOR,
24
24
  ALIASES: () => ALIASES,
25
25
  ALL_ARCHETYPES: () => ALL_ARCHETYPES,
26
+ ALT_BLIND_TOKEN_BUDGET_BREACH: () => ALT_BLIND_TOKEN_BUDGET_BREACH,
27
+ ALT_STRATEGY_IDS: () => ALT_STRATEGY_IDS,
26
28
  ARCHETYPE_FAMILY_FITS: () => ARCHETYPE_FAMILY_FITS,
27
29
  ARCHETYPE_FLOOR_DEFAULT: () => ARCHETYPE_FLOOR_DEFAULT,
30
+ BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE: () => BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE,
31
+ BLOCKED_MODEL_NOT_IN_ROSTER_CODE: () => BLOCKED_MODEL_NOT_IN_ROSTER_CODE,
28
32
  BRAIN_READ_ENV_NAMES: () => BRAIN_READ_ENV_NAMES,
33
+ BURST_SPAN_MS: () => BURST_SPAN_MS,
29
34
  COACH_CFG: () => COACH_CFG,
30
35
  COST_RANKING_REFERENCE_SHAPE: () => COST_RANKING_REFERENCE_SHAPE,
31
36
  CallError: () => CallError,
@@ -36,6 +41,7 @@ __export(index_exports, {
36
41
  DEFAULT_PROMOTIONS_ENDPOINT: () => DEFAULT_PROMOTIONS_ENDPOINT,
37
42
  DELEGATE_TOOL_DEFINITION: () => DELEGATE_TOOL_DEFINITION,
38
43
  DIALECT_VERSION: () => DIALECT_VERSION,
44
+ DISCIPLINE_GATES_V1_ALT_BLIND_HEADER: () => DISCIPLINE_GATES_V1_ALT_BLIND_HEADER,
39
45
  DISCIPLINE_GATES_V1_ALT_HEADER: () => DISCIPLINE_GATES_V1_ALT_HEADER,
40
46
  FamilyResolutionError: () => FamilyResolutionError,
41
47
  INTENT_ARCHETYPES: () => INTENT_ARCHETYPES,
@@ -52,6 +58,7 @@ __export(index_exports, {
52
58
  RULE_DISCIPLINE_GATES_V1: () => RULE_DISCIPLINE_GATES_V1,
53
59
  RULE_DISCIPLINE_GATES_V1_STRUCTURED: () => RULE_DISCIPLINE_GATES_V1_STRUCTURED,
54
60
  RULE_SEQUENTIAL_TOOL_CLIFF: () => RULE_SEQUENTIAL_TOOL_CLIFF,
61
+ STRATEGY_AUTHORSHIP_INDEPENDENT: () => STRATEGY_AUTHORSHIP_INDEPENDENT,
55
62
  STRATEGY_AUTHORSHIP_LIMITATION: () => STRATEGY_AUTHORSHIP_LIMITATION,
56
63
  TRANSLATOR_FLOOR: () => TRANSLATOR_FLOOR,
57
64
  _testResetMeasuredFailure: () => _testResetMeasuredFailure,
@@ -59,6 +66,7 @@ __export(index_exports, {
59
66
  _testWaitForMeasuredFailureRefresh: () => _testWaitForMeasuredFailureRefresh,
60
67
  _testWaitForPromotionsRefresh: () => _testWaitForPromotionsRefresh,
61
68
  allProfiles: () => allProfiles,
69
+ altBlindGatesBlockFor: () => altBlindGatesBlockFor,
62
70
  altGatesBlockFor: () => altGatesBlockFor,
63
71
  applyArchetypeConvention: () => applyArchetypeConvention,
64
72
  applySectionRewrites: () => applySectionRewrites,
@@ -72,9 +80,11 @@ __export(index_exports, {
72
80
  buildLLMJudge: () => buildLLMJudge,
73
81
  buildPairwiseJudgePrompt: () => buildPairwiseJudgePrompt,
74
82
  buildShadowProbeRow: () => buildShadowProbeRow,
83
+ burstCaveat: () => burstCaveat,
75
84
  call: () => call,
76
85
  captureGoldenIr: () => captureGoldenIr,
77
86
  chainProviderSpread: () => chainProviderSpread,
87
+ classifyEvidenceWindow: () => classifyEvidenceWindow,
78
88
  classifyStrategyOutcome: () => classifyStrategyOutcome,
79
89
  clearBrain: () => clearBrain,
80
90
  combineOrderSwappedVerdicts: () => combineOrderSwappedVerdicts,
@@ -94,6 +104,7 @@ __export(index_exports, {
94
104
  execute: () => execute,
95
105
  findBetterFit: () => findBetterFit,
96
106
  flushBrainDeadLetter: () => flushBrainDeadLetter,
107
+ formatEvidenceSpan: () => formatEvidenceSpan,
97
108
  getActionableAdvisories: () => getActionableAdvisories,
98
109
  getAllStarterChains: () => getAllStarterChains,
99
110
  getAllStarterChainsWithGrounding: () => getAllStarterChainsWithGrounding,
@@ -115,6 +126,7 @@ __export(index_exports, {
115
126
  getStarterChainWithGrounding: () => getStarterChainWithGrounding,
116
127
  hasMutation: () => hasMutation,
117
128
  hashShape: () => hashShape,
129
+ isAltStrategy: () => isAltStrategy,
118
130
  isArchetype: () => isArchetype,
119
131
  isAutoPromoteEnabledFromEnv: () => isAutoPromoteEnabledFromEnv,
120
132
  isBrainQueryActiveFor: () => isBrainQueryActiveFor,
@@ -158,8 +170,10 @@ __export(index_exports, {
158
170
  resetTokenizer: () => resetTokenizer,
159
171
  resolveConventionsForProfile: () => resolveConventionsForProfile,
160
172
  resolveGoldenCaptureRate: () => resolveGoldenCaptureRate,
173
+ resolveModelAlias: () => resolveModelAlias,
161
174
  resolvePricingAt: () => resolvePricingAt,
162
175
  resolveProviderKey: () => resolveProviderKey,
176
+ rowToAdvisory: () => rowToAdvisory,
163
177
  rubricFor: () => rubricFor,
164
178
  runAdvisor: () => runAdvisor,
165
179
  runGoldenEval: () => runGoldenEval,
@@ -168,6 +182,7 @@ __export(index_exports, {
168
182
  shouldCaptureGolden: () => shouldCaptureGolden,
169
183
  tryGetProfile: () => tryGetProfile,
170
184
  wilsonLowerBound: () => wilsonLowerBound,
185
+ withAltBlindDisciplineContract: () => withAltBlindDisciplineContract,
171
186
  withAltDisciplineContract: () => withAltDisciplineContract,
172
187
  withDisciplineContract: () => withDisciplineContract
173
188
  });
@@ -2012,6 +2027,9 @@ function _setProfileBrainHook(hook) {
2012
2027
  function canonicalId(id) {
2013
2028
  return brainHook.resolveAlias?.(id) ?? ALIASES[id] ?? id;
2014
2029
  }
2030
+ function resolveModelAlias(id) {
2031
+ return canonicalId(id);
2032
+ }
2015
2033
  var PROFILE_INDEX = new Map(
2016
2034
  PROFILES_RAW.map((p) => [p.id, p])
2017
2035
  );
@@ -2511,6 +2529,17 @@ function resolveFamilyEntry(family, ctx) {
2511
2529
  return winner.id;
2512
2530
  }
2513
2531
 
2532
+ // src/policy-match.ts
2533
+ function canonicalPolicySet(ids) {
2534
+ const set = /* @__PURE__ */ new Set();
2535
+ for (const id of ids ?? []) set.add(resolveModelAlias(id));
2536
+ return set;
2537
+ }
2538
+ function policySetHas(set, modelId) {
2539
+ if (set.size === 0) return false;
2540
+ return set.has(resolveModelAlias(modelId));
2541
+ }
2542
+
2514
2543
  // src/tokenizer.ts
2515
2544
  var tokenizerImpl = defaultCharBasedCounter;
2516
2545
  function defaultCharBasedCounter(text) {
@@ -2906,8 +2935,8 @@ function effectiveConventions(profile) {
2906
2935
  function passScoreTargets(ir, opts) {
2907
2936
  const constraints = ir.constraints ?? {};
2908
2937
  const policy = opts.policy ?? {};
2909
- const blockedSet = new Set(policy.blockedModels ?? []);
2910
- const preferredSet = new Set(policy.preferredModels ?? []);
2938
+ const blockedSet = canonicalPolicySet(policy.blockedModels);
2939
+ const preferredSet = canonicalPolicySet(policy.preferredModels);
2911
2940
  const scores = [];
2912
2941
  const policyMutations = [];
2913
2942
  const rawPromotion = opts.promotion;
@@ -2930,7 +2959,7 @@ function passScoreTargets(ir, opts) {
2930
2959
  continue;
2931
2960
  }
2932
2961
  const reasons = [];
2933
- if (blockedSet.has(modelId)) {
2962
+ if (policySetHas(blockedSet, modelId)) {
2934
2963
  reasons.push(`blocked_by_policy (consumer gated this model \u2014 see CompilePolicy.blockedModels)`);
2935
2964
  }
2936
2965
  if (opts.estimatedInputTokens > profile.maxContextTokens * 0.9) {
@@ -2960,7 +2989,7 @@ function passScoreTargets(ir, opts) {
2960
2989
  const qualityScore = Math.max(0, baseQuality - qualityPenalty);
2961
2990
  const callerOrderBoost = (modelIds.length - modelIds.indexOf(modelId)) * 0.1;
2962
2991
  const costPenalty = estimatedCostUsd * 5;
2963
- const preferredBoost = preferredSet.has(modelId) ? 0.5 : 0;
2992
+ const preferredBoost = policySetHas(preferredSet, modelId) ? 0.5 : 0;
2964
2993
  let latencyPenalty = 0;
2965
2994
  const maxLatencyMs = constraints.maxLatencyMs;
2966
2995
  if (typeof maxLatencyMs === "number" && maxLatencyMs > 0) {
@@ -3017,7 +3046,7 @@ function passScoreTargets(ir, opts) {
3017
3046
  description: `Model ${modelId} excluded \u2014 estimated cost $${estimatedCostUsd.toFixed(4)} exceeds policy ceiling $${policy.maxCostPerCallUsd.toFixed(4)}`
3018
3047
  });
3019
3048
  }
3020
- if (preferredSet.has(modelId) && reasons.length === 0) {
3049
+ if (policySetHas(preferredSet, modelId) && reasons.length === 0) {
3021
3050
  policyMutations.push({
3022
3051
  id: `policy-preferred-${modelId}`,
3023
3052
  source: "compile_policy",
@@ -4059,8 +4088,8 @@ function getDefaultFallbackChain(opts) {
4059
4088
  chain = [...starter];
4060
4089
  }
4061
4090
  if (policy?.blockedModels && policy.blockedModels.length > 0) {
4062
- const blocked = new Set(policy.blockedModels);
4063
- chain = chain.filter((id) => !blocked.has(id));
4091
+ const blocked = canonicalPolicySet(policy.blockedModels);
4092
+ chain = chain.filter((id) => !policySetHas(blocked, id));
4064
4093
  }
4065
4094
  const seen = /* @__PURE__ */ new Set();
4066
4095
  const deduped = [];
@@ -4163,8 +4192,8 @@ function getDefaultFallbackChainWithGrounding(opts) {
4163
4192
  chain = [...starter];
4164
4193
  }
4165
4194
  if (policy?.blockedModels && policy.blockedModels.length > 0) {
4166
- const blocked = new Set(policy.blockedModels);
4167
- chain = chain.filter((e) => !blocked.has(e.id));
4195
+ const blocked = canonicalPolicySet(policy.blockedModels);
4196
+ chain = chain.filter((e) => !policySetHas(blocked, e.id));
4168
4197
  }
4169
4198
  const seen = /* @__PURE__ */ new Set();
4170
4199
  const deduped = [];
@@ -5041,6 +5070,67 @@ function advisorRuleCrossFamilyFit(ctx) {
5041
5070
  ];
5042
5071
  }
5043
5072
 
5073
+ // src/advisor-rules/blocked-model-drift.ts
5074
+ var BLOCKED_MODEL_NOT_IN_ROSTER_CODE = "blocked-model-not-in-roster";
5075
+ var BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE = "blocked-model-family-sibling-served";
5076
+ var DOCS_URL = "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories";
5077
+ function familyOf2(modelId, profile) {
5078
+ return profile?.family ?? deriveFamilyFromModelId(modelId);
5079
+ }
5080
+ function isOnTheWayOut(status) {
5081
+ return status === "legacy" || status === "deprecated";
5082
+ }
5083
+ function advisorRuleBlockedModelDrift(ctx) {
5084
+ const blocked = ctx.policy?.blockedModels;
5085
+ if (!blocked || blocked.length === 0) return [];
5086
+ const resolve = ctx.resolveProfile ?? tryGetProfile;
5087
+ const out = [];
5088
+ const entries = [...new Set(blocked)].sort();
5089
+ const selectedProfile = resolve(ctx.selectedModelId);
5090
+ const selectedFamily = familyOf2(ctx.selectedModelId, selectedProfile);
5091
+ const orphans = entries.filter((e) => resolve(e) === void 0);
5092
+ if (orphans.length > 0) {
5093
+ const list = orphans.map((o) => `\`${o}\``).join(", ");
5094
+ const plural = orphans.length === 1 ? "entry" : "entries";
5095
+ const verb = orphans.length === 1 ? "matches" : "match";
5096
+ out.push({
5097
+ level: "warn",
5098
+ code: BLOCKED_MODEL_NOT_IN_ROSTER_CODE,
5099
+ message: `CompilePolicy.blockedModels ${plural} ${list} ${verb} no model in the current roster, so ${orphans.length === 1 ? "it is" : "they are"} inert \u2014 \`blockedModels\` is matched by exact model id, and nothing kgauto can select carries ${orphans.length === 1 ? "that id" : "those ids"}. The block will never fire.`,
5100
+ suggestion: `Check for a typo, or for an id that was retired from the roster since the block was written. This is how a block goes quiet without an error: tt-intel (2026-07-29) carried \`KGAUTO_BLOCKED_MODELS="claude-sonnet-4-6"\` across a roster retarget and the block stopped covering the traffic they believed it covered. Resolve the intended model id against the live roster \u2014 \`getRecommendedPrimary({ family, fallback })\` returns the id the family currently resolves to \u2014 and block that id, or drop the entry if it is no longer needed.`,
5101
+ docsUrl: DOCS_URL
5102
+ });
5103
+ }
5104
+ if (selectedFamily !== null) {
5105
+ const siblings = entries.filter((e) => {
5106
+ if (resolveModelAlias(e) === resolveModelAlias(ctx.selectedModelId)) return false;
5107
+ const p = resolve(e);
5108
+ if (familyOf2(e, p) !== selectedFamily) return false;
5109
+ if (p && selectedProfile && p.provider !== selectedProfile.provider) {
5110
+ return false;
5111
+ }
5112
+ return true;
5113
+ });
5114
+ if (siblings.length > 0) {
5115
+ const list = siblings.map((s) => `\`${s}\``).join(", ");
5116
+ const plural = siblings.length === 1 ? "" : "s";
5117
+ const retargetShaped = siblings.some((s) => {
5118
+ const p = resolve(s);
5119
+ return isOnTheWayOut(p?.status) && selectedProfile?.status === "current";
5120
+ });
5121
+ const retargetNote = retargetShaped ? ` The blocked id${plural} ${siblings.length === 1 ? "is" : "are"} legacy/deprecated while \`${ctx.selectedModelId}\` is current \u2014 that is the signature of a roster lifecycle move rather than a deliberate per-generation block, so this is more likely to be drift than intent.` : "";
5122
+ out.push({
5123
+ level: "warn",
5124
+ code: BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE,
5125
+ message: `\`${ctx.selectedModelId}\` was selected for this call. It is in the same family (\`${selectedFamily}\`) as blocked entr${siblings.length === 1 ? "y" : "ies"} ${list}, but its exact id differs \u2014 and \`CompilePolicy.blockedModels\` matches by exact id, so the block does not cover it.${retargetNote}`,
5126
+ suggestion: `Two readings, and kgauto cannot tell them apart: (1) intentional \u2014 you meant to gate that specific id and \`${ctx.selectedModelId}\` is fine, in which case nothing needs doing and you can filter this code; (2) drift \u2014 you meant to gate the family, and a roster change moved traffic to a sibling your block never named. This happened to tt-intel: when the \`claude-sonnet\` family primary retargeted from \`claude-sonnet-4-6\` to \`claude-sonnet-5\`, their literal-id gate stopped matching the family's routed traffic (their fix was local family resolution). If you meant the family, add \`${ctx.selectedModelId}\` to \`blockedModels\` \u2014 kgauto deliberately does NOT widen exact-id blocks into family globs, because that would silently change what every existing block covers.`,
5127
+ docsUrl: DOCS_URL
5128
+ });
5129
+ }
5130
+ }
5131
+ return out;
5132
+ }
5133
+
5044
5134
  // src/advisor.ts
5045
5135
  var QUALITY_FLOOR_FOR_RECOMMENDATION = 6;
5046
5136
  var TIER_DOWN_COST_RATIO = 0.5;
@@ -5059,6 +5149,12 @@ function runAdvisor(ir, result, profile, policy, phase2) {
5059
5149
  out.push(...detectToolBloat(ir, result));
5060
5150
  out.push(...detectHistoryUncached(ir, profile));
5061
5151
  out.push(...detectSingleModelArray(ir, policy));
5152
+ out.push(
5153
+ ...advisorRuleBlockedModelDrift({
5154
+ policy,
5155
+ selectedModelId: profile.id
5156
+ })
5157
+ );
5062
5158
  if (policy?.posture !== "locked") {
5063
5159
  out.push(...detectCostMismatchedArchetype(ir, profile, phase2));
5064
5160
  out.push(...detectModelStaleEvidence(ir, profile));
@@ -5170,18 +5266,27 @@ function detectHistoryUncached(ir, profile) {
5170
5266
  function detectSingleModelArray(ir, policy) {
5171
5267
  if (ir.models.length !== 1) return [];
5172
5268
  if (policy?.posture === "locked") return [];
5173
- const only = ir.models[0];
5269
+ const entry = ir.models[0];
5270
+ const only = typeof entry === "string" ? entry : `family:${entry.family}`;
5271
+ const blocked = canonicalPolicySet(policy?.blockedModels);
5272
+ let alternatives = [];
5273
+ try {
5274
+ alternatives = getDefaultFallbackChain({
5275
+ archetype: ir.intent.archetype,
5276
+ primary: only,
5277
+ posture: "preferred",
5278
+ policy
5279
+ }).filter((id) => resolveModelAlias(id) !== resolveModelAlias(only)).filter((id) => !policySetHas(blocked, id)).filter((id) => getModelCompatibility(id, { archetype: ir.intent.archetype }).status !== "reject");
5280
+ } catch {
5281
+ }
5282
+ const hasAlternative = alternatives.length > 0;
5283
+ const remedy = "Widen the chain AND pin your primary: `compile({ ...ir, models: getDefaultFallbackChain({ archetype: ir.intent.archetype, primary: '" + only + "', posture: 'preferred' }) }, { policy: { preferredModels: ['" + only + "'] } })`. The chain is a CANDIDATE SET \u2014 compile() scores it and does not honour its order, so without the `preferredModels` pin the extra entries can retarget your primary (and with it your cost profile). With the pin, `" + only + "` stays primary and the added entries serve only as the safety net. Note `posture` has no effect once `primary` is passed. If you gate models by spend, re-verify `policy.blockedModels` against the widened set before shipping. If single-model is intentional (compliance/brand promise), set `policy.posture = 'locked'` to silence this rule.";
5174
5284
  return [
5175
5285
  {
5176
- level: "warn",
5286
+ level: hasAlternative ? "critical" : "warn",
5177
5287
  code: "single-model-array",
5178
- message: `\`ir.models\` has length 1 (only "${only}") and posture is not 'locked'. A single-model chain has no safety net \u2014 the first 429 / 5xx / cliff hits the user as a failure. Master plan \xA71.2 closes the reliability gap with a 2-step minimum.`,
5179
- // alpha.80: `posture: 'preferred'` keeps the consumer's current model at
5180
- // position 0 and is therefore cost-neutral; `'open'` re-picks the
5181
- // primary and is NOT. This rule is about reliability, not cost, so both
5182
- // stay on offer — but the cost consequence of the second is now stated,
5183
- // since a reliability fix should not silently become a repricing.
5184
- suggestion: "Use `getDefaultFallbackChain({ archetype: ir.intent.archetype, primary: '" + only + "', posture: 'preferred' })` for a user-anchored chain \u2014 this keeps `" + only + "` as your primary and only adds fallbacks, so your cost profile is unchanged. `getDefaultFallbackChain({ archetype, posture: 'open' })` instead lets the library pick the PRIMARY, ordered by archetype performance rather than cost \u2014 check what it returns before adopting it. If single-model is intentional (compliance/brand promise), set `policy.posture = 'locked'` to silence this rule.",
5288
+ message: hasAlternative ? `\`ir.models\` has length 1 (only "${only}") for archetype "${ir.intent.archetype}" and posture is not 'locked'. A single-model chain has no safety net \u2014 the first 429 / 5xx / cliff hits the user as a failure \u2014 and a compatible, non-blocked alternative exists in the roster today (${alternatives[0]}), so this is critical: the missing safety net is adoptable now.` : `\`ir.models\` has length 1 (only "${only}") for archetype "${ir.intent.archetype}" and posture is not 'locked'. A single-model chain has no safety net \u2014 the first 429 / 5xx / cliff hits the user as a failure. No compatible non-blocked alternative is visible in the roster for this archetype, so this stays a warning.`,
5289
+ suggestion: remedy,
5185
5290
  docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#single-model-array"
5186
5291
  }
5187
5292
  ];
@@ -5735,6 +5840,15 @@ function compile(ir, opts = {}) {
5735
5840
  sectionRewritesApplied
5736
5841
  }
5737
5842
  );
5843
+ if (ir["policy"] !== void 0 && opts.policy === void 0) {
5844
+ rawAdvisories.push({
5845
+ level: "critical",
5846
+ code: "policy-in-ir-ignored",
5847
+ message: "The IR passed to compile() carries a `policy` field. `policy` belongs in the SECOND argument \u2014 `compile(ir, { policy })` \u2014 and inside the IR it is an unknown field that is completely ignored. If that policy names blockedModels, no block is being enforced on this call.",
5848
+ suggestion: "Move it: `compile(ir, { policy: { ... } })`. If you also configure policy correctly elsewhere on this path, remove the IR copy so the next reader is not misled.",
5849
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#public-api"
5850
+ });
5851
+ }
5738
5852
  const advisories = rawAdvisories.map((a) => ({
5739
5853
  ...a,
5740
5854
  kgautoRequestId: handle,
@@ -5853,7 +5967,7 @@ function validateFinalFit(ir, profile, tokens) {
5853
5967
  }
5854
5968
 
5855
5969
  // src/version.ts
5856
- var LIBRARY_VERSION = "2.0.0-alpha.82";
5970
+ var LIBRARY_VERSION = "2.0.0-alpha.85";
5857
5971
 
5858
5972
  // src/pricing-brain.ts
5859
5973
  function isPricingRow(x) {
@@ -7808,11 +7922,11 @@ async function call(ir, opts = {}) {
7808
7922
  }
7809
7923
  let policyBlockedFiltered;
7810
7924
  if (opts.policy?.blockedModels && opts.policy.blockedModels.length > 0) {
7811
- const blocked = new Set(opts.policy.blockedModels);
7925
+ const blocked = canonicalPolicySet(opts.policy.blockedModels);
7812
7926
  const filtered = [];
7813
7927
  const dropped = [];
7814
7928
  for (const t of targetsToTry) {
7815
- if (blocked.has(t)) {
7929
+ if (policySetHas(blocked, t)) {
7816
7930
  dropped.push(t);
7817
7931
  } else {
7818
7932
  filtered.push(t);
@@ -7852,10 +7966,18 @@ async function call(ir, opts = {}) {
7852
7966
  const failedProviders = /* @__PURE__ */ new Map();
7853
7967
  const sameModelRetryEnabled = opts.sameModelRetry ?? isSameModelRetryEnabledFromEnv();
7854
7968
  let retriedSameModel = false;
7969
+ const pushAttempt = (attempt) => {
7970
+ attempts.push(attempt);
7971
+ if (attempt.status === "success") return;
7972
+ try {
7973
+ opts.onFailedAttempt?.(attempt);
7974
+ } catch {
7975
+ }
7976
+ };
7855
7977
  for (let i = 0; i < targetsToTry.length; i++) {
7856
7978
  const targetModel = targetsToTry[i];
7857
7979
  if (opts.abortSignal?.aborted) {
7858
- attempts.push({
7980
+ pushAttempt({
7859
7981
  model: targetModel,
7860
7982
  status: "terminal",
7861
7983
  errorCode: "aborted",
@@ -7866,7 +7988,7 @@ async function call(ir, opts = {}) {
7866
7988
  const targetProfile = tryGetProfile(targetModel);
7867
7989
  const providerFailReason = targetProfile ? failedProviders.get(targetProfile.provider) : void 0;
7868
7990
  if (targetProfile && providerFailReason && !opts.noFallback) {
7869
- attempts.push({
7991
+ pushAttempt({
7870
7992
  model: targetModel,
7871
7993
  status: "terminal",
7872
7994
  errorCode: `${providerFailReason}_inferred`,
@@ -7885,7 +8007,7 @@ async function call(ir, opts = {}) {
7885
8007
  opts
7886
8008
  );
7887
8009
  } catch (err) {
7888
- attempts.push({
8010
+ pushAttempt({
7889
8011
  model: targetModel,
7890
8012
  status: "terminal",
7891
8013
  errorCode: "compile_error",
@@ -7923,7 +8045,7 @@ async function call(ir, opts = {}) {
7923
8045
  }
7924
8046
  if (!validated.ok && isStructuredContractViolation(validated.errorCode) && sameModelRetryEnabled && !retriedSameModel && !retrySuppressionNote) {
7925
8047
  retriedSameModel = true;
7926
- attempts.push({
8048
+ pushAttempt({
7927
8049
  model: targetModel,
7928
8050
  status: validated.errorType,
7929
8051
  errorCode: validated.errorCode,
@@ -7938,7 +8060,7 @@ async function call(ir, opts = {}) {
7938
8060
  servedByRetry = true;
7939
8061
  }
7940
8062
  if (validated.ok) {
7941
- attempts.push({
8063
+ pushAttempt({
7942
8064
  model: targetModel,
7943
8065
  status: "success",
7944
8066
  ...servedByRetry ? { sameModelRetry: true } : {}
@@ -8056,7 +8178,7 @@ async function call(ir, opts = {}) {
8056
8178
  advisories: activeCompile.advisories
8057
8179
  };
8058
8180
  }
8059
- attempts.push({
8181
+ pushAttempt({
8060
8182
  model: targetModel,
8061
8183
  status: validated.errorType,
8062
8184
  errorCode: validated.errorCode,
@@ -8636,6 +8758,13 @@ function combineOrderSwappedVerdicts(run1, run2) {
8636
8758
  if (run1 === run2) return run1;
8637
8759
  return "tied";
8638
8760
  }
8761
+ var ALT_STRATEGY_IDS = [
8762
+ "discipline-gates-v1-alt",
8763
+ "discipline-gates-v1-alt-blind"
8764
+ ];
8765
+ function isAltStrategy(id) {
8766
+ return id !== void 0 && ALT_STRATEGY_IDS.includes(id);
8767
+ }
8639
8768
  function replayRetryDelayMs(errorCode) {
8640
8769
  return errorCode === "rate_limit" ? 65e3 : 2e3;
8641
8770
  }
@@ -8689,7 +8818,34 @@ function altGatesBlockFor(args) {
8689
8818
  ...shapeAltering
8690
8819
  ]);
8691
8820
  }
8821
+ var ALT_BLIND_TOKEN_BUDGET_BREACH = {
8822
+ ceilingTokens: 264,
8823
+ measuredTokensTextWithTools: 285,
8824
+ note: "Blind arm exceeds the stated 264-token ceiling on text+tools (285) and costs ~2.4x the v1-alt arm. Not corrected: compressing it would require editing prose the arm depends on NOT having been edited by this seat. Read a blind-arm LOSS as confounded by token tax; a WIN is unaffected."
8825
+ };
8826
+ var DISCIPLINE_GATES_V1_ALT_BLIND_HEADER = "Before stating any conclusion, run this check:";
8827
+ var ALT_BLIND_BULLETS = {
8828
+ falsify: "- Before committing to an approach, state in one line what evidence would prove it wrong and how you would notice it. If nothing could falsify the approach, you hold a preference, not a plan \u2014 rework it until something could.",
8829
+ deviation: "- When you choose not to follow an applicable instruction, say so explicitly: name the instruction, why you are deviating, and what you are doing instead. Silent deviation is forbidden \u2014 an override is only legitimate when it is visible.",
8830
+ toolPredict: "- When using tools: before each call, state the result you expect. On mismatch, treat the gap as evidence your model of the system is wrong \u2014 revise the model before acting again; never silently retry.",
8831
+ verifyDelegated: "- Verify every delegated or sub-agent result before composing it into an answer: spot-check it against the source or an independent probe. An unverified sub-result is a claim you are repeating, not a fact you know.",
8832
+ markAssumed: '- In the final answer, keep verified claims and assumptions visibly distinct: mark anything unchecked as "assumed" or "unverified". Never let an assumption borrow the confidence of the verified claims beside it.'
8833
+ };
8834
+ function altBlindGatesBlockFor(args) {
8835
+ const parts = [
8836
+ "falsify",
8837
+ "deviation",
8838
+ ...args.hasTools ? ["toolPredict"] : [],
8839
+ "verifyDelegated",
8840
+ ...args.outputMode === "text" ? ["markAssumed"] : []
8841
+ ];
8842
+ return [
8843
+ DISCIPLINE_GATES_V1_ALT_BLIND_HEADER,
8844
+ ...parts.map((p) => ALT_BLIND_BULLETS[p])
8845
+ ].join("\n");
8846
+ }
8692
8847
  var STRATEGY_ALT_SECTION_ID = "__kgauto_strategy_eval_gates_alt__";
8848
+ var STRATEGY_ALT_BLIND_SECTION_ID = "__kgauto_strategy_eval_gates_alt_blind__";
8693
8849
  function withAltDisciplineContract(ir) {
8694
8850
  const outputMode = resolveOutputMode({
8695
8851
  declared: ir.constraints?.outputMode,
@@ -8708,6 +8864,28 @@ function withAltDisciplineContract(ir) {
8708
8864
  ]
8709
8865
  };
8710
8866
  }
8867
+ function withAltBlindDisciplineContract(ir) {
8868
+ const outputMode = resolveOutputMode({
8869
+ declared: ir.constraints?.outputMode,
8870
+ structuredOutput: ir.constraints?.structuredOutput,
8871
+ toolCount: ir.tools?.length ?? 0
8872
+ });
8873
+ const hasTools = (ir.tools?.length ?? 0) > 0;
8874
+ return {
8875
+ ...ir,
8876
+ sections: [
8877
+ ...ir.sections ?? [],
8878
+ {
8879
+ id: STRATEGY_ALT_BLIND_SECTION_ID,
8880
+ text: altBlindGatesBlockFor({ outputMode, hasTools })
8881
+ }
8882
+ ]
8883
+ };
8884
+ }
8885
+ var ALT_SECTION_ID_BY_STRATEGY = {
8886
+ "discipline-gates-v1-alt": STRATEGY_ALT_SECTION_ID,
8887
+ "discipline-gates-v1-alt-blind": STRATEGY_ALT_BLIND_SECTION_ID
8888
+ };
8711
8889
  async function runGoldenEval(opts) {
8712
8890
  const fetchFn = opts.fetchImpl ?? fetch;
8713
8891
  const progress = opts.onProgress ?? (() => {
@@ -8775,7 +8953,9 @@ async function runGoldenEval(opts) {
8775
8953
  }
8776
8954
  const armBIr = (ir) => {
8777
8955
  if (axis !== "strategy") return ir;
8778
- return strategyId === "discipline-gates-v1-alt" ? withAltDisciplineContract(ir) : withDisciplineContract(ir);
8956
+ if (strategyId === "discipline-gates-v1-alt") return withAltDisciplineContract(ir);
8957
+ if (strategyId === "discipline-gates-v1-alt-blind") return withAltBlindDisciplineContract(ir);
8958
+ return withDisciplineContract(ir);
8779
8959
  };
8780
8960
  const replay = async (ir, model, captureGates = false) => {
8781
8961
  let gates;
@@ -8787,13 +8967,14 @@ async function runGoldenEval(opts) {
8787
8967
  };
8788
8968
  const compiled = compile(evalIr);
8789
8969
  if (captureGates) {
8790
- if (strategyId === "discipline-gates-v1-alt") {
8970
+ if (isAltStrategy(strategyId)) {
8971
+ const altSectionId = ALT_SECTION_ID_BY_STRATEGY[strategyId];
8791
8972
  const altSection = (evalIr.sections ?? []).find(
8792
- (s) => s.id === STRATEGY_ALT_SECTION_ID
8973
+ (s) => s.id === altSectionId
8793
8974
  );
8794
8975
  gates = {
8795
8976
  fired: altSection !== void 0 && altSection.text.length > 0,
8796
- rule: "discipline-gates-v1-alt",
8977
+ rule: strategyId,
8797
8978
  gateTokens: altSection ? countTokens(`${altSection.text}
8798
8979
 
8799
8980
  `) : 0
@@ -9224,7 +9405,8 @@ function classifyStrategyOutcome(r) {
9224
9405
  if (r.losses > r.wins) return "loses";
9225
9406
  return "ties";
9226
9407
  }
9227
- var STRATEGY_AUTHORSHIP_LIMITATION = "Both gate wordings share one author (kgauto-Cairn); a shared blind spot is invisible to this experiment. Strong verdicts: both-lose (mechanism) and v1-loses/alt-wins (wording). An independently-authored alt would strengthen every other cell.";
9408
+ var STRATEGY_AUTHORSHIP_LIMITATION = "Only the v1 wording was measured on this run; no re-wording arm was triggered, so this result says nothing about whether the wording or the mechanism produced it.";
9409
+ var STRATEGY_AUTHORSHIP_INDEPENDENT = "Three arms: v1 and one re-wording by this seat, plus an independently authored arm (context-free subagent, no repo access, no knowledge of the experiment). A both-lose verdict therefore spans independent authorship and is not explained by one author's blind spot. Residual limitation: all three arms encode a similar set of underlying principles, so a wrong CHOICE of principles remains harder to see than a wrong wording of them.";
9228
9410
  async function runStrategyEvalWithAttribution(opts) {
9229
9411
  const primary = await runGoldenEval({
9230
9412
  ...opts,
@@ -9241,9 +9423,20 @@ async function runStrategyEvalWithAttribution(opts) {
9241
9423
  axis: "strategy",
9242
9424
  strategy: "discipline-gates-v1-alt"
9243
9425
  });
9244
- const altOutcome = classifyStrategyOutcome(alt);
9245
- const attribution = altOutcome === "wins" ? "wording-failure" : altOutcome === "loses" ? "mechanism-failure" : "wording-inconclusive";
9246
- return { attribution, primary, alt, limitation: STRATEGY_AUTHORSHIP_LIMITATION };
9426
+ const altBlind = await runGoldenEval({
9427
+ ...opts,
9428
+ axis: "strategy",
9429
+ strategy: "discipline-gates-v1-alt-blind"
9430
+ });
9431
+ const outcomes = [classifyStrategyOutcome(alt), classifyStrategyOutcome(altBlind)];
9432
+ const attribution = outcomes.includes("wins") ? "wording-failure" : outcomes.every((o) => o === "loses") ? "mechanism-failure" : "wording-inconclusive";
9433
+ return {
9434
+ attribution,
9435
+ primary,
9436
+ alt,
9437
+ altBlind,
9438
+ limitation: STRATEGY_AUTHORSHIP_INDEPENDENT
9439
+ };
9247
9440
  }
9248
9441
 
9249
9442
  // src/brain-proxy.ts
@@ -9875,6 +10068,30 @@ function createDelegate(opts) {
9875
10068
  }
9876
10069
 
9877
10070
  // src/advisories-api.ts
10071
+ var BURST_SPAN_MS = 5 * 60 * 1e3;
10072
+ function classifyEvidenceWindow(row) {
10073
+ const { evidence_first_at: first, evidence_last_at: last, evidence_n: n } = row;
10074
+ if (typeof first !== "string" || typeof last !== "string") return null;
10075
+ if (typeof n !== "number" || !Number.isFinite(n) || n <= 0) return null;
10076
+ const t0 = Date.parse(first);
10077
+ const t1 = Date.parse(last);
10078
+ if (Number.isNaN(t0) || Number.isNaN(t1)) return null;
10079
+ const spanMs = Math.max(0, t1 - t0);
10080
+ return { firstAt: first, lastAt: last, n, spanMs, isBurst: spanMs < BURST_SPAN_MS };
10081
+ }
10082
+ function formatEvidenceSpan(spanMs) {
10083
+ if (spanMs < 1e3) return `${spanMs}ms`;
10084
+ const s = Math.round(spanMs / 1e3);
10085
+ if (s < 90) return `${s}s`;
10086
+ const m = Math.round(s / 60);
10087
+ if (m < 90) return `${m}m`;
10088
+ const h = Math.round(m / 60);
10089
+ if (h < 48) return `${h}h`;
10090
+ return `${Math.round(h / 24)}d`;
10091
+ }
10092
+ function burstCaveat(w) {
10093
+ return `Evidence is ${w.n} observation${w.n === 1 ? "" : "s"} spanning ${formatEvidenceSpan(w.spanMs)} (${w.firstAt} \u2192 ${w.lastAt}) \u2014 that is a single burst, not a standing rate. Check it against your own deploy log before acting: a cluster this tight is usually one incident, and may already be fixed.`;
10094
+ }
9878
10095
  var SEVERITY_SET = /* @__PURE__ */ new Set(["info", "warn", "critical"]);
9879
10096
  var STATUS_SET = /* @__PURE__ */ new Set(["open", "snoozed", "resolved"]);
9880
10097
  var RESOLUTION_SOURCE_SET = /* @__PURE__ */ new Set([
@@ -9914,10 +10131,18 @@ function rowToAdvisory(row) {
9914
10131
  if (docsLink) suggestedFix.docsLink = docsLink;
9915
10132
  if (suggestion) suggestedFix.before = suggestion;
9916
10133
  }
10134
+ const evidenceWindow = classifyEvidenceWindow(
10135
+ row
10136
+ );
10137
+ const declaredSeverity = asSeverity(row.severity);
10138
+ const downgraded = evidenceWindow?.isBurst === true && declaredSeverity === "critical";
10139
+ const effectiveSeverity = downgraded ? "warn" : declaredSeverity;
9917
10140
  const out = {
9918
10141
  id: typeof row.id === "string" ? row.id : "",
9919
10142
  rule: typeof row.rule === "string" ? row.rule : "",
9920
- severity: asSeverity(row.severity),
10143
+ severity: effectiveSeverity,
10144
+ evidenceWindow,
10145
+ ...downgraded ? { severityBeforeBurstDowngrade: declaredSeverity } : {},
9921
10146
  openedAt: typeof row.opened_at === "string" ? row.opened_at : "",
9922
10147
  lastObservedAt: typeof row.last_observed_at === "string" ? row.last_observed_at : "",
9923
10148
  observationCount: typeof row.observation_count === "number" ? row.observation_count : 0,
@@ -9925,7 +10150,13 @@ function rowToAdvisory(row) {
9925
10150
  ...archetype ? { archetype } : {},
9926
10151
  ...model ? { model } : {}
9927
10152
  },
9928
- message: typeof row.message === "string" ? row.message : "",
10153
+ // The caveat goes INLINE in the message, not only in `evidenceWindow`.
10154
+ // A structured field a consumer must think to read is the same defect
10155
+ // one layer along: the substrate knowing and not telling. The whole
10156
+ // point is that the check costs a glance rather than a query.
10157
+ message: (typeof row.message === "string" ? row.message : "") + (evidenceWindow?.isBurst ? `
10158
+
10159
+ ${burstCaveat(evidenceWindow)}` : ""),
9929
10160
  suggestedFix,
9930
10161
  autoApplicable: false,
9931
10162
  // reserved — alpha.30+
@@ -10463,9 +10694,14 @@ function compile2(ir, opts) {
10463
10694
  ABSOLUTE_FLOOR,
10464
10695
  ALIASES,
10465
10696
  ALL_ARCHETYPES,
10697
+ ALT_BLIND_TOKEN_BUDGET_BREACH,
10698
+ ALT_STRATEGY_IDS,
10466
10699
  ARCHETYPE_FAMILY_FITS,
10467
10700
  ARCHETYPE_FLOOR_DEFAULT,
10701
+ BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE,
10702
+ BLOCKED_MODEL_NOT_IN_ROSTER_CODE,
10468
10703
  BRAIN_READ_ENV_NAMES,
10704
+ BURST_SPAN_MS,
10469
10705
  COACH_CFG,
10470
10706
  COST_RANKING_REFERENCE_SHAPE,
10471
10707
  CallError,
@@ -10476,6 +10712,7 @@ function compile2(ir, opts) {
10476
10712
  DEFAULT_PROMOTIONS_ENDPOINT,
10477
10713
  DELEGATE_TOOL_DEFINITION,
10478
10714
  DIALECT_VERSION,
10715
+ DISCIPLINE_GATES_V1_ALT_BLIND_HEADER,
10479
10716
  DISCIPLINE_GATES_V1_ALT_HEADER,
10480
10717
  FamilyResolutionError,
10481
10718
  INTENT_ARCHETYPES,
@@ -10492,6 +10729,7 @@ function compile2(ir, opts) {
10492
10729
  RULE_DISCIPLINE_GATES_V1,
10493
10730
  RULE_DISCIPLINE_GATES_V1_STRUCTURED,
10494
10731
  RULE_SEQUENTIAL_TOOL_CLIFF,
10732
+ STRATEGY_AUTHORSHIP_INDEPENDENT,
10495
10733
  STRATEGY_AUTHORSHIP_LIMITATION,
10496
10734
  TRANSLATOR_FLOOR,
10497
10735
  _testResetMeasuredFailure,
@@ -10499,6 +10737,7 @@ function compile2(ir, opts) {
10499
10737
  _testWaitForMeasuredFailureRefresh,
10500
10738
  _testWaitForPromotionsRefresh,
10501
10739
  allProfiles,
10740
+ altBlindGatesBlockFor,
10502
10741
  altGatesBlockFor,
10503
10742
  applyArchetypeConvention,
10504
10743
  applySectionRewrites,
@@ -10512,9 +10751,11 @@ function compile2(ir, opts) {
10512
10751
  buildLLMJudge,
10513
10752
  buildPairwiseJudgePrompt,
10514
10753
  buildShadowProbeRow,
10754
+ burstCaveat,
10515
10755
  call,
10516
10756
  captureGoldenIr,
10517
10757
  chainProviderSpread,
10758
+ classifyEvidenceWindow,
10518
10759
  classifyStrategyOutcome,
10519
10760
  clearBrain,
10520
10761
  combineOrderSwappedVerdicts,
@@ -10534,6 +10775,7 @@ function compile2(ir, opts) {
10534
10775
  execute,
10535
10776
  findBetterFit,
10536
10777
  flushBrainDeadLetter,
10778
+ formatEvidenceSpan,
10537
10779
  getActionableAdvisories,
10538
10780
  getAllStarterChains,
10539
10781
  getAllStarterChainsWithGrounding,
@@ -10555,6 +10797,7 @@ function compile2(ir, opts) {
10555
10797
  getStarterChainWithGrounding,
10556
10798
  hasMutation,
10557
10799
  hashShape,
10800
+ isAltStrategy,
10558
10801
  isArchetype,
10559
10802
  isAutoPromoteEnabledFromEnv,
10560
10803
  isBrainQueryActiveFor,
@@ -10598,8 +10841,10 @@ function compile2(ir, opts) {
10598
10841
  resetTokenizer,
10599
10842
  resolveConventionsForProfile,
10600
10843
  resolveGoldenCaptureRate,
10844
+ resolveModelAlias,
10601
10845
  resolvePricingAt,
10602
10846
  resolveProviderKey,
10847
+ rowToAdvisory,
10603
10848
  rubricFor,
10604
10849
  runAdvisor,
10605
10850
  runGoldenEval,
@@ -10608,6 +10853,7 @@ function compile2(ir, opts) {
10608
10853
  shouldCaptureGolden,
10609
10854
  tryGetProfile,
10610
10855
  wilsonLowerBound,
10856
+ withAltBlindDisciplineContract,
10611
10857
  withAltDisciplineContract,
10612
10858
  withDisciplineContract
10613
10859
  });