@warmdrift/kgauto-compiler 2.0.0-alpha.28 → 2.0.0-alpha.29

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
@@ -29,7 +29,10 @@ __export(index_exports, {
29
29
  INTENT_ARCHETYPES: () => INTENT_ARCHETYPES,
30
30
  MEASURED_GROUNDING_MIN_N: () => MEASURED_GROUNDING_MIN_N,
31
31
  PROVIDER_ENV_KEYS: () => PROVIDER_ENV_KEYS,
32
+ RULE_SEQUENTIAL_TOOL_CLIFF: () => RULE_SEQUENTIAL_TOOL_CLIFF,
33
+ TRANSLATOR_FLOOR: () => TRANSLATOR_FLOOR,
32
34
  allProfiles: () => allProfiles,
35
+ applySectionRewrites: () => applySectionRewrites,
33
36
  bucketContext: () => bucketContext,
34
37
  bucketHistory: () => bucketHistory,
35
38
  bucketToolCount: () => bucketToolCount,
@@ -40,6 +43,7 @@ __export(index_exports, {
40
43
  configureBrain: () => configureBrain,
41
44
  countTokens: () => countTokens,
42
45
  execute: () => execute,
46
+ getActionableAdvisories: () => getActionableAdvisories,
43
47
  getAllStarterChains: () => getAllStarterChains,
44
48
  getAllStarterChainsWithGrounding: () => getAllStarterChainsWithGrounding,
45
49
  getArchetypePerfScore: () => getArchetypePerfScore,
@@ -65,6 +69,7 @@ __export(index_exports, {
65
69
  loadChainsFromBrain: () => loadChainsFromBrain,
66
70
  loadModelsFromBrain: () => loadModelsFromBrain,
67
71
  loadPricingFromBrain: () => loadPricingFromBrain,
72
+ markAdvisoryResolved: () => markAdvisoryResolved,
68
73
  profileToRow: () => profileToRow,
69
74
  profilesByProvider: () => profilesByProvider,
70
75
  record: () => record,
@@ -586,6 +591,7 @@ function lowerAnthropic(ir, profile, hints) {
586
591
  const historyCacheableTokens = markIndex >= 0 ? sumHistoryTokens(history, markIndex) : 0;
587
592
  const totalCacheableTokens = cacheableTokens + historyCacheableTokens;
588
593
  const cacheSavings = totalCacheableTokens / 1e6 * profile.costInputPer1m * (1 - (profile.lowering.cache.discount ?? 0.1));
594
+ const toolChoice = hints.wireOverrides?.parallelToolCalls === false && tools && tools.length > 0 ? { type: "auto", disable_parallel_tool_use: true } : void 0;
589
595
  return {
590
596
  request: {
591
597
  provider: "anthropic",
@@ -597,7 +603,8 @@ function lowerAnthropic(ir, profile, hints) {
597
603
  // floor surprised every consumer once (PB-Cairn contract-gaps brief, Gap 3).
598
604
  // Profile is the single source of truth; consumers wanting a tighter
599
605
  // budget can pass providerOverrides.anthropic.max_tokens explicitly.
600
- max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens
606
+ max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens,
607
+ tool_choice: toolChoice
601
608
  },
602
609
  diagnostics: {
603
610
  cacheableTokens,
@@ -791,6 +798,7 @@ function lowerOpenAI(ir, profile, hints) {
791
798
  const history = (ir.history ?? []).filter((m) => m.role !== "system");
792
799
  const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
793
800
  const historyCacheableTokens = histMarkIndex >= 0 ? sumHistoryTokens(history, histMarkIndex) : 0;
801
+ const openaiParallelToolCalls = hints.wireOverrides?.parallelToolCalls === false && ir.tools && ir.tools.length > 0 ? false : void 0;
794
802
  return {
795
803
  request: {
796
804
  provider: "openai",
@@ -798,7 +806,8 @@ function lowerOpenAI(ir, profile, hints) {
798
806
  messages,
799
807
  tools: ir.tools && ir.tools.length > 0 ? toOpenAITools(ir.tools) : void 0,
800
808
  response_format: ir.constraints?.structuredOutput ? { type: "json_object" } : void 0,
801
- reasoning_effort: hints.forceTerseOutput ? "low" : void 0
809
+ reasoning_effort: hints.forceTerseOutput ? "low" : void 0,
810
+ parallel_tool_calls: openaiParallelToolCalls
802
811
  },
803
812
  diagnostics: {
804
813
  cacheableTokens: 0,
@@ -2406,9 +2415,19 @@ function runAdvisor(ir, result, profile, policy, phase2) {
2406
2415
  out.push(...detectModelStaleEvidence(ir, profile));
2407
2416
  out.push(...detectTierDown(ir, profile, phase2));
2408
2417
  }
2409
- out.push(...detectArchetypePerfFloorBreach(ir, profile));
2418
+ if (!translatorClearedToolCallCliff(phase2)) {
2419
+ out.push(...detectArchetypePerfFloorBreach(ir, profile));
2420
+ }
2410
2421
  return out;
2411
2422
  }
2423
+ function translatorClearedToolCallCliff(phase2) {
2424
+ const rewrites = phase2?.sectionRewritesApplied;
2425
+ if (!rewrites || rewrites.length === 0) return false;
2426
+ for (const rw of rewrites) {
2427
+ if (rw.kind === "tool_call_contract") return true;
2428
+ }
2429
+ return false;
2430
+ }
2412
2431
  function detectCachingOff(ir, profile) {
2413
2432
  if (profile.provider !== "anthropic") return [];
2414
2433
  const totalChars = ir.sections.reduce((s, sec) => s + sec.text.length, 0);
@@ -2608,6 +2627,47 @@ function detectArchetypePerfFloorBreach(ir, profile) {
2608
2627
  ];
2609
2628
  }
2610
2629
 
2630
+ // src/translator.ts
2631
+ var TRANSLATOR_FLOOR = ARCHETYPE_FLOOR_DEFAULT;
2632
+ var RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
2633
+ var SEQUENTIAL_TOOL_PREAMBLE = "IMPORTANT: Use one tool call per response. Wait for the tool result before deciding the next tool. Do NOT batch tool calls in parallel.";
2634
+ function applySectionRewrites(args) {
2635
+ const { ir, profile, archetype } = args;
2636
+ if (!Array.isArray(ir.sections) || ir.sections.length === 0) {
2637
+ return { rewrittenIR: ir, rewrites: [] };
2638
+ }
2639
+ if (!profile.archetypePerf) {
2640
+ return { rewrittenIR: ir, rewrites: [] };
2641
+ }
2642
+ const archetypeScore = profile.archetypePerf[archetype];
2643
+ const cliffFires = typeof archetypeScore === "number" && archetypeScore < TRANSLATOR_FLOOR;
2644
+ if (!cliffFires) {
2645
+ return { rewrittenIR: ir, rewrites: [] };
2646
+ }
2647
+ const rewrites = [];
2648
+ const newSections = ir.sections.map((section) => {
2649
+ if (section.kind !== "tool_call_contract") return section;
2650
+ const originalText = section.text;
2651
+ const transformedText = `${SEQUENTIAL_TOOL_PREAMBLE}
2652
+
2653
+ ${originalText}`;
2654
+ rewrites.push({
2655
+ sectionId: section.id,
2656
+ kind: "tool_call_contract",
2657
+ rule: RULE_SEQUENTIAL_TOOL_CLIFF,
2658
+ originalText,
2659
+ transformedText,
2660
+ wireOverrides: { parallelToolCalls: false }
2661
+ });
2662
+ return { ...section, text: transformedText };
2663
+ });
2664
+ if (rewrites.length === 0) {
2665
+ return { rewrittenIR: ir, rewrites: [] };
2666
+ }
2667
+ const rewrittenIR = { ...ir, sections: newSections };
2668
+ return { rewrittenIR, rewrites };
2669
+ }
2670
+
2611
2671
  // src/compile.ts
2612
2672
  var counter = 0;
2613
2673
  function makeHandle() {
@@ -2651,9 +2711,33 @@ function compile(ir, opts = {}) {
2651
2711
  const cliffs = passApplyCliffs(workingIR, profile, inputTokens);
2652
2712
  workingIR = cliffs.value.ir;
2653
2713
  accumulatedMutations.push(...cliffs.mutations);
2714
+ const translated = applySectionRewrites({
2715
+ ir: workingIR,
2716
+ profile,
2717
+ archetype: ir.intent.archetype
2718
+ });
2719
+ workingIR = translated.rewrittenIR;
2720
+ const sectionRewritesApplied = translated.rewrites;
2721
+ let wireOverrides;
2722
+ for (const rw of sectionRewritesApplied) {
2723
+ if (!rw.wireOverrides) continue;
2724
+ if (!wireOverrides) wireOverrides = {};
2725
+ if (rw.wireOverrides.parallelToolCalls !== void 0) {
2726
+ wireOverrides.parallelToolCalls = rw.wireOverrides.parallelToolCalls;
2727
+ }
2728
+ }
2729
+ for (const rw of sectionRewritesApplied) {
2730
+ accumulatedMutations.push({
2731
+ id: `translator:${rw.rule}:${rw.sectionId}`,
2732
+ source: "translator",
2733
+ passName: "translator",
2734
+ description: `Rewrote section "${rw.sectionId}" (kind=${rw.kind}) via rule "${rw.rule}".`
2735
+ });
2736
+ }
2654
2737
  const lowered = lower(workingIR, profile, {
2655
2738
  forceThinkingZero: cliffs.value.loweringHints.forceThinkingZero,
2656
- forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput
2739
+ forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput,
2740
+ wireOverrides
2657
2741
  });
2658
2742
  validateFinalFit(workingIR, profile, inputTokens);
2659
2743
  const handle = makeHandle();
@@ -2701,7 +2785,13 @@ function compile(ir, opts = {}) {
2701
2785
  opts.policy,
2702
2786
  {
2703
2787
  fallbackChain,
2704
- profileResolver: phase2ProfileResolver
2788
+ profileResolver: phase2ProfileResolver,
2789
+ // alpha.29 — feed translator rewrites to the advisor so the
2790
+ // `archetype-perf-floor-breach` rule can suppress when the translator
2791
+ // already cleared the cliff for the same archetype. Without this,
2792
+ // both the rewrite AND the advisory fire — noisy, and the advisory
2793
+ // would mislead consumers into thinking the cliff is unaddressed.
2794
+ sectionRewritesApplied
2705
2795
  }
2706
2796
  );
2707
2797
  return {
@@ -2714,7 +2804,9 @@ function compile(ir, opts = {}) {
2714
2804
  mutationsApplied: accumulatedMutations,
2715
2805
  fallbackChain,
2716
2806
  advisories,
2717
- diagnostics
2807
+ diagnostics,
2808
+ sectionRewritesApplied,
2809
+ wireOverrides
2718
2810
  };
2719
2811
  }
2720
2812
  function validateIR(ir) {
@@ -2887,7 +2979,11 @@ function registerCompile(appId, archetype, ir, result) {
2887
2979
  // alpha.28: shape fields for Glass-Box renderer.
2888
2980
  toolsCount,
2889
2981
  historyDepth,
2890
- systemPromptChars
2982
+ systemPromptChars,
2983
+ // alpha.29: translator activity — persisted on the brain row so
2984
+ // cross-app aggregates can answer "Sonnet narration rule fired N times,
2985
+ // outcome quality lifted to M."
2986
+ sectionRewritesApplied: result.sectionRewritesApplied
2891
2987
  });
2892
2988
  }
2893
2989
  function estimateSystemPromptChars(sections) {
@@ -3023,7 +3119,11 @@ function buildPayload(input, reg) {
3023
3119
  history_depth: input.historyDepth ?? reg?.historyDepth,
3024
3120
  system_prompt_chars: input.systemPromptChars ?? reg?.systemPromptChars,
3025
3121
  fell_over_from: fellOverFrom,
3026
- fallback_reason: fallbackReason
3122
+ fallback_reason: fallbackReason,
3123
+ // alpha.29 — translator activity (migration 019). Send NULL when no
3124
+ // rewrites fired so the brain's "did the translator do anything?"
3125
+ // queries can use `IS NOT NULL` cleanly.
3126
+ section_rewrites_applied: reg?.sectionRewritesApplied && reg.sectionRewritesApplied.length > 0 ? reg.sectionRewritesApplied : null
3027
3127
  };
3028
3128
  }
3029
3129
  function computeCostUsd(modelId, tokensIn, tokensOut) {
@@ -4478,6 +4578,278 @@ function clamp(n) {
4478
4578
  return Math.max(0, Math.min(1, n));
4479
4579
  }
4480
4580
 
4581
+ // src/advisories-api.ts
4582
+ var SEVERITY_SET = /* @__PURE__ */ new Set(["info", "warn", "critical"]);
4583
+ var STATUS_SET = /* @__PURE__ */ new Set(["open", "snoozed", "resolved"]);
4584
+ var RESOLUTION_SOURCE_SET = /* @__PURE__ */ new Set([
4585
+ "auto",
4586
+ "consumer-marked",
4587
+ "declined"
4588
+ ]);
4589
+ function asString(v) {
4590
+ return typeof v === "string" && v.length > 0 ? v : void 0;
4591
+ }
4592
+ function asSeverity(v) {
4593
+ if (typeof v === "string" && SEVERITY_SET.has(v)) {
4594
+ return v;
4595
+ }
4596
+ return "info";
4597
+ }
4598
+ function asStatus(v) {
4599
+ if (typeof v === "string" && STATUS_SET.has(v)) {
4600
+ return v;
4601
+ }
4602
+ return "open";
4603
+ }
4604
+ function asResolutionSource(v) {
4605
+ if (typeof v === "string" && RESOLUTION_SOURCE_SET.has(v)) {
4606
+ return v;
4607
+ }
4608
+ return void 0;
4609
+ }
4610
+ function rowToAdvisory(row) {
4611
+ const archetype = asString(row.applies_to_archetype);
4612
+ const model = asString(row.applies_to_model);
4613
+ const docsLink = asString(row.docs_url);
4614
+ const suggestion = asString(row.suggestion);
4615
+ let suggestedFix = null;
4616
+ if (docsLink || suggestion) {
4617
+ suggestedFix = { type: "manual" };
4618
+ if (docsLink) suggestedFix.docsLink = docsLink;
4619
+ if (suggestion) suggestedFix.before = suggestion;
4620
+ }
4621
+ const out = {
4622
+ id: typeof row.id === "string" ? row.id : "",
4623
+ rule: typeof row.rule === "string" ? row.rule : "",
4624
+ severity: asSeverity(row.severity),
4625
+ openedAt: typeof row.opened_at === "string" ? row.opened_at : "",
4626
+ lastObservedAt: typeof row.last_observed_at === "string" ? row.last_observed_at : "",
4627
+ observationCount: typeof row.observation_count === "number" ? row.observation_count : 0,
4628
+ appliesTo: {
4629
+ ...archetype ? { archetype } : {},
4630
+ ...model ? { model } : {}
4631
+ },
4632
+ message: typeof row.message === "string" ? row.message : "",
4633
+ suggestedFix,
4634
+ autoApplicable: false,
4635
+ // reserved — alpha.30+
4636
+ status: asStatus(row.status)
4637
+ };
4638
+ const resolvedAt = asString(row.resolved_at);
4639
+ if (resolvedAt) out.resolvedAt = resolvedAt;
4640
+ const resolutionSource = asResolutionSource(row.resolution_source);
4641
+ if (resolutionSource) out.resolutionSource = resolutionSource;
4642
+ const resolutionNote = asString(row.resolution_note);
4643
+ if (resolutionNote) out.resolutionNote = resolutionNote;
4644
+ return out;
4645
+ }
4646
+ function resolveFetch(injected) {
4647
+ return injected ?? ((...args) => globalThis.fetch(...args));
4648
+ }
4649
+ function normalizeEndpoint(endpoint) {
4650
+ return endpoint.replace(/\/+$/, "");
4651
+ }
4652
+ async function getActionableAdvisories(opts) {
4653
+ const {
4654
+ appId,
4655
+ severity,
4656
+ status,
4657
+ brainEndpoint,
4658
+ brainJwt,
4659
+ brainAnonKey,
4660
+ fetch: injectedFetch
4661
+ } = opts;
4662
+ if (!appId) {
4663
+ throw new Error("getActionableAdvisories: appId is required");
4664
+ }
4665
+ const doFetch = resolveFetch(injectedFetch);
4666
+ const base = normalizeEndpoint(brainEndpoint);
4667
+ const qs = new URLSearchParams();
4668
+ qs.set("app_id", `eq.${appId}`);
4669
+ if (severity) qs.set("severity", `eq.${severity}`);
4670
+ const effectiveStatus = status ?? "open";
4671
+ if (effectiveStatus !== "all") {
4672
+ qs.set("status", `eq.${effectiveStatus}`);
4673
+ }
4674
+ qs.set("order", "last_observed_at.desc");
4675
+ const url = `${base}/rest/v1/actionable_advisories_v?${qs.toString()}`;
4676
+ let res;
4677
+ try {
4678
+ res = await doFetch(url, {
4679
+ method: "GET",
4680
+ headers: {
4681
+ Authorization: `Bearer ${brainJwt}`,
4682
+ apikey: brainAnonKey,
4683
+ Accept: "application/json"
4684
+ }
4685
+ });
4686
+ } catch (err) {
4687
+ const msg = err instanceof Error ? err.message : String(err);
4688
+ throw new Error(`getActionableAdvisories: network error: ${msg}`);
4689
+ }
4690
+ if (res.status === 401 || res.status === 403) {
4691
+ throw new Error("getActionableAdvisories: brain auth misconfig");
4692
+ }
4693
+ if (res.status >= 500) {
4694
+ throw new Error(`getActionableAdvisories: brain unavailable (${res.status})`);
4695
+ }
4696
+ if (!res.ok) {
4697
+ throw new Error(`getActionableAdvisories: bad request (${res.status})`);
4698
+ }
4699
+ let rows;
4700
+ try {
4701
+ rows = await res.json();
4702
+ } catch {
4703
+ throw new Error("getActionableAdvisories: malformed brain response");
4704
+ }
4705
+ if (!Array.isArray(rows)) {
4706
+ throw new Error("getActionableAdvisories: expected array from brain");
4707
+ }
4708
+ const out = [];
4709
+ for (const raw of rows) {
4710
+ if (raw && typeof raw === "object") {
4711
+ out.push(rowToAdvisory(raw));
4712
+ }
4713
+ }
4714
+ return out;
4715
+ }
4716
+ async function markAdvisoryResolved(opts) {
4717
+ const {
4718
+ id,
4719
+ resolutionNote,
4720
+ brainEndpoint,
4721
+ brainJwt,
4722
+ brainAnonKey,
4723
+ fetch: injectedFetch
4724
+ } = opts;
4725
+ if (!id) {
4726
+ return { ok: false, reason: "id_required" };
4727
+ }
4728
+ const doFetch = resolveFetch(injectedFetch);
4729
+ const base = normalizeEndpoint(brainEndpoint);
4730
+ const lookupUrl = `${base}/rest/v1/actionable_advisories_v?id=eq.${encodeURIComponent(id)}&select=app_id,rule`;
4731
+ let lookupRes;
4732
+ try {
4733
+ lookupRes = await doFetch(lookupUrl, {
4734
+ method: "GET",
4735
+ headers: {
4736
+ Authorization: `Bearer ${brainJwt}`,
4737
+ apikey: brainAnonKey,
4738
+ Accept: "application/json"
4739
+ }
4740
+ });
4741
+ } catch (err) {
4742
+ const msg = err instanceof Error ? err.message : String(err);
4743
+ return { ok: false, reason: `network_error:${msg}` };
4744
+ }
4745
+ if (lookupRes.status === 401 || lookupRes.status === 403) {
4746
+ return { ok: false, reason: "brain_auth_misconfig" };
4747
+ }
4748
+ if (lookupRes.status >= 500) {
4749
+ return { ok: false, reason: "brain_unavailable" };
4750
+ }
4751
+ if (!lookupRes.ok) {
4752
+ return { ok: false, reason: `brain_lookup_failed:${lookupRes.status}` };
4753
+ }
4754
+ let lookupRows;
4755
+ try {
4756
+ lookupRows = await lookupRes.json();
4757
+ } catch {
4758
+ return { ok: false, reason: "brain_lookup_malformed" };
4759
+ }
4760
+ if (!Array.isArray(lookupRows) || lookupRows.length === 0) {
4761
+ return { ok: false, reason: "advisory_not_found" };
4762
+ }
4763
+ const tuple = lookupRows[0];
4764
+ const appId = typeof tuple.app_id === "string" ? tuple.app_id : "";
4765
+ const code = typeof tuple.rule === "string" ? tuple.rule : "";
4766
+ if (!appId || !code) {
4767
+ return { ok: false, reason: "advisory_tuple_invalid" };
4768
+ }
4769
+ const outcomesUrl = `${base}/rest/v1/compile_outcomes?app_id=eq.${encodeURIComponent(appId)}&select=id`;
4770
+ let outcomesRes;
4771
+ try {
4772
+ outcomesRes = await doFetch(outcomesUrl, {
4773
+ method: "GET",
4774
+ headers: {
4775
+ Authorization: `Bearer ${brainJwt}`,
4776
+ apikey: brainAnonKey,
4777
+ Accept: "application/json"
4778
+ }
4779
+ });
4780
+ } catch (err) {
4781
+ const msg = err instanceof Error ? err.message : String(err);
4782
+ return { ok: false, reason: `network_error:${msg}` };
4783
+ }
4784
+ if (outcomesRes.status === 401 || outcomesRes.status === 403) {
4785
+ return { ok: false, reason: "brain_auth_misconfig" };
4786
+ }
4787
+ if (outcomesRes.status >= 500) {
4788
+ return { ok: false, reason: "brain_unavailable" };
4789
+ }
4790
+ if (!outcomesRes.ok) {
4791
+ return { ok: false, reason: `brain_lookup_failed:${outcomesRes.status}` };
4792
+ }
4793
+ let outcomeRows;
4794
+ try {
4795
+ outcomeRows = await outcomesRes.json();
4796
+ } catch {
4797
+ return { ok: false, reason: "brain_lookup_malformed" };
4798
+ }
4799
+ if (!Array.isArray(outcomeRows)) {
4800
+ return { ok: false, reason: "brain_lookup_malformed" };
4801
+ }
4802
+ const outcomeIds = [];
4803
+ for (const row of outcomeRows) {
4804
+ if (row && typeof row === "object") {
4805
+ const idVal = row.id;
4806
+ if (typeof idVal === "number" && Number.isFinite(idVal)) {
4807
+ outcomeIds.push(idVal);
4808
+ }
4809
+ }
4810
+ }
4811
+ if (outcomeIds.length === 0) {
4812
+ return { ok: true };
4813
+ }
4814
+ const inList = outcomeIds.join(",");
4815
+ const patchUrl = `${base}/rest/v1/compile_outcome_advisories?outcome_id=in.(${inList})&code=eq.${encodeURIComponent(code)}&resolved_at=is.null`;
4816
+ const patchBody = {
4817
+ resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
4818
+ resolution_source: "consumer-marked"
4819
+ };
4820
+ if (resolutionNote !== void 0) {
4821
+ patchBody.resolution_note = resolutionNote;
4822
+ }
4823
+ let patchRes;
4824
+ try {
4825
+ patchRes = await doFetch(patchUrl, {
4826
+ method: "PATCH",
4827
+ headers: {
4828
+ Authorization: `Bearer ${brainJwt}`,
4829
+ apikey: brainAnonKey,
4830
+ "Content-Type": "application/json",
4831
+ Accept: "application/json",
4832
+ // PostgREST default is no return; we don't need the row back.
4833
+ Prefer: "return=minimal"
4834
+ },
4835
+ body: JSON.stringify(patchBody)
4836
+ });
4837
+ } catch (err) {
4838
+ const msg = err instanceof Error ? err.message : String(err);
4839
+ return { ok: false, reason: `network_error:${msg}` };
4840
+ }
4841
+ if (patchRes.status === 401 || patchRes.status === 403) {
4842
+ return { ok: false, reason: "brain_auth_misconfig" };
4843
+ }
4844
+ if (patchRes.status >= 500) {
4845
+ return { ok: false, reason: "brain_unavailable" };
4846
+ }
4847
+ if (!patchRes.ok) {
4848
+ return { ok: false, reason: `patch_failed:${patchRes.status}` };
4849
+ }
4850
+ return { ok: true };
4851
+ }
4852
+
4481
4853
  // src/models-brain.ts
4482
4854
  function isModelRow(x) {
4483
4855
  if (!x || typeof x !== "object") return false;
@@ -4614,7 +4986,10 @@ function compile2(ir, opts) {
4614
4986
  INTENT_ARCHETYPES,
4615
4987
  MEASURED_GROUNDING_MIN_N,
4616
4988
  PROVIDER_ENV_KEYS,
4989
+ RULE_SEQUENTIAL_TOOL_CLIFF,
4990
+ TRANSLATOR_FLOOR,
4617
4991
  allProfiles,
4992
+ applySectionRewrites,
4618
4993
  bucketContext,
4619
4994
  bucketHistory,
4620
4995
  bucketToolCount,
@@ -4625,6 +5000,7 @@ function compile2(ir, opts) {
4625
5000
  configureBrain,
4626
5001
  countTokens,
4627
5002
  execute,
5003
+ getActionableAdvisories,
4628
5004
  getAllStarterChains,
4629
5005
  getAllStarterChainsWithGrounding,
4630
5006
  getArchetypePerfScore,
@@ -4650,6 +5026,7 @@ function compile2(ir, opts) {
4650
5026
  loadChainsFromBrain,
4651
5027
  loadModelsFromBrain,
4652
5028
  loadPricingFromBrain,
5029
+ markAdvisoryResolved,
4653
5030
  profileToRow,
4654
5031
  profilesByProvider,
4655
5032
  record,