@warmdrift/kgauto-compiler 2.0.0-alpha.5 → 2.0.0-alpha.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +140 -3
  2. package/dist/chunk-CXH7KC4D.mjs +1413 -0
  3. package/dist/chunk-HHWBB46W.mjs +694 -0
  4. package/dist/chunk-NBO4R5PC.mjs +313 -0
  5. package/dist/chunk-P3TOAEG4.mjs +56 -0
  6. package/dist/chunk-RO22VFIF.mjs +29 -0
  7. package/dist/glassbox/index.d.mts +59 -0
  8. package/dist/glassbox/index.d.ts +59 -0
  9. package/dist/glassbox/index.js +312 -0
  10. package/dist/glassbox/index.mjs +12 -0
  11. package/dist/glassbox-routes/format.d.mts +24 -0
  12. package/dist/glassbox-routes/format.d.ts +24 -0
  13. package/dist/glassbox-routes/format.js +86 -0
  14. package/dist/glassbox-routes/format.mjs +18 -0
  15. package/dist/glassbox-routes/index.d.mts +191 -0
  16. package/dist/glassbox-routes/index.d.ts +191 -0
  17. package/dist/glassbox-routes/index.js +2657 -0
  18. package/dist/glassbox-routes/index.mjs +663 -0
  19. package/dist/glassbox-routes/react/index.d.mts +74 -0
  20. package/dist/glassbox-routes/react/index.d.ts +74 -0
  21. package/dist/glassbox-routes/react/index.js +819 -0
  22. package/dist/glassbox-routes/react/index.mjs +754 -0
  23. package/dist/index.d.mts +2046 -9
  24. package/dist/index.d.ts +2046 -9
  25. package/dist/index.js +6266 -1079
  26. package/dist/index.mjs +3387 -186
  27. package/dist/ir-dDcG8Pvu.d.mts +1337 -0
  28. package/dist/ir-rUUojj0s.d.ts +1337 -0
  29. package/dist/profiles.d.mts +292 -2
  30. package/dist/profiles.d.ts +292 -2
  31. package/dist/profiles.js +1024 -16
  32. package/dist/profiles.mjs +9 -1
  33. package/dist/types-BTeRoSvM.d.mts +149 -0
  34. package/dist/types-B_pdPjxm.d.ts +149 -0
  35. package/dist/types-UXPxWabQ.d.ts +131 -0
  36. package/dist/types-vGo-h0tZ.d.mts +131 -0
  37. package/package.json +42 -6
  38. package/dist/chunk-MBEI5UOM.mjs +0 -409
  39. package/dist/profiles-DHdCRBVH.d.mts +0 -571
  40. package/dist/profiles-MGq5Tnjv.d.ts +0 -571
package/dist/index.d.mts CHANGED
@@ -1,6 +1,9 @@
1
- import { M as ModelProfile, C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, R as RecordInput, O as OracleScore, e as CompileResult } from './profiles-DHdCRBVH.mjs';
2
- export { f as ALIASES, g as CacheStrategy, h as CallAttempt, i as CallError, j as CliffRule, k as Constraints, I as IntentDeclaration, L as LoweringSpec, l as Message, m as MutationApplied, n as NormalizedTokens, o as PromptSection, p as Provider, q as RecoveryRule, S as StructuredOutputCapability, r as SystemPromptMode, T as ToolCall, s as ToolDefinition, t as allProfiles, u as getProfile, v as profilesByProvider, w as tryGetProfile } from './profiles-DHdCRBVH.mjs';
3
- export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, IntentArchetypeName, OutputMode, ShapeSignature, ToolCountBucket, bucketContext, bucketHistory, bucketToolCount, hashShape, isArchetype, learningKey } from './dialect.mjs';
1
+ import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, B as BestPracticeAdvisory, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-dDcG8Pvu.mjs';
2
+ export { m as CallAttempt, n as CallError, o as ChainModelEntry, p as ChainWithGrounding, q as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, r as MutationApplied, s as NormalizedTokens, t as OutcomeKind, u as PerAxisMetricsByModel, v as PromptSection, w as SectionKind, x as ShadowProbeConfig, T as ToolCall, y as ToolDefinition } from './ir-dDcG8Pvu.mjs';
3
+ import { ModelProfile, ArchetypeConvention } from './profiles.mjs';
4
+ export { ALIASES, CacheStrategy, CliffRule, LATENCY_TIER_MS, LatencyTier, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, allProfiles, getProfile, latencyTierOf, profilesByProvider, tryGetProfile } from './profiles.mjs';
5
+ import { IntentArchetypeName } from './dialect.mjs';
6
+ export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, OutputMode, ShapeSignature, ToolCountBucket, bucketContext, bucketHistory, bucketToolCount, hashShape, isArchetype, learningKey } from './dialect.mjs';
4
7
 
5
8
  /**
6
9
  * compile() — the main orchestrator.
@@ -19,6 +22,15 @@ interface CompileOptions {
19
22
  toolRelevanceThreshold?: number;
20
23
  /** History compression — turns count threshold (default 8). */
21
24
  compressHistoryAfter?: number;
25
+ /**
26
+ * History compression — token threshold (alpha.7). When total history
27
+ * tokens exceed this AND there are more recent turns to keep, compress
28
+ * even when count threshold is below `compressHistoryAfter`. Catches
29
+ * fat-message bloat (tool-using agents pack many tool-call/result pairs
30
+ * into single assistant messages — count stays low, tokens explode).
31
+ * Default undefined (disabled — backward-compatible).
32
+ */
33
+ compressHistoryAboveTokens?: number;
22
34
  /**
23
35
  * Consumer-declared policy. Filters blocked models, enforces cost
24
36
  * ceiling, boosts preferred. See CompilePolicy in ir.ts.
@@ -42,6 +54,15 @@ interface ExecuteOptions {
42
54
  apiKeys?: ApiKeys;
43
55
  fetchImpl?: typeof fetch;
44
56
  providerOverrides?: ProviderOverrides;
57
+ /**
58
+ * alpha.34. When supplied AND the chosen provider supports streaming, the
59
+ * execute() per-provider branch switches to SSE wire format and invokes
60
+ * `onChunk(delta)` once per text-delta event. Single-shot behavior
61
+ * preserved when omitted (current consumers unaffected). Wired from
62
+ * `CallOptions.onChunk` by `call()` after gating on `profile.streaming`
63
+ * and `!opts.noStream`.
64
+ */
65
+ onChunk?: (chunk: string) => void;
45
66
  }
46
67
  interface ExecuteOk {
47
68
  ok: true;
@@ -81,17 +102,194 @@ declare function execute(request: CompiledRequest, opts?: ExecuteOptions): Promi
81
102
  * exhausted without success.
82
103
  */
83
104
  declare function call(ir: PromptIR, opts?: CallOptions): Promise<CallResult>;
105
+ /** Served-side result the AI-SDK consumer already holds from streamText. */
106
+ interface ProbeShadowServed {
107
+ /** Model id that actually served the user (becomes `current_model` on the row). */
108
+ model: string;
109
+ /** The served response text (stored as a preview; never the prompt). */
110
+ responseText: string;
111
+ /** Served prompt tokens (AI SDK `usage.promptTokens`). */
112
+ tokensIn: number;
113
+ /** Served completion tokens (AI SDK `usage.completionTokens`). */
114
+ tokensOut: number;
115
+ /** The user's actual wait in ms (alpha.46 served-latency axis). */
116
+ latencyMs: number;
117
+ }
118
+ /** Options for the standalone {@link probeShadow} export. */
119
+ interface ProbeShadowOptions {
120
+ /** The served leg the consumer supplies; kgauto runs the candidate leg. */
121
+ served: ProbeShadowServed;
122
+ /** Model id(s)/family alias(es) to shadow-test against the served model. */
123
+ candidates: string | string[];
124
+ /** Probability [0,1] a given call fires a probe. Default 0.05; pin 1 for dogfood. */
125
+ sampleRate?: number;
126
+ /** Phase 1 = 'off' (offline rollup). 'opus' inline judge is Phase 2. Default 'off'. */
127
+ judge?: 'off' | 'opus';
128
+ /** Override API keys (defaults: process.env). Gates candidate reachability. */
129
+ apiKeys?: ApiKeys;
130
+ /** Override fetch (for tests / custom transport). */
131
+ fetchImpl?: typeof fetch;
132
+ /** Provider-specific request fields shallow-merged into the candidate request. */
133
+ providerOverrides?: ProviderOverrides;
134
+ /** Forwarded to compile() for the candidate run (match the served-side compile). */
135
+ policy?: CompilePolicy;
136
+ toolRelevanceThreshold?: number;
137
+ compressHistoryAfter?: number;
138
+ }
139
+ /**
140
+ * s54 — standalone full-IR shadow probe for AI-SDK consumers (tt-intel hunt, IC
141
+ * chat) that own their own streamText round-trip and never call call(). Fire it
142
+ * from the streamText `onFinish` callback, wrapped in the platform's
143
+ * `waitUntil()` / `after()`, so it runs after the response is flushed — no
144
+ * blocking, no `sync:true`, no teardown race (cleaner than call()'s in-process
145
+ * fire-and-forget for Edge runtimes; L-086).
146
+ *
147
+ * Runs the SAME candidate loop as the call()-inline probe ({@link
148
+ * runProbeCandidates}): same gates (sample, self-skip, G4 judge-self,
149
+ * reachability, G6), same fidelity=1.0 full-IR rows, same alpha.46 latency
150
+ * capture. The consumer supplies the served leg it already has; kgauto runs the
151
+ * candidate(s) and writes the `probe_outcomes` row.
152
+ *
153
+ * Requires `configureBrain()` to have been called (same as call()).
154
+ * Fire-and-forget: never throws into the caller.
155
+ *
156
+ * @example
157
+ * const result = streamText({ model, system, messages,
158
+ * onFinish: ({ text, usage }) => {
159
+ * after(() => probeShadow(ir, {
160
+ * served: { model: servedModelId, responseText: text,
161
+ * tokensIn: usage.promptTokens, tokensOut: usage.completionTokens,
162
+ * latencyMs: Date.now() - t0 },
163
+ * candidates: ['deepseek-v4-pro'], sampleRate: 0.05,
164
+ * }));
165
+ * },
166
+ * });
167
+ */
168
+ declare function probeShadow(ir: PromptIR, opts: ProbeShadowOptions): Promise<void>;
169
+
170
+ /**
171
+ * alpha.33 — AI-SDK streamText helpers.
172
+ *
173
+ * The cross-consumer pattern surfaced 2026-05-20 (`streamText-cache-marker-
174
+ * propagation-gap` on `command-center/interfaces/kgauto.md ## Requested`):
175
+ * AI-SDK consumers using `streamText({ system: <string>, messages:
176
+ * convertToModelMessages(messages), model })` silently drop the Anthropic
177
+ * `cache_control` markers the compiler emits on `result.request.messages`.
178
+ * Two losses on that line:
179
+ * (a) `convertToModelMessages()` reads raw inputs not the lowered output,
180
+ * dropping per-message providerOptions; and
181
+ * (b) `streamText({ system: '<string>' })` strips any providerOptions
182
+ * on the system prefix.
183
+ *
184
+ * Net effect prior to this surface: `cache_read_input_tokens = 0` across
185
+ * every measured production call by IC + tt-intel even though both
186
+ * consumers had `historyCachePolicy: { strategy: 'all-but-latest' }` wired
187
+ * since alpha.5. The compiler did the right thing; the consumer integration
188
+ * pattern lost the markers at the wire boundary.
189
+ *
190
+ * This helper closes the gap. Pass the consumer's already-converted messages
191
+ * + the kgauto CompileResult and get back a `{ system, messages }` pair
192
+ * with cacheControl re-attached at the deterministic indices the compiler
193
+ * computed (`diagnostics.historyCacheMarkIndex` + `systemMessages` with
194
+ * its own cacheControl markers).
195
+ *
196
+ * No I/O. Pure transform. Idempotent — calling twice with the same inputs
197
+ * produces structurally-identical output.
198
+ */
84
199
 
85
200
  /**
86
- * Brain client — fire-and-forget telemetry to the central kgauto Supabase.
201
+ * AI-SDK-shaped converted-message structure. Matches what
202
+ * `convertToModelMessages()` returns at the wire layer. We don't import
203
+ * the AI-SDK type to avoid pulling that dep into the kgauto-compiler
204
+ * package — consumers pass their own already-converted messages.
205
+ */
206
+ interface AISDKConvertedMessage {
207
+ role: 'system' | 'user' | 'assistant' | 'tool';
208
+ content: unknown;
209
+ providerOptions?: {
210
+ anthropic?: {
211
+ cacheControl?: {
212
+ type: 'ephemeral';
213
+ };
214
+ };
215
+ };
216
+ }
217
+ /**
218
+ * Result of `attachCacheControlToStreamTextInput()` — ready to spread into
219
+ * `streamText(...)` directly.
220
+ *
221
+ * The `system` field is either the structured `SystemModelMessage[]` form
222
+ * (when the compiler computed at least one cacheable section + chose
223
+ * Anthropic) or the flat-string concatenation (when no cacheable sections
224
+ * exist OR the provider isn't Anthropic). Consumers can pass either form
225
+ * to `streamText({ system })` — the AI-SDK accepts both.
226
+ */
227
+ interface AttachCacheControlResult {
228
+ system: string | SystemModelMessage[];
229
+ messages: AISDKConvertedMessage[];
230
+ }
231
+ /**
232
+ * Attach Anthropic cache_control markers to a streamText input that the
233
+ * consumer has already prepared via `convertToModelMessages()`. Reads
234
+ * `result.diagnostics.historyCacheMarkIndex` for the position-on-history
235
+ * marker and `result.systemMessages` for the per-section system markers.
236
+ *
237
+ * The flat-string `system` form is returned when:
238
+ * - the compiler produced no `systemMessages` (e.g., zero sections kept), or
239
+ * - the chosen provider is not Anthropic, so cacheControl wouldn't
240
+ * achieve anything at the wire layer (other providers cache implicitly
241
+ * based on prefix shape, no marker needed).
87
242
  *
88
- * The brain is the centralized learning store. Apps POST outcomes here;
89
- * mutations flow back through a separate pull (in v2.1).
243
+ * Otherwise the structured `SystemModelMessage[]` form is returned
244
+ * preserves the per-section cacheControl markers across `streamText`.
90
245
  *
91
- * Design: never blocks the caller. Failures are silent (logged via optional
92
- * onError hook). Uses fetch() works in Node 18+, Edge runtimes, and browsers.
246
+ * @param result - kgauto CompileResult from `compile(ir, opts)`
247
+ * @param convertedMessages - the consumer's already-converted messages
248
+ * (from `convertToModelMessages(rawMessages)` in their AI-SDK call site)
249
+ * @returns `{ system, messages }` ready to spread into `streamText(...)`
93
250
  */
251
+ declare function attachCacheControlToStreamTextInput(result: CompileResult, convertedMessages: AISDKConvertedMessage[]): AttachCacheControlResult;
94
252
 
253
+ /**
254
+ * alpha.11 — opt-in nested config for brain-query mode (chains / archetype
255
+ * perf / pricing / models registry). Enabled by default when endpoint is
256
+ * set; per-table opt-out via explicit `false`.
257
+ *
258
+ * Locked via /plan-eng-review 2026-05-15 (decision D3). Structured group
259
+ * keeps the BrainConfig surface clean as more brain-driven tables ship.
260
+ */
261
+ interface BrainQueryConfig {
262
+ /** Default true when endpoint set. Brain-driven fallback chains. */
263
+ chains?: boolean;
264
+ /** Default true when endpoint set. Brain-driven archetype perf scores. */
265
+ perf?: boolean;
266
+ /** Default true when endpoint set. Brain-driven pricing with at-time resolution. */
267
+ pricing?: boolean;
268
+ /** Default true when endpoint set. Brain-driven model registry + aliases. */
269
+ models?: boolean;
270
+ /**
271
+ * alpha.38 — opt-in compile-time advisor for stale exclusions. Default
272
+ * `true` when endpoint is set. When enabled, the library reads
273
+ * `exclusion_findings` from the central kgauto-dashboard for the consumer's
274
+ * `app_id` (no consumer-side proxy work required) and surfaces a
275
+ * `stale-exclusion-candidate` advisory when compile()'s archetype has a
276
+ * recommend-probe finding open. Set `false` to silence (no fetch, no
277
+ * advisory).
278
+ */
279
+ findingsExclusions?: boolean;
280
+ /** SWR window in ms. Default 300_000 (5 min). */
281
+ cacheTtlMs?: number;
282
+ /** Override the GET URL when the read endpoint differs from the write one.
283
+ * Defaults to `${endpoint}/v2/config` when omitted. */
284
+ configEndpoint?: string;
285
+ /**
286
+ * alpha.38 — override the findings endpoint when the consumer wants to
287
+ * proxy `exclusion_findings` reads through their own service rather than
288
+ * reading directly from the kgauto-dashboard. Library appends `?app_id=X`.
289
+ * Defaults to `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions`.
290
+ */
291
+ findingsEndpoint?: string;
292
+ }
95
293
  interface BrainConfig {
96
294
  /** Brain HTTP endpoint base URL (e.g., https://kgauto-brain.vercel.app/api). */
97
295
  endpoint: string;
@@ -103,6 +301,9 @@ interface BrainConfig {
103
301
  sync?: boolean;
104
302
  /** Optional fetch override (for tests). */
105
303
  fetchImpl?: typeof fetch;
304
+ /** alpha.11 — brain-query mode for config tables. Default-on per table
305
+ * when endpoint is set; opt-out via `false`. See BrainQueryConfig. */
306
+ brainQuery?: BrainQueryConfig;
106
307
  }
107
308
  declare function configureBrain(config: BrainConfig): void;
108
309
  declare function clearBrain(): void;
@@ -114,6 +315,175 @@ declare function clearBrain(): void;
114
315
  * network error is swallowed/forwarded to onError.
115
316
  */
116
317
  declare function record(input: RecordInput): Promise<void>;
318
+ /**
319
+ * Wire shape POSTed by `record()` to the brain proxy's `/outcomes` endpoint.
320
+ *
321
+ * Exported so consumer proxies can `import { OutcomePayload } from
322
+ * '@warmdrift/kgauto-compiler'` instead of redefining the shape — that way
323
+ * TypeScript catches future schema additions (cache fields, advisory
324
+ * telemetry, etc.) at consumer build time, not silently at runtime.
325
+ *
326
+ * **Forward-compat rule:** consumer proxies should pass the body through to
327
+ * Supabase rather than reconstructing field-by-field. The recommended shape
328
+ * is `const row = { ...body }` (or `await supabase.from('compile_outcomes')
329
+ * .insert(body)` directly). Filtering proxies break schema evolution
330
+ * silently — see s17 root-cause investigation 2026-05-10.
331
+ */
332
+ interface OutcomePayload {
333
+ handle: string;
334
+ app_id?: string;
335
+ intent_archetype?: string;
336
+ /** The model that ACTUALLY RAN (post-fallback). */
337
+ model?: string;
338
+ /** The model v2 compile() originally targeted. NULL when no fallback. */
339
+ requested_model?: string;
340
+ provider?: string;
341
+ shape_key?: string;
342
+ learning_key?: string;
343
+ mutations_applied: string[];
344
+ tokens_in: number;
345
+ tokens_out: number;
346
+ estimated_tokens_in?: number;
347
+ latency_ms: number;
348
+ success: boolean;
349
+ empty_response: boolean;
350
+ error_type?: string;
351
+ tools_called?: string[];
352
+ oracle_score?: number;
353
+ oracle_dimensions?: Record<string, number>;
354
+ oracle_rationale?: string;
355
+ prompt_preview?: string;
356
+ response_preview?: string;
357
+ dialect_version: string;
358
+ cache_read_input_tokens?: number;
359
+ cache_creation_input_tokens?: number;
360
+ cost_usd_actual?: number;
361
+ ttft_ms?: number;
362
+ history_cacheable_tokens?: number;
363
+ history_tokens_at_compile?: number;
364
+ /**
365
+ * Mirrors `ir.constraints.toolOrchestration` from compile time. NULL when
366
+ * the consumer hadn't adopted the constraint (pre-alpha.20). Powers
367
+ * per-mode model-perf queries on the brain (the L-040 parallel-tool
368
+ * cliff lumps DeepSeek sequential perf with parallel without this).
369
+ */
370
+ tool_orchestration?: 'parallel' | 'sequential' | 'either' | null;
371
+ finish_reason?: string;
372
+ total_ms?: number;
373
+ tools_count?: number;
374
+ history_depth?: number;
375
+ system_prompt_chars?: number;
376
+ fell_over_from?: string;
377
+ fallback_reason?: 'rate_limit' | 'provider_auth_failed' | 'provider_error' | 'cliff' | 'cost_cap' | 'contract_violation';
378
+ /**
379
+ * Per-call SectionRewrite[] captured at compile time. Omitted (sent as
380
+ * undefined → stored NULL) when no rewrites fired. Powers cross-app
381
+ * learning aggregates ("rule X fired N times on (app, model, archetype),
382
+ * downstream outcome quality lifted by M points").
383
+ */
384
+ section_rewrites_applied?: SectionRewrite[] | null;
385
+ }
386
+ /**
387
+ * alpha.20 Entry 4: record a quality outcome for a previously-compiled call.
388
+ *
389
+ * Fires after the consumer's UX surfaces an approve/reject event (e.g., user
390
+ * clicks Approve on a hunt result). Joins to the original `compile_outcomes`
391
+ * row via outcomeId — enables per-(model, archetype) approve-rate measurement
392
+ * once N ≥ 10 outcomes accumulate.
393
+ *
394
+ * Fire-and-forget by default (matches record() semantics). Set BrainConfig.sync
395
+ * = true for runtime contexts that can't tolerate fire-and-forget teardown
396
+ * (Vercel Edge, Cloudflare Workers, AWS Lambda) — see L-086.
397
+ *
398
+ * Returns OutcomeResult with ok: false + stable reason on persistence
399
+ * failure. Never throws.
400
+ */
401
+ declare function recordOutcome(input: RecordOutcomeInput): Promise<OutcomeResult>;
402
+ /**
403
+ * True when the active brain config requests synchronous (awaited) writes.
404
+ * call()'s shadow-probe path reads this to decide whether to await the probe
405
+ * (Edge/Worker/Lambda — L-086) or fire-and-forget (Node). False when no brain
406
+ * is configured.
407
+ */
408
+ declare function isBrainSync(): boolean;
409
+ /**
410
+ * Full-IR inline shadow-probe record input (Shape B, Phase 1 — s51). Carries
411
+ * ONLY response previews + metadata; the prompt (system/context/payload) is
412
+ * never included — `promptHash` is an irreversible grouping key, not content.
413
+ */
414
+ interface ShadowProbeRecordInput {
415
+ appId: string;
416
+ archetype: string;
417
+ family: string;
418
+ candidateModel: string;
419
+ currentModel: string;
420
+ /** Irreversible grouping hash (NOT the prompt). */
421
+ promptHash: string;
422
+ /** Served model's response, truncated (RESPONSE text only — never the prompt). */
423
+ currentResponsePreview?: string;
424
+ /** Candidate model's response, truncated. */
425
+ candidateResponsePreview?: string;
426
+ tokensCurrentIn?: number;
427
+ tokensCurrentOut?: number;
428
+ tokensCandidateIn?: number;
429
+ tokensCandidateOut?: number;
430
+ /**
431
+ * Wall-clock latency of the served call, ms (alpha.46). The third swap-decision
432
+ * axis alongside quality + cost — a verdict needs to know the candidate is
433
+ * slower, not just better/cheaper. Served latency mirrors
434
+ * `compile_outcomes.latency_ms`; carried here so a probe row is self-contained.
435
+ */
436
+ latencyCurrentMs?: number;
437
+ /** Wall-clock latency of the candidate replay call, ms (alpha.46). */
438
+ latencyCandidateMs?: number;
439
+ /**
440
+ * alpha — probe-row class (migration 029). Defaults to `'completed'` (the
441
+ * pre-029 row shape: candidate ran, columns populated). `'aborted_latency_budget'`
442
+ * and `'skipped_slow_tier_sync'` are DIAGNOSTIC rows from sync-mode latency
443
+ * protection — no candidate response, no verdict, no false quality signal. A
444
+ * verdict rollup MUST filter to `outcome='completed'`.
445
+ */
446
+ outcome?: 'completed' | 'aborted_latency_budget' | 'skipped_slow_tier_sync';
447
+ }
448
+ /**
449
+ * Pure builder for the `probe_outcomes` row written by the inline shadow-probe.
450
+ * Exported so a test can assert the G3 privacy invariant: the row carries NO
451
+ * prompt/system/context text — only response previews + metadata + a hash.
452
+ *
453
+ * Phase 1 (judge: 'off'): `judge_verdict` / `judge_score` are null — the row
454
+ * is an unjudged sample for the Phase-2 offline batch judge. `prompt_fidelity`
455
+ * is 1.0 by construction (the candidate ran the full IR, not a truncated
456
+ * preview), and `replay_source='inline-full-ir'` marks it as a trustworthy row
457
+ * (vs the watchers' lossy `replay-preview`).
458
+ */
459
+ declare function buildShadowProbeRow(input: ShadowProbeRecordInput): {
460
+ app_id: string;
461
+ intent_archetype: string;
462
+ family: string;
463
+ candidate_model: string;
464
+ current_model: string;
465
+ prompt_hash: string;
466
+ current_response: string | null;
467
+ candidate_response: string | null;
468
+ judge_verdict: null;
469
+ judge_score: null;
470
+ tokens_current_in: number | null;
471
+ tokens_current_out: number | null;
472
+ tokens_candidate_in: number | null;
473
+ tokens_candidate_out: number | null;
474
+ latency_current_ms: number | null;
475
+ latency_candidate_ms: number | null;
476
+ prompt_fidelity: number;
477
+ replay_source: 'inline-full-ir';
478
+ outcome: 'completed' | 'aborted_latency_budget' | 'skipped_slow_tier_sync';
479
+ };
480
+ /**
481
+ * Persist one inline shadow-probe row to `probe_outcomes`. Fire-and-forget by
482
+ * default; honors `BrainConfig.sync` (L-086). Never throws — failures route to
483
+ * onError. Mirrors record()'s POST shape; consumer proxies forward
484
+ * `/probe_outcomes` the same way they forward `/outcomes`.
485
+ */
486
+ declare function recordShadowProbe(input: ShadowProbeRecordInput): Promise<void>;
117
487
 
118
488
  /**
119
489
  * Oracle contract — how an app tells the brain whether a response was good.
@@ -166,6 +536,34 @@ interface LLMJudgeOptions {
166
536
  */
167
537
  declare function buildLLMJudge(opts: LLMJudgeOptions): AppOracle;
168
538
 
539
+ /**
540
+ * Resolve the effective ArchetypeConvention[] for a given selected profile,
541
+ * walking family inheritance once. Model-specific entries on the selected
542
+ * profile take precedence over family-level entries for the same archetype.
543
+ *
544
+ * Pure; safe to call from any context (probe-watcher uses the same logic
545
+ * via `applyArchetypeConvention`).
546
+ */
547
+ declare function resolveConventionsForProfile(profile: ModelProfile): ArchetypeConvention[];
548
+ /**
549
+ * Pure helper: apply the matching ArchetypeConvention's suffix (and
550
+ * prefix, when meaningful) to a plain prompt-text string. Used by the
551
+ * exclusion-probe-watcher (`probeOne`) so probe calls carry the same
552
+ * forcing-function shape consumers see at compile time. Without this,
553
+ * every reasoner probe on a decisive archetype gets unfairly stay-excluded
554
+ * for hedging — as ID 20 demonstrated on 2026-05-28.
555
+ *
556
+ * Resolution: looks up the family-rep profile for `family` and reads its
557
+ * `archetypeConventions`. Returns the original text unchanged when no
558
+ * convention matches or when the suffix is already present.
559
+ *
560
+ * @param promptText raw user-prompt text (or prompt_preview from outcome)
561
+ * @param archetype intent_archetype from the finding row
562
+ * @param family family tag from deriveFamilyFromModelId / brain row
563
+ * @returns text with prefix/suffix applied (idempotent)
564
+ */
565
+ declare function applyArchetypeConvention(promptText: string, archetype: string, family: string): string;
566
+
169
567
  /**
170
568
  * Tokenizer abstraction.
171
569
  *
@@ -189,6 +587,1645 @@ declare function resetTokenizer(): void;
189
587
  */
190
588
  declare function countTokens(text: string): number;
191
589
 
590
+ /**
591
+ * archetype-fits — alpha.43.
592
+ *
593
+ * Static table of "this archetype tends to be a better fit for this family"
594
+ * recommendations. Powers the `cross-family-fit-candidate` compile-time
595
+ * advisor (see `advisor-rules/cross-family-fit.ts`).
596
+ *
597
+ * Strategic framing (Sacha, 2026-05-28): "If we get better results and
598
+ * better price then we do. Even if volume is currently low, that's not an
599
+ * argument to not do it. Volume can increase quickly if tools is great to
600
+ * use, let's not create future bottlenecks because we could have wired in
601
+ * better solution at moment of knowing."
602
+ *
603
+ * The convention substrate (passApplyConventions) is the NEGATIVE side:
604
+ * make a family usable on archetypes it currently fails. This table is the
605
+ * POSITIVE side: actively surface that a different family is the better
606
+ * fit for the archetype's shape — even when current volume is low.
607
+ *
608
+ * Entries are added only when:
609
+ * - the archetype's shape and the family's behavior have a clear
610
+ * architectural fit (not vibes)
611
+ * - real-world evidence (brain rows, probe outcomes, or published
612
+ * benchmark) backs the claim, OR the reasoning is structurally so clear
613
+ * that "wait for volume" would create a future bottleneck
614
+ *
615
+ * Alpha.43 ships two entries — `plan` and `critique`. Both fit the
616
+ * reasoner-family architectural read: plan is multi-step reasoning;
617
+ * critique rewards epistemic humility and explicit reasoning. Other
618
+ * archetype-family-fits ride later alphas as evidence accumulates.
619
+ *
620
+ * Anti-pattern: do NOT add archetype-family-fits for archetypes where the
621
+ * fit is unclear (summarize, classify, extract, hunt with parallel tools).
622
+ * The advisor only earns trust when its recommendations land.
623
+ */
624
+
625
+ /**
626
+ * One archetype-family-fit recommendation. Read by the compile-time
627
+ * `cross-family-fit-candidate` advisor to decide when to surface a positive
628
+ * recommendation. The advisor pulls `costGuidance` verbatim into the
629
+ * advisory message.
630
+ */
631
+ interface ArchetypeFamilyFit {
632
+ /** Intent archetype this fit applies to. */
633
+ archetype: IntentArchetypeName;
634
+ /** Family tag that fits the archetype better than alternatives. Matches the
635
+ * same family taxonomy used by `family-resolution.deriveFamilyFromModelId`
636
+ * (e.g. `'deepseek-reasoner'`, `'gemini-flash'`, `'claude-opus'`). */
637
+ betterFitFamily: string;
638
+ /** Architectural / evidentiary justification. Appears in the advisor's
639
+ * internal logs and the advisory `evidence` payload, NOT verbatim in the
640
+ * consumer-facing message. */
641
+ reason: string;
642
+ /** Cost-context clause surfaced VERBATIM in the consumer-facing advisory
643
+ * message (e.g. "substantially cheaper at current pricing"). Keep
644
+ * declarative; the advisor wraps this into the larger sentence. */
645
+ costGuidance: string;
646
+ }
647
+ /**
648
+ * Frozen registry. Add entries by extending the array. Order is irrelevant
649
+ * — the advisor filters by `(archetype, currentFamily)` independently.
650
+ */
651
+ declare const ARCHETYPE_FAMILY_FITS: readonly ArchetypeFamilyFit[];
652
+ /**
653
+ * Pure lookup: does `(archetype, currentFamily)` have a better-fit family?
654
+ * Returns the fit entry when the current family is NOT the better fit; null
655
+ * otherwise. Used by the advisor to decide whether to fire.
656
+ */
657
+ declare function findBetterFit(archetype: string, currentFamily: string): ArchetypeFamilyFit | null;
658
+
659
+ /**
660
+ * Best-practice advisor — alpha.6 Phase 1.
661
+ *
662
+ * Inspects an IR + the selected profile + compile diagnostics and emits a
663
+ * list of `BestPracticeAdvisory` entries describing detected gaps. Runs
664
+ * after `lower()` in the compile pipeline; the result lands on
665
+ * `CompileResult.advisories` for the consumer to log, surface, or filter.
666
+ *
667
+ * Driven by interfaces/kgauto.md `best-practice-advisories` (IC, 2026-05-07).
668
+ * Phase 1 ships 4 starter rules sourced from the s14 kgauto comment +
669
+ * s15 empirical seed of brain anti-patterns:
670
+ *
671
+ * 1. `caching-off-on-claude` system >2000 chars on Anthropic, no cacheable=true
672
+ * 2. `single-chunk-system` Anthropic, only one PromptSection >1000 chars
673
+ * 3. `tool-bloat` >10 tools on a short-output archetype
674
+ * 4. `history-uncached-on-claude` Anthropic, ≥2 history messages, no historyCachePolicy
675
+ *
676
+ * Each rule is a pure function: (ir, result, profile) → BestPracticeAdvisory[].
677
+ * No side effects. No randomness. Deterministic for a given IR.
678
+ *
679
+ * The thresholds (2000 chars, 1000 chars, 10 tools, 2 history) are chosen
680
+ * to balance noise vs. signal — too low fires on innocuous calls, too high
681
+ * misses real waste. They may tune with brain evidence over time; for now
682
+ * they're literals in the rule bodies. Make them configurable when the
683
+ * cost-watcher's R-rules graduate to here.
684
+ */
685
+
686
+ /** Subset of CompileResult fields the advisor needs. */
687
+ type AdvisorContext = Pick<CompileResult, 'target' | 'provider' | 'tokensIn' | 'diagnostics'>;
688
+ /**
689
+ * Optional Phase 2 (alpha.22) context — fallback chain + a profile resolver
690
+ * for cross-model comparison. Three new rules
691
+ * (`cost-mismatched-archetype`, `model-stale-evidence`, `tier-down`) consume
692
+ * this to surface measurement-substrate signals (alpha.20 clean-attribution +
693
+ * alpha.21 grounding labels) as actionable consumer guidance.
694
+ *
695
+ * When `fallbackChain` is empty, rules 1 + 3 stay silent (nothing to
696
+ * compare against). When `profileResolver` is omitted, the rules degrade
697
+ * gracefully — they can still inspect the chosen profile but not chain
698
+ * alternatives. Rule 2 (`model-stale-evidence`) is independent of chain
699
+ * shape and works on the chosen model alone.
700
+ */
701
+ interface RunAdvisorPhase2Context {
702
+ fallbackChain: string[];
703
+ profileResolver?: (id: string) => ModelProfile | undefined;
704
+ /**
705
+ * alpha.29 — translator rewrites that fired this compile. When a rewrite
706
+ * cleared the cliff (e.g. `tool_call_contract` → sequential-tool preamble
707
+ * + `parallelToolCalls: false`), the matching cliff advisor
708
+ * (`archetype-perf-floor-breach`) MUST suppress for the same call. Without
709
+ * suppression both fire — the advisory contradicts the rewrite ("cliff is
710
+ * unaddressed" vs "we just addressed it").
711
+ *
712
+ * Empty array / undefined → no suppression (alpha.28 behavior preserved).
713
+ */
714
+ sectionRewritesApplied?: SectionRewrite[];
715
+ }
716
+ /**
717
+ * alpha.42 — rule codes whose advisories are positioned for kgauto (not
718
+ * the consumer) to act on. Used by `compile()` to default the `ownership`
719
+ * stamp on each advisory when the rule didn't self-declare. Consumer-side
720
+ * rules don't need to be listed — they default to `'consumer-actionable'`
721
+ * via fall-through.
722
+ *
723
+ * - `model-stale-evidence`: kgauto's profile data is out of date; the
724
+ * consumer can't fix that, kgauto needs to update profiles or refresh
725
+ * archetypePerf scores.
726
+ * - `promote-ready`: kgauto's promotion-probe-watcher detected a
727
+ * candidate model worth promoting; consumer-side adoption is downstream
728
+ * of kgauto adding it to the chain / family taxonomy.
729
+ *
730
+ * Frozen so consumers and tests can't mutate the global ownership map.
731
+ */
732
+ declare const PRODUCER_OWNED_RULE_CODES: ReadonlySet<string>;
733
+ /**
734
+ * alpha.42 — pure function used by `compile()` to decide ownership for an
735
+ * advisory. Rule-self-declared wins; falls back to the static map; defaults
736
+ * `consumer-actionable`. Exported so consumer-side code (or a Glass-Box
737
+ * renderer) can derive the same classification from a rule code alone
738
+ * without needing the advisory object.
739
+ */
740
+ declare function deriveOwnership(code: string, selfDeclared?: 'consumer-actionable' | 'producer-owned'): 'consumer-actionable' | 'producer-owned';
741
+ /**
742
+ * Run all phased rules and return collected advisories. Order is fixed so
743
+ * output is stable across runs. The `policy` argument is alpha.9 — the
744
+ * `single-model-array` rule needs to know whether the consumer explicitly
745
+ * declared `posture: 'locked'` (in which case single-model is intentional
746
+ * and shouldn't warn).
747
+ *
748
+ * `phase2` is alpha.22 — gives the advisor access to the fallback chain +
749
+ * a profile resolver so the three new compile-time recommendation rules
750
+ * (`cost-mismatched-archetype`, `model-stale-evidence`, `tier-down`) can
751
+ * compare the chosen model against in-chain alternatives. Optional for
752
+ * backward compatibility with consumers calling `runAdvisor()` directly.
753
+ */
754
+ declare function runAdvisor(ir: PromptIR, result: AdvisorContext, profile: ModelProfile, policy?: CompilePolicy, phase2?: RunAdvisorPhase2Context): BestPracticeAdvisory[];
755
+
756
+ /**
757
+ * Translator primitive — alpha.31.
758
+ *
759
+ * Pure function. Walks `IR.sections`, matches each section's `kind` against
760
+ * a per-rule dispatch table keyed on (kind, profile, archetype), and applies
761
+ * a model-aware rewrite when a rule fires. Returns the rewritten IR + the
762
+ * list of rewrites for `CompileResult.sectionRewritesApplied` and brain
763
+ * persistence.
764
+ *
765
+ * This is the s37 translator-framing eureka in code: kgauto graduates from
766
+ * "gate" (alpha.28's cliff advisor: "consumer must accept adapter") to
767
+ * "translator" (alpha.29: "consumer declared the section kind, kgauto
768
+ * applies the adapter at compile time without consumer-side branching").
769
+ *
770
+ * Rules shipped:
771
+ *
772
+ * alpha.29 — tool_call_contract + archetypePerf[archetype] < TRANSLATOR_FLOOR
773
+ * → prepend sequential-tool-pattern guidance
774
+ * → emit wireOverrides: { parallelToolCalls: false }
775
+ * → rule_id: 'sequential-tool-cliff-below-floor'
776
+ *
777
+ * alpha.31 — narration_contract + profile.provider === 'anthropic'
778
+ * → prepend terse-log narration guidance
779
+ * → no wireOverrides
780
+ * → rule_id: 'narration-drift-anthropic'
781
+ *
782
+ * alpha.31 — narration_contract + profile.provider === 'deepseek'
783
+ * → prepend <thinking>-suppression guidance
784
+ * → no wireOverrides
785
+ * → rule_id: 'narration-thinking-leak-deepseek'
786
+ *
787
+ * Per-rule walk (alpha.31 refactor): the alpha.30 short-circuit
788
+ * `if (!cliffFires) return passthrough` was correct when only the
789
+ * cliff-gated tool_call_contract rule existed; alpha.31's narration rules
790
+ * fire on every call regardless of cliff (narration drift is steady-state,
791
+ * not a cliff condition). Each section now consults the dispatch table
792
+ * independently — first-match wins per (section.kind, profile, archetype).
793
+ *
794
+ * **Interaction with the cliff advisor (alpha.28):** when this translator
795
+ * fires for a `tool_call_contract` section, the advisor's
796
+ * `archetype-perf-floor-breach` rule MUST suppress for the same call — the
797
+ * cliff was structurally cleared by the rewrite, not unaddressed. The
798
+ * suppression check lives in `advisor.ts` and consults the
799
+ * `CompileResult.sectionRewritesApplied` list.
800
+ *
801
+ * Design contracts:
802
+ * command-center/advisory/kgauto/2026-05-21_alpha-29-translator-and-advisories-api.md
803
+ * command-center/advisory/kgauto/2026-05-22_alpha-31-narration-contract.md
804
+ */
805
+
806
+ /**
807
+ * Re-export of `ARCHETYPE_FLOOR_DEFAULT` as the canonical "translator fires
808
+ * below this score" threshold. Same constant as the cliff advisor — the
809
+ * single threshold is shared (alpha.28's "below this, advisor warns"; alpha.29's
810
+ * "below this, translator AUTO-APPLIES the adapter").
811
+ */
812
+ declare const TRANSLATOR_FLOOR = 6;
813
+ /**
814
+ * Stable identifier of the alpha.29 sequential-tool rule. Surfaces on
815
+ * `SectionRewrite.rule` and in brain aggregates. The brain treats this
816
+ * identifier together with the preamble string as the rule's wire
817
+ * fingerprint — both stay byte-stable across releases.
818
+ */
819
+ declare const RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
820
+ interface ApplySectionRewritesArgs {
821
+ ir: PromptIR;
822
+ profile: ModelProfile;
823
+ archetype: IntentArchetypeName;
824
+ }
825
+ interface ApplySectionRewritesResult {
826
+ /**
827
+ * IR with section.text fields possibly rewritten. When no rewrites fired,
828
+ * this is identical to the input IR (referentially distinct array but
829
+ * same section payloads).
830
+ */
831
+ rewrittenIR: PromptIR;
832
+ /**
833
+ * One entry per section the translator rewrote. Empty array when no
834
+ * rules fired. Order matches the corresponding section in
835
+ * `rewrittenIR.sections`.
836
+ */
837
+ rewrites: SectionRewrite[];
838
+ }
839
+ /**
840
+ * Pure function. Apply model-aware section rewrites to the IR at compile time.
841
+ *
842
+ * Discipline:
843
+ * - Never mutates the input IR; returns a new IR with new sections array
844
+ * when at least one rewrite fired; otherwise returns the input IR by
845
+ * reference (referential identity preserved on no-op).
846
+ * - Sections without a `kind` (or `kind === 'arbitrary'`) pass through
847
+ * unchanged.
848
+ * - Empty `sections` array → returns `{ rewrittenIR: ir, rewrites: [] }`.
849
+ * - Sections of the same `kind` are processed in array order; first-match
850
+ * wins per section. (Today every rule is a single-match rule.)
851
+ *
852
+ * @example
853
+ * ```ts
854
+ * import { applySectionRewrites } from '@warmdrift/kgauto-compiler';
855
+ * import { getProfile } from '@warmdrift/kgauto-compiler';
856
+ *
857
+ * const { rewrittenIR, rewrites } = applySectionRewrites({
858
+ * ir,
859
+ * profile: getProfile('deepseek-v4-pro'),
860
+ * archetype: 'hunt',
861
+ * });
862
+ * if (rewrites.length > 0) console.log('translator fired:', rewrites);
863
+ * ```
864
+ */
865
+ declare function applySectionRewrites(args: ApplySectionRewritesArgs): ApplySectionRewritesResult;
866
+
867
+ /**
868
+ * advisories-api — structured advisories API (alpha.29 Workstream B).
869
+ *
870
+ * Closes the L-117 family bottleneck: kgauto's `result.advisories[]` (the
871
+ * compile-time warnings about caching-off, tool-bloat, archetype-perf-floor
872
+ * breaches, etc.) used to disappear after the consumer read the compile
873
+ * result. The s34 caching-off advisory pattern is the canonical failure: an
874
+ * advisory fired 100+ times in 24h on `generate::sonnet` at 99.4% empty
875
+ * rate, and nobody knew because there was no structured channel to surface
876
+ * "what's open right now?"
877
+ *
878
+ * Migration 020 ships the substrate: `compile_outcome_advisories` gains
879
+ * lifecycle columns (`resolved_at`, `resolution_source`, `resolution_note`)
880
+ * and the `actionable_advisories_v` view rolls per-firing rows into
881
+ * per-(app_id, code) tuples with deterministic stable ids + server-side
882
+ * auto-resolution.
883
+ *
884
+ * Public surface:
885
+ * getActionableAdvisories({ appId, severity?, status?, brainEndpoint, brainJwt, brainAnonKey, fetch? })
886
+ * → Promise<ActionableAdvisory[]>
887
+ *
888
+ * markAdvisoryResolved({ id, resolutionNote?, brainEndpoint, brainJwt, brainAnonKey, fetch? })
889
+ * → Promise<{ ok: true } | { ok: false; reason: string }>
890
+ *
891
+ * Both functions are pure I/O — no module-level state. The fetch wiring
892
+ * mirrors `createProxyHandler` in `glassbox-routes/proxy.ts`: scoped JWT in
893
+ * `Authorization: Bearer`, `apikey` header carries the anon key.
894
+ *
895
+ * The auto-resolution rule is enforced server-side in `actionable_advisories_v`:
896
+ * • Latest firing > 14 days ago → status='resolved' (auto-pruned)
897
+ * • All firings have resolved_at set → status='resolved' (consumer-marked)
898
+ * • Otherwise → status='open'
899
+ *
900
+ * `markAdvisoryResolved` is the consumer override: "I fixed it; the next
901
+ * firing will reopen the rule, but until then it stays resolved."
902
+ */
903
+
904
+ /**
905
+ * Severity of an advisory. Maps to the `level` column on
906
+ * `compile_outcome_advisories` (info | warn | critical).
907
+ */
908
+ type AdvisorySeverity = 'info' | 'warn' | 'critical';
909
+ /**
910
+ * Status of an advisory rollup.
911
+ *
912
+ * - `open` — at least one unresolved firing in the last 14 days
913
+ * - `resolved` — either auto-pruned (no firings >14d) or consumer-marked
914
+ * - `snoozed` — reserved for alpha.30+ (snooze-until-date); type-accepted
915
+ * today but the view will never emit this value
916
+ */
917
+ type AdvisoryStatus = 'open' | 'snoozed' | 'resolved';
918
+ /**
919
+ * Source of resolution when status='resolved'.
920
+ *
921
+ * - `auto` — server-side rule auto-pruned (>14d since last firing)
922
+ * - `consumer-marked` — consumer called `markAdvisoryResolved`
923
+ * - `declined` — reserved (alpha.30+: consumer marked the suggestion
924
+ * inapplicable; the advisor will still fire but UIs can hide it)
925
+ */
926
+ type AdvisoryResolutionSource = 'auto' | 'consumer-marked' | 'declined';
927
+ /**
928
+ * Suggested-fix metadata. `null` when the advisor has no actionable fix
929
+ * (info-level rules can be observational). When set, the consumer's
930
+ * Admin UI can render a one-click apply (alpha.30+) or surface the
931
+ * before/after diff inline.
932
+ */
933
+ interface AdvisorySuggestedFix {
934
+ type: 'config-change' | 'one-liner' | 'env-var' | 'manual';
935
+ /** File:line hint if kgauto can infer (reserved — alpha.30+). */
936
+ siteHint?: string;
937
+ before?: string;
938
+ after?: string;
939
+ docsLink?: string;
940
+ }
941
+ /**
942
+ * Per-(app_id, code) advisory rollup. The `id` is stable across polls
943
+ * until the rule auto-resolves and re-opens (a new firing after the 14d
944
+ * boundary advances `opened_at` → new id). Treat id-changes as
945
+ * intentional "fresh re-open" signals.
946
+ *
947
+ * Wire-shape from `actionable_advisories_v`. The transformer maps the
948
+ * view's snake_case columns to camelCase. See `feedback_typed_boundary_transformers.md`
949
+ * (L-118) for the rationale.
950
+ */
951
+ interface ActionableAdvisory {
952
+ id: string;
953
+ rule: string;
954
+ severity: AdvisorySeverity;
955
+ openedAt: string;
956
+ lastObservedAt: string;
957
+ observationCount: number;
958
+ appliesTo: {
959
+ archetype?: IntentArchetypeName;
960
+ model?: string;
961
+ callSiteHint?: string;
962
+ };
963
+ message: string;
964
+ suggestedFix: AdvisorySuggestedFix | null;
965
+ /** Reserved — always `false` in alpha.29. alpha.30+ ships actual auto-apply. */
966
+ autoApplicable: boolean;
967
+ status: AdvisoryStatus;
968
+ resolvedAt?: string;
969
+ resolutionSource?: AdvisoryResolutionSource;
970
+ resolutionNote?: string;
971
+ }
972
+ /**
973
+ * Filter + transport for `getActionableAdvisories`. The brain JWT must
974
+ * carry an `app_id` claim matching `opts.appId` — RLS enforces tenant
975
+ * isolation on the underlying table, so a mismatch silently returns [].
976
+ */
977
+ interface GetActionableAdvisoriesOptions {
978
+ appId: string;
979
+ /** Severity filter; if omitted, all severities are returned. */
980
+ severity?: AdvisorySeverity;
981
+ /** Status filter; defaults to 'open'. Pass 'all' for the full set. */
982
+ status?: 'open' | 'snoozed' | 'resolved' | 'all';
983
+ brainEndpoint: string;
984
+ brainJwt: string;
985
+ brainAnonKey: string;
986
+ fetch?: typeof fetch;
987
+ }
988
+ interface MarkAdvisoryResolvedOptions {
989
+ /** Stable id from a prior `getActionableAdvisories` call. */
990
+ id: string;
991
+ resolutionNote?: string;
992
+ brainEndpoint: string;
993
+ brainJwt: string;
994
+ brainAnonKey: string;
995
+ fetch?: typeof fetch;
996
+ }
997
+ /**
998
+ * Query the open advisory set for an app. Pulls from
999
+ * `actionable_advisories_v` (per-(app_id, code) rollup with stable ids
1000
+ * + server-side auto-resolution).
1001
+ *
1002
+ * Default behavior (no status filter): returns only `status='open'`.
1003
+ * Pass `status: 'all'` to see resolved + open together — useful for
1004
+ * Admin UIs that show "recently fixed" badges.
1005
+ *
1006
+ * Fetch failures bubble out as thrown Errors. (`markAdvisoryResolved`
1007
+ * uses the ok/reason envelope; this read path throws to match
1008
+ * existing kgauto query semantics where the consumer can decide to
1009
+ * retry or render an error state.)
1010
+ */
1011
+ declare function getActionableAdvisories(opts: GetActionableAdvisoriesOptions): Promise<ActionableAdvisory[]>;
1012
+ /**
1013
+ * Mark an advisory as consumer-resolved.
1014
+ *
1015
+ * Lookup strategy:
1016
+ * 1. Query `actionable_advisories_v?id=eq.<id>` to find the (app_id, code)
1017
+ * tuple for this advisory.
1018
+ * 2. PATCH the latest unresolved firing in `compile_outcome_advisories`
1019
+ * matching that tuple via the underlying outcome's app_id.
1020
+ *
1021
+ * The (app_id, code) lookup is necessary because `compile_outcome_advisories`
1022
+ * has no `app_id` column — it inherits scope via the FK to compile_outcomes.
1023
+ * PostgREST cannot PATCH with a JOIN predicate, so the markAdvisoryResolved
1024
+ * path is a two-step round-trip. The cost is one extra GET per resolve call;
1025
+ * acceptable because marks are low-frequency operator actions, not per-call
1026
+ * hot path.
1027
+ *
1028
+ * Idempotent re-marks: if the advisory is already resolved (no unresolved
1029
+ * firings match), the PATCH affects zero rows and the call still returns
1030
+ * `ok: true`. The function returns `ok: false` only on transport / auth /
1031
+ * lookup failures.
1032
+ *
1033
+ * Returns ok/reason envelope (vs throwing) because consumer Admin UIs
1034
+ * typically want to render the failure inline rather than crash.
1035
+ */
1036
+ declare function markAdvisoryResolved(opts: MarkAdvisoryResolvedOptions): Promise<{
1037
+ ok: true;
1038
+ } | {
1039
+ ok: false;
1040
+ reason: string;
1041
+ }>;
1042
+ /**
1043
+ * Resolution sources supported by the alpha.39 `markExclusionFindingHandled`
1044
+ * API. Mirrors the subset of `exclusion_findings.resolution_source` CHECK
1045
+ * constraint values that consumers can self-set:
1046
+ *
1047
+ * - `'consumer-marked'` — generic "we've handled this; stop reminding."
1048
+ * Use this for "we evaluated and chose not to act" or "we'll act when
1049
+ * ready but acknowledge the finding now."
1050
+ * - `'declined'` — explicit "this exclusion is intentional; do not surface
1051
+ * again." Stronger signal than consumer-marked; useful for compliance
1052
+ * exclusions, brand-promise exclusions, etc.
1053
+ * - `'probed-unblock'` — alpha.40+ probe-path verdict: consumer ran a live
1054
+ * probe and decided to unblock the excluded model. Library accepts the
1055
+ * value today so the probe path doesn't need a follow-up API release.
1056
+ * - `'probed-stay-excluded'` — alpha.40+ probe-path verdict: consumer
1057
+ * probed and confirmed the exclusion. Same forward-compat shape as
1058
+ * `'probed-unblock'`.
1059
+ *
1060
+ * The `'auto'` resolution_source is NOT exposed here — that's reserved
1061
+ * for the brain's own automatic resolution (e.g. when the detection
1062
+ * conditions no longer hold). Consumer code sets only the four values
1063
+ * above.
1064
+ */
1065
+ type ExclusionResolutionSource = 'consumer-marked' | 'declined' | 'probed-unblock' | 'probed-stay-excluded';
1066
+ interface MarkExclusionFindingHandledOptions {
1067
+ /** App id the finding belongs to. Required (RLS scopes writes by this). */
1068
+ appId: string;
1069
+ /** Archetype the finding applies to (e.g. 'hunt', 'classify'). */
1070
+ archetype: string;
1071
+ /** Canonical model id that the consumer had excluded. */
1072
+ excludedModel: string;
1073
+ /** Resolution semantics — see `ExclusionResolutionSource` for the four
1074
+ * values consumers can set. */
1075
+ resolution: ExclusionResolutionSource;
1076
+ /** Optional free-form note explaining the decision. Surfaces in operator
1077
+ * digests + dashboards alongside the resolution_source. */
1078
+ resolutionNote?: string;
1079
+ /** Brain Supabase URL base (e.g. `https://<project>.supabase.co`). The
1080
+ * function appends `/rest/v1/exclusion_findings?...`. */
1081
+ brainEndpoint: string;
1082
+ /** Consumer-scoped JWT carrying the `app_id` claim. The brain's RLS
1083
+ * policy enforces that the JWT's app_id matches the finding's app_id;
1084
+ * cross-tenant writes fail at the database layer regardless of input. */
1085
+ brainJwt: string;
1086
+ /** Supabase anon key for the `apikey` header (PostgREST requires it). */
1087
+ brainAnonKey: string;
1088
+ /** Injected fetch for tests. Defaults to global fetch. */
1089
+ fetch?: typeof fetch;
1090
+ }
1091
+ /**
1092
+ * Mark a stale-exclusion finding as handled. Returns an `ok/reason` envelope
1093
+ * matching `markAdvisoryResolved` — consumer Admin UIs typically render the
1094
+ * failure inline rather than crash.
1095
+ *
1096
+ * Idempotent: if no row matches the (app_id, archetype, excludedModel)
1097
+ * tuple (already resolved, never existed, cron not yet UPSERTed), PostgREST
1098
+ * returns 200 with zero affected rows and we return `{ ok: true }`. The
1099
+ * caller's "I marked it as handled" intent is satisfied regardless of
1100
+ * whether the row was already in that state.
1101
+ *
1102
+ * Reasons surfaced on failure:
1103
+ * - `app_id_required` / `archetype_required` / `excluded_model_required`
1104
+ * - `resolution_invalid` — `resolution` not one of the four documented values
1105
+ * - `brain_auth_misconfig` — 401/403 (JWT / anon key wrong)
1106
+ * - `brain_unavailable` — 5xx
1107
+ * - `network_error:<message>` — fetch threw
1108
+ * - `patch_failed:<status>` — anything else non-2xx
1109
+ */
1110
+ declare function markExclusionFindingHandled(opts: MarkExclusionFindingHandledOptions): Promise<{
1111
+ ok: true;
1112
+ } | {
1113
+ ok: false;
1114
+ reason: string;
1115
+ }>;
1116
+
1117
+ /**
1118
+ * Archetype-cliff compatibility — alpha.28 (tt-intel-Cairn ratified).
1119
+ *
1120
+ * One question, one answer: *given this model and this intent, can it work
1121
+ * — and if not, what adapter (if any) would make it work?*
1122
+ *
1123
+ * Replaces the silent-archetype-cliff failure mode where a consumer picks a
1124
+ * model that's structurally wrong for the intent and kgauto compiles cleanly
1125
+ * without surfacing the gap. The triggering incident: tt-intel shipped
1126
+ * `deepseek-v4-pro` as the hunt default per a local spec; the kgauto coord
1127
+ * doc said L-040 — V4 is structurally wrong for hunt (sequential tools).
1128
+ * `archetypePerf.hunt = 4` was already in the profile data. The compiler
1129
+ * stayed silent. This API + the matching advisor rule surfaces it.
1130
+ *
1131
+ * Pure function. No network. No brain query. No side effects. ~1ms.
1132
+ *
1133
+ * Consultation doc:
1134
+ * command-center/advisory/kgauto/2026-05-21_archetype-cliff-advisor.md
1135
+ *
1136
+ * Refinements applied per tt-intel-Cairn ratification (2026-05-21):
1137
+ * R1: every variant carries `archetypePerf: number` (raw score) — and
1138
+ * `requires-adapter` adds `archetypePerfWithAdapter: number` so
1139
+ * consumer policy can be expressed as "accept adapter only when score
1140
+ * crosses some threshold WITH the adapter on."
1141
+ * R2: every variant carries a plain-English `reason: string`. No internal
1142
+ * jargon ("L-040", "archetypePerf=4") — the consumer chooses whether
1143
+ * to render it as UI hint or operator-tooling tooltip.
1144
+ * R3: `Adapter` is a CLOSED discriminated union, not `| string`. alpha.28
1145
+ * ships ONE variant (`toolOrchestration: 'sequential'`). Future
1146
+ * adapter parameters extend the union explicitly in named releases.
1147
+ * NO escape hatch — the whole point is catching "I added a new
1148
+ * adapter and forgot to update consumer policy" at compile time.
1149
+ */
1150
+
1151
+ /**
1152
+ * Minimum `archetypePerf[archetype]` score to count as `compatible` under
1153
+ * Option A (default policy). Below this, a documented adapter is needed
1154
+ * to lift the model above the floor; if no adapter exists, the model is
1155
+ * rejected.
1156
+ *
1157
+ * Matches `QUALITY_FLOOR_FOR_RECOMMENDATION` in `advisor.ts` — kgauto's
1158
+ * library-wide convention for "below this score, swap recommendations stop."
1159
+ */
1160
+ declare const ARCHETYPE_FLOOR_DEFAULT = 6;
1161
+ /**
1162
+ * Absolute floor — below this, the cliff is too steep for ANY adapter to
1163
+ * lift cleanly. Reserved under Option A (unused today; every below-floor
1164
+ * case is gated by adapter availability). Would gate `reject` vs
1165
+ * `requires-adapter` under a future Option B per consultation doc Q1.
1166
+ *
1167
+ * Exported so consumer-side policy can read it (e.g. "accept adapter only
1168
+ * when archetypePerf >= ABSOLUTE_FLOOR + 1"). Not used internally by
1169
+ * `getModelCompatibility` today — the gate is "does an adapter exist for
1170
+ * this cliff?", not score-based.
1171
+ */
1172
+ declare const ABSOLUTE_FLOOR = 4;
1173
+ /**
1174
+ * The intent the call is expressing — archetype + optional orchestration
1175
+ * mode. Same shape as `ir.intent.archetype` + `ir.constraints.toolOrchestration`
1176
+ * so a consumer can pass `{ archetype: ir.intent.archetype,
1177
+ * toolOrchestration: ir.constraints?.toolOrchestration }` directly.
1178
+ */
1179
+ interface CompatibilityIntent {
1180
+ archetype: IntentArchetypeName;
1181
+ toolOrchestration?: 'parallel' | 'sequential' | 'either';
1182
+ }
1183
+ /**
1184
+ * `Adapter` — re-exported above. Canonical definition lives in `ir.ts` to
1185
+ * avoid an import cycle (compatibility.ts → profiles.ts → ir.ts).
1186
+ *
1187
+ * **CLOSED discriminated union per R3.** Future adapter parameters extend
1188
+ * the union explicitly in named alpha releases. No `| string` escape hatch
1189
+ * — consumer policy code SHOULD write exhaustive `switch (adapter.parameter)`
1190
+ * and rely on the compiler to flag "I added a new adapter parameter and
1191
+ * forgot to update the consumer's policy."
1192
+ *
1193
+ * alpha.28 variants:
1194
+ * - `{ parameter: 'toolOrchestration'; value: 'sequential'; consequence }`
1195
+ * Lifts DeepSeek V4-family on `hunt` from sequential-tool cliff (L-040).
1196
+ * The "consequence" plain-English-ifies the trade-off:
1197
+ * "Tool calls run one at a time — slower but reliable."
1198
+ *
1199
+ * alpha.29+ likely additions (per tt-intel-Cairn priority list):
1200
+ * - `{ parameter: 'parallelToolCalls'; value: false; consequence }`
1201
+ * - `{ parameter: 'maxTools'; value: number; consequence }`
1202
+ * - `{ parameter: 'thinkingBudget'; value: 0; consequence }`
1203
+ *
1204
+ * Each new variant lands in its own named release with the union extended
1205
+ * in `ir.ts`. Consumers see the change at compile time.
1206
+ */
1207
+ /**
1208
+ * The compatibility verdict for a (model, intent) pair. Discriminated union
1209
+ * on `status` — `compatible` | `requires-adapter` | `reject`.
1210
+ *
1211
+ * **Every variant carries `archetypePerf` (R1) + `reason` (R2):**
1212
+ * - `archetypePerf` — the raw 0-10 score for (model, archetype). Lets
1213
+ * consumers build their own thresholds without re-importing the profile
1214
+ * registry.
1215
+ * - `reason` — plain-English, consumer-renderable. NOT internal jargon
1216
+ * like "L-040 cliff" or "archetypePerf=4". Examples in R2 ratification:
1217
+ * - compatible: "Suited for hunt-style parallel discovery."
1218
+ * - requires-adapter: "Best with sequential tool calls for hunt — slower but works."
1219
+ * - reject: "Not suited for hunt — would underperform significantly."
1220
+ *
1221
+ * `requires-adapter` additionally carries:
1222
+ * - `archetypePerfWithAdapter` — estimated post-adapter score. May be an
1223
+ * estimate (we don't measure post-adapter scores yet); kgauto's prior is
1224
+ * "adapter lifts to ARCHETYPE_FLOOR_DEFAULT + 1" unless brain-evidenced.
1225
+ * - `adapter` — the closed-union variant describing the structural change.
1226
+ *
1227
+ * Backward-compat: an unknown model returns `reject` with a "model not
1228
+ * registered" reason; callers never throw. Unknown archetype is impossible
1229
+ * at the type level (`IntentArchetypeName` is a closed union).
1230
+ */
1231
+ type ModelCompatibility = {
1232
+ status: 'compatible';
1233
+ reason: string;
1234
+ archetypePerf: number;
1235
+ } | {
1236
+ status: 'requires-adapter';
1237
+ reason: string;
1238
+ archetypePerf: number;
1239
+ archetypePerfWithAdapter: number;
1240
+ adapter: Adapter;
1241
+ } | {
1242
+ status: 'reject';
1243
+ reason: string;
1244
+ archetypePerf: number;
1245
+ };
1246
+ /**
1247
+ * Compatibility query — *does this model fit this intent, and if not,
1248
+ * what would?*
1249
+ *
1250
+ * **Rules (Option A from consultation doc Q1):**
1251
+ * 1. If model is unregistered → `reject` with "model not registered" reason.
1252
+ * 2. If intent provides `toolOrchestration: 'sequential'` AND that adapter
1253
+ * silences the cliff (because the cliff IS the sequential-tool one)
1254
+ * → return `compatible` with raw score (NOT the post-adapter estimate
1255
+ * — caller already paid the adapter, score reflects reality).
1256
+ * 3. If raw `archetypePerf[archetype] >= ARCHETYPE_FLOOR_DEFAULT`
1257
+ * → `compatible`.
1258
+ * 4. If below floor BUT a documented adapter exists that lifts to floor
1259
+ * → `requires-adapter` with adapter + estimated post-adapter score.
1260
+ * 5. If below floor AND no adapter exists → `reject`.
1261
+ *
1262
+ * **Pure function.** Deterministic for `(modelId, intent)`. No I/O.
1263
+ *
1264
+ * @example
1265
+ * ```ts
1266
+ * import { getModelCompatibility } from '@warmdrift/kgauto-compiler';
1267
+ *
1268
+ * const c = getModelCompatibility('deepseek-v4-pro', { archetype: 'hunt' });
1269
+ * // → { status: 'requires-adapter',
1270
+ * // reason: 'Best with sequential tool calls for hunt — slower but works.',
1271
+ * // archetypePerf: 4,
1272
+ * // archetypePerfWithAdapter: 7,
1273
+ * // adapter: {
1274
+ * // parameter: 'toolOrchestration',
1275
+ * // value: 'sequential',
1276
+ * // consequence: 'Tool calls run one at a time...'
1277
+ * // } }
1278
+ *
1279
+ * // With the adapter already declared:
1280
+ * const c2 = getModelCompatibility('deepseek-v4-pro', {
1281
+ * archetype: 'hunt',
1282
+ * toolOrchestration: 'sequential',
1283
+ * });
1284
+ * // → { status: 'compatible',
1285
+ * // reason: 'Suited for hunt with sequential tool calls.',
1286
+ * // archetypePerf: 4 }
1287
+ * ```
1288
+ */
1289
+ declare function getModelCompatibility(modelId: string, intent: CompatibilityIntent): ModelCompatibility;
1290
+
1291
+ /**
1292
+ * alpha.22 — sync introspection: is brain-query mode active for a given
1293
+ * table? Used by the advisor (`model-stale-evidence` rule) to decide
1294
+ * whether a `judgment`-grounded chosen model is a measurement gap worth
1295
+ * surfacing. Returns false on cold start, when configureBrain() was never
1296
+ * called, or when the consumer explicitly opted the table out via
1297
+ * `BrainConfig.brainQuery.<table> = false`.
1298
+ */
1299
+ declare function isBrainQueryActiveFor(table: string): boolean;
1300
+ interface GetPerAxisMetricsOpts {
1301
+ /** App id to filter on. Required. */
1302
+ appId: string;
1303
+ /** Intent archetype to filter on. Required. */
1304
+ archetype: string;
1305
+ /** Canonical model id to filter on. Required. */
1306
+ model: string;
1307
+ /**
1308
+ * Window in days. Default 30. Only rows with
1309
+ * `created_at > now() - windowDays` are counted.
1310
+ */
1311
+ windowDays?: number;
1312
+ /**
1313
+ * Consumer-declared quality floor (0..1 oracle/approve-rate scale).
1314
+ * When set, the response's `qualityFloorMet` is true/false; when omitted,
1315
+ * `qualityFloorMet` is null (no floor declared, no judgment).
1316
+ */
1317
+ qualityFloor?: number;
1318
+ /** Pluggable fetch (tests inject mock). Defaults to global fetch. */
1319
+ fetch?: typeof fetch;
1320
+ /**
1321
+ * PostgREST base endpoint (e.g. `https://kgauto-brain.vercel.app/api`).
1322
+ * When omitted, falls back to the active configureBrainQuery runtime's
1323
+ * endpoint. Returns null when neither is set.
1324
+ */
1325
+ endpoint?: string;
1326
+ /** Bearer token. Forwarded as `Authorization: Bearer ${apiKey}`. */
1327
+ apiKey?: string;
1328
+ }
1329
+ /**
1330
+ * Call the `get_per_axis_metrics` RPC and return the typed result.
1331
+ *
1332
+ * Returns null when:
1333
+ * - no endpoint provided AND no configureBrainQuery runtime active
1334
+ * - RPC returns empty / null / unexpected shape
1335
+ * - brain unreachable / fetch throws / HTTP error
1336
+ *
1337
+ * Never throws — operator-facing query, must not blow up the caller.
1338
+ */
1339
+ declare function getPerAxisMetrics(opts: GetPerAxisMetricsOpts): Promise<PerAxisMetrics | null>;
1340
+
1341
+ /**
1342
+ * env.ts — provider env-key resolution + reachability predicates.
1343
+ *
1344
+ * Centralizes the per-provider env var names that kgauto checks for
1345
+ * reachability. Used by:
1346
+ *
1347
+ * - execute.ts — to find an API key when one isn't passed via apiKeys
1348
+ * - call.ts — to auto-filter unreachable models from the fallback walk
1349
+ * - getDefaultFallbackChain — opt-in chain filter when consumer passes `reachability`
1350
+ * - operator scripts — getReachabilityDiagnostic() prints what's wired up
1351
+ *
1352
+ * Keeping the map in ONE place means execute() and the reachability check
1353
+ * always agree. Without this, kgauto could declare a model "reachable" because
1354
+ * env.ts found GOOGLE_GENERATIVE_AI_API_KEY, while execute() looks at
1355
+ * GOOGLE_API_KEY only and 401s — shipping the bug we're trying to fix.
1356
+ *
1357
+ * Resolution order (apiKeys takes precedence):
1358
+ * 1. opts.apiKeys?.[provider]
1359
+ * 2. process.env[name] for each name in PROVIDER_ENV_KEYS[provider] (first-present wins)
1360
+ *
1361
+ * alpha.10 (2026-05-14). Resolves the auto-filter-unreachable-models-silently
1362
+ * request from PB after first-deploy 401 on the alpha.9 summarize chain.
1363
+ */
1364
+
1365
+ /**
1366
+ * Providers kgauto can resolve keys for today. Subset of `Provider` — `mistral`
1367
+ * and `xai` are declared in the type union but not yet executable (no profiles,
1368
+ * no execute() handler, no env-var convention). Narrowing here keeps the
1369
+ * reachability check structurally honest.
1370
+ */
1371
+ type SupportedProvider = 'anthropic' | 'google' | 'openai' | 'deepseek';
1372
+ /**
1373
+ * Per-provider env var names kgauto recognizes. Order doesn't matter —
1374
+ * first-present wins. Multiple names per provider supported because Google
1375
+ * has historical drift (`GOOGLE_API_KEY` from older Google Cloud SDKs,
1376
+ * `GEMINI_API_KEY` in many examples, `GOOGLE_GENERATIVE_AI_API_KEY` is the
1377
+ * Vercel AI SDK convention used by IC + tt-intel adapters).
1378
+ *
1379
+ * Frozen so consumers/tests can't mutate (would break the cache invariant
1380
+ * that execute() and reachability checks agree).
1381
+ */
1382
+ declare const PROVIDER_ENV_KEYS: Readonly<Record<SupportedProvider, readonly string[]>>;
1383
+ interface ReachabilityOpts {
1384
+ /** Explicit keys (alpha.3 ApiKeys). Checked first; takes precedence over env. */
1385
+ apiKeys?: ApiKeys;
1386
+ /**
1387
+ * Override env source. Defaults to `process.env` in Node-shaped runtimes,
1388
+ * `{}` everywhere else. Pass `{}` explicitly in tests for hermetic runs.
1389
+ */
1390
+ envSource?: Record<string, string | undefined>;
1391
+ }
1392
+ /**
1393
+ * Resolve a usable API key for the provider. Returns the key string, or
1394
+ * undefined if neither apiKeys nor any of the env names are set.
1395
+ *
1396
+ * Used internally by execute.ts so the reachability check and the actual
1397
+ * call check stay in sync.
1398
+ */
1399
+ declare function resolveProviderKey(provider: Provider, opts?: ReachabilityOpts): string | undefined;
1400
+ /**
1401
+ * True iff the provider has a usable key — either via explicit `apiKeys`
1402
+ * or one of the `PROVIDER_ENV_KEYS[provider]` names is set in envSource.
1403
+ */
1404
+ declare function isProviderReachable(provider: Provider, opts?: ReachabilityOpts): boolean;
1405
+ /**
1406
+ * True iff the model's profile exists AND its provider is reachable.
1407
+ * Unknown model id returns false (treat as unreachable; the chain walker
1408
+ * will surface "no reachable models" if everything filters out).
1409
+ */
1410
+ declare function isModelReachable(modelId: string, opts?: ReachabilityOpts): boolean;
1411
+ interface ProviderReachability {
1412
+ reachable: boolean;
1413
+ /** How the key was found. `null` when unreachable. */
1414
+ via: 'apiKeys' | 'env' | null;
1415
+ /** Which env var name supplied the key (only when via === 'env'). */
1416
+ envKeyFound?: string;
1417
+ }
1418
+ /**
1419
+ * Snapshot of which providers are reachable from the current env / apiKeys.
1420
+ * Useful for operator scripts ("kgauto diagnose"), startup-time logging,
1421
+ * and the cost-watcher's "which consumer is missing what" report.
1422
+ *
1423
+ * Does NOT log the key value itself — only the env var name that supplied it.
1424
+ */
1425
+ declare function getReachabilityDiagnostic(opts?: ReachabilityOpts): Record<SupportedProvider, ProviderReachability>;
1426
+ /**
1427
+ * Brain-read env contract — canonical names + accepted fallbacks for the
1428
+ * env vars kgauto's brain-read APIs need.
1429
+ *
1430
+ * Affected APIs: `getActionableAdvisories`, `markAdvisoryResolved`,
1431
+ * `markExclusionFindingHandled`, `markPromoteReadyHandled`,
1432
+ * `getStaleExclusionFindings`, and future brain-read surfaces. Each accepts
1433
+ * `brainEndpoint`/`brainJwt`/`brainAnonKey` as call-site arguments; this
1434
+ * helper centralizes resolution from the consumer's environment.
1435
+ *
1436
+ * Resolution order (first-truthy-trimmed wins):
1437
+ * endpoint = KGAUTO_V2_BRAIN_SUPABASE_URL ?? KGAUTO_V2_BRAIN_URL
1438
+ * jwt = KGAUTO_V2_BRAIN_JWT ?? GLASSBOX_BRAIN_JWT
1439
+ * anonKey = KGAUTO_V2_BRAIN_ANON_KEY (no fallback)
1440
+ *
1441
+ * Why fallbacks exist:
1442
+ *
1443
+ * 1. Pre-alpha.42, some consumers set `KGAUTO_V2_BRAIN_URL` pointing at
1444
+ * the kgauto-dashboard URL (write target). The canonical
1445
+ * `KGAUTO_V2_BRAIN_SUPABASE_URL` is the Supabase project URL (read
1446
+ * target — PostgREST against `/rest/v1/`). Until consumers split the
1447
+ * two names, the fallback grabs whichever URL is set. When BOTH are
1448
+ * set, canonical wins (the consumer has explicitly split).
1449
+ *
1450
+ * 2. The s33 Glass-Box ship provisioned `GLASSBOX_BRAIN_JWT` across all
1451
+ * consumers with the same `app_id` claim shape, signed by the same
1452
+ * JWT_SECRET. Reusing it for brain-read avoids re-minting + re-pasting
1453
+ * a second JWT per consumer per surface.
1454
+ *
1455
+ * `missingEnv` lists the CANONICAL names that aren't satisfied by either
1456
+ * canonical OR fallback. Consumer policy: if `missingEnv.length > 0`,
1457
+ * render `not_configured`; otherwise pass `endpoint`/`jwt`/`anonKey` to
1458
+ * `getActionableAdvisories({ ... })` et al.
1459
+ *
1460
+ * Pre-trim semantics carry from `readKeyValue` — paste-newline-trap
1461
+ * (L-060 / L-083 / L-108) closure extends to brain env vars.
1462
+ *
1463
+ * Filed by tt-intel-Cairn (s89, 2026-05-27) after the s89 actionable-
1464
+ * advisories ref template hit `malformed brain response` on prod because
1465
+ * the endpoint env var pointed at the kgauto-dashboard URL instead of the
1466
+ * Supabase URL, AND because IC's ref template used a third env name
1467
+ * (`KGAUTO_V2_BRAIN_ENDPOINT`) that was unset. Three distinct name shapes
1468
+ * across two consumers — the durable closure is one canonical contract.
1469
+ */
1470
+ interface BrainReadEnv {
1471
+ /** Supabase project URL (PostgREST base). Undefined when neither canonical nor fallback is set. */
1472
+ endpoint?: string;
1473
+ /** JWT carrying `app_id` claim, signed by brain JWT_SECRET. Undefined when neither canonical nor fallback is set. */
1474
+ jwt?: string;
1475
+ /** Supabase anon (publishable) key. Undefined when not set. */
1476
+ anonKey?: string;
1477
+ /**
1478
+ * Canonical names not satisfied by either canonical OR fallback. Subset
1479
+ * (in order) of:
1480
+ * ['KGAUTO_V2_BRAIN_SUPABASE_URL', 'KGAUTO_V2_BRAIN_JWT', 'KGAUTO_V2_BRAIN_ANON_KEY']
1481
+ * Consumer policy: render `not_configured` when length > 0.
1482
+ */
1483
+ missingEnv: string[];
1484
+ }
1485
+ /**
1486
+ * Resolve brain-read env vars. Defaults to `process.env`; pass `envSource`
1487
+ * for hermetic tests. Trims surrounding whitespace and treats
1488
+ * empty-after-trim as unset (same shape as `resolveProviderKey`).
1489
+ */
1490
+ declare function readBrainReadEnv(envSource?: Record<string, string | undefined>): BrainReadEnv;
1491
+
1492
+ /**
1493
+ * getDefaultFallbackChain — the alpha.9 cascading ship.
1494
+ *
1495
+ * Returns a per-archetype fallback chain that walks the cost/performance
1496
+ * Pareto frontier (master plan §1.3 + §3). Three customer postures:
1497
+ *
1498
+ * locked — caller passes [theOneModel]; never call this function
1499
+ * preferred — caller passes `primary`; chain returned is [primary, ...fallbacks]
1500
+ * open — caller passes no `primary`; chain returned is [best, ...fallbacks]
1501
+ *
1502
+ * The chain at each step:
1503
+ * 1. Costs strictly less than the previous (no expensive sideways moves)
1504
+ * 2. Comes from a different provider than the previous step where possible
1505
+ * (correlated outages don't kill consecutive attempts)
1506
+ * 3. Stays above the archetype's perf floor (skip models scored <baseline
1507
+ * for archetypes where degradation would be unacceptable)
1508
+ *
1509
+ * In alpha.9 the chain is **hand-curated** per archetype (§3.3 starter
1510
+ * table). Brain-query mode lands in alpha.10. Policy.blockedModels filters
1511
+ * the result; policy.maxCostPerCallUsd is NOT applied here because the
1512
+ * function doesn't see the IR's token counts — that filtering happens at
1513
+ * `passScoreTargets()` time inside compile().
1514
+ *
1515
+ * The function is **pure** — no brain query, no I/O, no randomness. Same
1516
+ * inputs always produce the same chain.
1517
+ */
1518
+
1519
+ /**
1520
+ * Posture passed into `getDefaultFallbackChain`. The chain function only
1521
+ * sees `'open'` and `'preferred'` — callers in `'locked'` posture should
1522
+ * pass `models: [theOneModel]` directly and skip this function entirely.
1523
+ *
1524
+ * Equivalent to `CompilePolicy.posture` minus `'locked'`. Kept distinct so
1525
+ * the type system enforces "don't ask for a chain when you don't want one."
1526
+ */
1527
+ type FallbackPosture = 'open' | 'preferred';
1528
+ interface GetDefaultFallbackChainOpts {
1529
+ /** The archetype the call is performing. Drives chain shape. */
1530
+ archetype: IntentArchetypeName;
1531
+ /**
1532
+ * The user-selected or caller-anchored primary model. When provided, it
1533
+ * appears at position 0 of the returned chain and fallbacks follow.
1534
+ * When omitted, the function picks the best-perf model for the archetype
1535
+ * as position 0 (open posture).
1536
+ */
1537
+ primary?: string;
1538
+ /**
1539
+ * Informational. `'preferred'` and `'open'` produce the same chain shape
1540
+ * given the same `primary`/no-primary input — posture is a tag the brain
1541
+ * uses to distinguish "user-anchored" from "library-anchored" telemetry.
1542
+ */
1543
+ posture?: FallbackPosture;
1544
+ /**
1545
+ * Cap on chain length. Default 3. Min 1. Useful when the consumer wants
1546
+ * to keep the worst-case latency low (each fallback adds a round-trip).
1547
+ */
1548
+ maxDepth?: number;
1549
+ /**
1550
+ * Consumer-side gating. `blockedModels` are filtered from the chain.
1551
+ * `preferredModels` is informational (no boost applied at this layer —
1552
+ * compile()'s `passScoreTargets` handles preference ranking).
1553
+ * `maxCostPerCallUsd` is NOT applied here — needs IR-level token
1554
+ * estimation. Use compile()'s policy plumbing instead.
1555
+ */
1556
+ policy?: CompilePolicy;
1557
+ /**
1558
+ * alpha.10. When provided, the chain is filtered to models whose provider
1559
+ * has a reachable API key (via `apiKeys` or one of `PROVIDER_ENV_KEYS[provider]`).
1560
+ * Models whose provider can't be reached are silently dropped. If filtering
1561
+ * leaves the chain empty, returns `[]` — caller decides what to do (call()
1562
+ * throws CallError; this function stays pure).
1563
+ *
1564
+ * Pass `{}` to opt in with `process.env` as the env source. Pass `{ apiKeys, envSource }`
1565
+ * for explicit control (tests, non-Node runtimes). Omit entirely for the
1566
+ * legacy unfiltered behavior — preserves alpha.9 callers byte-for-byte.
1567
+ */
1568
+ reachability?: ReachabilityOpts;
1569
+ /**
1570
+ * alpha.20 E3: consumer-declared tool-orchestration shape. Currently
1571
+ * only affects `archetype: 'hunt'`, where 'sequential' swaps the
1572
+ * parallel-tool-tier-0 chain (Flash → Pro → Sonnet → Haiku) for a
1573
+ * DeepSeek-tier-0 chain (V4-Pro → Flash → Sonnet) — DeepSeek's L-040
1574
+ * parallel-tool cliff doesn't apply when the consumer commits to
1575
+ * single-step orchestration.
1576
+ *
1577
+ * Other archetypes are NOT mode-aware in this release — they ship the
1578
+ * same chain regardless of toolOrchestration. Future versions may
1579
+ * extend mode-awareness to ask/generate/etc. when brain evidence
1580
+ * supports it.
1581
+ *
1582
+ * Default (omitted or 'either'): parallel chain. Back-compat with all
1583
+ * pre-alpha.20 callers.
1584
+ */
1585
+ toolOrchestration?: 'parallel' | 'sequential' | 'either';
1586
+ }
1587
+ /**
1588
+ * Returns the fallback chain for an archetype as a plain `string[]` of
1589
+ * model ids.
1590
+ *
1591
+ * @deprecated since alpha.21 — prefer
1592
+ * {@link getDefaultFallbackChainWithGrounding}, which returns the same chain
1593
+ * shape with a `grounding` label on every entry (measured / capability-fact /
1594
+ * judgment). The string[] return is preserved indefinitely for back-compat —
1595
+ * no functional change in alpha.21. Existing callers don't need to migrate
1596
+ * unless they want to surface the grounding gap to users.
1597
+ */
1598
+ declare function getDefaultFallbackChain(opts: GetDefaultFallbackChainOpts): string[];
1599
+ /**
1600
+ * Returns a shallow copy of the hand-curated starter chain for an archetype.
1601
+ * Useful for tests + the `scripts/digest.mjs` operator readout.
1602
+ */
1603
+ declare function getStarterChain(archetype: IntentArchetypeName): string[];
1604
+ /**
1605
+ * Returns a shallow copy of all starter chains keyed by archetype.
1606
+ * Useful for the `digest.mjs` readout and consumer audits.
1607
+ */
1608
+ declare function getAllStarterChains(): Record<IntentArchetypeName, string[]>;
1609
+ /**
1610
+ * alpha.20 E3 introspection — returns the sequential-mode overlay for an
1611
+ * archetype, or `undefined` when no overlay is registered (the archetype
1612
+ * is mode-agnostic and reuses `STARTER_CHAINS[archetype]`).
1613
+ *
1614
+ * Useful for tests + the `scripts/digest.mjs` operator readout to surface
1615
+ * the mode-aware chains.
1616
+ */
1617
+ declare function getSequentialStarterChain(archetype: IntentArchetypeName): string[] | undefined;
1618
+ /**
1619
+ * alpha.21 (s78 Entry 1) — returns the fallback chain as `ChainEntry[]`,
1620
+ * with a `grounding` label on every position.
1621
+ *
1622
+ * Same selection logic as {@link getDefaultFallbackChain} (primary anchoring,
1623
+ * blockedModels filter, dedupe, reachability filter, maxDepth cap) — the
1624
+ * only difference is the return shape: each position is a `ChainEntry`
1625
+ * carrying `{ id, grounding, reason?, n? }` instead of a bare string.
1626
+ *
1627
+ * Use this when surfacing the chain to consumers who care WHY each entry
1628
+ * sits where it sits — Glass-Box panels, operator dashboards, eval
1629
+ * scaffolding deciding which entries deserve measurement priority.
1630
+ *
1631
+ * Returns `[]` when filtering empties the chain (same semantics as the
1632
+ * string variant) — consumer decides what to do.
1633
+ */
1634
+ declare function getDefaultFallbackChainWithGrounding(opts: GetDefaultFallbackChainOpts): ChainEntry[];
1635
+ /**
1636
+ * alpha.21 introspection — returns the grounded starter chain for an
1637
+ * archetype (no primary anchoring, no policy filtering, no maxDepth cap).
1638
+ * Use this when you want the raw, hand-curated grounded chain — every
1639
+ * entry carries a `grounding` label and optional reason/n.
1640
+ */
1641
+ declare function getStarterChainWithGrounding(archetype: IntentArchetypeName): ChainEntry[];
1642
+ /**
1643
+ * alpha.21 introspection — all grounded starter chains keyed by archetype.
1644
+ * Useful for the `digest.mjs` readout and consumer audits that want to
1645
+ * surface the grounding gap across the entire chain table.
1646
+ */
1647
+ declare function getAllStarterChainsWithGrounding(): Record<IntentArchetypeName, ChainEntry[]>;
1648
+ /**
1649
+ * alpha.21 introspection — sequential-mode overlay with grounding labels,
1650
+ * or `undefined` when no overlay is registered for the archetype.
1651
+ */
1652
+ declare function getSequentialStarterChainWithGrounding(archetype: IntentArchetypeName): ChainEntry[] | undefined;
1653
+
1654
+ /**
1655
+ * chains-brain — alpha.11 KG-11 adapter.
1656
+ *
1657
+ * Brain-driven STARTER_CHAINS for `getDefaultFallbackChain`. Reads
1658
+ * `kgauto_chains` table via the shared brain-query SWR cache (D6 + D8);
1659
+ * falls back to bundled STARTER_CHAINS on cold-start, brain-down, or
1660
+ * empty/missing table (D2 + D4).
1661
+ *
1662
+ * Behavioral note (locked via D2): the sync API surface returns bundled on
1663
+ * cold-start, with a background refresh fired. Subsequent calls within the
1664
+ * 5-min TTL return brain data. Vercel cold-start consumers see the seed
1665
+ * snapshot (functionally identical to pre-alpha.11); warm-start consumers
1666
+ * see live brain mutations within 5 min.
1667
+ */
1668
+ /**
1669
+ * Sync reader for the brain-driven chains map. Returns bundled
1670
+ * STARTER_CHAINS when brain-query is disabled, cold, or unreachable.
1671
+ */
1672
+ declare const loadChainsFromBrain: () => Record<"ask" | "hunt" | "classify" | "summarize" | "generate" | "extract" | "plan" | "critique" | "transform", string[]>;
1673
+
1674
+ /**
1675
+ * archetype-perf-brain — alpha.11 KG-12 adapter.
1676
+ *
1677
+ * Brain-driven archetypePerf scores. Substrate for the future closed-loop
1678
+ * tuning engine (KG-12.5): brain telemetry → human or automated bumps →
1679
+ * brain UPDATE → consumers see new scores within 5-min cache TTL with
1680
+ * zero refresh.
1681
+ *
1682
+ * Today: data migrates to brain. No runtime call site reads archetypePerf
1683
+ * (it's metadata for the master plan §2.5 anti-hallucination guardrail +
1684
+ * future auto-tuning). The adapter exists so future readers — auto-tuning
1685
+ * + operator scripts + KG-12.5 — have a shipped substrate to consume.
1686
+ */
1687
+
1688
+ type ArchetypePerfMap = Map<string, Partial<Record<IntentArchetypeName, number>>>;
1689
+ /**
1690
+ * alpha.21: per-(model, archetype) row count map. Same shape as
1691
+ * ArchetypePerfMap but stores brain row counts when the brain backs a
1692
+ * placement. Undefined entries → no row count seen → score is the
1693
+ * hand-curated cold-start prior (grounding='judgment').
1694
+ */
1695
+ type ArchetypePerfNMap = Map<string, Partial<Record<IntentArchetypeName, number>>>;
1696
+ /**
1697
+ * Sync reader for the brain-driven archetypePerf map. Returns bundled
1698
+ * profile.archetypePerf data when brain-query is disabled, cold, or
1699
+ * unreachable. Identical shape pre/post-alpha.11 by design (D2).
1700
+ */
1701
+ declare const loadArchetypePerfFromBrain: () => ArchetypePerfMap;
1702
+ /**
1703
+ * alpha.21 — sync reader for the brain row-count map paired with
1704
+ * archetype-perf. Returns empty map (no measured backing) on cold start /
1705
+ * brain-down / unreachable — all `getArchetypePerfScore` calls then
1706
+ * resolve to `grounding: 'judgment'`. When the brain table includes an
1707
+ * `n` column on each row, this map mirrors those counts so consumers can
1708
+ * see how many measurements back each score.
1709
+ */
1710
+ declare const loadArchetypePerfNFromBrain: () => ArchetypePerfNMap;
1711
+ /**
1712
+ * Threshold above which a brain row count counts as 'measured' grounding.
1713
+ * Below this, the score is treated as 'judgment' (cold-start prior or
1714
+ * not-yet-enough-evidence). Mirrors the alpha.20 `getCleanPerfScore`
1715
+ * `minRows` default — same rule for consistency.
1716
+ */
1717
+ declare const MEASURED_GROUNDING_MIN_N = 10;
1718
+ /**
1719
+ * alpha.21 — return shape for the extended {@link getArchetypePerfScore}.
1720
+ * Wraps the existing 0..10 score with:
1721
+ *
1722
+ * - `n`: brain row count backing this score (0 when no measurement).
1723
+ * - `grounding`: derived label — 'measured' when n >= 10, else 'judgment'.
1724
+ *
1725
+ * The score itself is unchanged from pre-alpha.21 (numeric, 5 = neutral
1726
+ * default). 'capability-fact' is NOT a perf-score grounding — capability
1727
+ * decisions live on chain entries, not on perf scores.
1728
+ */
1729
+ interface ArchetypePerfScoreResult {
1730
+ /** 0..10 perf score. 5 = neutral default when no entry exists. */
1731
+ score: number;
1732
+ /**
1733
+ * Brain row count backing this score. 0 when bundled (cold-start prior)
1734
+ * or when the brain row didn't carry an `n` column.
1735
+ */
1736
+ n: number;
1737
+ /**
1738
+ * Provenance — 'measured' when `n >= 10`, else 'judgment'.
1739
+ * Never 'capability-fact' (that label is reserved for chain-entry
1740
+ * inclusion/exclusion decisions).
1741
+ */
1742
+ grounding: Grounding;
1743
+ }
1744
+ /**
1745
+ * Per-model accessor with grounding (alpha.21). Returns 5 (neutral) when no
1746
+ * entry is found — consistent with the master plan §3.3 "missing archetypes
1747
+ * default to 5" convention documented in profiles.ts
1748
+ * ModelProfile.archetypePerf.
1749
+ *
1750
+ * Backwards-compat note: pre-alpha.21 callers expected `number` here. The
1751
+ * new return shape `{ score, n, grounding }` is a breaking shape change at
1752
+ * the type level, but `.score` carries the legacy value. Callers reading
1753
+ * `.score` field-by-field continue working; callers using the bare number
1754
+ * arithmetically need to switch to `.score`. The migration is single-line
1755
+ * (`const x = getArchetypePerfScore(...)` → `const x = getArchetypePerfScore(...).score`).
1756
+ */
1757
+ declare function getArchetypePerfScore(modelId: string, archetype: IntentArchetypeName): ArchetypePerfScoreResult;
1758
+
1759
+ /**
1760
+ * pricing-brain — alpha.11 KG-13 adapter.
1761
+ *
1762
+ * Brain-driven pricing data with **time-bounded resolution** (`valid_from`
1763
+ * / `valid_until` columns). The V4-Pro 75%-off promo through 2026-05-31
1764
+ * gets modeled as two rows; `at` parameter resolution picks the correct
1765
+ * row per call timestamp. Promo flips happen automatically at the
1766
+ * boundary without alpha cuts.
1767
+ *
1768
+ * SWR cache holds the FULL pricing snapshot (all active rows for all
1769
+ * models). Per-call `at` filtering is in-memory — keeps the SWR semantics
1770
+ * uniform with other adapters (one cache, one snapshot, sync reads).
1771
+ */
1772
+ interface PricingRow {
1773
+ modelId: string;
1774
+ costInputPer1m: number;
1775
+ costOutputPer1m: number;
1776
+ cacheInputPer1m?: number;
1777
+ cacheCreationPer1m?: number;
1778
+ validFrom: number;
1779
+ validUntil?: number;
1780
+ source?: string;
1781
+ }
1782
+ /**
1783
+ * Sync reader for the brain-driven pricing snapshot. Returns bundled
1784
+ * profile pricing when brain-query is disabled, cold, or unreachable.
1785
+ * Caller filters by `at` via {@link resolvePricingAt}.
1786
+ */
1787
+ declare const loadPricingFromBrain: () => PricingRow[];
1788
+ /**
1789
+ * Resolve the active pricing row for a model at a given timestamp.
1790
+ * Picks the row with the latest `valid_from <= at` whose
1791
+ * `valid_until > at` (or NULL — open-ended).
1792
+ *
1793
+ * Returns `undefined` when no row matches. Callers should fall back to
1794
+ * profile static pricing in that case.
1795
+ */
1796
+ declare function resolvePricingAt(modelId: string, at?: Date): PricingRow | undefined;
1797
+
1798
+ /**
1799
+ * models-brain — alpha.11 KG-14 adapter (the largest of the four).
1800
+ *
1801
+ * Brain-driven model registry + aliases. Two adapters share the same
1802
+ * SWR snapshot:
1803
+ *
1804
+ * - `loadModelsFromBrain()` — `Map<modelId, ModelProfile>` from
1805
+ * `kgauto_models` table (cliffs/lowering/recovery as JSONB columns).
1806
+ * - `loadAliasesFromBrain()` — `Record<aliasId, canonicalId>` from
1807
+ * `kgauto_aliases` table.
1808
+ *
1809
+ * After alpha.11, new-model onboarding becomes brain INSERT (vs PR + alpha
1810
+ * cut + 3 consumer refreshes). The auto-onboard pipeline
1811
+ * (`scripts/check-model-releases.mjs`) shifts from emitting profile.ts
1812
+ * edits to writing brain rows directly.
1813
+ *
1814
+ * **D5 — alias resolution stable regardless of canonical's active state.**
1815
+ * `canonicalId('deepseek-chat') → 'deepseek-v4-flash'` even when the
1816
+ * canonical row is `active=false`. Aliases are wire-format contracts;
1817
+ * legacy callers' resolution promise outlives the canonical's active
1818
+ * status. Deprecation (`active=false`) affects chain composition only.
1819
+ */
1820
+
1821
+ /**
1822
+ * Exported brain-row shape for `kgauto_models`. Mirrors the SQL table
1823
+ * (`v2/brain/migrations/010_kgauto_models_and_aliases.sql`) — column names
1824
+ * are snake_case to match PostgREST. Used by operator scripts that write
1825
+ * to brain (auto-onboard, promote-model) — see `profileToRow()`.
1826
+ *
1827
+ * Read path stays internal via `RawModelRow` to keep `rowToProfile()`'s
1828
+ * tolerance contract from leaking into write callers.
1829
+ */
1830
+ interface ModelBrainRow {
1831
+ model_id: string;
1832
+ provider: string;
1833
+ status?: string;
1834
+ max_context_tokens?: number;
1835
+ max_output_tokens?: number;
1836
+ max_tools?: number;
1837
+ parallel_tool_calls?: boolean;
1838
+ structured_output?: string;
1839
+ system_prompt_mode?: string;
1840
+ streaming?: boolean;
1841
+ cliffs?: unknown;
1842
+ lowering?: unknown;
1843
+ recovery?: unknown;
1844
+ strengths?: string[] | null;
1845
+ weaknesses?: string[] | null;
1846
+ cost_input_per_1m?: number;
1847
+ cost_output_per_1m?: number;
1848
+ notes?: string | null;
1849
+ verified_against_docs?: string | null;
1850
+ archetype_perf?: Record<string, number> | null;
1851
+ version_added?: string;
1852
+ version_removed?: string | null;
1853
+ active?: boolean;
1854
+ /** alpha.41 — model-family tag (migration 024 column). */
1855
+ family?: string | null;
1856
+ /** alpha.49 — explicit latency bucket (migration 028 column). */
1857
+ latency_tier?: string | null;
1858
+ /** alpha.49 — per-archetype prompt-shape conventions (migration 028 column). */
1859
+ archetype_conventions?: ArchetypeConvention[] | null;
1860
+ }
1861
+ interface ProfileToRowOptions {
1862
+ /** e.g. `'2.0.0-alpha.12'` — leave undefined to omit from row. */
1863
+ versionAdded?: string;
1864
+ /** Pass `null` to clear; omit to leave field unset. */
1865
+ versionRemoved?: string | null;
1866
+ /** Defaults to true if omitted. */
1867
+ active?: boolean;
1868
+ /**
1869
+ * Override verifiedAgainstDocs (e.g. set to `null` for auto-onboard).
1870
+ * When omitted, the profile's own value is used. Pass `null` explicitly
1871
+ * to write a SQL NULL (e.g. unverified auto-onboard rows).
1872
+ */
1873
+ verifiedAgainstDocs?: string | null;
1874
+ }
1875
+ /**
1876
+ * Inverse of `rowToProfile` — serialize a `ModelProfile` to a `kgauto_models`
1877
+ * row payload for INSERT/UPSERT. Used by operator scripts that write to
1878
+ * brain (auto-onboard pipeline, promote-model verification CLI).
1879
+ *
1880
+ * Row-level fields (`version_added`, `version_removed`, `active`) are
1881
+ * operator-controlled and pass through `opts`. `verifiedAgainstDocs` can
1882
+ * also be overridden via `opts` — auto-onboard explicitly passes `null` to
1883
+ * mark unverified rows (the column is DATE, doesn't accept the
1884
+ * `'UNVERIFIED-AUTO-ONBOARD'` sentinel used in PROFILES_RAW).
1885
+ */
1886
+ declare function profileToRow(profile: ModelProfile, opts?: ProfileToRowOptions): ModelBrainRow;
1887
+ /**
1888
+ * Sync reader for the brain-driven model registry. Returns bundled
1889
+ * PROFILES_RAW when brain-query is disabled, cold, or unreachable.
1890
+ */
1891
+ declare const loadModelsFromBrain: () => Map<string, ModelProfile>;
1892
+ /**
1893
+ * Sync reader for the brain-driven aliases map. Returns bundled ALIASES
1894
+ * when brain-query is disabled, cold, or unreachable.
1895
+ *
1896
+ * D5: this map carries both active and inactive canonical mappings —
1897
+ * alias resolution is stable regardless of canonical's `active` state.
1898
+ */
1899
+ declare const loadAliasesFromBrain: () => Record<string, string>;
1900
+
1901
+ /**
1902
+ * exclusion-findings-brain — alpha.38 KG-19 adapter.
1903
+ *
1904
+ * Per-tenant SWR cache for the `exclusion_findings` table populated by the
1905
+ * `kgauto-exclusion-re-evaluation-watch` cron (alpha.37 substrate). Distinct
1906
+ * from the cross-tenant `brain-query.ts` snapshot because exclusion findings
1907
+ * are scoped per `app_id` — one process = one consumer = one appId, but the
1908
+ * cache key supports multi-app processes by keying snapshots by appId.
1909
+ *
1910
+ * Architecture mirrors `brain-query.ts` but with a per-(appId) snapshot:
1911
+ *
1912
+ * - **Sync API surface.** `getStaleExclusionFindings({ appId, archetype })`
1913
+ * returns `ExclusionFindingRow[]` immediately. First call returns the
1914
+ * bundled fallback (empty array); async refresh fires in background;
1915
+ * subsequent calls within TTL return brain data.
1916
+ *
1917
+ * - **Per-appId snapshot.** Each appId gets its own cache entry. One fetch
1918
+ * per appId per TTL window. Tests can reset between cases.
1919
+ *
1920
+ * - **Tolerant.** Brain down / endpoint misconfigured / unexpected shape →
1921
+ * silent bundled fallback (empty array). Never throws. Warns once per
1922
+ * process per error to avoid log spam.
1923
+ *
1924
+ * - **Opt-in.** Activation gated on `configureExclusionFindingsBrain()`
1925
+ * having been called with a runtime. The public `configureBrain()` in
1926
+ * brain.ts wires this up automatically when `BrainConfig.brainQuery
1927
+ * .findingsExclusions !== false`.
1928
+ *
1929
+ * Default endpoint:
1930
+ * `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions`
1931
+ * The route accepts `?app_id=X` and returns a JSON array of findings
1932
+ * for that app filtered to `resolved_at IS NULL`. Public read; data
1933
+ * carries no consumer PII (app id, archetype, model id, cost ratio,
1934
+ * savings estimate).
1935
+ */
1936
+ /**
1937
+ * Shape of one row from the `exclusion_findings` cache table. Mirrors the
1938
+ * snake_case JSONB returned by the brain RPC + the dashboard endpoint.
1939
+ * Camel-case mapping happens at the boundary (rowToFinding) so the in-memory
1940
+ * shape stays consistent with the rest of the library.
1941
+ */
1942
+ interface ExclusionFindingRow {
1943
+ /** Intent archetype the finding applies to (e.g. 'hunt', 'classify'). */
1944
+ archetype: string;
1945
+ /** Canonical model id that the consumer has excluded (zero traffic in window). */
1946
+ excludedModel: string;
1947
+ /** Provider of the excluded model (e.g. 'deepseek', 'openai'). */
1948
+ excludedProvider: string;
1949
+ /** Detection verdict — alpha.37 ships 'recommend-probe' only. */
1950
+ verdict: 'recommend-probe' | 'unblock' | 'stay-excluded' | 'inconclusive';
1951
+ /**
1952
+ * Estimated 30-day savings in USD if the excluded model becomes primary
1953
+ * on this archetype. Null when pricing is incomplete or excluded model is
1954
+ * more expensive than the leader.
1955
+ */
1956
+ estimatedSavingsUsd30d: number | null;
1957
+ /** Renderable summary; produced by the detector / RPC. */
1958
+ message: string;
1959
+ /** Actionable recommendation; produced by the detector / RPC. */
1960
+ suggestion: string;
1961
+ /** Detector confidence tier. */
1962
+ confidence: 'high' | 'medium' | 'low';
1963
+ /**
1964
+ * Free-form evidence pack (cost ratio, leader info, promo flags, parallel-
1965
+ * tool hint, etc.). Surfaced verbatim to advisor rules for richer messages.
1966
+ * Optional — older detector runs may not populate every field.
1967
+ */
1968
+ evidence?: Record<string, unknown>;
1969
+ }
1970
+ /**
1971
+ * Default endpoint hosted on the kgauto-dashboard. Public read — data carries
1972
+ * no PII (app id, archetype, model id, cost ratio, savings estimate). Mirrors
1973
+ * the cross-tenant `/api/kgauto-v2/config` pattern.
1974
+ */
1975
+ declare const DEFAULT_FINDINGS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions";
1976
+ /**
1977
+ * Sync introspection — is the findings-brain active? Used by advisor rules
1978
+ * to decide whether to even attempt a read.
1979
+ */
1980
+ declare function isExclusionFindingsBrainActive(): boolean;
1981
+ interface GetExclusionFindingsOpts {
1982
+ /** App id to read findings for. Required. */
1983
+ appId: string;
1984
+ /**
1985
+ * Optional archetype filter. When set, returns only findings where
1986
+ * `archetype` matches. When omitted, returns all findings for the app.
1987
+ */
1988
+ archetype?: string;
1989
+ }
1990
+ /**
1991
+ * Sync reader. Returns the cached findings for `appId`, optionally filtered
1992
+ * to a single archetype. First call returns empty array and triggers async
1993
+ * refresh; subsequent calls within TTL return brain data.
1994
+ *
1995
+ * NEVER throws. Brain down / endpoint misconfigured / mapper exception →
1996
+ * empty array.
1997
+ */
1998
+ declare function getStaleExclusionFindings(opts: GetExclusionFindingsOpts): ExclusionFindingRow[];
1999
+
2000
+ /**
2001
+ * Family resolution — alpha.41.
2002
+ *
2003
+ * "I want the latest Opus" → kgauto picks the current+active model in the
2004
+ * `claude-opus` family. Closes the loop where consumer code carries hardcoded
2005
+ * `claude-opus-4-6` literals long after `claude-opus-4-7` ships and goes
2006
+ * current — the s47 trigger (IC's `generate` chain still routing 43 calls to
2007
+ * legacy 4-6 in production).
2008
+ *
2009
+ * Two surfaces:
2010
+ * - `getRecommendedPrimary({ family, ..., fallback })` — public, sync,
2011
+ * used at IR-construction time when the consumer wants a literal id back
2012
+ * (with a fallback floor for cold-start brain).
2013
+ * - `resolveFamilyEntry({ family, archetype?, appId? })` — internal,
2014
+ * called from compile() when an IR's `models[]` entry is shaped
2015
+ * `{ family: string }`. Throws `FamilyResolutionError` on failure.
2016
+ *
2017
+ * Both routes share the same algorithm (locked in the alpha.41 Phase 0
2018
+ * design contract); they differ only in the fallback ergonomics. The
2019
+ * public route accepts a required `fallback: string`; the IR route throws.
2020
+ *
2021
+ * Pure resolution. No network. No async. Brain-registry reads go through
2022
+ * the existing SWR cache (`loadModelsFromBrain` from `models-brain.ts`) —
2023
+ * cold-start returns bundled profiles, which still resolve via the
2024
+ * `deriveFamilyFromModelId` fallback when the brain row's `family` column
2025
+ * is null (G1 contract: graceful pre-migration behavior).
2026
+ *
2027
+ * @see command-center/advisory/kgauto/2026-05-26_alpha-41-model-family-aliases-and-promotion-probe-watcher.md
2028
+ */
2029
+
2030
+ interface GetRecommendedPrimaryOptions {
2031
+ /**
2032
+ * Family tag (e.g. `'claude-opus'`, `'gemini-flash'`). See the Phase 0
2033
+ * design contract's family taxonomy table for the locked initial set;
2034
+ * extensible via brain migrations.
2035
+ */
2036
+ family: string;
2037
+ /**
2038
+ * Optional archetype gate. When provided, candidates must clear
2039
+ * {@link ARCHETYPE_FLOOR_DEFAULT} on `archetypePerf[archetype]`. Also used
2040
+ * as the primary sort key (DESC) when multiple candidates qualify.
2041
+ */
2042
+ archetype?: IntentArchetypeName;
2043
+ /**
2044
+ * Optional consumer-app id. When provided, candidates matching a
2045
+ * `stay-excluded` finding for `(appId, archetype)` in the
2046
+ * exclusion-findings cache (alpha.38 substrate) are filtered out.
2047
+ */
2048
+ appId?: string;
2049
+ /**
2050
+ * Consumer-posture tag. `'locked'` short-circuits resolution and returns
2051
+ * the literal `fallback` unconditionally — useful for compliance /
2052
+ * contract / brand-promise flows where the consumer doesn't want kgauto
2053
+ * picking the model on their behalf.
2054
+ */
2055
+ posture?: 'preferred' | 'open' | 'locked';
2056
+ /**
2057
+ * Last-resort literal model id. REQUIRED. Returned when (a) brain
2058
+ * registry is cold / no candidates exist, (b) `posture === 'locked'`,
2059
+ * (c) every candidate was filtered out by archetype / exclusion gates.
2060
+ *
2061
+ * The fallback is NOT validated against the family — kgauto trusts the
2062
+ * consumer to pass a meaningful floor. The contract intent is "even when
2063
+ * everything below is on fire, you still get a model id back."
2064
+ */
2065
+ fallback: string;
2066
+ }
2067
+ /**
2068
+ * Thrown by `resolveFamilyEntry` (the internal compile-time twin) when a
2069
+ * `{ family: string }` IR entry can't resolve to any current+active model.
2070
+ * Surfaces with the family string + a one-line cause so consumer error
2071
+ * handling can distinguish "you typo'd the family tag" from "brain is cold
2072
+ * and nothing matches."
2073
+ *
2074
+ * The public `getRecommendedPrimary` does NOT throw — it returns
2075
+ * `fallback` instead.
2076
+ */
2077
+ declare class FamilyResolutionError extends Error {
2078
+ readonly family: string;
2079
+ readonly cause: string;
2080
+ constructor(family: string, cause: string);
2081
+ }
2082
+ /**
2083
+ * Deterministic model_id → family inference. Pure function; no brain
2084
+ * lookup. Used as the runtime fallback when a brain row's `family` column
2085
+ * is null (pre-migration 024) and as the canonical mapping that migration
2086
+ * 024's CASE statement mirrors.
2087
+ *
2088
+ * Returns null for unrecognized ids — caller must handle (typically by
2089
+ * skipping the row in family resolution).
2090
+ *
2091
+ * Order matters: more specific patterns first (e.g. `flash-lite` before
2092
+ * `flash`; `pro` before `chat`). The brain-side CASE statement uses the
2093
+ * same priority.
2094
+ */
2095
+ declare function deriveFamilyFromModelId(modelId: string): string | null;
2096
+ /**
2097
+ * Public sync resolver. Pure (modulo brain snapshot read). Returns the
2098
+ * literal model id of the best candidate, or `fallback` when resolution
2099
+ * yields nothing.
2100
+ */
2101
+ declare function getRecommendedPrimary(opts: GetRecommendedPrimaryOptions): string;
2102
+
2103
+ /**
2104
+ * promote-ready-brain — alpha.41 substrate.
2105
+ *
2106
+ * Per-tenant SWR cache for the `promote_ready_findings` table populated by
2107
+ * the autonomous `promotion-probe-watcher` (Mode 2). Mirrors
2108
+ * `exclusion-findings-brain.ts` shape byte-for-byte where applicable; this
2109
+ * is the read-side substrate for the compile-time `promote-ready` advisor
2110
+ * rule.
2111
+ *
2112
+ * Architecture (mirror of exclusion-findings-brain):
2113
+ *
2114
+ * - **Sync API surface.** `getPromoteReadyFindings({ appId, archetype,
2115
+ * family })` returns `PromoteReadyFindingRow[]` immediately. First call
2116
+ * returns the bundled fallback (empty array); async refresh fires in
2117
+ * background; subsequent calls within TTL return brain data.
2118
+ *
2119
+ * - **Per-appId snapshot.** Each appId gets its own cache entry. One fetch
2120
+ * per appId per TTL window. Tests reset between cases via
2121
+ * `_testResetPromoteReadyFindings()`.
2122
+ *
2123
+ * - **Tolerant.** Brain down / endpoint misconfigured / unexpected shape →
2124
+ * silent bundled fallback (empty array). Never throws. Warns once per
2125
+ * process per error to avoid log spam.
2126
+ *
2127
+ * - **Opt-in.** Activation gated on `configurePromoteReadyBrain()` having
2128
+ * been called with a runtime. The public `configureBrain()` in brain.ts
2129
+ * wires this up automatically when
2130
+ * `BrainConfig.brainQuery.findingsPromoteReady !== false`.
2131
+ *
2132
+ * Plus: `markPromoteReadyHandled` — direct PostgREST PATCH against the
2133
+ * brain (no kgauto proxy). Mirrors `markExclusionFindingHandled` shape
2134
+ * byte-for-byte. Idempotent on `resolved_at=is.null` filter.
2135
+ *
2136
+ * Default endpoint:
2137
+ * `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/promote-ready`
2138
+ * The route accepts `?app_id=X` and returns a JSON array of findings
2139
+ * for that app filtered to `resolved_at IS NULL`.
2140
+ */
2141
+
2142
+ /**
2143
+ * Shape of one row from the `promote_ready_findings` cache table. Mirrors
2144
+ * the snake_case JSONB returned by the brain endpoint, mapped to camelCase
2145
+ * at the boundary (rowToFinding) so the in-memory shape stays consistent
2146
+ * with the rest of the library.
2147
+ */
2148
+ interface PromoteReadyFindingRow {
2149
+ /** Intent archetype the finding applies to. */
2150
+ archetype: string;
2151
+ /** Model family (e.g. 'claude-opus', 'gemini-flash'). */
2152
+ family: string;
2153
+ /** The candidate model that the probe validated. */
2154
+ candidateModel: string;
2155
+ /** The current production model the candidate was compared against. */
2156
+ currentModel: string;
2157
+ /** Sample size of the probe run (typically 10). */
2158
+ sampleN: number;
2159
+ /** Fraction of probes where the judge verdict was 'candidate-better' or
2160
+ * 'tied'. 0.000 to 1.000. */
2161
+ judgePassRate: number;
2162
+ /** Mean judge score across the probe sample. 1.00 to 5.00. */
2163
+ judgeAvgScore: number;
2164
+ /** Signed cost delta as a fraction (negative = candidate is cheaper).
2165
+ * Null when pricing data was incomplete at probe time. */
2166
+ costDeltaPct: number | null;
2167
+ /** ISO timestamp of detection (when the probe wrote the row). */
2168
+ detectedAt: string;
2169
+ }
2170
+ /**
2171
+ * Resolution sources supported by alpha.41 `markPromoteReadyHandled`. The
2172
+ * three values map to the three CHECK-constrained resolution values on
2173
+ * `promote_ready_findings.resolution`:
2174
+ *
2175
+ * - `'promoted'` — consumer migrated to the candidate model. Strong
2176
+ * positive signal; the probe was right.
2177
+ * - `'declined'` — consumer evaluated and chose not to promote.
2178
+ * Strong negative signal; revisit only on new
2179
+ * family entries or material score swings.
2180
+ * - `'still-evaluating'` — consumer acknowledges the finding but defers
2181
+ * the decision. Acknowledges-without-deciding;
2182
+ * finding silences this cycle but next probe may
2183
+ * re-surface.
2184
+ */
2185
+ type PromoteReadyResolution = 'promoted' | 'declined' | 'still-evaluating';
2186
+ interface MarkPromoteReadyHandledOptions {
2187
+ /** App id the finding belongs to. Required (RLS scopes writes by this). */
2188
+ appId: string;
2189
+ /** Archetype the finding applies to (e.g. 'hunt', 'classify'). */
2190
+ archetype: IntentArchetypeName | string;
2191
+ /** Model family the finding applies to (e.g. 'claude-opus'). */
2192
+ family: string;
2193
+ /** Resolution semantics — see `PromoteReadyResolution`. */
2194
+ resolution: PromoteReadyResolution;
2195
+ /** Optional free-form note explaining the decision. */
2196
+ resolutionNote?: string;
2197
+ /** Brain Supabase URL base (e.g. `https://<project>.supabase.co`). */
2198
+ brainEndpoint: string;
2199
+ /** Consumer-scoped JWT carrying the `app_id` claim. */
2200
+ brainJwt: string;
2201
+ /** Supabase anon key for the `apikey` header. */
2202
+ brainAnonKey: string;
2203
+ /** Injected fetch for tests. Defaults to global fetch. */
2204
+ fetch?: typeof fetch;
2205
+ }
2206
+ /**
2207
+ * Mark a probe-validated promote-ready finding as handled. Returns an
2208
+ * `ok/reason` envelope matching `markExclusionFindingHandled`.
2209
+ *
2210
+ * Idempotent: if no row matches the (app_id, archetype, family) tuple
2211
+ * (already resolved, never existed, watcher not yet UPSERTed), PostgREST
2212
+ * returns 200/204 with zero affected rows and we return `{ ok: true }`.
2213
+ *
2214
+ * Reasons surfaced on failure:
2215
+ * - `app_id_required` / `archetype_required` / `family_required`
2216
+ * - `resolution_invalid` — not one of the three documented values
2217
+ * - `brain_auth_misconfig` — 401/403
2218
+ * - `brain_unavailable` — 5xx
2219
+ * - `network_error:<message>` — fetch threw
2220
+ * - `patch_failed:<status>` — anything else non-2xx
2221
+ */
2222
+ declare function markPromoteReadyHandled(opts: MarkPromoteReadyHandledOptions): Promise<{
2223
+ ok: true;
2224
+ } | {
2225
+ ok: false;
2226
+ reason: string;
2227
+ }>;
2228
+
192
2229
  /**
193
2230
  * @warmdrift/kgauto v2 — prompt compiler + central learning brain.
194
2231
  *
@@ -235,4 +2272,4 @@ declare function countTokens(text: string): number;
235
2272
  */
236
2273
  declare function compile(ir: PromptIR, opts?: CompileOptions): CompileResult;
237
2274
 
238
- export { ApiKeys, type AppOracle, type BrainConfig, CallOptions, CallResult, type CompileOptions, CompilePolicy, CompileResult, CompiledRequest, type ExecuteErr, type ExecuteOk, type ExecuteOptions, type ExecuteResult, type LLMJudgeOptions, ModelProfile, NormalizedResponse, type OracleContext, OracleScore, PromptIR, ProviderOverrides, RecordInput, buildLLMJudge, call, clearBrain, compile, configureBrain, countTokens, execute, record, resetTokenizer, setTokenizer };
2275
+ export { ABSOLUTE_FLOOR, type AISDKConvertedMessage, ARCHETYPE_FAMILY_FITS, ARCHETYPE_FLOOR_DEFAULT, type ActionableAdvisory, Adapter, type AdvisoryResolutionSource, type AdvisorySeverity, type AdvisoryStatus, type AdvisorySuggestedFix, ApiKeys, type AppOracle, type ApplySectionRewritesArgs, type ApplySectionRewritesResult, ArchetypeConvention, type ArchetypeFamilyFit, type ArchetypePerfMap, type ArchetypePerfNMap, type ArchetypePerfScoreResult, type AttachCacheControlResult, BestPracticeAdvisory, type BrainConfig, type BrainQueryConfig, type BrainReadEnv, CallOptions, CallResult, ChainEntry, type CompatibilityIntent, type CompileOptions, CompilePolicy, CompileResult, CompiledRequest, DEFAULT_FINDINGS_ENDPOINT, type ExclusionFindingRow, type ExclusionResolutionSource, type ExecuteErr, type ExecuteOk, type ExecuteOptions, type ExecuteResult, type FallbackPosture, FamilyResolutionError, type GetActionableAdvisoriesOptions, type GetDefaultFallbackChainOpts, type GetPerAxisMetricsOpts, type GetRecommendedPrimaryOptions, Grounding, IntentArchetypeName, type LLMJudgeOptions, MEASURED_GROUNDING_MIN_N, type MarkAdvisoryResolvedOptions, type MarkExclusionFindingHandledOptions, type MarkPromoteReadyHandledOptions, type ModelBrainRow, type ModelCompatibility, ModelProfile, NormalizedResponse, type OracleContext, OracleScore, type OutcomePayload, OutcomeResult, PRODUCER_OWNED_RULE_CODES, PROVIDER_ENV_KEYS, PerAxisMetrics, type PricingRow, type ProbeShadowOptions, type ProbeShadowServed, type ProfileToRowOptions, type PromoteReadyFindingRow, type PromoteReadyResolution, PromptIR, Provider, ProviderOverrides, type ProviderReachability, RULE_SEQUENTIAL_TOOL_CLIFF, type ReachabilityOpts, RecordInput, RecordOutcomeInput, type RunAdvisorPhase2Context, SectionRewrite, type ShadowProbeRecordInput, type SupportedProvider, SystemModelMessage, TRANSLATOR_FLOOR, applyArchetypeConvention, applySectionRewrites, attachCacheControlToStreamTextInput, buildLLMJudge, buildShadowProbeRow, call, clearBrain, compile, configureBrain, countTokens, deriveFamilyFromModelId, deriveOwnership, execute, findBetterFit, getActionableAdvisories, getAllStarterChains, getAllStarterChainsWithGrounding, getArchetypePerfScore, getDefaultFallbackChain, getDefaultFallbackChainWithGrounding, getModelCompatibility, getPerAxisMetrics, getReachabilityDiagnostic, getRecommendedPrimary, getSequentialStarterChain, getSequentialStarterChainWithGrounding, getStaleExclusionFindings, getStarterChain, getStarterChainWithGrounding, isBrainQueryActiveFor, isBrainSync, isExclusionFindingsBrainActive, isModelReachable, isProviderReachable, loadAliasesFromBrain, loadArchetypePerfFromBrain, loadArchetypePerfNFromBrain, loadChainsFromBrain, loadModelsFromBrain, loadPricingFromBrain, markAdvisoryResolved, markExclusionFindingHandled, markPromoteReadyHandled, probeShadow, profileToRow, readBrainReadEnv, record, recordOutcome, recordShadowProbe, resetTokenizer, resolveConventionsForProfile, resolvePricingAt, resolveProviderKey, runAdvisor, setTokenizer };