@warmdrift/kgauto-compiler 2.0.0-alpha.9 → 2.0.0-alpha.91

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 (55) hide show
  1. package/README.md +176 -46
  2. package/dist/brain-proxy.d.mts +113 -0
  3. package/dist/brain-proxy.d.ts +113 -0
  4. package/dist/brain-proxy.js +193 -0
  5. package/dist/brain-proxy.mjs +6 -0
  6. package/dist/chunk-54IXD5BT.mjs +858 -0
  7. package/dist/chunk-65ZMX5OT.mjs +169 -0
  8. package/dist/chunk-AUZTO6Q5.mjs +219 -0
  9. package/dist/{chunk-5TI6PNSK.mjs → chunk-BVEXV5KC.mjs} +11 -0
  10. package/dist/chunk-NBO4R5PC.mjs +313 -0
  11. package/dist/chunk-P3TOAEG4.mjs +56 -0
  12. package/dist/chunk-RO22VFIF.mjs +29 -0
  13. package/dist/chunk-T53ISC2F.mjs +2008 -0
  14. package/dist/dialect.d.mts +41 -3
  15. package/dist/dialect.d.ts +41 -3
  16. package/dist/dialect.js +14 -2
  17. package/dist/dialect.mjs +5 -3
  18. package/dist/glassbox/index.d.mts +59 -0
  19. package/dist/glassbox/index.d.ts +59 -0
  20. package/dist/glassbox/index.js +312 -0
  21. package/dist/glassbox/index.mjs +12 -0
  22. package/dist/glassbox-routes/format.d.mts +24 -0
  23. package/dist/glassbox-routes/format.d.ts +24 -0
  24. package/dist/glassbox-routes/format.js +86 -0
  25. package/dist/glassbox-routes/format.mjs +18 -0
  26. package/dist/glassbox-routes/index.d.mts +191 -0
  27. package/dist/glassbox-routes/index.d.ts +191 -0
  28. package/dist/glassbox-routes/index.js +3326 -0
  29. package/dist/glassbox-routes/index.mjs +668 -0
  30. package/dist/glassbox-routes/react/index.d.mts +74 -0
  31. package/dist/glassbox-routes/react/index.d.ts +74 -0
  32. package/dist/glassbox-routes/react/index.js +819 -0
  33. package/dist/glassbox-routes/react/index.mjs +754 -0
  34. package/dist/index.d.mts +3782 -99
  35. package/dist/index.d.ts +3782 -99
  36. package/dist/index.js +10970 -2043
  37. package/dist/index.mjs +6279 -276
  38. package/dist/ir-CTx026t0.d.ts +1887 -0
  39. package/dist/ir-DeYMLWge.d.mts +1887 -0
  40. package/dist/key-health.d.mts +166 -0
  41. package/dist/key-health.d.ts +166 -0
  42. package/dist/key-health.js +247 -0
  43. package/dist/key-health.mjs +12 -0
  44. package/dist/profiles.d.mts +352 -2
  45. package/dist/profiles.d.ts +352 -2
  46. package/dist/profiles.js +1412 -52
  47. package/dist/profiles.mjs +19 -1
  48. package/dist/types-BKbRtmUb.d.ts +131 -0
  49. package/dist/types-Cp9ot1HV.d.ts +142 -0
  50. package/dist/types-DD36cCbZ.d.mts +142 -0
  51. package/dist/types-cBzinzUR.d.mts +131 -0
  52. package/package.json +62 -9
  53. package/dist/chunk-3KVKELZN.mjs +0 -657
  54. package/dist/profiles-BYVOc1eW.d.ts +0 -700
  55. package/dist/profiles-NUZOIzGr.d.mts +0 -700
package/dist/index.d.mts CHANGED
@@ -1,7 +1,11 @@
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, B as BestPracticeAdvisory } from './profiles-NUZOIzGr.mjs';
2
- export { f as ALIASES, g as CacheStrategy, h as CallAttempt, i as CallError, j as CliffRule, k as Constraints, F as FallbackReason, H as HistoryCachePolicy, 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-NUZOIzGr.mjs';
3
- import { IntentArchetypeName } from './dialect.mjs';
4
- export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, 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, B as BestPracticeAdvisory, F as FallbackReason, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OutcomeSource, i as OracleScore, j as Adapter, k as PerAxisMetrics, l as Provider, m as ChainEntry, G as Grounding } from './ir-DeYMLWge.mjs';
2
+ export { n as CallAttempt, o as CallError, p as ChainModelEntry, q as ChainWithGrounding, r as Constraints, E as EffortLevel, s as GoldenCaptureOptions, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, t as MutationApplied, u as NormalizedTokens, v as OutcomeKind, w as PerAxisMetricsByModel, x as PromptSection, y as SectionKind, z as ShadowProbeConfig, T as ToolCall, D as ToolDefinition, J as captureGoldenIr, K as hasMutation, L as mutationId, Q as parseGoldenCaptureRate, U as resolveGoldenCaptureRate, V as shouldCaptureGolden } from './ir-DeYMLWge.mjs';
3
+ import { ModelProfile, ArchetypeConvention } from './profiles.mjs';
4
+ export { ALIASES, CacheStrategy, CliffRule, LATENCY_TIER_MS, LatencyTier, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, _testClearConsumerProfiles, allProfiles, bestEffortProfile, getProfile, inferProviderFromId, latencyTierOf, profilesByProvider, registerProfiles, resolveModelAlias, tryGetProfile } from './profiles.mjs';
5
+ export { BrainForwardConfig, BrainForwardRoutes, createBrainForwardRoutes } from './brain-proxy.mjs';
6
+ export { KEY_FINGERPRINT_DOMAIN, KEY_FINGERPRINT_LENGTH, KeyHealthConfig, KeyHealthProvider, KeyHealthResponseBody, KeyHealthResult, KeyHealthRoute, createKeyHealthRoute, keyFingerprint } from './key-health.mjs';
7
+ import { IntentArchetypeName, OutputMode } from './dialect.mjs';
8
+ export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, ShapeSignature, ToolCountBucket, bucketContext, bucketHistory, bucketToolCount, hashShape, isArchetype, learningKey } from './dialect.mjs';
5
9
 
6
10
  /**
7
11
  * compile() — the main orchestrator.
@@ -34,6 +38,15 @@ interface CompileOptions {
34
38
  * ceiling, boosts preferred. See CompilePolicy in ir.ts.
35
39
  */
36
40
  policy?: CompilePolicy;
41
+ /**
42
+ * alpha.68 / Release A (delegation-fanout-accelerator §5.0, R0 linkage) —
43
+ * transport for the fan-out parent handle. Threaded from
44
+ * `CallOptions.parentHandle` on the call() path (and settable directly on the
45
+ * public compile() path). Release A does NOT route on it — it only labels the
46
+ * outcome row (fanout_role / trace_id / parent_handle) at record-registration
47
+ * time. `registerCompile` reads it to derive the linkage. Absent ⇒ root call.
48
+ */
49
+ parentHandle?: string;
37
50
  }
38
51
 
39
52
  /**
@@ -52,6 +65,29 @@ interface ExecuteOptions {
52
65
  apiKeys?: ApiKeys;
53
66
  fetchImpl?: typeof fetch;
54
67
  providerOverrides?: ProviderOverrides;
68
+ /**
69
+ * alpha.34. When supplied AND the chosen provider supports streaming, the
70
+ * execute() per-provider branch switches to SSE wire format and invokes
71
+ * `onChunk(delta)` once per text-delta event. Single-shot behavior
72
+ * preserved when omitted (current consumers unaffected). Wired from
73
+ * `CallOptions.onChunk` by `call()` after gating on `profile.streaming`
74
+ * and `!opts.noStream`.
75
+ */
76
+ onChunk?: (chunk: string) => void;
77
+ /**
78
+ * alpha.78 — abort signal for the provider fetch. call() composes
79
+ * `AbortSignal.timeout(attemptTimeoutMs)` with the caller's own
80
+ * `CallOptions.abortSignal`; direct execute() consumers may pass anything.
81
+ * TimeoutError reasons classify retryable `timeout` (chain walks);
82
+ * AbortError reasons classify terminal `aborted` (caller cancelled).
83
+ */
84
+ signal?: AbortSignal;
85
+ /**
86
+ * alpha.78 — per-chunk stall bound, streaming paths only (see
87
+ * StreamingOptions.stallTimeoutMs). Ignored on non-streaming requests,
88
+ * where `signal` carries the total attempt bound instead.
89
+ */
90
+ stallTimeoutMs?: number;
55
91
  }
56
92
  interface ExecuteOk {
57
93
  ok: true;
@@ -65,6 +101,19 @@ interface ExecuteErr {
65
101
  errorCode: string;
66
102
  message: string;
67
103
  raw: unknown;
104
+ /**
105
+ * alpha.66 — real token usage when the failure is a SYNTHESIZED
106
+ * structured-output contract violation (the provider returned 200 with
107
+ * usage; the response just violated the contract). Absent on transport-
108
+ * level failures (4xx/5xx/network) where no usage exists. Lets the
109
+ * brain's failure rows carry true `tokens_in` for the cliff class —
110
+ * PB's 2026-05-18 `chain-walk-on-structured-output-parse-failed` ask 4
111
+ * (tokens_in=0 on a 72s parse-fail made diagnosis ambiguous).
112
+ */
113
+ tokens?: {
114
+ input: number;
115
+ output: number;
116
+ };
68
117
  }
69
118
  type ExecuteResult = ExecuteOk | ExecuteErr;
70
119
  declare function execute(request: CompiledRequest, opts?: ExecuteOptions): Promise<ExecuteResult>;
@@ -85,26 +134,347 @@ declare function execute(request: CompiledRequest, opts?: ExecuteOptions): Promi
85
134
  * Hard cap at fallbackChain.length + 1 attempts. Terminal errors short-circuit.
86
135
  */
87
136
 
137
+ declare function call(ir: PromptIR, opts?: CallOptions): Promise<CallResult>;
138
+ /** Served-side result the AI-SDK consumer already holds from streamText. */
139
+ interface ProbeShadowServed {
140
+ /** Model id that actually served the user (becomes `current_model` on the row). */
141
+ model: string;
142
+ /** The served response text (stored as a preview; never the prompt). */
143
+ responseText: string;
144
+ /** Served prompt tokens (AI SDK `usage.promptTokens`). */
145
+ tokensIn: number;
146
+ /** Served completion tokens (AI SDK `usage.completionTokens`). */
147
+ tokensOut: number;
148
+ /** The user's actual wait in ms (alpha.46 served-latency axis). */
149
+ latencyMs: number;
150
+ }
151
+ /** Options for the standalone {@link probeShadow} export. */
152
+ interface ProbeShadowOptions {
153
+ /** The served leg the consumer supplies; kgauto runs the candidate leg. */
154
+ served: ProbeShadowServed;
155
+ /** Model id(s)/family alias(es) to shadow-test against the served model. */
156
+ candidates: string | string[];
157
+ /** Probability [0,1] a given call fires a probe. Default 0.05; pin 1 for dogfood. */
158
+ sampleRate?: number;
159
+ /** Phase 1 = 'off' (offline rollup). 'opus' inline judge is Phase 2. Default 'off'. */
160
+ judge?: 'off' | 'opus';
161
+ /** Override API keys (defaults: process.env). Gates candidate reachability. */
162
+ apiKeys?: ApiKeys;
163
+ /** Override fetch (for tests / custom transport). */
164
+ fetchImpl?: typeof fetch;
165
+ /** Provider-specific request fields shallow-merged into the candidate request. */
166
+ providerOverrides?: ProviderOverrides;
167
+ /** Forwarded to compile() for the candidate run (match the served-side compile). */
168
+ policy?: CompilePolicy;
169
+ toolRelevanceThreshold?: number;
170
+ compressHistoryAfter?: number;
171
+ }
172
+ /**
173
+ * s54 — standalone full-IR shadow probe for AI-SDK consumers (tt-intel hunt, IC
174
+ * chat) that own their own streamText round-trip and never call call(). Fire it
175
+ * from the streamText `onFinish` callback, wrapped in the platform's
176
+ * `waitUntil()` / `after()`, so it runs after the response is flushed — no
177
+ * blocking, no `sync:true`, no teardown race (cleaner than call()'s in-process
178
+ * fire-and-forget for Edge runtimes; L-086).
179
+ *
180
+ * Runs the SAME candidate loop as the call()-inline probe ({@link
181
+ * runProbeCandidates}): same gates (sample, self-skip, G4 judge-self,
182
+ * reachability, G6), same fidelity=1.0 full-IR rows, same alpha.46 latency
183
+ * capture. The consumer supplies the served leg it already has; kgauto runs the
184
+ * candidate(s) and writes the `probe_outcomes` row.
185
+ *
186
+ * Requires `configureBrain()` to have been called (same as call()).
187
+ * Fire-and-forget: never throws into the caller.
188
+ *
189
+ * @example
190
+ * const result = streamText({ model, system, messages,
191
+ * onFinish: ({ text, usage }) => {
192
+ * after(() => probeShadow(ir, {
193
+ * served: { model: servedModelId, responseText: text,
194
+ * tokensIn: usage.promptTokens, tokensOut: usage.completionTokens,
195
+ * latencyMs: Date.now() - t0 },
196
+ * candidates: ['deepseek-v4-pro'], sampleRate: 0.05,
197
+ * }));
198
+ * },
199
+ * });
200
+ */
201
+ declare function probeShadow(ir: PromptIR, opts: ProbeShadowOptions): Promise<void>;
202
+
88
203
  /**
89
- * Compile, execute, normalize, record. Returns a CallResult once a provider
90
- * actually serves the request. Throws CallError if the fallback chain is
91
- * exhausted without success.
204
+ * alpha.33 AI-SDK streamText helpers.
205
+ *
206
+ * The cross-consumer pattern surfaced 2026-05-20 (`streamText-cache-marker-
207
+ * propagation-gap` on `command-center/interfaces/kgauto.md ## Requested`):
208
+ * AI-SDK consumers using `streamText({ system: <string>, messages:
209
+ * convertToModelMessages(messages), model })` silently drop the Anthropic
210
+ * `cache_control` markers the compiler emits on `result.request.messages`.
211
+ * Two losses on that line:
212
+ * (a) `convertToModelMessages()` reads raw inputs not the lowered output,
213
+ * dropping per-message providerOptions; and
214
+ * (b) `streamText({ system: '<string>' })` strips any providerOptions
215
+ * on the system prefix.
216
+ *
217
+ * Net effect prior to this surface: `cache_read_input_tokens = 0` across
218
+ * every measured production call by IC + tt-intel even though both
219
+ * consumers had `historyCachePolicy: { strategy: 'all-but-latest' }` wired
220
+ * since alpha.5. The compiler did the right thing; the consumer integration
221
+ * pattern lost the markers at the wire boundary.
222
+ *
223
+ * This helper closes the gap. Pass the consumer's already-converted messages
224
+ * + the kgauto CompileResult and get back a `{ system, messages }` pair
225
+ * with cacheControl re-attached at the deterministic indices the compiler
226
+ * computed (`diagnostics.historyCacheMarkIndex` + `systemMessages` with
227
+ * its own cacheControl markers).
228
+ *
229
+ * No I/O. Pure transform. Idempotent — calling twice with the same inputs
230
+ * produces structurally-identical output.
92
231
  */
93
- declare function call(ir: PromptIR, opts?: CallOptions): Promise<CallResult>;
94
232
 
95
233
  /**
96
- * Brain client — fire-and-forget telemetry to the central kgauto Supabase.
234
+ * AI-SDK-shaped converted-message structure. Matches what
235
+ * `convertToModelMessages()` returns at the wire layer. We don't import
236
+ * the AI-SDK type to avoid pulling that dep into the kgauto-compiler
237
+ * package — consumers pass their own already-converted messages.
238
+ */
239
+ interface AISDKConvertedMessage {
240
+ role: 'system' | 'user' | 'assistant' | 'tool';
241
+ content: unknown;
242
+ providerOptions?: {
243
+ anthropic?: {
244
+ cacheControl?: {
245
+ type: 'ephemeral';
246
+ };
247
+ };
248
+ };
249
+ }
250
+ /**
251
+ * Result of `attachCacheControlToStreamTextInput()` — ready to spread into
252
+ * `streamText(...)` directly.
253
+ *
254
+ * The `system` field is either the structured `SystemModelMessage[]` form
255
+ * (when the compiler computed at least one cacheable section + chose
256
+ * Anthropic) or the flat-string concatenation (when no cacheable sections
257
+ * exist OR the provider isn't Anthropic). Consumers can pass either form
258
+ * to `streamText({ system })` — the AI-SDK accepts both.
259
+ */
260
+ interface AttachCacheControlResult {
261
+ system: string | SystemModelMessage[];
262
+ messages: AISDKConvertedMessage[];
263
+ }
264
+ /**
265
+ * Attach Anthropic cache_control markers to a streamText input that the
266
+ * consumer has already prepared via `convertToModelMessages()`. Reads
267
+ * `result.diagnostics.historyCacheMarkIndex` for the position-on-history
268
+ * marker and `result.systemMessages` for the per-section system markers.
269
+ *
270
+ * The flat-string `system` form is returned when:
271
+ * - the compiler produced no `systemMessages` (e.g., zero sections kept), or
272
+ * - the chosen provider is not Anthropic, so cacheControl wouldn't
273
+ * achieve anything at the wire layer (other providers cache implicitly
274
+ * based on prefix shape, no marker needed).
275
+ *
276
+ * Otherwise the structured `SystemModelMessage[]` form is returned —
277
+ * preserves the per-section cacheControl markers across `streamText`.
278
+ *
279
+ * @param result - kgauto CompileResult from `compile(ir, opts)`
280
+ * @param convertedMessages - the consumer's already-converted messages
281
+ * (from `convertToModelMessages(rawMessages)` in their AI-SDK call site)
282
+ * @returns `{ system, messages }` ready to spread into `streamText(...)`
283
+ */
284
+ declare function attachCacheControlToStreamTextInput(result: CompileResult, convertedMessages: AISDKConvertedMessage[]): AttachCacheControlResult;
285
+
286
+ /**
287
+ * alpha.52 — official AI-SDK-v6 compile adapter + compile-then-discard guard.
288
+ *
289
+ * Until now each AI-SDK consumer (tt-intel, IC) hand-rolled this adapter in
290
+ * its own `lib/kgauto-v2/index.ts`: `compile()` → reassemble the system param
291
+ * per provider → extract kept tool names per provider → re-derive the history
292
+ * cache-mark index (a copy of the compiler's own `historyCacheMarkIndex`
293
+ * logic — drift-prone). This centralizes that boilerplate and DRYs the two
294
+ * near-identical wrappers.
97
295
  *
98
- * The brain is the centralized learning store. Apps POST outcomes here;
99
- * mutations flow back through a separate pull (in v2.1).
296
+ * It also closes the compile-then-discard hole. The discard pattern is:
297
+ *
298
+ * const c = compileForAISDKv6(ir); // compile runs
299
+ * const out = await generateText({ // …but a hand-built prompt
300
+ * model: getModel(otherId), prompt }); // + a DIFFERENT model run
301
+ * await record({ handle: c.handle, … }); // brain row attributed to `c`
302
+ *
303
+ * The recorded row's `mutations_applied` / `estimated_tokens_in` /
304
+ * `system_prompt_chars` then describe a compile that never reached the wire.
305
+ * A library-level runtime guard could NOT catch this while the adapter lived
306
+ * in consumer code (the consumer wrapper always reads `compile()`'s result to
307
+ * build its own object, so any getter there is "consumed" every time,
308
+ * regardless of whether the final caller used the wrapper output). With the
309
+ * adapter IN the library, the object the FINAL caller reads is library-owned,
310
+ * so consume-tracking getters on `.system` / `.model` / `.raw` detect non-use
311
+ * and `record()` warns. See `interfaces/kgauto.md` (## Requested:
312
+ * `compiled-output-discarded-guard`).
313
+ *
314
+ * The guard is OPT-IN-BY-USE: only `compileForAISDKv6` arms tracking, so
315
+ * `call()` paths and raw `compile()` users never see a false warning.
316
+ */
317
+
318
+ interface CompileForAISDKv6Result {
319
+ /**
320
+ * Pass to `streamText`/`generateText({ model })` — the caller maps this id
321
+ * to an AI-SDK `LanguageModel`. Reading this marks the compile "consumed"
322
+ * (silences the compile-then-discard guard).
323
+ */
324
+ readonly model: string;
325
+ /**
326
+ * System parameter for `streamText`/`generateText({ system })`. Returns the
327
+ * structured `SystemModelMessage[]` form when the target is Anthropic AND a
328
+ * cacheable section exists (preserves the cache_control marker across the
329
+ * wire); a flat concatenated string otherwise. Reading this marks
330
+ * "consumed". (Same rule as `attachCacheControlToStreamTextInput`.)
331
+ */
332
+ readonly system: string | SystemModelMessage[];
333
+ /**
334
+ * The raw kgauto `CompileResult` — for `attachCacheControlToStreamTextInput(raw, msgs)`
335
+ * and `probeShadow(raw.ir-equivalent, …)` paths. Reading this marks
336
+ * "consumed" (it means you're using the compile output via the raw result).
337
+ */
338
+ readonly raw: CompileResult;
339
+ /** Tool names that survived budget + relevance — filter your SDK tool map to these. */
340
+ keptToolNames: Set<string>;
341
+ /** providerOptions for `streamText` — Anthropic cache_control on the cacheable prefix. Undefined otherwise. */
342
+ providerOptions?: {
343
+ anthropic?: {
344
+ cacheControl?: {
345
+ type: 'ephemeral';
346
+ };
347
+ };
348
+ };
349
+ /**
350
+ * Index (into post-strip history) for the Anthropic history cache marker
351
+ * (alpha.33). Mirror of `result.diagnostics.historyCacheMarkIndex` — no
352
+ * consumer re-derivation needed. Undefined when no marker fires, and (since
353
+ * alpha.55) always undefined for non-Anthropic targets: the marker is an
354
+ * Anthropic wire concept, other providers cache prefixes implicitly. The
355
+ * ungated value remains on `diagnostics.historyCacheMarkIndex`.
356
+ */
357
+ historyCacheMarkIndex?: number;
358
+ /** Compile handle — pass to `record()` after the call. */
359
+ handle: string;
360
+ /**
361
+ * Mutation ids the compiler fired (informational).
362
+ *
363
+ * ⚠️ alpha.78 — element type differs BY SURFACE: this adapter carries
364
+ * `string[]` (ids), while `CompileResult`/`CallResult.mutationsApplied`
365
+ * carry `MutationApplied[]` (objects with `description`, `rankDelta`, …).
366
+ * Coding to one surface's type while reading the other's runtime is a
367
+ * silent false negative (PB 2026-07-25). Use the shape-proof helpers
368
+ * `mutationId(m)` / `hasMutation(list, 'quality-gate-measured-*')` from
369
+ * the package root instead of `typeof` checks. Neither element type can
370
+ * change without breaking a live consumer (tt-intel joins these ids;
371
+ * object readers want `description`), so the divergence is documented
372
+ * rather than unified.
373
+ */
374
+ mutationsApplied: string[];
375
+ /** Best-practice advisories (alpha.6). Empty when none fired. */
376
+ advisories: BestPracticeAdvisory[];
377
+ /** Compiler diagnostics + the three commonly-logged top-level fields. */
378
+ diagnostics: CompileResult['diagnostics'] & {
379
+ targetProvider: string;
380
+ estimatedCostUsd: number;
381
+ fallbackChain: string[];
382
+ };
383
+ /** The compiled IR — pass to `probeShadow(ir, …)` in `onFinish` (alpha.48). */
384
+ ir: PromptIR;
385
+ }
386
+ /**
387
+ * Compile a `PromptIR` and lower it to an AI-SDK-v6 `streamText`/`generateText`
388
+ * bundle. Replaces the hand-rolled per-consumer adapter.
100
389
  *
101
- * Design: never blocks the caller. Failures are silent (logged via optional
102
- * onError hook). Uses fetch() works in Node 18+, Edge runtimes, and browsers.
390
+ * Arms the compile-then-discard guard: read `.system` / `.model` / `.raw` to
391
+ * serve the call. If you `record()` the handle without reading any of them,
392
+ * `record()` emits a dev-mode warning that the compile was discarded.
103
393
  */
394
+ declare function compileForAISDKv6(ir: PromptIR, opts?: CompileOptions): CompileForAISDKv6Result;
104
395
 
396
+ /**
397
+ * alpha.11 — opt-in nested config for brain-query mode (chains / archetype
398
+ * perf / pricing / models registry). Enabled by default when endpoint is
399
+ * set; per-table opt-out via explicit `false`.
400
+ *
401
+ * Locked via /plan-eng-review 2026-05-15 (decision D3). Structured group
402
+ * keeps the BrainConfig surface clean as more brain-driven tables ship.
403
+ */
404
+ interface BrainQueryConfig {
405
+ /** Default true when endpoint set. Brain-driven fallback chains. */
406
+ chains?: boolean;
407
+ /** Default true when endpoint set. Brain-driven archetype perf scores. */
408
+ perf?: boolean;
409
+ /** Default true when endpoint set. Brain-driven pricing with at-time resolution. */
410
+ pricing?: boolean;
411
+ /** Default true when endpoint set. Brain-driven model registry + aliases. */
412
+ models?: boolean;
413
+ /**
414
+ * alpha.38 — opt-in compile-time advisor for stale exclusions. Default
415
+ * `true` when endpoint is set. When enabled, the library reads
416
+ * `exclusion_findings` from the central kgauto-dashboard for the consumer's
417
+ * `app_id` (no consumer-side proxy work required) and surfaces a
418
+ * `stale-exclusion-candidate` advisory when compile()'s archetype has a
419
+ * recommend-probe finding open. Set `false` to silence (no fetch, no
420
+ * advisory).
421
+ */
422
+ findingsExclusions?: boolean;
423
+ /**
424
+ * alpha.64 — hard opt-out of the surface-promotions fetch layer (Stage 2).
425
+ * Default true; only matters when consent (`BrainConfig.autoPromote` /
426
+ * `KGAUTO_AUTO_PROMOTE`) is present — without consent the layer is off
427
+ * regardless. Set `false` to disable the fetch even while consented
428
+ * (debug/emergency lever).
429
+ */
430
+ promotions?: boolean;
431
+ /** SWR window in ms. Default 300_000 (5 min). */
432
+ cacheTtlMs?: number;
433
+ /** Override the GET URL when the read endpoint differs from the write one.
434
+ * Defaults to `${endpoint}/v2/config` when omitted. */
435
+ configEndpoint?: string;
436
+ /**
437
+ * alpha.38 — override the findings endpoint when the consumer wants to
438
+ * proxy `exclusion_findings` reads through their own service rather than
439
+ * reading directly from the kgauto-dashboard. Library appends `?app_id=X`.
440
+ * Defaults to `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions`.
441
+ */
442
+ findingsEndpoint?: string;
443
+ /**
444
+ * alpha.64 — override the surface-promotions endpoint (Stage 2). Only
445
+ * consulted when the consumer opted in via `BrainConfig.autoPromote` /
446
+ * `KGAUTO_AUTO_PROMOTE`. Library appends `?app_id=X`. Defaults to
447
+ * `https://kgauto-dashboard.vercel.app/api/kgauto-v2/promotions`.
448
+ */
449
+ promotionsEndpoint?: string;
450
+ /**
451
+ * alpha.70 — hard opt-out of the measured-failure gate fetch layer.
452
+ * Default true (the gate is opt-OUT, see `BrainConfig.measuredFailureGate`).
453
+ */
454
+ measuredFailure?: boolean;
455
+ /**
456
+ * alpha.70 — override the measured-failure endpoint. Library appends
457
+ * `?app_id=X`. Defaults to
458
+ * `https://kgauto-dashboard.vercel.app/api/kgauto-v2/measured-failure`.
459
+ */
460
+ measuredFailureEndpoint?: string;
461
+ }
105
462
  interface BrainConfig {
106
463
  /** Brain HTTP endpoint base URL (e.g., https://kgauto-brain.vercel.app/api). */
107
464
  endpoint: string;
465
+ /**
466
+ * alpha.73 — the consumer's app id, declared once so brain-driven levers can
467
+ * start their first read at configuration time instead of at the first
468
+ * compile.
469
+ *
470
+ * Optional and purely an optimisation: every IR already carries `appId`, and
471
+ * omitting this changes no verdict — it only means the measured-failure
472
+ * gate's warm-up starts when `call()` runs rather than when the module
473
+ * initialises. Declaring it lets a short-lived isolate spend its startup
474
+ * time on the fetch, so the bounded wait in `call()` usually costs nothing.
475
+ * Consumers running one app per process should set it.
476
+ */
477
+ appId?: string;
108
478
  /** Bearer token for auth. */
109
479
  apiKey?: string;
110
480
  /** Optional error hook for debugging. Defaults to console.warn. */
@@ -113,16 +483,163 @@ interface BrainConfig {
113
483
  sync?: boolean;
114
484
  /** Optional fetch override (for tests). */
115
485
  fetchImpl?: typeof fetch;
486
+ /** alpha.11 — brain-query mode for config tables. Default-on per table
487
+ * when endpoint is set; opt-out via `false`. See BrainQueryConfig. */
488
+ brainQuery?: BrainQueryConfig;
489
+ /**
490
+ * alpha.52 — emit a dev-mode `console.warn` when a `compileForAISDKv6()`
491
+ * result is passed to record() but its `.system` / `.model` / `.raw` were
492
+ * never read (the compile-then-discard pattern: the recorded brain row's
493
+ * `mutations_applied` / `estimated_tokens_in` / `system_prompt_chars`
494
+ * describe a compile that did NOT shape the served call). Default: warn
495
+ * when `NODE_ENV !== 'production'`, silent in production. Set `true` to
496
+ * force-on (e.g. a prod audit window) or `false` to silence. No-op for
497
+ * `call()` paths and raw `compile()` users — only `compileForAISDKv6`
498
+ * arms the tracking, so good actors never see a false warning.
499
+ */
500
+ warnOnDiscardedCompile?: boolean;
501
+ /**
502
+ * alpha.59 — per-leg timeout (ms) applied to every brain WRITE POST
503
+ * (record() primary + advisory secondary, recordOutcome(),
504
+ * recordShadowProbe()) via `AbortSignal.timeout`. Default 10000.
505
+ *
506
+ * Why: `sync: true` puts these fetches on the USER path (Edge consumers
507
+ * await record() before responding), and alpha.56's representation
508
+ * passthrough added a second sequential POST (advisory secondary) to that
509
+ * same path — an unbounded hang on either leg holds the user to the Edge
510
+ * limit (GE's `brainconfig-first-class-timeout` filing; GE bounded it at
511
+ * 3s via a hand-rolled fetchImpl wrapper every sync consumer had to
512
+ * rediscover).
513
+ *
514
+ * A fired timeout follows each leg's existing degraded-brain path
515
+ * (fire-and-forget: swallowed via onError; sync: `persistence_failed`
516
+ * result — never a throw into the user path). Wraps the configured
517
+ * `fetchImpl` rather than replacing it, so it composes with
518
+ * consumer-supplied impls. Set `0` to disable (pre-alpha.59 unbounded
519
+ * behavior). Brain-query reads (config tables) are cached + SWR and are
520
+ * not affected.
521
+ */
522
+ timeoutMs?: number;
523
+ /**
524
+ * alpha.64 (Stage 2 of the eval trust ladder) — consent switch for the
525
+ * surface-promotion routing effect. Default OFF.
526
+ *
527
+ * When true (or when the `KGAUTO_AUTO_PROMOTE` env var is '1'/'true' and
528
+ * this field is left undefined — env-as-consent, the KGAUTO_GOLDEN_CAPTURE
529
+ * precedent; an explicit `false` here overrides the env), compile()
530
+ * consults the brain's active `kgauto_promotions` rows for this app and
531
+ * boosts the promoted model at scoring time. Promotions are written only
532
+ * by the automated golden-eval trigger after a promote-ready verdict on a
533
+ * price-dominant (cheaper) candidate, and every promotion sits behind the
534
+ * 7-day rollback guard (daily watcher auto-reverts on regression vs the
535
+ * frozen baseline).
536
+ *
537
+ * Not opted in ⇒ promotions have ZERO routing effect (they remain visible
538
+ * as advisories + dashboard rows). Consumer sovereignty is preserved even
539
+ * when opted in: `forceModel`, `policy.blockedModels`, and cost ceilings
540
+ * always win, and a non-empty `policy.preferredModels` defers the
541
+ * promotion entirely.
542
+ */
543
+ autoPromote?: boolean;
544
+ /**
545
+ * alpha.70 — the measured-failure quality gate. **Default ON** wherever
546
+ * the brain is configured; set `false` (or `KGAUTO_MEASURED_FAILURE_GATE=0`)
547
+ * to disable. An explicit value here wins over the env var.
548
+ *
549
+ * Why this is opt-OUT while `autoPromote` is opt-IN: a promotion silently
550
+ * changes WHICH model serves you on kgauto's evidence, so it needs
551
+ * consent. This gate only ever DE-RANKS a model that the consumer's own
552
+ * outcome rows show failing them — the failures are already being paid
553
+ * for on their bill and their users' latency, and the model stays
554
+ * available as a graceful fallback. Requiring an opt-in to stop paying
555
+ * would be the wrong default.
556
+ *
557
+ * Consumer sovereignty is unchanged: `forceModel` still wins. Unlike a
558
+ * promotion, `policy.preferredModels` does NOT defer the gate — a
559
+ * preference says which model you would like to lead, not that a
560
+ * measurably-failing one works.
561
+ */
562
+ measuredFailureGate?: boolean;
116
563
  }
117
564
  declare function configureBrain(config: BrainConfig): void;
118
565
  declare function clearBrain(): void;
566
+ interface BrainHealthSnapshot {
567
+ configState: 'configured' | 'not_configured';
568
+ /** Host of the configured endpoint (never the full URL — no secrets/paths). */
569
+ endpointHost?: string;
570
+ /** True when writes are awaited (BrainConfig.sync). */
571
+ sync: boolean;
572
+ /** Write POSTs attempted (all routes, primary + secondary). */
573
+ sent: number;
574
+ /** Write POSTs acknowledged 2xx without redirect. */
575
+ acked: number;
576
+ /** Write POSTs that failed (non-2xx, redirect, timeout, network throw). */
577
+ failed: number;
578
+ /** Subset of `failed` that failed the redirect check (middleware-drift class). */
579
+ redirected: number;
580
+ lastAckAt?: string;
581
+ lastFailureAt?: string;
582
+ /** Most recent failure message, truncated. */
583
+ lastFailure?: string;
584
+ deadLetterCount: number;
585
+ }
586
+ interface BrainDeadLetterEntry {
587
+ /** Brain route segment the payload was bound for. */
588
+ route: 'outcomes' | 'compile_outcome_quality' | 'probe_outcomes' | 'compile_outcome_advisories' | 'golden_irs';
589
+ /**
590
+ * Endpoint the payload was originally bound for. Flush replays ONLY entries
591
+ * matching the currently-configured endpoint — a reconfigure must never
592
+ * replay another brain's payloads into the new target (caught live by
593
+ * smoke-brain-timeout: a hung-socket test payload auto-flushed into the
594
+ * real brain after the smoke re-pointed configureBrain).
595
+ */
596
+ endpoint: string;
597
+ /** The exact JSON body that failed to land. */
598
+ payload: unknown;
599
+ failedAt: string;
600
+ /** Delivery attempts so far (1 = the original failed POST). */
601
+ attempts: number;
602
+ lastError: string;
603
+ }
604
+ /**
605
+ * Process-local brain write delivery ledger. `acked` is the only number that
606
+ * means "a row landed" — fire-and-forget callers that need delivery evidence
607
+ * read this (or set `BrainConfig.sync`). Cheap enough to attach to any debug
608
+ * or health surface the consumer already exposes.
609
+ */
610
+ declare function brainHealth(): BrainHealthSnapshot;
611
+ /** Read-only view of the pending dead-letter (for consumer-side persistence). */
612
+ declare function peekBrainDeadLetter(): readonly BrainDeadLetterEntry[];
613
+ /**
614
+ * Replay pending dead-letter payloads against the configured brain. Delivered
615
+ * entries are removed; failures increment `attempts` and entries are dropped
616
+ * after 3 total attempts (bounded — never an infinite retry, per the Redis
617
+ * DLQ rule). Safe to call any time; no-ops when unconfigured or already
618
+ * flushing. Also runs opportunistically after any successful write.
619
+ */
620
+ declare function flushBrainDeadLetter(): Promise<{
621
+ attempted: number;
622
+ delivered: number;
623
+ remaining: number;
624
+ }>;
119
625
  /**
120
- * Record the outcome of a compiled call. Fire-and-forget by default.
626
+ * alpha.87 `KGAUTO_SOURCE` env default for the synthetic self-mark
627
+ * (migration 056). An explicit `source` on the input always wins; when
628
+ * absent, the env var marks every outcome row this PROCESS writes — the
629
+ * zero-code path for replay harnesses and smoke environments that share
630
+ * `call()`/`record()` with real traffic (PB s89's ask: their harness sets
631
+ * `KGAUTO_SOURCE=smoke` in the harness env and touches no call sites).
121
632
  *
122
- * Returns a Promise so callers in `sync` mode can await; in async mode the
123
- * promise resolves immediately (after the request is queued) and any
124
- * network error is swallowed/forwarded to onError.
633
+ * An unrecognized value maps to `'synthetic'` with a one-time warning
634
+ * rather than passing through: migration 056's CHECK constraint would
635
+ * reject the row server-side and the fire-and-forget write would swallow
636
+ * the rejection — silent data loss — while dropping the value entirely
637
+ * would mark declared-synthetic traffic as organic and poison liveness
638
+ * stats. `'synthetic'` keeps both the row and the discriminator honest.
125
639
  */
640
+ declare function resolveOutcomeSource(explicit?: string): OutcomeSource | undefined;
641
+ /** @internal — test hook: re-arm the one-time invalid-KGAUTO_SOURCE warning. */
642
+ declare function _testResetOutcomeSourceWarning(): void;
126
643
  declare function record(input: RecordInput): Promise<void>;
127
644
  /**
128
645
  * Wire shape POSTed by `record()` to the brain proxy's `/outcomes` endpoint.
@@ -156,6 +673,17 @@ interface OutcomePayload {
156
673
  latency_ms: number;
157
674
  success: boolean;
158
675
  empty_response: boolean;
676
+ /**
677
+ * alpha.86 (migration 056) — synthetic-writer self-mark. Key OMITTED for
678
+ * organic traffic (and against pre-056 brains). NULL in the table means
679
+ * organic; liveness rules compute over `source IS NULL` rows.
680
+ */
681
+ source?: string;
682
+ /**
683
+ * alpha.89 (migration 065) — per-end-user metering: the consumer's opaque
684
+ * customer id, truncated to 128 chars at write. NULL = no end user.
685
+ */
686
+ end_user_id?: string;
159
687
  error_type?: string;
160
688
  tools_called?: string[];
161
689
  oracle_score?: number;
@@ -169,8 +697,580 @@ interface OutcomePayload {
169
697
  cost_usd_actual?: number;
170
698
  ttft_ms?: number;
171
699
  history_cacheable_tokens?: number;
700
+ effort?: string;
172
701
  history_tokens_at_compile?: number;
702
+ /**
703
+ * Mirrors `ir.constraints.toolOrchestration` from compile time. NULL when
704
+ * the consumer hadn't adopted the constraint (pre-alpha.20). Powers
705
+ * per-mode model-perf queries on the brain (the L-040 parallel-tool
706
+ * cliff lumps DeepSeek sequential perf with parallel without this).
707
+ */
708
+ tool_orchestration?: 'parallel' | 'sequential' | 'either' | null;
709
+ finish_reason?: string;
710
+ total_ms?: number;
711
+ tools_count?: number;
712
+ history_depth?: number;
713
+ system_prompt_chars?: number;
714
+ fell_over_from?: string;
715
+ fallback_reason?: FallbackReason;
716
+ /**
717
+ * alpha.71 (migration 044) — the precise `errorCode` behind
718
+ * `fallback_reason`. Key OMITTED when no fallback fired, so brains that
719
+ * haven't applied 044 never see it.
720
+ */
721
+ fell_over_error_code?: string;
722
+ /**
723
+ * True when the same-model retry (CallOptions.sameModelRetry) fired
724
+ * during this call. Key OMITTED (not false) when no retry fired — safe
725
+ * against brains that haven't applied migration 039 yet.
726
+ */
727
+ retried_same_model?: boolean;
728
+ /**
729
+ * Per-call SectionRewrite[] captured at compile time. Omitted (sent as
730
+ * undefined → stored NULL) when no rewrites fired. Powers cross-app
731
+ * learning aggregates ("rule X fired N times on (app, model, archetype),
732
+ * downstream outcome quality lifted by M points").
733
+ */
734
+ section_rewrites_applied?: SectionRewrite[] | null;
735
+ /**
736
+ * R0 linkage (§5.0). Parent call's handle when this row is a fan-out branch;
737
+ * key OMITTED (undefined → dropped by JSON.stringify → stored NULL) for a
738
+ * root, safe against pre-042 brains.
739
+ */
740
+ parent_handle?: string;
741
+ /**
742
+ * R0 linkage (§5.0). Root handle of the fan-out trace (= parent_handle when a
743
+ * branch, else this row's own handle). Emitted for every registered compile.
744
+ */
745
+ trace_id?: string;
746
+ /**
747
+ * R0 linkage (§5.0). root | branch | composer. Emitted for every registered
748
+ * compile; surface baselines filter to root/NULL so branch traffic never
749
+ * contaminates a promotion/eval baseline. Release A emits only root/branch.
750
+ */
751
+ fanout_role?: 'root' | 'branch' | 'composer';
752
+ /**
753
+ * RD discipline gate-token accounting (§5.D). Measured token tax of the
754
+ * discipline_contract gate block; 0 when the gate didn't fire.
755
+ */
756
+ discipline_gate_tokens?: number;
757
+ }
758
+ /**
759
+ * alpha.20 Entry 4: record a quality outcome for a previously-compiled call.
760
+ *
761
+ * Fires after the consumer's UX surfaces an approve/reject event (e.g., user
762
+ * clicks Approve on a hunt result). Joins to the original `compile_outcomes`
763
+ * row via outcomeId — enables per-(model, archetype) approve-rate measurement
764
+ * once N ≥ 10 outcomes accumulate.
765
+ *
766
+ * Fire-and-forget by default (matches record() semantics). Set BrainConfig.sync
767
+ * = true for runtime contexts that can't tolerate fire-and-forget teardown
768
+ * (Vercel Edge, Cloudflare Workers, AWS Lambda) — see L-086.
769
+ *
770
+ * Returns (alpha.61): `{ok: true}` only when the POST was acknowledged 2xx
771
+ * (sync mode); `{ok: 'queued'}` in fire-and-forget mode (handed to the
772
+ * runtime, NOT acked — read `brainHealth()` for delivery evidence);
773
+ * `{ok: false, reason}` on known failure. Never throws.
774
+ */
775
+ declare function recordOutcome(input: RecordOutcomeInput): Promise<OutcomeResult>;
776
+ /**
777
+ * True when the active brain config requests synchronous (awaited) writes.
778
+ * call()'s shadow-probe path reads this to decide whether to await the probe
779
+ * (Edge/Worker/Lambda — L-086) or fire-and-forget (Node). False when no brain
780
+ * is configured.
781
+ */
782
+ declare function isBrainSync(): boolean;
783
+ /**
784
+ * Full-IR inline shadow-probe record input (Shape B, Phase 1 — s51). Carries
785
+ * ONLY response previews + metadata; the prompt (system/context/payload) is
786
+ * never included — `promptHash` is an irreversible grouping key, not content.
787
+ */
788
+ interface ShadowProbeRecordInput {
789
+ appId: string;
790
+ archetype: string;
791
+ family: string;
792
+ candidateModel: string;
793
+ currentModel: string;
794
+ /** Irreversible grouping hash (NOT the prompt). */
795
+ promptHash: string;
796
+ /** Served model's response, truncated (RESPONSE text only — never the prompt). */
797
+ currentResponsePreview?: string;
798
+ /** Candidate model's response, truncated. */
799
+ candidateResponsePreview?: string;
800
+ tokensCurrentIn?: number;
801
+ tokensCurrentOut?: number;
802
+ tokensCandidateIn?: number;
803
+ tokensCandidateOut?: number;
804
+ /**
805
+ * Wall-clock latency of the served call, ms (alpha.46). The third swap-decision
806
+ * axis alongside quality + cost — a verdict needs to know the candidate is
807
+ * slower, not just better/cheaper. Served latency mirrors
808
+ * `compile_outcomes.latency_ms`; carried here so a probe row is self-contained.
809
+ */
810
+ latencyCurrentMs?: number;
811
+ /** Wall-clock latency of the candidate replay call, ms (alpha.46). */
812
+ latencyCandidateMs?: number;
813
+ /**
814
+ * alpha — probe-row class (migration 029; `candidate_error` added by 032).
815
+ * Defaults to `'completed'` (the pre-029 row shape: candidate ran, columns
816
+ * populated). `'aborted_latency_budget'` and `'skipped_slow_tier_sync'` are
817
+ * DIAGNOSTIC rows from sync-mode latency protection; `'candidate_error'`
818
+ * (alpha.53) is the failed-candidate diagnostic — the candidate call
819
+ * errored, with the error class + latency-at-death recorded instead of
820
+ * silence (the IC demo-night probe deaths were invisible for ~90 min under
821
+ * the old record-no-row rule). Diagnostic rows carry no candidate response
822
+ * and no verdict — no false quality signal. A verdict rollup MUST filter to
823
+ * `outcome='completed'`.
824
+ */
825
+ outcome?: 'completed' | 'aborted_latency_budget' | 'skipped_slow_tier_sync' | 'candidate_error';
826
+ /**
827
+ * alpha.53 (migration 032) — error class for `outcome='candidate_error'`
828
+ * rows. Values follow execute()'s taxonomy (`rate_limit`, `timeout`,
829
+ * `server_error`, `model_not_found`, `auth`, `invalid_request`, `unknown`)
830
+ * plus `execute_rejected` (the execute promise rejected outright). NULL /
831
+ * omitted on all other row classes.
832
+ */
833
+ errorClass?: string;
834
+ }
835
+ /**
836
+ * Pure builder for the `probe_outcomes` row written by the inline shadow-probe.
837
+ * Exported so a test can assert the G3 privacy invariant: the row carries NO
838
+ * prompt/system/context text — only response previews + metadata + a hash.
839
+ *
840
+ * Phase 1 (judge: 'off'): `judge_verdict` / `judge_score` are null — the row
841
+ * is an unjudged sample for the Phase-2 offline batch judge. `prompt_fidelity`
842
+ * is 1.0 by construction (the candidate ran the full IR, not a truncated
843
+ * preview), and `replay_source='inline-full-ir'` marks it as a trustworthy row
844
+ * (vs the watchers' lossy `replay-preview`).
845
+ */
846
+ declare function buildShadowProbeRow(input: ShadowProbeRecordInput): {
847
+ app_id: string;
848
+ intent_archetype: string;
849
+ family: string;
850
+ candidate_model: string;
851
+ current_model: string;
852
+ prompt_hash: string;
853
+ current_response: string | null;
854
+ candidate_response: string | null;
855
+ judge_verdict: null;
856
+ judge_score: null;
857
+ tokens_current_in: number | null;
858
+ tokens_current_out: number | null;
859
+ tokens_candidate_in: number | null;
860
+ tokens_candidate_out: number | null;
861
+ latency_current_ms: number | null;
862
+ latency_candidate_ms: number | null;
863
+ prompt_fidelity: number;
864
+ replay_source: 'inline-full-ir';
865
+ outcome: 'completed' | 'aborted_latency_budget' | 'skipped_slow_tier_sync' | 'candidate_error';
866
+ error_class: string | null;
867
+ };
868
+ /**
869
+ * Persist one inline shadow-probe row to `probe_outcomes`. Fire-and-forget by
870
+ * default; honors `BrainConfig.sync` (L-086). Never throws — failures route to
871
+ * onError. Mirrors record()'s POST shape; consumer proxies forward
872
+ * `/probe_outcomes` the same way they forward `/outcomes`.
873
+ */
874
+ declare function recordShadowProbe(input: ShadowProbeRecordInput): Promise<void>;
875
+ /**
876
+ * Golden-IR capture input. UNLIKE every other brain write, this row carries the
877
+ * RAW full PromptIR — an explicit, documented posture change from the s51
878
+ * "brain holds no raw consumer prompts" rule, gated on consumer opt-in
879
+ * (`KGAUTO_GOLDEN_CAPTURE` env / `CallOptions.goldenCapture`). The `consent`
880
+ * field records the provenance of that opt-in at capture time.
881
+ */
882
+ interface GoldenIrRecordInput {
883
+ appId: string;
884
+ archetype: string;
885
+ /** hashShape() of the call at compile time (peek before record() pops). */
886
+ shapeKey?: string;
887
+ /** The full PromptIR, verbatim. Plain JSON by construction (ir.ts). */
888
+ ir: unknown;
889
+ incumbentModel: string;
890
+ incumbentOutput?: string;
891
+ incumbentLatencyMs?: number;
892
+ incumbentTokensIn?: number;
893
+ incumbentTokensOut?: number;
894
+ /** 'sampled' (capture flag fired on live traffic) | 'curated' (operator). */
895
+ source: 'sampled' | 'curated';
896
+ /** Consent provenance, e.g. 'KGAUTO_GOLDEN_CAPTURE=0.1 (consumer env opt-in)'. */
897
+ consent: string;
898
+ /** Optional link back to the compile handle of the captured call. */
899
+ outcomeHandle?: string;
900
+ }
901
+ /** Pure builder for the `kgauto_golden_irs` row (snake_case wire shape). */
902
+ declare function buildGoldenIrRow(input: GoldenIrRecordInput): {
903
+ app_id: string;
904
+ intent_archetype: string;
905
+ shape_key: string | null;
906
+ ir: unknown;
907
+ incumbent_model: string;
908
+ incumbent_output: string | null;
909
+ incumbent_latency_ms: number | null;
910
+ incumbent_tokens_in: number | null;
911
+ incumbent_tokens_out: number | null;
912
+ source: 'sampled' | 'curated';
913
+ consent: string;
914
+ outcome_handle: string | null;
915
+ };
916
+ /**
917
+ * Persist one golden IR to `kgauto_golden_irs`. Same G1 write-leg discipline as
918
+ * every other brain route (redirect check, ledger, dead-letter); fire-and-forget
919
+ * by default, honors `BrainConfig.sync`. Never throws.
920
+ */
921
+ declare function recordGoldenIr(input: GoldenIrRecordInput): Promise<void>;
922
+
923
+ /**
924
+ * Golden-set eval engine (alpha.62, eval spine — design brief 2026-07-17).
925
+ *
926
+ * Implements the quality-floor-guarded model-swap contract:
927
+ *
928
+ * > A model replaces another on a surface only by demonstrating
929
+ * > same-or-better quality on that surface's real workload — never by
930
+ * > price, recency, or judgment alone.
931
+ *
932
+ * One eval run: load the active golden set for (app, archetype), replay every
933
+ * IR on BOTH the incumbent and the candidate (fresh outputs on both sides —
934
+ * fair comparison, no stale stored output), apply mechanical hard floors,
935
+ * then a pairwise LLM judge (order-swapped to cancel position bias), and
936
+ * aggregate under the non-inferiority rule:
937
+ *
938
+ * promote-ready ⇔ wins-or-ties ≥ threshold (default 80%)
939
+ * AND zero hard-floor violations
940
+ * AND candidate p50 latency ≤ ratio × incumbent p50
941
+ *
942
+ * Evidence lands as brain rows: one `kgauto_golden_eval_runs` aggregate + one
943
+ * `probe_outcomes` row per case (`replay_source='golden-replay'`, full
944
+ * fidelity by construction) + an evidence-attached advisory on the consumer's
945
+ * advisory surface (trust-ladder Stage 1: eval runs, human clicks promote).
946
+ *
947
+ * Judging is PAIRWISE, not absolute — it operationalizes the quality-floor
948
+ * Common Pattern directly ("same or better, never less"). Each pair is judged
949
+ * twice with A/B order swapped; disagreement between the two orders is scored
950
+ * a tie (the honest reading of positional noise).
951
+ *
952
+ * This module is operator-grade: it talks to the brain via direct PostgREST
953
+ * with a service key (the watchers' convention), never through consumer
954
+ * proxies, and it deliberately does NOT call record() — eval traffic must not
955
+ * pollute compile_outcomes.
956
+ */
957
+
958
+ /**
959
+ * Default judge model (judge chain tier 0). Exported so operator scripts
960
+ * (golden-eval-trigger's judge pre-flight) probe the SAME model the engine
961
+ * will call — two inline literals of one concept is the s75 drift shape.
962
+ * 2026-08-25: the judge had no pre-flight at all, so an Anthropic billing
963
+ * outage would have burned incumbent+candidate replay spend on non-Anthropic
964
+ * surfaces before dying verdictless at judge time.
965
+ *
966
+ * 2026-08-25 (same session): moved 'claude-opus-4-8' → 'claude-opus-5'. The
967
+ * guard test caught the old default sitting on a status:'legacy' roster
968
+ * entry (4-8 went legacy 2026-07-25 with the Opus 5 generation; nobody moved
969
+ * the judge). Verdict comparability across the switch is preserved by
970
+ * `judge_model` on every run + case row (migrations 024/036).
971
+ */
972
+ declare const DEFAULT_JUDGE_MODEL = "claude-opus-5";
973
+ /**
974
+ * What "better" means per archetype. Fed verbatim into the pairwise judge
975
+ * prompt. Kept deliberately short — the judge sees the full request, so the
976
+ * rubric only needs to name the failure modes that matter for the archetype.
977
+ */
978
+ declare const JUDGE_RUBRICS: Record<string, string>;
979
+ declare function rubricFor(archetype: string): string;
980
+ /** Render the golden IR's request for the judge (system sections + user turn). */
981
+ declare function renderIrForJudge(ir: PromptIR): string;
982
+ declare function buildPairwiseJudgePrompt(args: {
983
+ archetype: string;
984
+ renderedInput: string;
985
+ outputA: string;
986
+ outputB: string;
987
+ }): string;
988
+ type PairwiseWinner = 'A' | 'B' | 'tie';
989
+ /** Parse the judge's JSON verdict. Returns undefined when unparseable. */
990
+ declare function parseJudgeVerdict(raw: string): {
991
+ winner: PairwiseWinner;
992
+ rationale?: string;
993
+ } | undefined;
994
+ /**
995
+ * Combine the two order-swapped verdicts into a case verdict. Both verdicts
996
+ * are expressed in incumbent/candidate terms BEFORE this call (the caller
997
+ * un-swaps run 2). Agreement → that verdict; disagreement → 'tied' (positional
998
+ * noise reads as a tie, never as a win).
999
+ */
1000
+ declare function combineOrderSwappedVerdicts(run1: 'candidate-better' | 'current-better' | 'tied', run2: 'candidate-better' | 'current-better' | 'tied'): 'candidate-better' | 'current-better' | 'tied';
1001
+ /**
1002
+ * Release B — the eval's comparison primitive is arm-agnostic: a MODEL
1003
+ * comparison varies `model` and holds `ir`; a STRATEGY comparison varies
1004
+ * `ir` and holds `model`. Same replay, same judge, same order-swap, same
1005
+ * floors.
1006
+ */
1007
+ type GoldenEvalAxis = 'model' | 'strategy';
1008
+ /** Strategies the eval can measure. Closed set — a strategy is only
1009
+ * measurable against its exact frozen bytes. The `-alt` wording is
1010
+ * EVAL-ONLY: it exists to attribute a v1 loss to wording vs mechanism
1011
+ * (§6) and never ships in a production compile. */
1012
+ type GoldenEvalStrategyId = 'discipline-gates-v1' | 'discipline-gates-v1-alt' | 'discipline-gates-v1-alt-blind';
1013
+ /** Both re-wordings of v1. Dispatch keys on this, never on a string prefix,
1014
+ * so adding a fourth arm is one edit rather than a grep. */
1015
+ declare const ALT_STRATEGY_IDS: readonly GoldenEvalStrategyId[];
1016
+ declare function isAltStrategy(id: GoldenEvalStrategyId | undefined): boolean;
1017
+ interface GoldenEvalOptions {
1018
+ appId: string;
1019
+ archetype: string;
1020
+ /**
1021
+ * Release B — comparison axis. Default 'model' (alpha.62 behavior,
1022
+ * unchanged). On 'strategy': arm A = the golden IR as stored (gates-off),
1023
+ * arm B = the same IR with a `discipline_contract` section appended
1024
+ * (gates-on), both replayed on ONE model (`strategyModel` or the resolved
1025
+ * incumbent). `candidateModel` is ignored on the strategy axis;
1026
+ * `strategy` is required.
1027
+ */
1028
+ axis?: GoldenEvalAxis;
1029
+ /** Required when axis==='strategy': the strategy under measurement. */
1030
+ strategy?: GoldenEvalStrategyId;
1031
+ /**
1032
+ * axis==='strategy' only: the model both arms run on. Default: the
1033
+ * resolved incumbent (most-captured model in the golden set).
1034
+ */
1035
+ strategyModel?: string;
1036
+ /** Required when axis is 'model' (the default). */
1037
+ candidateModel?: string;
1038
+ /**
1039
+ * Incumbent to compare against. Default: the most frequent incumbent_model
1040
+ * across the loaded golden set (the surface's de-facto leader).
1041
+ */
1042
+ incumbentModel?: string;
1043
+ /** Judge model id. Default `DEFAULT_JUDGE_MODEL` (judge chain tier 0). */
1044
+ judgeModel?: string;
1045
+ /** Max golden cases to load (newest first). Default 50. */
1046
+ limit?: number;
1047
+ /** Non-inferiority threshold on wins-or-ties. Default 0.8. */
1048
+ winOrTieThreshold?: number;
1049
+ /** Latency hard floor: candidate p50 ≤ ratio × incumbent p50. Default 3. */
1050
+ latencyFloorRatio?: number;
1051
+ /** Minimum judged cases for a non-inconclusive verdict. Default 5. */
1052
+ minJudgeableCases?: number;
1053
+ /** What fired the eval. Default 'manual' (Stage 1). */
1054
+ triggerSource?: 'manual' | 'supply' | 'price' | 'demand';
1055
+ /** Brain access — direct PostgREST (operator convention). */
1056
+ supabaseUrl: string;
1057
+ serviceKey: string;
1058
+ /** Provider keys for the replay + judge calls. Default: process.env. */
1059
+ apiKeys?: ApiKeys;
1060
+ fetchImpl?: typeof fetch;
1061
+ /** Replay + judge but write NOTHING to the brain. */
1062
+ dryRun?: boolean;
1063
+ onProgress?: (message: string) => void;
1064
+ }
1065
+ interface GoldenEvalCase {
1066
+ goldenIrId: number;
1067
+ verdict: 'candidate-better' | 'tied' | 'current-better' | 'inconclusive';
1068
+ /**
1069
+ * Release B — the RAW order-swapped pair, in incumbent/candidate terms,
1070
+ * BEFORE `combineOrderSwappedVerdicts` folds disagreement into 'tied'.
1071
+ * The fold is public API and unchanged; this records what it discards,
1072
+ * because positional DISAGREEMENT RATE is an objective reliability metric
1073
+ * needing no ground truth (§4.0 — the strategy experiment's primary
1074
+ * metric is positional consistency, not judge quality).
1075
+ */
1076
+ orderVerdicts?: {
1077
+ run1: 'candidate-better' | 'current-better' | 'tied';
1078
+ run2: 'candidate-better' | 'current-better' | 'tied';
1079
+ };
1080
+ judgeRationale?: string;
1081
+ /** Hard-floor violations on the candidate side for this case. */
1082
+ floorViolations: Array<'empty' | 'schema' | 'candidate_error'>;
1083
+ errorClass?: string;
1084
+ incumbent?: {
1085
+ latencyMs: number;
1086
+ tokensIn: number;
1087
+ tokensOut: number;
1088
+ text: string;
1089
+ };
1090
+ candidate?: {
1091
+ latencyMs: number;
1092
+ tokensIn: number;
1093
+ tokensOut: number;
1094
+ text: string;
1095
+ };
1096
+ /** Case excluded from the denominator (incumbent replay/judge failed). */
1097
+ excludedReason?: string;
1098
+ }
1099
+ interface GoldenEvalRunResult {
1100
+ verdict: 'promote-ready' | 'not-inferior' | 'inconclusive';
1101
+ runId?: number;
1102
+ /**
1103
+ * Release B — which axis produced this verdict. Load-bearing, not
1104
+ * cosmetic: a results table that can't tell you which axis produced a
1105
+ * verdict is a false-attribution engine. On 'strategy',
1106
+ * incumbentModel === candidateModel (the model held constant) and
1107
+ * `strategy` names the arm-B mutation.
1108
+ */
1109
+ axis: GoldenEvalAxis;
1110
+ strategy?: GoldenEvalStrategyId;
1111
+ appId: string;
1112
+ archetype: string;
1113
+ incumbentModel: string;
1114
+ candidateModel: string;
1115
+ judgeModel: string;
1116
+ nCases: number;
1117
+ wins: number;
1118
+ ties: number;
1119
+ losses: number;
1120
+ floorViolations: number;
1121
+ floorDetail: Record<string, number>;
1122
+ winOrTieRatio: number | null;
1123
+ latencyRatio: number | null;
1124
+ costIncumbentUsd: number | null;
1125
+ costCandidateUsd: number | null;
1126
+ advisoryOutcomeId?: number;
1127
+ cases: GoldenEvalCase[];
1128
+ notes: string[];
1129
+ }
1130
+ declare function withDisciplineContract(ir: PromptIR): PromptIR;
1131
+ declare const DISCIPLINE_GATES_V1_ALT_HEADER = "Before stating any conclusion, run this check:";
1132
+ declare function altGatesBlockFor(args: {
1133
+ outputMode: 'text' | 'json' | 'tool_call';
1134
+ hasTools: boolean;
1135
+ }): string;
1136
+ declare const ALT_BLIND_TOKEN_BUDGET_BREACH: {
1137
+ readonly ceilingTokens: 264;
1138
+ readonly measuredTokensTextWithTools: 285;
1139
+ readonly note: string;
1140
+ };
1141
+ declare const DISCIPLINE_GATES_V1_ALT_BLIND_HEADER = "Before stating any conclusion, run this check:";
1142
+ /**
1143
+ * The variant matrix — and this is the ONE place this seat's judgment enters
1144
+ * the blind arm, so it is stated rather than buried.
1145
+ *
1146
+ * cc's instruction: adapt MECHANICALLY where the injection format demands it,
1147
+ * note the diff, never edit semantics. Choosing which gates to drop per
1148
+ * surface is a selection, not an edit — the bytes of every retained gate are
1149
+ * untouched — but the selection is still mine, so:
1150
+ *
1151
+ * NO TOOLS drops `toolPredict`. Forced, not chosen: the string opens
1152
+ * "When using tools" and is literally inapplicable without them.
1153
+ * Mirrors v1 dropping its compressed-item bullet.
1154
+ * STRUCTURED drops `markAssumed` ONLY. It is the sole gate whose entire
1155
+ * function is text in the final answer ('mark anything unchecked
1156
+ * as "assumed"'), which a JSON/tool_call schema has no field for
1157
+ * and which would corrupt the parse.
1158
+ *
1159
+ * The judgment call worth flagging: v1 drops TWO bullets on structured
1160
+ * surfaces, and a stricter reading would also drop `falsify` ("state in one
1161
+ * line") and `deviation` ("say so explicitly"), since both demand output
1162
+ * text. I kept them. Their output demand is incidental (and conditional, for
1163
+ * `deviation`) while their primary effect is on reasoning before the answer
1164
+ * exists — whereas v1's dropped pair (`label`, `gap`) are purely
1165
+ * output-shaping. Dropping three of five would leave a two-gate arm that no
1166
+ * longer tests the same mechanism, and an arm crippled by my formatting
1167
+ * choice would read as a wording loss that was actually a scoping loss.
1168
+ * If the structured surface shows anomalous results, this is the first
1169
+ * thing to re-examine.
1170
+ */
1171
+ declare function altBlindGatesBlockFor(args: {
1172
+ outputMode: 'text' | 'json' | 'tool_call';
1173
+ hasTools: boolean;
1174
+ }): string;
1175
+ /**
1176
+ * The alt arm injects its block DIRECTLY as an untagged section — it must
1177
+ * not carry `kind: 'discipline_contract'`, or the translator would prepend
1178
+ * the v1 bytes on top and the arm would measure both wordings at once. The
1179
+ * variant choice mirrors matchRule()'s exactly (same outputMode + hasTools
1180
+ * inputs), so the alt arm no-ops nowhere v1 fires and fires nowhere v1
1181
+ * no-ops — the attribution is about WORDING, and everything else is held.
1182
+ */
1183
+ declare function withAltDisciplineContract(ir: PromptIR): PromptIR;
1184
+ /**
1185
+ * Same injection contract as `withAltDisciplineContract` — untagged section,
1186
+ * so the translator never prepends the v1 bytes on top and the arm measures
1187
+ * exactly one wording. Same variant inputs, so the blind arm no-ops nowhere
1188
+ * v1 fires and fires nowhere v1 no-ops; the comparison is about WORDING and
1189
+ * everything else is held.
1190
+ */
1191
+ declare function withAltBlindDisciplineContract(ir: PromptIR): PromptIR;
1192
+ declare function runGoldenEval(opts: GoldenEvalOptions): Promise<GoldenEvalRunResult>;
1193
+ /**
1194
+ * Aggregate outcome of one strategy run, in gates-on terms. 'loses' is the
1195
+ * only branch that costs a third replay — and the only one where wording
1196
+ * attribution matters.
1197
+ */
1198
+ type StrategyOutcome = 'wins' | 'ties' | 'loses' | 'inconclusive';
1199
+ declare function classifyStrategyOutcome(r: GoldenEvalRunResult): StrategyOutcome;
1200
+ /**
1201
+ * The §6 attribution matrix. The load-bearing distinction: a WORDING failure
1202
+ * recorded as a mechanism failure would let Factor B permanently disable a
1203
+ * real capability on evidence about one author's prose.
1204
+ *
1205
+ * THREE arms since 2026-07-29. Both re-wordings run on a v1 loss, and a win
1206
+ * by EITHER is enough to acquit the mechanism — the question "does some
1207
+ * wording of this work?" is answered by one existence proof, so there is no
1208
+ * reason to require agreement between the alts.
1209
+ *
1210
+ * v1 vs off | alt / alt-blind vs off | attribution
1211
+ * ----------+------------------------+------------------------------------
1212
+ * wins | (not run) | mechanism-works — ship
1213
+ * ties | (not run) | no-lift — inconclusive at n, re-eval
1214
+ * loses | either wins | wording-failure — do NOT disable
1215
+ * loses | BOTH lose | mechanism-failure — Factor B may disable
1216
+ * loses | neither wins, not both lose | wording-inconclusive — no disable
1217
+ *
1218
+ * The `mechanism-failure` cell is the one that changed character. It used to
1219
+ * rest on two wordings by one author, so a shared blind spot (the principles
1220
+ * being the wrong principles) was invisible and the verdict was hedged. The
1221
+ * blind arm was authored by a context-free subagent with no knowledge of this
1222
+ * repo, the experiment, or who was asking — so a both-lose verdict now spans
1223
+ * independent authorship and is strong on its own terms. That is exactly the
1224
+ * gap `STRATEGY_AUTHORSHIP_LIMITATION` was written to confess, which is why
1225
+ * the limitation text is now conditional on whether the blind arm ran.
1226
+ */
1227
+ type StrategyAttribution = 'mechanism-works' | 'no-lift' | 'wording-failure' | 'mechanism-failure' | 'wording-inconclusive' | 'inconclusive';
1228
+ interface StrategyAttributionResult {
1229
+ attribution: StrategyAttribution;
1230
+ primary: GoldenEvalRunResult;
1231
+ /** Present ONLY when the primary lost (the loss-triggered arms). */
1232
+ alt?: GoldenEvalRunResult;
1233
+ /** The independently-authored arm. Present ONLY when the primary lost. */
1234
+ altBlind?: GoldenEvalRunResult;
1235
+ /** The authorship limitation, restated on every result so no downstream
1236
+ * reader can cite an attribution without it. Which string this carries
1237
+ * depends on whether the blind arm actually ran — see below. */
1238
+ limitation: string;
173
1239
  }
1240
+ /**
1241
+ * Carried when the blind arm did NOT run — i.e. v1 won or tied, so no
1242
+ * re-wording was measured at all and any claim about wording is unevidenced.
1243
+ */
1244
+ declare const STRATEGY_AUTHORSHIP_LIMITATION: string;
1245
+ /**
1246
+ * Carried when both re-wording arms ran. The shared-author caveat is GONE by
1247
+ * construction, and saying so is the point: the previous version of this
1248
+ * string confessed a gap that has since been closed, and a stale confession
1249
+ * is its own kind of false statement — a reader would discount a verdict
1250
+ * that no longer deserves discounting.
1251
+ */
1252
+ declare const STRATEGY_AUTHORSHIP_INDEPENDENT: string;
1253
+ /**
1254
+ * Run the strategy eval with loss-triggered wording attribution: v1 first;
1255
+ * the alt arm replays ONLY on a v1 loss (mirrors the engine's retry
1256
+ * posture — don't pay for extra evidence until a result demands it).
1257
+ */
1258
+ declare function runStrategyEvalWithAttribution(opts: Omit<GoldenEvalOptions, 'axis' | 'strategy' | 'candidateModel'>): Promise<StrategyAttributionResult>;
1259
+
1260
+ /**
1261
+ * alpha.60 — the library's own version, baked as a constant so Edge/Worker
1262
+ * runtimes (no fs, no require) can report it on wire surfaces. First
1263
+ * consumer: `createKeyHealthRoute` carries it as `library_version`, which is
1264
+ * how the operator dashboard's Fleet panel sees per-consumer vendor drift
1265
+ * LIVE instead of via wrap-time package.json probes (the L-093 family
1266
+ * "declared state lags actual" fix at the vendor-version axis — s47 found
1267
+ * IC 13 alphas stale that way).
1268
+ *
1269
+ * Kept in sync with package.json by hand at each version bump; the drift
1270
+ * guard in `tests/version.test.ts` fails the suite (and therefore
1271
+ * `prepublishOnly`) when they diverge — a stale constant cannot reach npm.
1272
+ */
1273
+ declare const LIBRARY_VERSION = "2.0.0-alpha.91";
174
1274
 
175
1275
  /**
176
1276
  * Oracle contract — how an app tells the brain whether a response was good.
@@ -223,6 +1323,34 @@ interface LLMJudgeOptions {
223
1323
  */
224
1324
  declare function buildLLMJudge(opts: LLMJudgeOptions): AppOracle;
225
1325
 
1326
+ /**
1327
+ * Resolve the effective ArchetypeConvention[] for a given selected profile,
1328
+ * walking family inheritance once. Model-specific entries on the selected
1329
+ * profile take precedence over family-level entries for the same archetype.
1330
+ *
1331
+ * Pure; safe to call from any context (probe-watcher uses the same logic
1332
+ * via `applyArchetypeConvention`).
1333
+ */
1334
+ declare function resolveConventionsForProfile(profile: ModelProfile): ArchetypeConvention[];
1335
+ /**
1336
+ * Pure helper: apply the matching ArchetypeConvention's suffix (and
1337
+ * prefix, when meaningful) to a plain prompt-text string. Used by the
1338
+ * exclusion-probe-watcher (`probeOne`) so probe calls carry the same
1339
+ * forcing-function shape consumers see at compile time. Without this,
1340
+ * every reasoner probe on a decisive archetype gets unfairly stay-excluded
1341
+ * for hedging — as ID 20 demonstrated on 2026-05-28.
1342
+ *
1343
+ * Resolution: looks up the family-rep profile for `family` and reads its
1344
+ * `archetypeConventions`. Returns the original text unchanged when no
1345
+ * convention matches or when the suffix is already present.
1346
+ *
1347
+ * @param promptText raw user-prompt text (or prompt_preview from outcome)
1348
+ * @param archetype intent_archetype from the finding row
1349
+ * @param family family tag from deriveFamilyFromModelId / brain row
1350
+ * @returns text with prefix/suffix applied (idempotent)
1351
+ */
1352
+ declare function applyArchetypeConvention(promptText: string, archetype: string, family: string): string;
1353
+
226
1354
  /**
227
1355
  * Tokenizer abstraction.
228
1356
  *
@@ -247,120 +1375,2675 @@ declare function resetTokenizer(): void;
247
1375
  declare function countTokens(text: string): number;
248
1376
 
249
1377
  /**
250
- * Best-practice advisor alpha.6 Phase 1.
1378
+ * delegateRelease D, the R2 primitive (delegation-fanout accelerator §5.2,
1379
+ * design contract advisory/kgauto/2026-07-24_delegation-fanout-accelerator-design.md).
251
1380
  *
252
- * Inspects an IR + the selected profile + compile diagnostics and emits a
253
- * list of `BestPracticeAdvisory` entries describing detected gaps. Runs
254
- * after `lower()` in the compile pipeline; the result lands on
255
- * `CompileResult.advisories` for the consumer to log, surface, or filter.
1381
+ * A consumer-mountable TOOL the orchestrating model calls mid-loop:
1382
+ * `{ sub_archetype, input, quality_floor? }`. kgauto selects the executor
1383
+ * from evidence, runs the sub-call through the compiler + call(), returns
1384
+ * the result into the loop, links parent↔child rows (R0), and enforces
1385
+ * `policy.maxCostPerTraceUsd` against the running trace spend — the field
1386
+ * that shipped INERT in Release A precisely so this release could turn it on.
256
1387
  *
257
- * Driven by interfaces/kgauto.md `best-practice-advisories` (IC, 2026-05-07).
258
- * Phase 1 ships 4 starter rules sourced from the s14 kgauto comment +
259
- * s15 empirical seed of brain anti-patterns:
1388
+ * THE AUTHORITY SPLIT IS THE CONTAINMENT (§3):
1389
+ * - the MODEL decides whether and what to delegate (kgauto never
1390
+ * decomposes uninvited §10);
1391
+ * - KGAUTO decides only who runs it — and never selects a model absent
1392
+ * from the consumer's declared `ir.models`;
1393
+ * - the CONSUMER consents: default OFF, `KGAUTO_AUTO_PROMOTE` posture
1394
+ * (explicit option beats `KGAUTO_DELEGATE` env; neither ⇒ the handler
1395
+ * refuses observably, never silently).
260
1396
  *
261
- * 1. `caching-off-on-claude` system >2000 chars on Anthropic, no cacheable=true
262
- * 2. `single-chunk-system` Anthropic, only one PromptSection >1000 chars
263
- * 3. `tool-bloat` >10 tools on a short-output archetype
264
- * 4. `history-uncached-on-claude` Anthropic, ≥2 history messages, no historyCachePolicy
1397
+ * Budget refusals and floor refusals are RETURNED to the model as
1398
+ * structured tool results, never thrown the orchestrator must be able to
1399
+ * compose with what it has (a refusal mid-loop that crashes the loop would
1400
+ * convert a budget into an outage).
265
1401
  *
266
- * Each rule is a pure function: (ir, result, profile) BestPracticeAdvisory[].
267
- * No side effects. No randomness. Deterministic for a given IR.
1402
+ * Composition-verification (§7a): every sub-result is 'trusted' until the
1403
+ * orchestrator/consumer reports otherwise via `reportComposition`
1404
+ * absence-of-report IS the recorded state (migration 052). Rung 3 reads
1405
+ * this to attribute composition failures to stitching, not executor choice.
268
1406
  *
269
- * The thresholds (2000 chars, 1000 chars, 10 tools, 2 history) are chosen
270
- * to balance noise vs. signal too low fires on innocuous calls, too high
271
- * misses real waste. They may tune with brain evidence over time; for now
272
- * they're literals in the rule bodies. Make them configurable when the
273
- * cost-watcher's R-rules graduate to here.
1407
+ * Trace-budget honesty (v1 limits, stated where consumers read):
1408
+ * - the in-process ledger sums DELEGATED spend for this trace (parent's
1409
+ * own root-call spend is not visible to a library ledger until a
1410
+ * brain-informed ledger lands; documented on `maxCostPerTraceUsd`);
1411
+ * - enforcement is estimate-ahead: a sub-call whose compile-time estimate
1412
+ * would cross the ceiling is refused BEFORE any spend;
1413
+ * - realized spend is computed from actual tokens × the executor
1414
+ * profile's prices after each sub-call.
274
1415
  */
275
1416
 
276
- /** Subset of CompileResult fields the advisor needs. */
277
- type AdvisorContext = Pick<CompileResult, 'target' | 'provider' | 'tokensIn' | 'diagnostics'>;
1417
+ declare function isDelegateEnabledFromEnv(envSource?: Record<string, string | undefined>): boolean;
1418
+ /** Arguments the ORCHESTRATING MODEL supplies when it calls the tool. */
1419
+ interface DelegateToolArgs {
1420
+ /** The sub-task's archetype — its own learning_key downstream. */
1421
+ sub_archetype: IntentArchetypeName | string;
1422
+ /** Complete, self-contained sub-task input. The model owns fidelity here
1423
+ * (authority split): kgauto runs exactly what it is handed. */
1424
+ input: string;
1425
+ /**
1426
+ * Minimum archetype-perf score (0..10) the executor must carry for this
1427
+ * sub-archetype. Candidates below the floor are excluded BEFORE ranking;
1428
+ * if nothing in the parent's declared pool clears it, the tool refuses
1429
+ * with the scores so the model can lower the floor or do the work itself.
1430
+ */
1431
+ quality_floor?: number;
1432
+ }
1433
+ type DelegateRefusalReason = 'delegate_not_enabled' | 'invalid_sub_archetype' | 'no_qualified_executor' | 'trace_budget_exhausted' | 'call_failed';
1434
+ type DelegateResult = {
1435
+ ok: true;
1436
+ /** The sub-result text (or serialized structured output). */
1437
+ output: string;
1438
+ /** Branch handle — pass to reportComposition; joins the brain row. */
1439
+ subHandle: string;
1440
+ executorModel: string;
1441
+ costUsd: number;
1442
+ latencyMs: number;
1443
+ /** Always 'trusted' at return time — flips only via reportComposition. */
1444
+ verification: 'trusted';
1445
+ } | {
1446
+ ok: false;
1447
+ reason: DelegateRefusalReason;
1448
+ /** Human/model-readable detail — written to be COMPOSABLE (“continue
1449
+ * without this sub-result”), never a stack trace. */
1450
+ detail: string;
1451
+ };
278
1452
  /**
279
- * Run all phased rules and return collected advisories. Order is fixed so
280
- * output is stable across runs. The `policy` argument is alpha.9 — the
281
- * `single-model-array` rule needs to know whether the consumer explicitly
282
- * declared `posture: 'locked'` (in which case single-model is intentional
283
- * and shouldn't warn).
1453
+ * Provider-agnostic tool definition. Consumers adapt `inputSchema` to their
1454
+ * SDK's tool shape (AI-SDK `parameters`, Anthropic `input_schema`, …). The
1455
+ * description IS prompt surface it teaches the model the authority split
1456
+ * and the compose-on-refusal discipline (gates 4/5 of discipline-gates-v1
1457
+ * in tool-description form).
284
1458
  */
285
- declare function runAdvisor(ir: PromptIR, result: AdvisorContext, profile: ModelProfile, policy?: CompilePolicy): BestPracticeAdvisory[];
286
-
287
- /**
288
- * getDefaultFallbackChain — the alpha.9 cascading ship.
1459
+ declare const DELEGATE_TOOL_DEFINITION: {
1460
+ readonly name: "delegate";
1461
+ readonly description: string;
1462
+ readonly inputSchema: {
1463
+ readonly type: "object";
1464
+ readonly properties: {
1465
+ readonly sub_archetype: {
1466
+ readonly type: "string";
1467
+ readonly enum: ("ask" | "hunt" | "classify" | "summarize" | "generate" | "extract" | "plan" | "critique" | "transform" | "judge")[];
1468
+ readonly description: "What kind of work the sub-task is (its routing archetype).";
1469
+ };
1470
+ readonly input: {
1471
+ readonly type: "string";
1472
+ readonly description: "Complete, self-contained sub-task input. Include everything the executor needs — it sees nothing else.";
1473
+ };
1474
+ readonly quality_floor: {
1475
+ readonly type: "number";
1476
+ readonly minimum: 0;
1477
+ readonly maximum: 10;
1478
+ readonly description: "Optional minimum executor quality score (0-10) for this archetype. Omit to accept the evidence-ranked default.";
1479
+ };
1480
+ };
1481
+ readonly required: readonly ["sub_archetype", "input"];
1482
+ readonly additionalProperties: false;
1483
+ };
1484
+ };
1485
+ interface CreateDelegateOpts {
1486
+ /** The PARENT call's IR — supplies the declared model pool (the containment
1487
+ * boundary), appId, and dialect context. */
1488
+ parentIr: PromptIR;
1489
+ /** The parent's compile/call handle — R0 linkage root. Branch rows record
1490
+ * `parent_handle=<this>` and inherit `trace_id`. */
1491
+ parentHandle: string;
1492
+ /**
1493
+ * Options forwarded to the sub-`call()` (apiKeys, fetchImpl,
1494
+ * attemptTimeoutMs, policy…). `policy.maxCostPerTraceUsd` here is what the
1495
+ * ledger enforces. `parentHandle` is set by the factory — a value passed
1496
+ * in callOpts is overridden.
1497
+ */
1498
+ callOpts?: CallOptions & {
1499
+ policy?: CompilePolicy;
1500
+ };
1501
+ /** Explicit consent — beats KGAUTO_DELEGATE env (AUTO_PROMOTE posture). */
1502
+ enabled?: boolean;
1503
+ }
1504
+ interface DelegateHandle {
1505
+ toolDefinition: typeof DELEGATE_TOOL_DEFINITION;
1506
+ handler: (args: DelegateToolArgs) => Promise<DelegateResult>;
1507
+ /**
1508
+ * §7a — report what the orchestrator did with a sub-result. Writes a
1509
+ * migration-052 row via the brain-read env trio (RLS-scoped to appId).
1510
+ * Unreported sub-results are 'trusted' by definition — report only
1511
+ * 'verified' and 'discarded'.
1512
+ */
1513
+ reportComposition: (report: {
1514
+ subHandle: string;
1515
+ disposition: 'verified' | 'discarded';
1516
+ note?: string;
1517
+ }) => Promise<{
1518
+ ok: boolean;
1519
+ reason?: string;
1520
+ }>;
1521
+ /** Ledger introspection: delegated spend recorded for this trace so far. */
1522
+ traceSpendUsd: () => number;
1523
+ }
1524
+ declare function createDelegate(opts: CreateDelegateOpts): DelegateHandle;
1525
+
1526
+ /**
1527
+ * archetype-fits — alpha.43.
289
1528
  *
290
- * Returns a per-archetype fallback chain that walks the cost/performance
291
- * Pareto frontier (master plan §1.3 + §3). Three customer postures:
1529
+ * Static table of "this archetype tends to be a better fit for this family"
1530
+ * recommendations. Powers the `cross-family-fit-candidate` compile-time
1531
+ * advisor (see `advisor-rules/cross-family-fit.ts`).
292
1532
  *
293
- * locked — caller passes [theOneModel]; never call this function
294
- * preferred caller passes `primary`; chain returned is [primary, ...fallbacks]
295
- * open — caller passes no `primary`; chain returned is [best, ...fallbacks]
1533
+ * Strategic framing (Sacha, 2026-05-28): "If we get better results and
1534
+ * better price then we do. Even if volume is currently low, that's not an
1535
+ * argument to not do it. Volume can increase quickly if tools is great to
1536
+ * use, let's not create future bottlenecks because we could have wired in
1537
+ * better solution at moment of knowing."
296
1538
  *
297
- * The chain at each step:
298
- * 1. Costs strictly less than the previous (no expensive sideways moves)
299
- * 2. Comes from a different provider than the previous step where possible
300
- * (correlated outages don't kill consecutive attempts)
301
- * 3. Stays above the archetype's perf floor (skip models scored <baseline
302
- * for archetypes where degradation would be unacceptable)
1539
+ * The convention substrate (passApplyConventions) is the NEGATIVE side:
1540
+ * make a family usable on archetypes it currently fails. This table is the
1541
+ * POSITIVE side: actively surface that a different family is the better
1542
+ * fit for the archetype's shape even when current volume is low.
303
1543
  *
304
- * In alpha.9 the chain is **hand-curated** per archetype (§3.3 starter
305
- * table). Brain-query mode lands in alpha.10. Policy.blockedModels filters
306
- * the result; policy.maxCostPerCallUsd is NOT applied here because the
307
- * function doesn't see the IR's token counts — that filtering happens at
308
- * `passScoreTargets()` time inside compile().
1544
+ * Entries are added only when:
1545
+ * - the archetype's shape and the family's behavior have a clear
1546
+ * architectural fit (not vibes)
1547
+ * - real-world evidence (brain rows, probe outcomes, or published
1548
+ * benchmark) backs the claim, OR the reasoning is structurally so clear
1549
+ * that "wait for volume" would create a future bottleneck
309
1550
  *
310
- * The function is **pure**no brain query, no I/O, no randomness. Same
311
- * inputs always produce the same chain.
1551
+ * Alpha.43 ships two entries`plan` and `critique`. Both fit the
1552
+ * reasoner-family architectural read: plan is multi-step reasoning;
1553
+ * critique rewards epistemic humility and explicit reasoning. Other
1554
+ * archetype-family-fits ride later alphas as evidence accumulates.
1555
+ *
1556
+ * Anti-pattern: do NOT add archetype-family-fits for archetypes where the
1557
+ * fit is unclear (summarize, classify, extract, hunt with parallel tools).
1558
+ * The advisor only earns trust when its recommendations land.
312
1559
  */
313
1560
 
314
1561
  /**
315
- * Posture passed into `getDefaultFallbackChain`. The chain function only
316
- * sees `'open'` and `'preferred'` callers in `'locked'` posture should
317
- * pass `models: [theOneModel]` directly and skip this function entirely.
1562
+ * One archetype-family-fit recommendation. Read by the compile-time
1563
+ * `cross-family-fit-candidate` advisor to decide when to surface a positive
1564
+ * recommendation. The advisor pulls `costGuidance` verbatim into the
1565
+ * advisory message.
1566
+ */
1567
+ interface ArchetypeFamilyFit {
1568
+ /** Intent archetype this fit applies to. */
1569
+ archetype: IntentArchetypeName;
1570
+ /** Family tag that fits the archetype better than alternatives. Matches the
1571
+ * same family taxonomy used by `family-resolution.deriveFamilyFromModelId`
1572
+ * (e.g. `'deepseek-reasoner'`, `'gemini-flash'`, `'claude-opus'`). */
1573
+ betterFitFamily: string;
1574
+ /** Architectural / evidentiary justification. Appears in the advisor's
1575
+ * internal logs and the advisory `evidence` payload, NOT verbatim in the
1576
+ * consumer-facing message. */
1577
+ reason: string;
1578
+ /** Cost-context clause surfaced VERBATIM in the consumer-facing advisory
1579
+ * message (e.g. "substantially cheaper at current pricing"). Keep
1580
+ * declarative; the advisor wraps this into the larger sentence. */
1581
+ costGuidance: string;
1582
+ }
1583
+ /**
1584
+ * Frozen registry. Add entries by extending the array. Order is irrelevant
1585
+ * — the advisor filters by `(archetype, currentFamily)` independently.
1586
+ */
1587
+ declare const ARCHETYPE_FAMILY_FITS: readonly ArchetypeFamilyFit[];
1588
+ /**
1589
+ * Pure lookup: does `(archetype, currentFamily)` have a better-fit family?
1590
+ * Returns the fit entry when the current family is NOT the better fit; null
1591
+ * otherwise. Used by the advisor to decide whether to fire.
1592
+ */
1593
+ declare function findBetterFit(archetype: string, currentFamily: string): ArchetypeFamilyFit | null;
1594
+
1595
+ /**
1596
+ * Best-practice advisor — alpha.6 Phase 1.
318
1597
  *
319
- * Equivalent to `CompilePolicy.posture` minus `'locked'`. Kept distinct so
320
- * the type system enforces "don't ask for a chain when you don't want one."
1598
+ * Inspects an IR + the selected profile + compile diagnostics and emits a
1599
+ * list of `BestPracticeAdvisory` entries describing detected gaps. Runs
1600
+ * after `lower()` in the compile pipeline; the result lands on
1601
+ * `CompileResult.advisories` for the consumer to log, surface, or filter.
1602
+ *
1603
+ * Driven by interfaces/kgauto.md `best-practice-advisories` (IC, 2026-05-07).
1604
+ * Phase 1 ships 4 starter rules sourced from the s14 kgauto comment +
1605
+ * s15 empirical seed of brain anti-patterns:
1606
+ *
1607
+ * 1. `caching-off-on-claude` system >2000 chars on Anthropic, no cacheable=true
1608
+ * 2. `single-chunk-system` Anthropic, only one PromptSection >1000 chars
1609
+ * 3. `tool-bloat` >10 tools on a short-output archetype
1610
+ * 4. `history-uncached-on-claude` Anthropic, ≥2 history messages, no historyCachePolicy
1611
+ *
1612
+ * Each rule is a pure function: (ir, result, profile) → BestPracticeAdvisory[].
1613
+ * No side effects. No randomness. Deterministic for a given IR.
1614
+ *
1615
+ * The thresholds (2000 chars, 1000 chars, 10 tools, 2 history) are chosen
1616
+ * to balance noise vs. signal — too low fires on innocuous calls, too high
1617
+ * misses real waste. They may tune with brain evidence over time; for now
1618
+ * they're literals in the rule bodies. Make them configurable when the
1619
+ * cost-watcher's R-rules graduate to here.
321
1620
  */
322
- type FallbackPosture = 'open' | 'preferred';
323
- interface GetDefaultFallbackChainOpts {
324
- /** The archetype the call is performing. Drives chain shape. */
1621
+
1622
+ /** Subset of CompileResult fields the advisor needs. */
1623
+ type AdvisorContext = Pick<CompileResult, 'target' | 'provider' | 'tokensIn' | 'diagnostics'>;
1624
+ /**
1625
+ * Optional Phase 2 (alpha.22) context — fallback chain + a profile resolver
1626
+ * for cross-model comparison. Three new rules
1627
+ * (`cost-mismatched-archetype`, `model-stale-evidence`, `tier-down`) consume
1628
+ * this to surface measurement-substrate signals (alpha.20 clean-attribution +
1629
+ * alpha.21 grounding labels) as actionable consumer guidance.
1630
+ *
1631
+ * When `fallbackChain` is empty, rules 1 + 3 stay silent (nothing to
1632
+ * compare against). When `profileResolver` is omitted, the rules degrade
1633
+ * gracefully — they can still inspect the chosen profile but not chain
1634
+ * alternatives. Rule 2 (`model-stale-evidence`) is independent of chain
1635
+ * shape and works on the chosen model alone.
1636
+ */
1637
+ interface RunAdvisorPhase2Context {
1638
+ fallbackChain: string[];
1639
+ profileResolver?: (id: string) => ModelProfile | undefined;
1640
+ /**
1641
+ * alpha.29 — translator rewrites that fired this compile. When a rewrite
1642
+ * cleared the cliff (e.g. `tool_call_contract` → sequential-tool preamble
1643
+ * + `parallelToolCalls: false`), the matching cliff advisor
1644
+ * (`archetype-perf-floor-breach`) MUST suppress for the same call. Without
1645
+ * suppression both fire — the advisory contradicts the rewrite ("cliff is
1646
+ * unaddressed" vs "we just addressed it").
1647
+ *
1648
+ * Empty array / undefined → no suppression (alpha.28 behavior preserved).
1649
+ */
1650
+ sectionRewritesApplied?: SectionRewrite[];
1651
+ }
1652
+ /**
1653
+ * alpha.42 — rule codes whose advisories are positioned for kgauto (not
1654
+ * the consumer) to act on. Used by `compile()` to default the `ownership`
1655
+ * stamp on each advisory when the rule didn't self-declare. Consumer-side
1656
+ * rules don't need to be listed — they default to `'consumer-actionable'`
1657
+ * via fall-through.
1658
+ *
1659
+ * - `model-stale-evidence`: kgauto's profile data is out of date; the
1660
+ * consumer can't fix that, kgauto needs to update profiles or refresh
1661
+ * archetypePerf scores.
1662
+ * - `promote-ready`: kgauto's promotion-probe-watcher detected a
1663
+ * candidate model worth promoting; consumer-side adoption is downstream
1664
+ * of kgauto adding it to the chain / family taxonomy.
1665
+ *
1666
+ * Frozen so consumers and tests can't mutate the global ownership map.
1667
+ */
1668
+ declare const PRODUCER_OWNED_RULE_CODES: ReadonlySet<string>;
1669
+ /**
1670
+ * alpha.42 — pure function used by `compile()` to decide ownership for an
1671
+ * advisory. Rule-self-declared wins; falls back to the static map; defaults
1672
+ * `consumer-actionable`. Exported so consumer-side code (or a Glass-Box
1673
+ * renderer) can derive the same classification from a rule code alone
1674
+ * without needing the advisory object.
1675
+ */
1676
+ declare function deriveOwnership(code: string, selfDeclared?: 'consumer-actionable' | 'producer-owned'): 'consumer-actionable' | 'producer-owned';
1677
+ /**
1678
+ * Run all phased rules and return collected advisories. Order is fixed so
1679
+ * output is stable across runs. The `policy` argument is alpha.9 — the
1680
+ * `single-model-array` rule needs to know whether the consumer explicitly
1681
+ * declared `posture: 'locked'` (in which case single-model is intentional
1682
+ * and shouldn't warn).
1683
+ *
1684
+ * `phase2` is alpha.22 — gives the advisor access to the fallback chain +
1685
+ * a profile resolver so the three new compile-time recommendation rules
1686
+ * (`cost-mismatched-archetype`, `model-stale-evidence`, `tier-down`) can
1687
+ * compare the chosen model against in-chain alternatives. Optional for
1688
+ * backward compatibility with consumers calling `runAdvisor()` directly.
1689
+ */
1690
+ declare function runAdvisor(ir: PromptIR, result: AdvisorContext, profile: ModelProfile, policy?: CompilePolicy, phase2?: RunAdvisorPhase2Context): BestPracticeAdvisory[];
1691
+
1692
+ /**
1693
+ * promote-ready-brain — alpha.41 substrate.
1694
+ *
1695
+ * Per-tenant SWR cache for the `promote_ready_findings` table populated by
1696
+ * the autonomous `promotion-probe-watcher` (Mode 2). Mirrors
1697
+ * `exclusion-findings-brain.ts` shape byte-for-byte where applicable; this
1698
+ * is the read-side substrate for the compile-time `promote-ready` advisor
1699
+ * rule.
1700
+ *
1701
+ * Architecture (mirror of exclusion-findings-brain):
1702
+ *
1703
+ * - **Sync API surface.** `getPromoteReadyFindings({ appId, archetype,
1704
+ * family })` returns `PromoteReadyFindingRow[]` immediately. First call
1705
+ * returns the bundled fallback (empty array); async refresh fires in
1706
+ * background; subsequent calls within TTL return brain data.
1707
+ *
1708
+ * - **Per-appId snapshot.** Each appId gets its own cache entry. One fetch
1709
+ * per appId per TTL window. Tests reset between cases via
1710
+ * `_testResetPromoteReadyFindings()`.
1711
+ *
1712
+ * - **Tolerant.** Brain down / endpoint misconfigured / unexpected shape →
1713
+ * silent bundled fallback (empty array). Never throws. Warns once per
1714
+ * process per error to avoid log spam.
1715
+ *
1716
+ * - **Opt-in.** Activation gated on `configurePromoteReadyBrain()` having
1717
+ * been called with a runtime. The public `configureBrain()` in brain.ts
1718
+ * wires this up automatically when
1719
+ * `BrainConfig.brainQuery.findingsPromoteReady !== false`.
1720
+ *
1721
+ * Plus: `markPromoteReadyHandled` — direct PostgREST PATCH against the
1722
+ * brain (no kgauto proxy). Mirrors `markExclusionFindingHandled` shape
1723
+ * byte-for-byte. Idempotent on `resolved_at=is.null` filter.
1724
+ *
1725
+ * Default endpoint:
1726
+ * `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/promote-ready`
1727
+ * The route accepts `?app_id=X` and returns a JSON array of findings
1728
+ * for that app filtered to `resolved_at IS NULL`.
1729
+ */
1730
+
1731
+ /**
1732
+ * Shape of one row from the `promote_ready_findings` cache table. Mirrors
1733
+ * the snake_case JSONB returned by the brain endpoint, mapped to camelCase
1734
+ * at the boundary (rowToFinding) so the in-memory shape stays consistent
1735
+ * with the rest of the library.
1736
+ */
1737
+ interface PromoteReadyFindingRow {
1738
+ /** Intent archetype the finding applies to. */
1739
+ archetype: string;
1740
+ /** Model family (e.g. 'claude-opus', 'gemini-flash'). */
1741
+ family: string;
1742
+ /** The candidate model that the probe validated. */
1743
+ candidateModel: string;
1744
+ /** The current production model the candidate was compared against. */
1745
+ currentModel: string;
1746
+ /** Sample size of the probe run (typically 10). */
1747
+ sampleN: number;
1748
+ /** Fraction of probes where the judge verdict was 'candidate-better' or
1749
+ * 'tied'. 0.000 to 1.000. */
1750
+ judgePassRate: number;
1751
+ /** Mean judge score across the probe sample. 1.00 to 5.00. */
1752
+ judgeAvgScore: number;
1753
+ /** Signed cost delta as a fraction (negative = candidate is cheaper).
1754
+ * Null when pricing data was incomplete at probe time. */
1755
+ costDeltaPct: number | null;
1756
+ /** ISO timestamp of detection (when the probe wrote the row). */
1757
+ detectedAt: string;
1758
+ }
1759
+ /**
1760
+ * Resolution sources supported by alpha.41 `markPromoteReadyHandled`. The
1761
+ * three values map to the three CHECK-constrained resolution values on
1762
+ * `promote_ready_findings.resolution`:
1763
+ *
1764
+ * - `'promoted'` — consumer migrated to the candidate model. Strong
1765
+ * positive signal; the probe was right.
1766
+ * - `'declined'` — consumer evaluated and chose not to promote.
1767
+ * Strong negative signal; revisit only on new
1768
+ * family entries or material score swings.
1769
+ * - `'still-evaluating'` — consumer acknowledges the finding but defers
1770
+ * the decision. Acknowledges-without-deciding;
1771
+ * finding silences this cycle but next probe may
1772
+ * re-surface.
1773
+ */
1774
+ type PromoteReadyResolution = 'promoted' | 'declined' | 'still-evaluating';
1775
+ interface MarkPromoteReadyHandledOptions {
1776
+ /** App id the finding belongs to. Required (RLS scopes writes by this). */
1777
+ appId: string;
1778
+ /** Archetype the finding applies to (e.g. 'hunt', 'classify'). */
1779
+ archetype: IntentArchetypeName | string;
1780
+ /** Model family the finding applies to (e.g. 'claude-opus'). */
1781
+ family: string;
1782
+ /** Resolution semantics — see `PromoteReadyResolution`. */
1783
+ resolution: PromoteReadyResolution;
1784
+ /** Optional free-form note explaining the decision. */
1785
+ resolutionNote?: string;
1786
+ /** Brain Supabase URL base (e.g. `https://<project>.supabase.co`). */
1787
+ brainEndpoint: string;
1788
+ /** Consumer-scoped JWT carrying the `app_id` claim. */
1789
+ brainJwt: string;
1790
+ /** Supabase anon key for the `apikey` header. */
1791
+ brainAnonKey: string;
1792
+ /** Injected fetch for tests. Defaults to global fetch. */
1793
+ fetch?: typeof fetch;
1794
+ }
1795
+ /**
1796
+ * Mark a probe-validated promote-ready finding as handled. Returns an
1797
+ * `ok/reason` envelope matching `markExclusionFindingHandled`.
1798
+ *
1799
+ * Idempotent: if no row matches the (app_id, archetype, family) tuple
1800
+ * (already resolved, never existed, watcher not yet UPSERTed), PostgREST
1801
+ * returns 200/204 with zero affected rows and we return `{ ok: true }`.
1802
+ *
1803
+ * Reasons surfaced on failure:
1804
+ * - `app_id_required` / `archetype_required` / `family_required`
1805
+ * - `resolution_invalid` — not one of the three documented values
1806
+ * - `brain_auth_misconfig` — 401/403
1807
+ * - `brain_unavailable` — 5xx
1808
+ * - `network_error:<message>` — fetch threw
1809
+ * - `patch_failed:<status>` — anything else non-2xx
1810
+ */
1811
+ declare function markPromoteReadyHandled(opts: MarkPromoteReadyHandledOptions): Promise<{
1812
+ ok: true;
1813
+ } | {
1814
+ ok: false;
1815
+ reason: string;
1816
+ }>;
1817
+
1818
+ /**
1819
+ * blocked-model-drift — advisor rule for the two ways a consumer's
1820
+ * `CompilePolicy.blockedModels` can stop meaning what the consumer meant,
1821
+ * without anything anywhere reporting a problem.
1822
+ *
1823
+ * ── The incidents this is grounded in (tt-intel s113 + s119) ─────────────
1824
+ *
1825
+ * (Correction, s83: an earlier draft cited "claude-sonnet-5 served 30% of
1826
+ * tt-intel's ask traffic" as the motivating incident. That number was a
1827
+ * FOSSIL — tt-intel's own L-188 traced all 11 calls to a 29-second burst
1828
+ * from their own prior spend-gate experiment, fixed minutes later, and
1829
+ * their block was in fact working. Do not resurrect it.)
1830
+ *
1831
+ * The real, verified incidents:
1832
+ *
1833
+ * 1. alpha.72 retargeted the curated `claude-sonnet` family primary from
1834
+ * `claude-sonnet-4-6` (now `legacy`) to `claude-sonnet-5` (now
1835
+ * `current`), and tt-intel's literal-id gate STOPPED MATCHING the
1836
+ * family's routed traffic — their s113 response was to build
1837
+ * consumer-side family→concrete-id resolution (`parseBlockedModels`)
1838
+ * before ids reach kgauto. Every consumer without that local machinery
1839
+ * is exposed to the same silent retarget: `blockedModels` is matched by
1840
+ * exact id, so a block written against yesterday's primary says nothing
1841
+ * about today's.
1842
+ *
1843
+ * 2. tt-intel s119 (2026-07-29 filing): a blocked model SERVED when an
1844
+ * unblocked ALIAS of it sat in the candidate set (`deepseek-chat` ≡
1845
+ * `deepseek-v4-flash`). That one was a kgauto correctness bug, fixed in
1846
+ * alpha.85 by canonical matching (`policy-match.ts`) — but it proved
1847
+ * the class: a block-list meaning drifts whenever the roster's id
1848
+ * surface moves under it, and no layer errors.
1849
+ *
1850
+ * ── What this rule is NOT ────────────────────────────────────────────────
1851
+ *
1852
+ * It does not change matching semantics. Exact-ID matching is arguably the
1853
+ * correct contract: family-glob matching would silently widen every
1854
+ * existing consumer's block-list, which is a breaking semantic change and
1855
+ * not kgauto's to make unilaterally. The gap here is silence, not
1856
+ * semantics — so the fix is a signal, not a behavior change. Selection is
1857
+ * untouched; a consumer who blocked one exact id still gets exactly that
1858
+ * id blocked and nothing else.
1859
+ *
1860
+ * ── The two branches ─────────────────────────────────────────────────────
1861
+ *
1862
+ * (a) `blocked-model-not-in-roster` — a `blockedModels` entry resolves to
1863
+ * no model in the current roster (after alias resolution). The block is
1864
+ * inert: it can never match anything. Causes are a typo, a model
1865
+ * retired out of the roster, or a stale env var carried forward. There
1866
+ * is no reading under which an entry matching nothing is what the
1867
+ * consumer wanted, so this is unambiguous.
1868
+ *
1869
+ * (b) `blocked-model-family-sibling-served` — the model selected for THIS
1870
+ * call is in the same family as a blocked entry but is a different
1871
+ * exact id. This is the tt-intel shape. Unlike (a) it IS ambiguous:
1872
+ * "block `claude-sonnet-4-6` specifically, `claude-sonnet-5` is fine"
1873
+ * is a legitimate and common intent. So the message states both
1874
+ * readings and says how to act on either. It escalates its wording —
1875
+ * not its level — when the blocked sibling is `legacy`/`deprecated` and
1876
+ * the served sibling is `current`, because that combination is the
1877
+ * signature of a roster lifecycle move rather than a deliberate
1878
+ * per-generation block.
1879
+ *
1880
+ * Both fire at `warn`, and both fire regardless of `policy.posture`.
1881
+ * `posture: 'locked'` means "do not recommend models to me" — these are not
1882
+ * recommendations, they are reports that the consumer's own declared
1883
+ * constraint is not doing what its author expects. Same reasoning as the
1884
+ * alpha.28 `archetype-perf-floor-breach` cliff advisor, which is also
1885
+ * posture-independent because it reports a structural fact rather than a
1886
+ * preference.
1887
+ *
1888
+ * Companion watcher: `v2/scripts/blocked-model-drift-watch.mjs` rolls the
1889
+ * same two branches up across a consumer's recent traffic from the brain,
1890
+ * so the signal survives a consumer who never reads `result.advisories[]`.
1891
+ *
1892
+ * L-073 family ("no errors = healthy"): as with DeepSeek's `deepseek-chat`
1893
+ * compat alias and the alpha.47/.43 field-drop chain, nothing errored,
1894
+ * nothing 404'd, latency did not move — and the cached intent was wrong for
1895
+ * an unknown duration. The detection loop has to be built deliberately
1896
+ * because the failure emits no natural signal.
1897
+ */
1898
+
1899
+ /** Stable rule code — branch (a). Written to `compile_outcome_advisories.code`. */
1900
+ declare const BLOCKED_MODEL_NOT_IN_ROSTER_CODE = "blocked-model-not-in-roster";
1901
+ /** Stable rule code — branch (b). Written to `compile_outcome_advisories.code`. */
1902
+ declare const BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE = "blocked-model-family-sibling-served";
1903
+
1904
+ /**
1905
+ * Translator primitive — alpha.31.
1906
+ *
1907
+ * Pure function. Walks `IR.sections`, matches each section's `kind` against
1908
+ * a per-rule dispatch table keyed on (kind, profile, archetype), and applies
1909
+ * a model-aware rewrite when a rule fires. Returns the rewritten IR + the
1910
+ * list of rewrites for `CompileResult.sectionRewritesApplied` and brain
1911
+ * persistence.
1912
+ *
1913
+ * This is the s37 translator-framing eureka in code: kgauto graduates from
1914
+ * "gate" (alpha.28's cliff advisor: "consumer must accept adapter") to
1915
+ * "translator" (alpha.29: "consumer declared the section kind, kgauto
1916
+ * applies the adapter at compile time without consumer-side branching").
1917
+ *
1918
+ * Rules shipped:
1919
+ *
1920
+ * alpha.29 — tool_call_contract + archetypePerf[archetype] < TRANSLATOR_FLOOR
1921
+ * → prepend sequential-tool-pattern guidance
1922
+ * → emit wireOverrides: { parallelToolCalls: false }
1923
+ * → rule_id: 'sequential-tool-cliff-below-floor'
1924
+ *
1925
+ * alpha.31 — narration_contract + profile.provider === 'anthropic'
1926
+ * → prepend terse-log narration guidance
1927
+ * → no wireOverrides
1928
+ * → rule_id: 'narration-drift-anthropic'
1929
+ *
1930
+ * alpha.31 — narration_contract + profile.provider === 'deepseek'
1931
+ * → prepend <thinking>-suppression guidance
1932
+ * → no wireOverrides
1933
+ * → rule_id: 'narration-thinking-leak-deepseek'
1934
+ *
1935
+ * Per-rule walk (alpha.31 refactor): the alpha.30 short-circuit
1936
+ * `if (!cliffFires) return passthrough` was correct when only the
1937
+ * cliff-gated tool_call_contract rule existed; alpha.31's narration rules
1938
+ * fire on every call regardless of cliff (narration drift is steady-state,
1939
+ * not a cliff condition). Each section now consults the dispatch table
1940
+ * independently — first-match wins per (section.kind, profile, archetype).
1941
+ *
1942
+ * **Interaction with the cliff advisor (alpha.28):** when this translator
1943
+ * fires for a `tool_call_contract` section, the advisor's
1944
+ * `archetype-perf-floor-breach` rule MUST suppress for the same call — the
1945
+ * cliff was structurally cleared by the rewrite, not unaddressed. The
1946
+ * suppression check lives in `advisor.ts` and consults the
1947
+ * `CompileResult.sectionRewritesApplied` list.
1948
+ *
1949
+ * Design contracts:
1950
+ * command-center/advisory/kgauto/2026-05-21_alpha-29-translator-and-advisories-api.md
1951
+ * command-center/advisory/kgauto/2026-05-22_alpha-31-narration-contract.md
1952
+ */
1953
+
1954
+ /**
1955
+ * Re-export of `ARCHETYPE_FLOOR_DEFAULT` as the canonical "translator fires
1956
+ * below this score" threshold. Same constant as the cliff advisor — the
1957
+ * single threshold is shared (alpha.28's "below this, advisor warns"; alpha.29's
1958
+ * "below this, translator AUTO-APPLIES the adapter").
1959
+ */
1960
+ declare const TRANSLATOR_FLOOR = 6;
1961
+ /**
1962
+ * Stable identifier of the alpha.29 sequential-tool rule. Surfaces on
1963
+ * `SectionRewrite.rule` and in brain aggregates. The brain treats this
1964
+ * identifier together with the preamble string as the rule's wire
1965
+ * fingerprint — both stay byte-stable across releases.
1966
+ */
1967
+ declare const RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
1968
+ /**
1969
+ * alpha.68 / Release A — stable identifier of the discipline-gates rule.
1970
+ * Fires on `discipline_contract` sections that pass the two-factor eligibility
1971
+ * screen (Factor A archetype + Factor C output-shape). Surfaces on
1972
+ * `SectionRewrite.rule` and in brain aggregates.
1973
+ *
1974
+ * Versioned (`v1`) deliberately: Factor B evidence (Release B) is only valid
1975
+ * against the EXACT bytes that produced it, so a silent gate edit would
1976
+ * invalidate every standing verdict. A real gate change bumps this to `v2` and
1977
+ * resets Factor B to unmeasured for every tuple.
1978
+ */
1979
+ declare const RULE_DISCIPLINE_GATES_V1 = "discipline-gates-v1";
1980
+ /**
1981
+ * Release B — stable identifier of the STRUCTURED-SAFE discipline-gates
1982
+ * variant (design contract §5.D second clause, discharged via §4.0's merge:
1983
+ * "the judge must run gates 1–4 only — which IS Path 1's structured-safe
1984
+ * variant, arrived at as a subset-drop of frozen bytes rather than new
1985
+ * prose"). Fires where the full block is Factor-C-forbidden: `json` and
1986
+ * `tool_call` surfaces, where gates 5+6 are shape-altering and would
1987
+ * manufacture the structured-output violations alpha.66 retries.
1988
+ *
1989
+ * Versioned with the SAME v1 stamp as its parent: its bytes are a strict
1990
+ * subset of `discipline-gates-v1`'s, so a v1 wording change is a variant
1991
+ * wording change by construction, and both bump together.
1992
+ */
1993
+ declare const RULE_DISCIPLINE_GATES_V1_STRUCTURED = "discipline-gates-v1-structured";
1994
+ interface ApplySectionRewritesArgs {
1995
+ ir: PromptIR;
1996
+ profile: ModelProfile;
325
1997
  archetype: IntentArchetypeName;
326
1998
  /**
327
- * The user-selected or caller-anchored primary model. When provided, it
328
- * appears at position 0 of the returned chain and fallbacks follow.
329
- * When omitted, the function picks the best-perf model for the archetype
330
- * as position 0 (open posture).
1999
+ * alpha.68 / Release A resolved output shape for Factor C (§5.D). `'json'`
2000
+ * structured surface (the discipline gate MUST NOT fire gates 5+6 are
2001
+ * shape-altering and would break the consumer's parser). `'text'` free-form
2002
+ * surface (the gate may fire). Optional: when omitted, derived from
2003
+ * `ir.constraints?.structuredOutput` (true ⇒ 'json', else 'text') so callers
2004
+ * / tests need not pass it. compile() passes it explicitly.
331
2005
  */
332
- primary?: string;
2006
+ outputMode?: OutputMode;
2007
+ }
2008
+ interface ApplySectionRewritesResult {
333
2009
  /**
334
- * Informational. `'preferred'` and `'open'` produce the same chain shape
335
- * given the same `primary`/no-primary input posture is a tag the brain
336
- * uses to distinguish "user-anchored" from "library-anchored" telemetry.
2010
+ * IR with section.text fields possibly rewritten. When no rewrites fired,
2011
+ * this is identical to the input IR (referentially distinct array but
2012
+ * same section payloads).
337
2013
  */
338
- posture?: FallbackPosture;
2014
+ rewrittenIR: PromptIR;
339
2015
  /**
340
- * Cap on chain length. Default 3. Min 1. Useful when the consumer wants
341
- * to keep the worst-case latency low (each fallback adds a round-trip).
2016
+ * One entry per section the translator rewrote. Empty array when no
2017
+ * rules fired. Order matches the corresponding section in
2018
+ * `rewrittenIR.sections`.
342
2019
  */
343
- maxDepth?: number;
2020
+ rewrites: SectionRewrite[];
2021
+ }
2022
+ /**
2023
+ * Pure function. Apply model-aware section rewrites to the IR at compile time.
2024
+ *
2025
+ * Discipline:
2026
+ * - Never mutates the input IR; returns a new IR with new sections array
2027
+ * when at least one rewrite fired; otherwise returns the input IR by
2028
+ * reference (referential identity preserved on no-op).
2029
+ * - Sections without a `kind` (or `kind === 'arbitrary'`) pass through
2030
+ * unchanged.
2031
+ * - Empty `sections` array → returns `{ rewrittenIR: ir, rewrites: [] }`.
2032
+ * - Sections of the same `kind` are processed in array order; first-match
2033
+ * wins per section. (Today every rule is a single-match rule.)
2034
+ *
2035
+ * @example
2036
+ * ```ts
2037
+ * import { applySectionRewrites } from '@warmdrift/kgauto-compiler';
2038
+ * import { getProfile } from '@warmdrift/kgauto-compiler';
2039
+ *
2040
+ * const { rewrittenIR, rewrites } = applySectionRewrites({
2041
+ * ir,
2042
+ * profile: getProfile('deepseek-v4-pro'),
2043
+ * archetype: 'hunt',
2044
+ * });
2045
+ * if (rewrites.length > 0) console.log('translator fired:', rewrites);
2046
+ * ```
2047
+ */
2048
+ declare function applySectionRewrites(args: ApplySectionRewritesArgs): ApplySectionRewritesResult;
2049
+
2050
+ /**
2051
+ * advisories-api — structured advisories API (alpha.29 Workstream B).
2052
+ *
2053
+ * Closes the L-117 family bottleneck: kgauto's `result.advisories[]` (the
2054
+ * compile-time warnings about caching-off, tool-bloat, archetype-perf-floor
2055
+ * breaches, etc.) used to disappear after the consumer read the compile
2056
+ * result. The s34 caching-off advisory pattern is the canonical failure: an
2057
+ * advisory fired 100+ times in 24h on `generate::sonnet` at 99.4% empty
2058
+ * rate, and nobody knew because there was no structured channel to surface
2059
+ * "what's open right now?"
2060
+ *
2061
+ * Migration 020 ships the substrate: `compile_outcome_advisories` gains
2062
+ * lifecycle columns (`resolved_at`, `resolution_source`, `resolution_note`)
2063
+ * and the `actionable_advisories_v` view rolls per-firing rows into
2064
+ * per-(app_id, code) tuples with deterministic stable ids + server-side
2065
+ * auto-resolution.
2066
+ *
2067
+ * Public surface:
2068
+ * getActionableAdvisories({ appId, severity?, status?, brainEndpoint, brainJwt, brainAnonKey, fetch? })
2069
+ * → Promise<ActionableAdvisory[]>
2070
+ *
2071
+ * markAdvisoryResolved({ id, resolutionNote?, brainEndpoint, brainJwt, brainAnonKey, fetch? })
2072
+ * → Promise<{ ok: true } | { ok: false; reason: string }>
2073
+ *
2074
+ * Both functions are pure I/O — no module-level state. The fetch wiring
2075
+ * mirrors `createProxyHandler` in `glassbox-routes/proxy.ts`: scoped JWT in
2076
+ * `Authorization: Bearer`, `apikey` header carries the anon key.
2077
+ *
2078
+ * The auto-resolution rule is enforced server-side in `actionable_advisories_v`:
2079
+ * • Latest firing > 14 days ago → status='resolved' (auto-pruned)
2080
+ * • All firings have resolved_at set → status='resolved' (consumer-marked)
2081
+ * • Otherwise → status='open'
2082
+ *
2083
+ * `markAdvisoryResolved` is the consumer override: "I fixed it; the next
2084
+ * firing will reopen the rule, but until then it stays resolved."
2085
+ */
2086
+
2087
+ /**
2088
+ * Severity of an advisory. Maps to the `level` column on
2089
+ * `compile_outcome_advisories` (info | warn | critical).
2090
+ */
2091
+ type AdvisorySeverity = 'info' | 'warn' | 'critical';
2092
+ /**
2093
+ * Status of an advisory rollup.
2094
+ *
2095
+ * - `open` — at least one unresolved firing in the last 14 days
2096
+ * - `resolved` — either auto-pruned (no firings >14d) or consumer-marked
2097
+ * - `snoozed` — reserved for alpha.30+ (snooze-until-date); type-accepted
2098
+ * today but the view will never emit this value
2099
+ */
2100
+ type AdvisoryStatus = 'open' | 'snoozed' | 'resolved';
2101
+ /**
2102
+ * Source of resolution when status='resolved'.
2103
+ *
2104
+ * - `auto` — server-side rule auto-pruned (>14d since last firing)
2105
+ * - `consumer-marked` — consumer called `markAdvisoryResolved`
2106
+ * - `declined` — reserved (alpha.30+: consumer marked the suggestion
2107
+ * inapplicable; the advisor will still fire but UIs can hide it)
2108
+ */
2109
+ type AdvisoryResolutionSource = 'auto' | 'consumer-marked' | 'declined';
2110
+ /**
2111
+ * Suggested-fix metadata. `null` when the advisor has no actionable fix
2112
+ * (info-level rules can be observational). When set, the consumer's
2113
+ * Admin UI can render a one-click apply (alpha.30+) or surface the
2114
+ * before/after diff inline.
2115
+ */
2116
+ interface AdvisorySuggestedFix {
2117
+ type: 'config-change' | 'one-liner' | 'env-var' | 'manual';
2118
+ /** File:line hint if kgauto can infer (reserved — alpha.30+). */
2119
+ siteHint?: string;
2120
+ before?: string;
2121
+ after?: string;
2122
+ docsLink?: string;
2123
+ }
2124
+ /**
2125
+ * Per-(app_id, code) advisory rollup. The `id` is stable across polls
2126
+ * until the rule auto-resolves and re-opens (a new firing after the 14d
2127
+ * boundary advances `opened_at` → new id). Treat id-changes as
2128
+ * intentional "fresh re-open" signals.
2129
+ *
2130
+ * Wire-shape from `actionable_advisories_v`. The transformer maps the
2131
+ * view's snake_case columns to camelCase. See `feedback_typed_boundary_transformers.md`
2132
+ * (L-118) for the rationale.
2133
+ */
2134
+ /**
2135
+ * The window of evidence a finding was computed from — migration 054.
2136
+ *
2137
+ * READ THE DISTINCTION BEFORE USING THIS. It is NOT `openedAt` /
2138
+ * `lastObservedAt` / `observationCount`, which describe the ADVISORY (how
2139
+ * long it has been firing, how many times the watcher ran and still saw the
2140
+ * condition). This describes what the generator LOOKED AT.
2141
+ *
2142
+ * A daily cron that keeps firing on a single 29-second burst reports
2143
+ * `observationCount: 11` spanning 11 days — the most standing-looking of
2144
+ * standing conditions — while its evidence is one event from 11 days ago.
2145
+ * Separating the two is the entire point.
2146
+ *
2147
+ * `null` when the generator did not state its window. Honest unknown; it
2148
+ * must never be read as "not a burst". Compile-time library rules carry
2149
+ * null legitimately — they fire on ONE call, so their evidence is the call
2150
+ * in hand and there is no window to state.
2151
+ */
2152
+ interface AdvisoryEvidenceWindow {
2153
+ firstAt: string;
2154
+ lastAt: string;
2155
+ n: number;
2156
+ /** `lastAt - firstAt`, precomputed so no caller re-derives it wrong. */
2157
+ spanMs: number;
344
2158
  /**
345
- * Consumer-side gating. `blockedModels` are filtered from the chain.
346
- * `preferredModels` is informational (no boost applied at this layer —
347
- * compile()'s `passScoreTargets` handles preference ranking).
348
- * `maxCostPerCallUsd` is NOT applied here — needs IR-level token
349
- * estimation. Use compile()'s policy plumbing instead.
2159
+ * `true` when the evidence is clustered tightly enough to be ONE EVENT
2160
+ * rather than a standing rate. See `classifyEvidenceWindow`.
350
2161
  */
351
- policy?: CompilePolicy;
2162
+ isBurst: boolean;
352
2163
  }
353
- declare function getDefaultFallbackChain(opts: GetDefaultFallbackChainOpts): string[];
354
2164
  /**
355
- * Returns a shallow copy of the hand-curated starter chain for an archetype.
356
- * Useful for tests + the `scripts/digest.mjs` operator readout.
2165
+ * Burst-vs-rate, computed rather than judged.
2166
+ *
2167
+ * Origin: tt-intel s118. A cost query showed `claude-sonnet-5` at 30% of
2168
+ * their `ask` traffic and 80% of ask spend. Every number true, every
2169
+ * mechanism check correct, and every correct check made them more certain
2170
+ * the spend gate had regressed. All eleven calls sat in a 29-second window —
2171
+ * their own prior experiment, fixed six minutes after the last one. Their
2172
+ * formulation: **a cluster is an event, not a rate.**
2173
+ *
2174
+ * The rule, deliberately crude because a subtle one would need tuning per
2175
+ * rule and would then be wrong per rule: evidence is a burst when it spans
2176
+ * less than `BURST_SPAN_MS` (5 minutes). Multiple observations inside five
2177
+ * minutes are one incident — a deploy, a retry storm, a test run, a
2178
+ * benchmark — not a pattern of behavior over time.
2179
+ *
2180
+ * Two deliberate non-features:
2181
+ *
2182
+ * - **n is not in the test.** Two rows 4 minutes apart are as much a single
2183
+ * event as eleven are. Requiring a minimum n would let the smallest, least
2184
+ * evidenced findings skip the check.
2185
+ * - **It does not try to detect fossils.** A burst is not necessarily stale;
2186
+ * it is merely not a rate. Only the consumer's own deploy log can turn
2187
+ * "one event" into "an event we already fixed", and this library cannot
2188
+ * see that. Claiming otherwise would be the same over-reach the rule
2189
+ * exists to correct.
357
2190
  */
358
- declare function getStarterChain(archetype: IntentArchetypeName): string[];
2191
+ declare const BURST_SPAN_MS: number;
2192
+ declare function classifyEvidenceWindow(row: {
2193
+ evidence_first_at?: string | null;
2194
+ evidence_last_at?: string | null;
2195
+ evidence_n?: number | null;
2196
+ }): AdvisoryEvidenceWindow | null;
2197
+ /** Human-readable span for advisory text. Terse by design — it sits inline. */
2198
+ declare function formatEvidenceSpan(spanMs: number): string;
359
2199
  /**
360
- * Returns a shallow copy of all starter chains keyed by archetype.
361
- * Useful for the `digest.mjs` readout and consumer audits.
2200
+ * The sentence that travels with a burst-shaped finding. Written to be
2201
+ * usable verbatim in advisory text, and to say what the library CAN claim
2202
+ * (one event) rather than what it cannot (that the event is stale).
362
2203
  */
363
- declare function getAllStarterChains(): Record<IntentArchetypeName, string[]>;
2204
+ declare function burstCaveat(w: AdvisoryEvidenceWindow): string;
2205
+ interface ActionableAdvisory {
2206
+ id: string;
2207
+ rule: string;
2208
+ severity: AdvisorySeverity;
2209
+ openedAt: string;
2210
+ lastObservedAt: string;
2211
+ observationCount: number;
2212
+ /**
2213
+ * Migration 054. `null` when the generator did not state a window — an
2214
+ * honest unknown, NOT an assertion that the evidence is well-spread.
2215
+ */
2216
+ evidenceWindow: AdvisoryEvidenceWindow | null;
2217
+ /**
2218
+ * The severity the rule ASKED for, present only when this advisory's
2219
+ * effective `severity` was downgraded because its evidence is burst-shaped.
2220
+ * Kept so a consumer can see the downgrade happened rather than silently
2221
+ * receiving a quieter advisory than the generator wrote.
2222
+ */
2223
+ severityBeforeBurstDowngrade?: AdvisorySeverity;
2224
+ appliesTo: {
2225
+ archetype?: IntentArchetypeName;
2226
+ model?: string;
2227
+ callSiteHint?: string;
2228
+ };
2229
+ message: string;
2230
+ suggestedFix: AdvisorySuggestedFix | null;
2231
+ /** Reserved — always `false` in alpha.29. alpha.30+ ships actual auto-apply. */
2232
+ autoApplicable: boolean;
2233
+ status: AdvisoryStatus;
2234
+ resolvedAt?: string;
2235
+ resolutionSource?: AdvisoryResolutionSource;
2236
+ resolutionNote?: string;
2237
+ }
2238
+ /**
2239
+ * Filter + transport for `getActionableAdvisories`. The brain JWT must
2240
+ * carry an `app_id` claim matching `opts.appId` — RLS enforces tenant
2241
+ * isolation on the underlying table, so a mismatch silently returns [].
2242
+ */
2243
+ interface GetActionableAdvisoriesOptions {
2244
+ appId: string;
2245
+ /** Severity filter; if omitted, all severities are returned. */
2246
+ severity?: AdvisorySeverity;
2247
+ /** Status filter; defaults to 'open'. Pass 'all' for the full set. */
2248
+ status?: 'open' | 'snoozed' | 'resolved' | 'all';
2249
+ /**
2250
+ * alpha.78 (PB adoption-gap ask 2): the trio now DEFAULTS from
2251
+ * `readBrainReadEnv()` when omitted, so a consumer that passes nothing
2252
+ * gets correct behavior from the canonical env names instead of a
2253
+ * self-authored config error. Explicit values still win.
2254
+ */
2255
+ brainEndpoint?: string;
2256
+ brainJwt?: string;
2257
+ brainAnonKey?: string;
2258
+ fetch?: typeof fetch;
2259
+ }
2260
+ interface MarkAdvisoryResolvedOptions {
2261
+ /** Stable id from a prior `getActionableAdvisories` call. */
2262
+ id: string;
2263
+ resolutionNote?: string;
2264
+ /**
2265
+ * alpha.78 (PB adoption-gap ask 2): the trio now DEFAULTS from
2266
+ * `readBrainReadEnv()` when omitted, so a consumer that passes nothing
2267
+ * gets correct behavior from the canonical env names instead of a
2268
+ * self-authored config error. Explicit values still win.
2269
+ */
2270
+ brainEndpoint?: string;
2271
+ brainJwt?: string;
2272
+ brainAnonKey?: string;
2273
+ fetch?: typeof fetch;
2274
+ }
2275
+ /**
2276
+ * Map a single `actionable_advisories_v` row (snake_case, Postgres
2277
+ * native) to the public `ActionableAdvisory` shape (camelCase). Single
2278
+ * canonical mapping site for this boundary (L-118).
2279
+ */
2280
+ declare function rowToAdvisory(row: Record<string, unknown>): ActionableAdvisory;
2281
+ /**
2282
+ * Query the open advisory set for an app. Pulls from
2283
+ * `actionable_advisories_v` (per-(app_id, code) rollup with stable ids
2284
+ * + server-side auto-resolution).
2285
+ *
2286
+ * Default behavior (no status filter): returns only `status='open'`.
2287
+ * Pass `status: 'all'` to see resolved + open together — useful for
2288
+ * Admin UIs that show "recently fixed" badges.
2289
+ *
2290
+ * Fetch failures bubble out as thrown Errors. (`markAdvisoryResolved`
2291
+ * uses the ok/reason envelope; this read path throws to match
2292
+ * existing kgauto query semantics where the consumer can decide to
2293
+ * retry or render an error state.)
2294
+ */
2295
+ declare function getActionableAdvisories(opts: GetActionableAdvisoriesOptions): Promise<ActionableAdvisory[]>;
2296
+ /**
2297
+ * Mark an advisory as consumer-resolved.
2298
+ *
2299
+ * Lookup strategy:
2300
+ * 1. Query `actionable_advisories_v?id=eq.<id>` to find the (app_id, code)
2301
+ * tuple for this advisory.
2302
+ * 2. PATCH EVERY unresolved firing in `compile_outcome_advisories`
2303
+ * matching that tuple via the underlying outcome's app_id. (One call
2304
+ * closes the whole rollup — the alpha.71-era docblock said "latest
2305
+ * firing", which was never what the code did; corrected alpha.78.)
2306
+ *
2307
+ * The (app_id, code) lookup is necessary because `compile_outcome_advisories`
2308
+ * has no `app_id` column — it inherits scope via the FK to compile_outcomes.
2309
+ * PostgREST cannot PATCH with a JOIN predicate, so the markAdvisoryResolved
2310
+ * path is a two-step round-trip. The cost is one extra GET per resolve call;
2311
+ * acceptable because marks are low-frequency operator actions, not per-call
2312
+ * hot path.
2313
+ *
2314
+ * alpha.78 envelope (PB `resolve-envelope-cannot-close-a-rollup`, 2026-07-25):
2315
+ * the return now reports WHAT HAPPENED, not that the request was received —
2316
+ * `firingsResolved` is the count of rows this call actually flipped, and
2317
+ * `status` is the rollup's state after the write. PB measured the old
2318
+ * `ok: true` live against prod: the PATCH was being RLS-filtered to zero
2319
+ * rows (consumer JWTs had read-grant but no update-grant — migration 049
2320
+ * adds it) and the envelope reported success anyway. "When an API can
2321
+ * succeed without doing anything, the return value should distinguish those
2322
+ * cases" — this is that distinction. `firingsResolved: 0, status: 'open'`
2323
+ * on a rollup you expected to close now points at the write grant.
2324
+ *
2325
+ * Idempotent re-marks stay ok: an already-resolved advisory returns
2326
+ * `{ ok: true, firingsResolved: 0, status: 'resolved' }`.
2327
+ *
2328
+ * Returns ok/reason envelope (vs throwing) because consumer Admin UIs
2329
+ * typically want to render the failure inline rather than crash.
2330
+ */
2331
+ declare function markAdvisoryResolved(opts: MarkAdvisoryResolvedOptions): Promise<{
2332
+ ok: true;
2333
+ firingsResolved: number;
2334
+ status: 'open' | 'resolved' | 'unknown';
2335
+ } | {
2336
+ ok: false;
2337
+ reason: string;
2338
+ }>;
2339
+ /**
2340
+ * Resolution sources supported by the alpha.39 `markExclusionFindingHandled`
2341
+ * API. Mirrors the subset of `exclusion_findings.resolution_source` CHECK
2342
+ * constraint values that consumers can self-set:
2343
+ *
2344
+ * - `'consumer-marked'` — generic "we've handled this; stop reminding."
2345
+ * Use this for "we evaluated and chose not to act" or "we'll act when
2346
+ * ready but acknowledge the finding now."
2347
+ * - `'declined'` — explicit "this exclusion is intentional; do not surface
2348
+ * again." Stronger signal than consumer-marked; useful for compliance
2349
+ * exclusions, brand-promise exclusions, etc.
2350
+ * - `'probed-unblock'` — alpha.40+ probe-path verdict: consumer ran a live
2351
+ * probe and decided to unblock the excluded model. Library accepts the
2352
+ * value today so the probe path doesn't need a follow-up API release.
2353
+ * - `'probed-stay-excluded'` — alpha.40+ probe-path verdict: consumer
2354
+ * probed and confirmed the exclusion. Same forward-compat shape as
2355
+ * `'probed-unblock'`.
2356
+ *
2357
+ * The `'auto'` resolution_source is NOT exposed here — that's reserved
2358
+ * for the brain's own automatic resolution (e.g. when the detection
2359
+ * conditions no longer hold). Consumer code sets only the four values
2360
+ * above.
2361
+ */
2362
+ type ExclusionResolutionSource = 'consumer-marked' | 'declined' | 'probed-unblock' | 'probed-stay-excluded';
2363
+ interface MarkExclusionFindingHandledOptions {
2364
+ /** App id the finding belongs to. Required (RLS scopes writes by this). */
2365
+ appId: string;
2366
+ /** Archetype the finding applies to (e.g. 'hunt', 'classify'). */
2367
+ archetype: string;
2368
+ /** Canonical model id that the consumer had excluded. */
2369
+ excludedModel: string;
2370
+ /** Resolution semantics — see `ExclusionResolutionSource` for the four
2371
+ * values consumers can set. */
2372
+ resolution: ExclusionResolutionSource;
2373
+ /** Optional free-form note explaining the decision. Surfaces in operator
2374
+ * digests + dashboards alongside the resolution_source. */
2375
+ resolutionNote?: string;
2376
+ /** Brain Supabase URL base (e.g. `https://<project>.supabase.co`). The
2377
+ * function appends `/rest/v1/exclusion_findings?...`.
2378
+ * alpha.78: defaults from `readBrainReadEnv()` when omitted. */
2379
+ brainEndpoint?: string;
2380
+ /** Consumer-scoped JWT carrying the `app_id` claim. The brain's RLS
2381
+ * policy enforces that the JWT's app_id matches the finding's app_id;
2382
+ * cross-tenant writes fail at the database layer regardless of input.
2383
+ * alpha.78: defaults from `readBrainReadEnv()` when omitted. */
2384
+ brainJwt?: string;
2385
+ /** Supabase anon key for the `apikey` header (PostgREST requires it).
2386
+ * alpha.78: defaults from `readBrainReadEnv()` when omitted. */
2387
+ brainAnonKey?: string;
2388
+ /** Injected fetch for tests. Defaults to global fetch. */
2389
+ fetch?: typeof fetch;
2390
+ }
2391
+ /**
2392
+ * Mark a stale-exclusion finding as handled. Returns an `ok/reason` envelope
2393
+ * matching `markAdvisoryResolved` — consumer Admin UIs typically render the
2394
+ * failure inline rather than crash.
2395
+ *
2396
+ * Idempotent: if no row matches the (app_id, archetype, excludedModel)
2397
+ * tuple (already resolved, never existed, cron not yet UPSERTed), PostgREST
2398
+ * returns 200 with zero affected rows and we return `{ ok: true }`. The
2399
+ * caller's "I marked it as handled" intent is satisfied regardless of
2400
+ * whether the row was already in that state.
2401
+ *
2402
+ * Reasons surfaced on failure:
2403
+ * - `app_id_required` / `archetype_required` / `excluded_model_required`
2404
+ * - `resolution_invalid` — `resolution` not one of the four documented values
2405
+ * - `brain_auth_misconfig` — 401/403 (JWT / anon key wrong)
2406
+ * - `brain_unavailable` — 5xx
2407
+ * - `network_error:<message>` — fetch threw
2408
+ * - `patch_failed:<status>` — anything else non-2xx
2409
+ */
2410
+ declare function markExclusionFindingHandled(opts: MarkExclusionFindingHandledOptions): Promise<{
2411
+ ok: true;
2412
+ } | {
2413
+ ok: false;
2414
+ reason: string;
2415
+ }>;
2416
+
2417
+ /**
2418
+ * Archetype-cliff compatibility — alpha.28 (tt-intel-Cairn ratified).
2419
+ *
2420
+ * One question, one answer: *given this model and this intent, can it work
2421
+ * — and if not, what adapter (if any) would make it work?*
2422
+ *
2423
+ * Replaces the silent-archetype-cliff failure mode where a consumer picks a
2424
+ * model that's structurally wrong for the intent and kgauto compiles cleanly
2425
+ * without surfacing the gap. The triggering incident: tt-intel shipped
2426
+ * `deepseek-v4-pro` as the hunt default per a local spec; the kgauto coord
2427
+ * doc said L-040 — V4 is structurally wrong for hunt (sequential tools).
2428
+ * `archetypePerf.hunt = 4` was already in the profile data. The compiler
2429
+ * stayed silent. This API + the matching advisor rule surfaces it.
2430
+ *
2431
+ * Pure function. No network. No brain query. No side effects. ~1ms.
2432
+ *
2433
+ * Consultation doc:
2434
+ * command-center/advisory/kgauto/2026-05-21_archetype-cliff-advisor.md
2435
+ *
2436
+ * Refinements applied per tt-intel-Cairn ratification (2026-05-21):
2437
+ * R1: every variant carries `archetypePerf: number` (raw score) — and
2438
+ * `requires-adapter` adds `archetypePerfWithAdapter: number` so
2439
+ * consumer policy can be expressed as "accept adapter only when score
2440
+ * crosses some threshold WITH the adapter on."
2441
+ * R2: every variant carries a plain-English `reason: string`. No internal
2442
+ * jargon ("L-040", "archetypePerf=4") — the consumer chooses whether
2443
+ * to render it as UI hint or operator-tooling tooltip.
2444
+ * R3: `Adapter` is a CLOSED discriminated union, not `| string`. alpha.28
2445
+ * ships ONE variant (`toolOrchestration: 'sequential'`). Future
2446
+ * adapter parameters extend the union explicitly in named releases.
2447
+ * NO escape hatch — the whole point is catching "I added a new
2448
+ * adapter and forgot to update consumer policy" at compile time.
2449
+ */
2450
+
2451
+ /**
2452
+ * Minimum `archetypePerf[archetype]` score to count as `compatible` under
2453
+ * Option A (default policy). Below this, a documented adapter is needed
2454
+ * to lift the model above the floor; if no adapter exists, the model is
2455
+ * rejected.
2456
+ *
2457
+ * Matches `QUALITY_FLOOR_FOR_RECOMMENDATION` in `advisor.ts` — kgauto's
2458
+ * library-wide convention for "below this score, swap recommendations stop."
2459
+ */
2460
+ declare const ARCHETYPE_FLOOR_DEFAULT = 6;
2461
+ /**
2462
+ * Absolute floor — below this, the cliff is too steep for ANY adapter to
2463
+ * lift cleanly. Reserved under Option A (unused today; every below-floor
2464
+ * case is gated by adapter availability). Would gate `reject` vs
2465
+ * `requires-adapter` under a future Option B per consultation doc Q1.
2466
+ *
2467
+ * Exported so consumer-side policy can read it (e.g. "accept adapter only
2468
+ * when archetypePerf >= ABSOLUTE_FLOOR + 1"). Not used internally by
2469
+ * `getModelCompatibility` today — the gate is "does an adapter exist for
2470
+ * this cliff?", not score-based.
2471
+ */
2472
+ declare const ABSOLUTE_FLOOR = 4;
2473
+ /**
2474
+ * The intent the call is expressing — archetype + optional orchestration
2475
+ * mode. Same shape as `ir.intent.archetype` + `ir.constraints.toolOrchestration`
2476
+ * so a consumer can pass `{ archetype: ir.intent.archetype,
2477
+ * toolOrchestration: ir.constraints?.toolOrchestration }` directly.
2478
+ */
2479
+ interface CompatibilityIntent {
2480
+ archetype: IntentArchetypeName;
2481
+ toolOrchestration?: 'parallel' | 'sequential' | 'either';
2482
+ }
2483
+ /**
2484
+ * `Adapter` — re-exported above. Canonical definition lives in `ir.ts` to
2485
+ * avoid an import cycle (compatibility.ts → profiles.ts → ir.ts).
2486
+ *
2487
+ * **CLOSED discriminated union per R3.** Future adapter parameters extend
2488
+ * the union explicitly in named alpha releases. No `| string` escape hatch
2489
+ * — consumer policy code SHOULD write exhaustive `switch (adapter.parameter)`
2490
+ * and rely on the compiler to flag "I added a new adapter parameter and
2491
+ * forgot to update the consumer's policy."
2492
+ *
2493
+ * alpha.28 variants:
2494
+ * - `{ parameter: 'toolOrchestration'; value: 'sequential'; consequence }`
2495
+ * Lifts DeepSeek V4-family on `hunt` from sequential-tool cliff (L-040).
2496
+ * The "consequence" plain-English-ifies the trade-off:
2497
+ * "Tool calls run one at a time — slower but reliable."
2498
+ *
2499
+ * alpha.29+ likely additions (per tt-intel-Cairn priority list):
2500
+ * - `{ parameter: 'parallelToolCalls'; value: false; consequence }`
2501
+ * - `{ parameter: 'maxTools'; value: number; consequence }`
2502
+ * - `{ parameter: 'thinkingBudget'; value: 0; consequence }`
2503
+ *
2504
+ * Each new variant lands in its own named release with the union extended
2505
+ * in `ir.ts`. Consumers see the change at compile time.
2506
+ */
2507
+ /**
2508
+ * The compatibility verdict for a (model, intent) pair. Discriminated union
2509
+ * on `status` — `compatible` | `requires-adapter` | `reject`.
2510
+ *
2511
+ * **Every variant carries `archetypePerf` (R1) + `reason` (R2):**
2512
+ * - `archetypePerf` — the raw 0-10 score for (model, archetype). Lets
2513
+ * consumers build their own thresholds without re-importing the profile
2514
+ * registry.
2515
+ * - `reason` — plain-English, consumer-renderable. NOT internal jargon
2516
+ * like "L-040 cliff" or "archetypePerf=4". Examples in R2 ratification:
2517
+ * - compatible: "Suited for hunt-style parallel discovery."
2518
+ * - requires-adapter: "Best with sequential tool calls for hunt — slower but works."
2519
+ * - reject: "Not suited for hunt — would underperform significantly."
2520
+ *
2521
+ * `requires-adapter` additionally carries:
2522
+ * - `archetypePerfWithAdapter` — estimated post-adapter score. May be an
2523
+ * estimate (we don't measure post-adapter scores yet); kgauto's prior is
2524
+ * "adapter lifts to ARCHETYPE_FLOOR_DEFAULT + 1" unless brain-evidenced.
2525
+ * - `adapter` — the closed-union variant describing the structural change.
2526
+ *
2527
+ * Backward-compat: an unknown model returns `reject` with a "model not
2528
+ * registered" reason; callers never throw. Unknown archetype is impossible
2529
+ * at the type level (`IntentArchetypeName` is a closed union).
2530
+ */
2531
+ type ModelCompatibility = {
2532
+ status: 'compatible';
2533
+ reason: string;
2534
+ archetypePerf: number;
2535
+ } | {
2536
+ status: 'requires-adapter';
2537
+ reason: string;
2538
+ archetypePerf: number;
2539
+ archetypePerfWithAdapter: number;
2540
+ adapter: Adapter;
2541
+ } | {
2542
+ status: 'reject';
2543
+ reason: string;
2544
+ archetypePerf: number;
2545
+ };
2546
+ /**
2547
+ * Compatibility query — *does this model fit this intent, and if not,
2548
+ * what would?*
2549
+ *
2550
+ * **Rules (Option A from consultation doc Q1):**
2551
+ * 1. If model is unregistered → `reject` with "model not registered" reason.
2552
+ * 2. If intent provides `toolOrchestration: 'sequential'` AND that adapter
2553
+ * silences the cliff (because the cliff IS the sequential-tool one)
2554
+ * → return `compatible` with raw score (NOT the post-adapter estimate
2555
+ * — caller already paid the adapter, score reflects reality).
2556
+ * 3. If raw `archetypePerf[archetype] >= ARCHETYPE_FLOOR_DEFAULT`
2557
+ * → `compatible`.
2558
+ * 4. If below floor BUT a documented adapter exists that lifts to floor
2559
+ * → `requires-adapter` with adapter + estimated post-adapter score.
2560
+ * 5. If below floor AND no adapter exists → `reject`.
2561
+ *
2562
+ * **Pure function.** Deterministic for `(modelId, intent)`. No I/O.
2563
+ *
2564
+ * @example
2565
+ * ```ts
2566
+ * import { getModelCompatibility } from '@warmdrift/kgauto-compiler';
2567
+ *
2568
+ * const c = getModelCompatibility('deepseek-v4-pro', { archetype: 'hunt' });
2569
+ * // → { status: 'requires-adapter',
2570
+ * // reason: 'Best with sequential tool calls for hunt — slower but works.',
2571
+ * // archetypePerf: 4,
2572
+ * // archetypePerfWithAdapter: 7,
2573
+ * // adapter: {
2574
+ * // parameter: 'toolOrchestration',
2575
+ * // value: 'sequential',
2576
+ * // consequence: 'Tool calls run one at a time...'
2577
+ * // } }
2578
+ *
2579
+ * // With the adapter already declared:
2580
+ * const c2 = getModelCompatibility('deepseek-v4-pro', {
2581
+ * archetype: 'hunt',
2582
+ * toolOrchestration: 'sequential',
2583
+ * });
2584
+ * // → { status: 'compatible',
2585
+ * // reason: 'Suited for hunt with sequential tool calls.',
2586
+ * // archetypePerf: 4 }
2587
+ * ```
2588
+ */
2589
+ declare function getModelCompatibility(modelId: string, intent: CompatibilityIntent): ModelCompatibility;
2590
+
2591
+ /**
2592
+ * alpha.22 — sync introspection: is brain-query mode active for a given
2593
+ * table? Used by the advisor (`model-stale-evidence` rule) to decide
2594
+ * whether a `judgment`-grounded chosen model is a measurement gap worth
2595
+ * surfacing. Returns false on cold start, when configureBrain() was never
2596
+ * called, or when the consumer explicitly opted the table out via
2597
+ * `BrainConfig.brainQuery.<table> = false`.
2598
+ */
2599
+ declare function isBrainQueryActiveFor(table: string): boolean;
2600
+ interface GetPerAxisMetricsOpts {
2601
+ /** App id to filter on. Required. */
2602
+ appId: string;
2603
+ /** Intent archetype to filter on. Required. */
2604
+ archetype: string;
2605
+ /** Canonical model id to filter on. Required. */
2606
+ model: string;
2607
+ /**
2608
+ * Window in days. Default 30. Only rows with
2609
+ * `created_at > now() - windowDays` are counted.
2610
+ */
2611
+ windowDays?: number;
2612
+ /**
2613
+ * Consumer-declared quality floor (0..1 oracle/approve-rate scale).
2614
+ * When set, the response's `qualityFloorMet` is true/false; when omitted,
2615
+ * `qualityFloorMet` is null (no floor declared, no judgment).
2616
+ */
2617
+ qualityFloor?: number;
2618
+ /** Pluggable fetch (tests inject mock). Defaults to global fetch. */
2619
+ fetch?: typeof fetch;
2620
+ /**
2621
+ * PostgREST base endpoint (e.g. `https://kgauto-brain.vercel.app/api`).
2622
+ * When omitted, falls back to the active configureBrainQuery runtime's
2623
+ * endpoint. Returns null when neither is set.
2624
+ */
2625
+ endpoint?: string;
2626
+ /** Bearer token. Forwarded as `Authorization: Bearer ${apiKey}`. */
2627
+ apiKey?: string;
2628
+ }
2629
+ /**
2630
+ * Call the `get_per_axis_metrics` RPC and return the typed result.
2631
+ *
2632
+ * Returns null when:
2633
+ * - no endpoint provided AND no configureBrainQuery runtime active
2634
+ * - RPC returns empty / null / unexpected shape
2635
+ * - brain unreachable / fetch throws / HTTP error
2636
+ *
2637
+ * Never throws — operator-facing query, must not blow up the caller.
2638
+ */
2639
+ declare function getPerAxisMetrics(opts: GetPerAxisMetricsOpts): Promise<PerAxisMetrics | null>;
2640
+
2641
+ /**
2642
+ * env.ts — provider env-key resolution + reachability predicates.
2643
+ *
2644
+ * Centralizes the per-provider env var names that kgauto checks for
2645
+ * reachability. Used by:
2646
+ *
2647
+ * - execute.ts — to find an API key when one isn't passed via apiKeys
2648
+ * - call.ts — to auto-filter unreachable models from the fallback walk
2649
+ * - getDefaultFallbackChain — opt-in chain filter when consumer passes `reachability`
2650
+ * - operator scripts — getReachabilityDiagnostic() prints what's wired up
2651
+ *
2652
+ * Keeping the map in ONE place means execute() and the reachability check
2653
+ * always agree. Without this, kgauto could declare a model "reachable" because
2654
+ * env.ts found GOOGLE_GENERATIVE_AI_API_KEY, while execute() looks at
2655
+ * GOOGLE_API_KEY only and 401s — shipping the bug we're trying to fix.
2656
+ *
2657
+ * Resolution order (apiKeys takes precedence):
2658
+ * 1. opts.apiKeys?.[provider]
2659
+ * 2. process.env[name] for each name in PROVIDER_ENV_KEYS[provider] (first-present wins)
2660
+ *
2661
+ * alpha.10 (2026-05-14). Resolves the auto-filter-unreachable-models-silently
2662
+ * request from PB after first-deploy 401 on the alpha.9 summarize chain.
2663
+ */
2664
+
2665
+ /**
2666
+ * Providers kgauto can resolve keys for today. Subset of `Provider` — `mistral`
2667
+ * and `xai` are declared in the type union but not yet executable (no profiles,
2668
+ * no execute() handler, no env-var convention). Narrowing here keeps the
2669
+ * reachability check structurally honest.
2670
+ */
2671
+ type SupportedProvider = 'anthropic' | 'google' | 'openai' | 'deepseek' | 'zai' | 'moonshot';
2672
+ /**
2673
+ * Per-provider env var names kgauto recognizes. Order doesn't matter —
2674
+ * first-present wins. Multiple names per provider supported because Google
2675
+ * has historical drift (`GOOGLE_API_KEY` from older Google Cloud SDKs,
2676
+ * `GEMINI_API_KEY` in many examples, `GOOGLE_GENERATIVE_AI_API_KEY` is the
2677
+ * Vercel AI SDK convention used by IC + tt-intel adapters).
2678
+ *
2679
+ * Frozen so consumers/tests can't mutate (would break the cache invariant
2680
+ * that execute() and reachability checks agree).
2681
+ */
2682
+ declare const PROVIDER_ENV_KEYS: Readonly<Record<SupportedProvider, readonly string[]>>;
2683
+ interface ReachabilityOpts {
2684
+ /** Explicit keys (alpha.3 ApiKeys). Checked first; takes precedence over env. */
2685
+ apiKeys?: ApiKeys;
2686
+ /**
2687
+ * Override env source. Defaults to `process.env` in Node-shaped runtimes,
2688
+ * `{}` everywhere else. Pass `{}` explicitly in tests for hermetic runs.
2689
+ */
2690
+ envSource?: Record<string, string | undefined>;
2691
+ }
2692
+ /**
2693
+ * Resolve a usable API key for the provider. Returns the key string, or
2694
+ * undefined if neither apiKeys nor any of the env names are set.
2695
+ *
2696
+ * Used internally by execute.ts so the reachability check and the actual
2697
+ * call check stay in sync.
2698
+ */
2699
+ declare function resolveProviderKey(provider: Provider, opts?: ReachabilityOpts): string | undefined;
2700
+ /**
2701
+ * True iff the provider has a usable key — either via explicit `apiKeys`
2702
+ * or one of the `PROVIDER_ENV_KEYS[provider]` names is set in envSource.
2703
+ */
2704
+ declare function isProviderReachable(provider: Provider, opts?: ReachabilityOpts): boolean;
2705
+ /**
2706
+ * True iff the model's profile exists AND its provider is reachable.
2707
+ * Unknown model id returns false (treat as unreachable; the chain walker
2708
+ * will surface "no reachable models" if everything filters out).
2709
+ */
2710
+ declare function isModelReachable(modelId: string, opts?: ReachabilityOpts): boolean;
2711
+ interface ProviderReachability {
2712
+ reachable: boolean;
2713
+ /** How the key was found. `null` when unreachable. */
2714
+ via: 'apiKeys' | 'env' | null;
2715
+ /** Which env var name supplied the key (only when via === 'env'). */
2716
+ envKeyFound?: string;
2717
+ }
2718
+ /**
2719
+ * Snapshot of which providers are reachable from the current env / apiKeys.
2720
+ * Useful for operator scripts ("kgauto diagnose"), startup-time logging,
2721
+ * and the cost-watcher's "which consumer is missing what" report.
2722
+ *
2723
+ * Does NOT log the key value itself — only the env var name that supplied it.
2724
+ */
2725
+ declare function getReachabilityDiagnostic(opts?: ReachabilityOpts): Record<SupportedProvider, ProviderReachability>;
2726
+ /**
2727
+ * Brain-read env contract — canonical names + accepted fallbacks for the
2728
+ * env vars kgauto's brain-read APIs need.
2729
+ *
2730
+ * Affected APIs: `getActionableAdvisories`, `markAdvisoryResolved`,
2731
+ * `markExclusionFindingHandled`, `markPromoteReadyHandled`,
2732
+ * `getStaleExclusionFindings`, and future brain-read surfaces. Each accepts
2733
+ * `brainEndpoint`/`brainJwt`/`brainAnonKey` as call-site arguments; this
2734
+ * helper centralizes resolution from the consumer's environment.
2735
+ *
2736
+ * Resolution order (first-truthy-trimmed wins):
2737
+ * endpoint = KGAUTO_V2_BRAIN_SUPABASE_URL ?? KGAUTO_V2_BRAIN_URL
2738
+ * jwt = KGAUTO_V2_BRAIN_JWT ?? GLASSBOX_BRAIN_JWT
2739
+ * anonKey = KGAUTO_V2_BRAIN_ANON_KEY (no fallback)
2740
+ *
2741
+ * Why fallbacks exist:
2742
+ *
2743
+ * 1. Pre-alpha.42, some consumers set `KGAUTO_V2_BRAIN_URL` pointing at
2744
+ * the kgauto-dashboard URL (write target). The canonical
2745
+ * `KGAUTO_V2_BRAIN_SUPABASE_URL` is the Supabase project URL (read
2746
+ * target — PostgREST against `/rest/v1/`). Until consumers split the
2747
+ * two names, the fallback grabs whichever URL is set. When BOTH are
2748
+ * set, canonical wins (the consumer has explicitly split).
2749
+ *
2750
+ * 2. The s33 Glass-Box ship provisioned `GLASSBOX_BRAIN_JWT` across all
2751
+ * consumers with the same `app_id` claim shape, signed by the same
2752
+ * JWT_SECRET. Reusing it for brain-read avoids re-minting + re-pasting
2753
+ * a second JWT per consumer per surface.
2754
+ *
2755
+ * `missingEnv` lists the CANONICAL names that aren't satisfied by either
2756
+ * canonical OR fallback. Consumer policy: if `missingEnv.length > 0`,
2757
+ * render `not_configured`; otherwise pass `endpoint`/`jwt`/`anonKey` to
2758
+ * `getActionableAdvisories({ ... })` et al.
2759
+ *
2760
+ * Pre-trim semantics carry from `readKeyValue` — paste-newline-trap
2761
+ * (L-060 / L-083 / L-108) closure extends to brain env vars.
2762
+ *
2763
+ * Filed by tt-intel-Cairn (s89, 2026-05-27) after the s89 actionable-
2764
+ * advisories ref template hit `malformed brain response` on prod because
2765
+ * the endpoint env var pointed at the kgauto-dashboard URL instead of the
2766
+ * Supabase URL, AND because IC's ref template used a third env name
2767
+ * (`KGAUTO_V2_BRAIN_ENDPOINT`) that was unset. Three distinct name shapes
2768
+ * across two consumers — the durable closure is one canonical contract.
2769
+ */
2770
+ interface BrainReadEnv {
2771
+ /** Supabase project URL (PostgREST base). Undefined when neither canonical nor fallback is set. */
2772
+ endpoint?: string;
2773
+ /** JWT carrying `app_id` claim, signed by brain JWT_SECRET. Undefined when neither canonical nor fallback is set. */
2774
+ jwt?: string;
2775
+ /** Supabase anon (publishable) key. Undefined when not set. */
2776
+ anonKey?: string;
2777
+ /**
2778
+ * Canonical names not satisfied by either canonical OR fallback. Subset
2779
+ * (in order) of:
2780
+ * ['KGAUTO_V2_BRAIN_SUPABASE_URL', 'KGAUTO_V2_BRAIN_JWT', 'KGAUTO_V2_BRAIN_ANON_KEY']
2781
+ * Consumer policy: render `not_configured` when length > 0.
2782
+ */
2783
+ missingEnv: string[];
2784
+ }
2785
+ /**
2786
+ * alpha.78 (PB adoption-gap ask 2) — the canonical brain-read env names as
2787
+ * an exported constant, so consumers reference them instead of retyping
2788
+ * (PB invented three plausible-but-wrong names and carried the resulting
2789
+ * self-authored 503 for two months).
2790
+ */
2791
+ declare const BRAIN_READ_ENV_NAMES: {
2792
+ readonly endpoint: "KGAUTO_V2_BRAIN_SUPABASE_URL";
2793
+ readonly jwt: "KGAUTO_V2_BRAIN_JWT";
2794
+ readonly anonKey: "KGAUTO_V2_BRAIN_ANON_KEY";
2795
+ /** Accepted fallbacks, in resolution order after the canonical name. */
2796
+ readonly fallbacks: {
2797
+ readonly endpoint: readonly ["KGAUTO_V2_BRAIN_URL"];
2798
+ readonly jwt: readonly ["GLASSBOX_BRAIN_JWT"];
2799
+ readonly anonKey: readonly [];
2800
+ };
2801
+ };
2802
+ /**
2803
+ * Resolve brain-read env vars. Defaults to `process.env`; pass `envSource`
2804
+ * for hermetic tests. Trims surrounding whitespace and treats
2805
+ * empty-after-trim as unset (same shape as `resolveProviderKey`).
2806
+ */
2807
+ declare function readBrainReadEnv(envSource?: Record<string, string | undefined>): BrainReadEnv;
2808
+
2809
+ /**
2810
+ * getDefaultFallbackChain — the alpha.9 cascading ship.
2811
+ *
2812
+ * Returns a per-archetype fallback chain that walks the cost/performance
2813
+ * Pareto frontier (master plan §1.3 + §3). Three customer postures:
2814
+ *
2815
+ * locked — caller passes [theOneModel]; never call this function
2816
+ * preferred — caller passes `primary`; chain returned is [primary, ...fallbacks]
2817
+ * open — caller passes no `primary`; chain returned is [best, ...fallbacks]
2818
+ *
2819
+ * ## What the default chain optimizes for — READ THIS BEFORE CITING IT
2820
+ *
2821
+ * The default (`optimizeFor: 'quality'`) chain is ordered by **archetype
2822
+ * performance with provider diversity**, NOT by cost. It is a reliability
2823
+ * ladder: "if tier 0 fails, who else can do this job well."
2824
+ *
2825
+ * This docstring previously claimed each step "costs strictly less than the
2826
+ * previous." **That claim was false for all ten archetypes** (verified
2827
+ * 2026-07-29, alpha.80) and it was load-bearing — kgauto's own cost
2828
+ * advisories cited `posture: 'open'` as a cost remedy on the strength of it.
2829
+ * At the time, `ask` open posture led with `claude-sonnet-4-6` (retargeted
2830
+ * to `claude-sonnet-5` in alpha.90) at ~8.6x the cost
2831
+ * of the model the cost advisories recommend. tt-intel came within one
2832
+ * un-run function call of tripling their hottest path's spend by following
2833
+ * kgauto's own documented advice. See
2834
+ * `advisory/kgauto/from-tt-intelligence/2026-07-28_chain-builder-and-cost-advisories-give-opposite-answers.md`.
2835
+ *
2836
+ * Some non-monotone steps are deliberate and correct: `plan` walks UP to
2837
+ * Opus on 429, `critique`/`judge` never degrade below a reasoning floor,
2838
+ * and cross-provider anchors are chosen for outage-independence rather
2839
+ * than price. The defect was the unconditional claim, not the chains.
2840
+ *
2841
+ * The default chain at each step:
2842
+ * 1. Comes from a different provider than the previous step where possible
2843
+ * (correlated outages don't kill consecutive attempts)
2844
+ * 2. Stays above the archetype's perf floor (skip models scored <baseline
2845
+ * for archetypes where degradation would be unacceptable)
2846
+ * 3. Makes NO cost guarantee. Pass `optimizeFor: 'cost'` when cost order
2847
+ * is what you want — that mode DOES guarantee monotone-cheaper, and
2848
+ * `assertChainCostMonotonicity` pins it.
2849
+ *
2850
+ * In alpha.9 the chain is **hand-curated** per archetype (§3.3 starter
2851
+ * table). Brain-query mode lands in alpha.10. Policy.blockedModels filters
2852
+ * the result; policy.maxCostPerCallUsd is NOT applied here because the
2853
+ * function doesn't see the IR's token counts — that filtering happens at
2854
+ * `passScoreTargets()` time inside compile().
2855
+ *
2856
+ * The function is **pure** — no brain query, no I/O, no randomness. Same
2857
+ * inputs always produce the same chain.
2858
+ */
2859
+
2860
+ /**
2861
+ * Posture passed into `getDefaultFallbackChain`. The chain function only
2862
+ * sees `'open'` and `'preferred'` — callers in `'locked'` posture should
2863
+ * pass `models: [theOneModel]` directly and skip this function entirely.
2864
+ *
2865
+ * Equivalent to `CompilePolicy.posture` minus `'locked'`. Kept distinct so
2866
+ * the type system enforces "don't ask for a chain when you don't want one."
2867
+ */
2868
+ type FallbackPosture = 'open' | 'preferred';
2869
+ interface GetDefaultFallbackChainOpts {
2870
+ /** The archetype the call is performing. Drives chain shape. */
2871
+ archetype: IntentArchetypeName;
2872
+ /**
2873
+ * The user-selected or caller-anchored primary model. When provided, it
2874
+ * appears at position 0 of the returned chain and fallbacks follow.
2875
+ * When omitted, the function picks the best-perf model for the archetype
2876
+ * as position 0 (open posture).
2877
+ */
2878
+ primary?: string;
2879
+ /**
2880
+ * Informational. `'preferred'` and `'open'` produce the same chain shape
2881
+ * given the same `primary`/no-primary input — posture is a tag the brain
2882
+ * uses to distinguish "user-anchored" from "library-anchored" telemetry.
2883
+ */
2884
+ posture?: FallbackPosture;
2885
+ /**
2886
+ * Cap on chain length. Default 3. Min 1. Useful when the consumer wants
2887
+ * to keep the worst-case latency low (each fallback adds a round-trip).
2888
+ */
2889
+ maxDepth?: number;
2890
+ /**
2891
+ * Consumer-side gating. `blockedModels` are filtered from the chain.
2892
+ * `preferredModels` is informational (no boost applied at this layer —
2893
+ * compile()'s `passScoreTargets` handles preference ranking).
2894
+ * `maxCostPerCallUsd` is NOT applied here — needs IR-level token
2895
+ * estimation. Use compile()'s policy plumbing instead.
2896
+ */
2897
+ policy?: CompilePolicy;
2898
+ /**
2899
+ * alpha.10. When provided, the chain is filtered to models whose provider
2900
+ * has a reachable API key (via `apiKeys` or one of `PROVIDER_ENV_KEYS[provider]`).
2901
+ * Models whose provider can't be reached are silently dropped. If filtering
2902
+ * leaves the chain empty, returns `[]` — caller decides what to do (call()
2903
+ * throws CallError; this function stays pure).
2904
+ *
2905
+ * Pass `{}` to opt in with `process.env` as the env source. Pass `{ apiKeys, envSource }`
2906
+ * for explicit control (tests, non-Node runtimes). Omit entirely for the
2907
+ * legacy unfiltered behavior — preserves alpha.9 callers byte-for-byte.
2908
+ */
2909
+ reachability?: ReachabilityOpts;
2910
+ /**
2911
+ * alpha.20 E3: consumer-declared tool-orchestration shape. Currently
2912
+ * only affects `archetype: 'hunt'`, where 'sequential' swaps the
2913
+ * parallel-tool-tier-0 chain (Flash → Pro → Sonnet → Haiku) for a
2914
+ * DeepSeek-tier-0 chain (V4-Pro → Flash → Sonnet) — DeepSeek's L-040
2915
+ * parallel-tool cliff doesn't apply when the consumer commits to
2916
+ * single-step orchestration.
2917
+ *
2918
+ * Other archetypes are NOT mode-aware in this release — they ship the
2919
+ * same chain regardless of toolOrchestration. Future versions may
2920
+ * extend mode-awareness to ask/generate/etc. when brain evidence
2921
+ * supports it.
2922
+ *
2923
+ * Default (omitted or 'either'): parallel chain. Back-compat with all
2924
+ * pre-alpha.20 callers.
2925
+ */
2926
+ toolOrchestration?: 'parallel' | 'sequential' | 'either';
2927
+ /**
2928
+ * alpha.80 — what the chain ORDER optimizes for.
2929
+ *
2930
+ * 'quality' (default) — status quo, byte-for-byte. Hand-curated /
2931
+ * brain-loaded archetype ladder: best perf first, provider diversity
2932
+ * down the chain. Makes NO cost guarantee (see module docstring).
2933
+ *
2934
+ * 'cost' — cheapest-first among every `status: 'current'` model whose
2935
+ * `archetypePerf[archetype]` clears {@link ARCHETYPE_FLOOR_DEFAULT}.
2936
+ * Guarantees monotone-cheaper. Considers the WHOLE roster, not just
2937
+ * the curated chain — which is the point: `gemini-2.5-flash` ties
2938
+ * `claude-haiku-4-5` on `ask` perf at a third of the price and is
2939
+ * absent from the curated `ask` ladder entirely.
2940
+ *
2941
+ * The quality floor is what keeps 'cost' honest: a model with no evidence
2942
+ * scores the neutral 5 and is therefore excluded, so cost mode can never
2943
+ * bottom-feed into unmeasured models. Quality stays a binary floor; cost
2944
+ * optimizes only above it.
2945
+ *
2946
+ * Default 'quality' — existing consumers see zero change on bump.
2947
+ */
2948
+ optimizeFor?: 'quality' | 'cost';
2949
+ }
2950
+ /**
2951
+ * Reference call shape used to RANK models by cost. Deliberately a blend
2952
+ * rather than input-only: ranking by `costInputPer1m` alone (which the
2953
+ * advisor's `cost-mismatched-archetype` rule does) mis-orders any pair
2954
+ * whose output multiple differs, and real traffic runs input-heavy
2955
+ * (L-050: >85% input is the universal efficiency signal).
2956
+ *
2957
+ * This ranks; it does not bill. `estimateChainCostUsd` is exported so
2958
+ * callers who know their real shape can compute against it instead.
2959
+ */
2960
+ declare const COST_RANKING_REFERENCE_SHAPE: {
2961
+ readonly inputTokens: 4000;
2962
+ readonly outputTokens: 250;
2963
+ };
2964
+ /**
2965
+ * Estimated USD for one call at a given shape. Exported so the advisor and
2966
+ * consumer-side code share ONE derivation of "what does this model cost
2967
+ * here" — two independent derivations of one concept will drift (s75).
2968
+ */
2969
+ declare function estimateModelCostUsd(profile: ModelProfile, shape?: {
2970
+ inputTokens: number;
2971
+ outputTokens: number;
2972
+ }): number;
2973
+ /**
2974
+ * @deprecated alpha.81 — renamed to {@link estimateModelCostUsd}; it takes a
2975
+ * single MODEL, not a chain. Preserved because alpha.80 shipped this name and
2976
+ * a consumer adopted it within hours. Identical behavior.
2977
+ */
2978
+ declare const estimateChainCostUsd: typeof estimateModelCostUsd;
2979
+ /**
2980
+ * How many distinct providers a chain spans. `1` means every fallback shares
2981
+ * one provider's fate — the chain buys you retries, not outage independence.
2982
+ * Exported so a cost-mode consumer can check what they traded away.
2983
+ */
2984
+ declare function chainProviderSpread(chain: readonly string[]): number;
2985
+ /**
2986
+ * Returns the fallback chain for an archetype as a plain `string[]` of
2987
+ * model ids.
2988
+ *
2989
+ * @deprecated since alpha.21 — prefer
2990
+ * {@link getDefaultFallbackChainWithGrounding}, which returns the same chain
2991
+ * shape with a `grounding` label on every entry (measured / capability-fact /
2992
+ * judgment). The string[] return is preserved indefinitely for back-compat —
2993
+ * no functional change in alpha.21. Existing callers don't need to migrate
2994
+ * unless they want to surface the grounding gap to users.
2995
+ */
2996
+ declare function getDefaultFallbackChain(opts: GetDefaultFallbackChainOpts): string[];
2997
+ /**
2998
+ * Returns a shallow copy of the hand-curated starter chain for an archetype.
2999
+ * Useful for tests + the `scripts/digest.mjs` operator readout.
3000
+ */
3001
+ declare function getStarterChain(archetype: IntentArchetypeName): string[];
3002
+ /**
3003
+ * Returns a shallow copy of all starter chains keyed by archetype.
3004
+ * Useful for the `digest.mjs` readout and consumer audits.
3005
+ */
3006
+ declare function getAllStarterChains(): Record<IntentArchetypeName, string[]>;
3007
+ /**
3008
+ * alpha.20 E3 introspection — returns the sequential-mode overlay for an
3009
+ * archetype, or `undefined` when no overlay is registered (the archetype
3010
+ * is mode-agnostic and reuses `STARTER_CHAINS[archetype]`).
3011
+ *
3012
+ * Useful for tests + the `scripts/digest.mjs` operator readout to surface
3013
+ * the mode-aware chains.
3014
+ */
3015
+ declare function getSequentialStarterChain(archetype: IntentArchetypeName): string[] | undefined;
3016
+ /**
3017
+ * alpha.21 (s78 Entry 1) — returns the fallback chain as `ChainEntry[]`,
3018
+ * with a `grounding` label on every position.
3019
+ *
3020
+ * Same selection logic as {@link getDefaultFallbackChain} (primary anchoring,
3021
+ * blockedModels filter, dedupe, reachability filter, maxDepth cap) — the
3022
+ * only difference is the return shape: each position is a `ChainEntry`
3023
+ * carrying `{ id, grounding, reason?, n? }` instead of a bare string.
3024
+ *
3025
+ * Use this when surfacing the chain to consumers who care WHY each entry
3026
+ * sits where it sits — Glass-Box panels, operator dashboards, eval
3027
+ * scaffolding deciding which entries deserve measurement priority.
3028
+ *
3029
+ * Returns `[]` when filtering empties the chain (same semantics as the
3030
+ * string variant) — consumer decides what to do.
3031
+ */
3032
+ declare function getDefaultFallbackChainWithGrounding(opts: GetDefaultFallbackChainOpts): ChainEntry[];
3033
+ /**
3034
+ * alpha.21 introspection — returns the grounded starter chain for an
3035
+ * archetype (no primary anchoring, no policy filtering, no maxDepth cap).
3036
+ * Use this when you want the raw, hand-curated grounded chain — every
3037
+ * entry carries a `grounding` label and optional reason/n.
3038
+ */
3039
+ declare function getStarterChainWithGrounding(archetype: IntentArchetypeName): ChainEntry[];
3040
+ /**
3041
+ * alpha.21 introspection — all grounded starter chains keyed by archetype.
3042
+ * Useful for the `digest.mjs` readout and consumer audits that want to
3043
+ * surface the grounding gap across the entire chain table.
3044
+ */
3045
+ declare function getAllStarterChainsWithGrounding(): Record<IntentArchetypeName, ChainEntry[]>;
3046
+ /**
3047
+ * alpha.21 introspection — sequential-mode overlay with grounding labels,
3048
+ * or `undefined` when no overlay is registered for the archetype.
3049
+ */
3050
+ declare function getSequentialStarterChainWithGrounding(archetype: IntentArchetypeName): ChainEntry[] | undefined;
3051
+
3052
+ /**
3053
+ * chains-brain — alpha.11 KG-11 adapter.
3054
+ *
3055
+ * Brain-driven STARTER_CHAINS for `getDefaultFallbackChain`. Reads
3056
+ * `kgauto_chains` table via the shared brain-query SWR cache (D6 + D8);
3057
+ * falls back to bundled STARTER_CHAINS on cold-start, brain-down, or
3058
+ * empty/missing table (D2 + D4).
3059
+ *
3060
+ * Behavioral note (locked via D2): the sync API surface returns bundled on
3061
+ * cold-start, with a background refresh fired. Subsequent calls within the
3062
+ * 5-min TTL return brain data. Vercel cold-start consumers see the seed
3063
+ * snapshot (functionally identical to pre-alpha.11); warm-start consumers
3064
+ * see live brain mutations within 5 min.
3065
+ */
3066
+ /**
3067
+ * Sync reader for the brain-driven chains map. Returns bundled
3068
+ * STARTER_CHAINS when brain-query is disabled, cold, or unreachable.
3069
+ */
3070
+ declare const loadChainsFromBrain: () => Record<"ask" | "hunt" | "classify" | "summarize" | "generate" | "extract" | "plan" | "critique" | "transform" | "judge", string[]>;
3071
+
3072
+ /**
3073
+ * archetype-perf-brain — alpha.11 KG-12 adapter.
3074
+ *
3075
+ * Brain-driven archetypePerf scores. Substrate for the future closed-loop
3076
+ * tuning engine (KG-12.5): brain telemetry → human or automated bumps →
3077
+ * brain UPDATE → consumers see new scores within 5-min cache TTL with
3078
+ * zero refresh.
3079
+ *
3080
+ * Today: data migrates to brain. No runtime call site reads archetypePerf
3081
+ * (it's metadata for the master plan §2.5 anti-hallucination guardrail +
3082
+ * future auto-tuning). The adapter exists so future readers — auto-tuning
3083
+ * + operator scripts + KG-12.5 — have a shipped substrate to consume.
3084
+ */
3085
+
3086
+ type ArchetypePerfMap = Map<string, Partial<Record<IntentArchetypeName, number>>>;
3087
+ /**
3088
+ * alpha.21: per-(model, archetype) row count map. Same shape as
3089
+ * ArchetypePerfMap but stores brain row counts when the brain backs a
3090
+ * placement. Undefined entries → no row count seen → score is the
3091
+ * hand-curated cold-start prior (grounding='judgment').
3092
+ */
3093
+ type ArchetypePerfNMap = Map<string, Partial<Record<IntentArchetypeName, number>>>;
3094
+ /**
3095
+ * Sync reader for the brain-driven archetypePerf map. Returns bundled
3096
+ * profile.archetypePerf data when brain-query is disabled, cold, or
3097
+ * unreachable. Identical shape pre/post-alpha.11 by design (D2).
3098
+ */
3099
+ declare const loadArchetypePerfFromBrain: () => ArchetypePerfMap;
3100
+ /**
3101
+ * alpha.21 — sync reader for the brain row-count map paired with
3102
+ * archetype-perf. Returns empty map (no measured backing) on cold start /
3103
+ * brain-down / unreachable — all `getArchetypePerfScore` calls then
3104
+ * resolve to `grounding: 'judgment'`. When the brain table includes an
3105
+ * `n` column on each row, this map mirrors those counts so consumers can
3106
+ * see how many measurements back each score.
3107
+ */
3108
+ declare const loadArchetypePerfNFromBrain: () => ArchetypePerfNMap;
3109
+ /**
3110
+ * Threshold above which a brain row count counts as 'measured' grounding.
3111
+ * Below this, the score is treated as 'judgment' (cold-start prior or
3112
+ * not-yet-enough-evidence). Mirrors the alpha.20 `getCleanPerfScore`
3113
+ * `minRows` default — same rule for consistency.
3114
+ */
3115
+ declare const MEASURED_GROUNDING_MIN_N = 10;
3116
+ /**
3117
+ * alpha.21 — return shape for the extended {@link getArchetypePerfScore}.
3118
+ * Wraps the existing 0..10 score with:
3119
+ *
3120
+ * - `n`: brain row count backing this score (0 when no measurement).
3121
+ * - `grounding`: derived label — 'measured' when n >= 10, else 'judgment'.
3122
+ *
3123
+ * The score itself is unchanged from pre-alpha.21 (numeric, 5 = neutral
3124
+ * default). 'capability-fact' is NOT a perf-score grounding — capability
3125
+ * decisions live on chain entries, not on perf scores.
3126
+ */
3127
+ interface ArchetypePerfScoreResult {
3128
+ /** 0..10 perf score. 5 = neutral default when no entry exists. */
3129
+ score: number;
3130
+ /**
3131
+ * Brain row count backing this score. 0 when bundled (cold-start prior)
3132
+ * or when the brain row didn't carry an `n` column.
3133
+ */
3134
+ n: number;
3135
+ /**
3136
+ * Provenance — 'measured' when `n >= 10`, else 'judgment'.
3137
+ * Never 'capability-fact' (that label is reserved for chain-entry
3138
+ * inclusion/exclusion decisions).
3139
+ */
3140
+ grounding: Grounding;
3141
+ }
3142
+ /**
3143
+ * Per-model accessor with grounding (alpha.21). Returns 5 (neutral) when no
3144
+ * entry is found — consistent with the master plan §3.3 "missing archetypes
3145
+ * default to 5" convention documented in profiles.ts
3146
+ * ModelProfile.archetypePerf.
3147
+ *
3148
+ * Backwards-compat note: pre-alpha.21 callers expected `number` here. The
3149
+ * new return shape `{ score, n, grounding }` is a breaking shape change at
3150
+ * the type level, but `.score` carries the legacy value. Callers reading
3151
+ * `.score` field-by-field continue working; callers using the bare number
3152
+ * arithmetically need to switch to `.score`. The migration is single-line
3153
+ * (`const x = getArchetypePerfScore(...)` → `const x = getArchetypePerfScore(...).score`).
3154
+ */
3155
+ declare function getArchetypePerfScore(modelId: string, archetype: IntentArchetypeName): ArchetypePerfScoreResult;
3156
+
3157
+ /**
3158
+ * pricing-brain — alpha.11 KG-13 adapter.
3159
+ *
3160
+ * Brain-driven pricing data with **time-bounded resolution** (`valid_from`
3161
+ * / `valid_until` columns). The V4-Pro 75%-off promo through 2026-05-31
3162
+ * gets modeled as two rows; `at` parameter resolution picks the correct
3163
+ * row per call timestamp. Promo flips happen automatically at the
3164
+ * boundary without alpha cuts.
3165
+ *
3166
+ * SWR cache holds the FULL pricing snapshot (all active rows for all
3167
+ * models). Per-call `at` filtering is in-memory — keeps the SWR semantics
3168
+ * uniform with other adapters (one cache, one snapshot, sync reads).
3169
+ */
3170
+ interface PricingRow {
3171
+ modelId: string;
3172
+ costInputPer1m: number;
3173
+ costOutputPer1m: number;
3174
+ cacheInputPer1m?: number;
3175
+ cacheCreationPer1m?: number;
3176
+ validFrom: number;
3177
+ validUntil?: number;
3178
+ source?: string;
3179
+ }
3180
+ /**
3181
+ * Sync reader for the brain-driven pricing snapshot. Returns bundled
3182
+ * profile pricing when brain-query is disabled, cold, or unreachable.
3183
+ * Caller filters by `at` via {@link resolvePricingAt}.
3184
+ */
3185
+ declare const loadPricingFromBrain: () => PricingRow[];
3186
+ /**
3187
+ * Resolve the active pricing row for a model at a given timestamp.
3188
+ * Picks the row with the latest `valid_from <= at` whose
3189
+ * `valid_until > at` (or NULL — open-ended).
3190
+ *
3191
+ * Returns `undefined` when no row matches. Callers should fall back to
3192
+ * profile static pricing in that case.
3193
+ */
3194
+ declare function resolvePricingAt(modelId: string, at?: Date): PricingRow | undefined;
3195
+
3196
+ /**
3197
+ * models-brain — alpha.11 KG-14 adapter (the largest of the four).
3198
+ *
3199
+ * Brain-driven model registry + aliases. Two adapters share the same
3200
+ * SWR snapshot:
3201
+ *
3202
+ * - `loadModelsFromBrain()` — `Map<modelId, ModelProfile>` from
3203
+ * `kgauto_models` table (cliffs/lowering/recovery as JSONB columns).
3204
+ * - `loadAliasesFromBrain()` — `Record<aliasId, canonicalId>` from
3205
+ * `kgauto_aliases` table.
3206
+ *
3207
+ * After alpha.11, new-model onboarding becomes brain INSERT (vs PR + alpha
3208
+ * cut + 3 consumer refreshes). The auto-onboard pipeline
3209
+ * (`scripts/check-model-releases.mjs`) shifts from emitting profile.ts
3210
+ * edits to writing brain rows directly.
3211
+ *
3212
+ * **D5 — alias resolution stable regardless of canonical's active state.**
3213
+ * `canonicalId('deepseek-chat') → 'deepseek-v4-flash'` even when the
3214
+ * canonical row is `active=false`. Aliases are wire-format contracts;
3215
+ * legacy callers' resolution promise outlives the canonical's active
3216
+ * status. Deprecation (`active=false`) affects chain composition only.
3217
+ */
3218
+
3219
+ /**
3220
+ * Exported brain-row shape for `kgauto_models`. Mirrors the SQL table
3221
+ * (`v2/brain/migrations/010_kgauto_models_and_aliases.sql`) — column names
3222
+ * are snake_case to match PostgREST. Used by operator scripts that write
3223
+ * to brain (auto-onboard, promote-model) — see `profileToRow()`.
3224
+ *
3225
+ * Read path stays internal via `RawModelRow` to keep `rowToProfile()`'s
3226
+ * tolerance contract from leaking into write callers.
3227
+ */
3228
+ interface ModelBrainRow {
3229
+ model_id: string;
3230
+ provider: string;
3231
+ status?: string;
3232
+ max_context_tokens?: number;
3233
+ max_output_tokens?: number;
3234
+ max_tools?: number;
3235
+ parallel_tool_calls?: boolean;
3236
+ structured_output?: string;
3237
+ system_prompt_mode?: string;
3238
+ streaming?: boolean;
3239
+ cliffs?: unknown;
3240
+ lowering?: unknown;
3241
+ recovery?: unknown;
3242
+ strengths?: string[] | null;
3243
+ weaknesses?: string[] | null;
3244
+ cost_input_per_1m?: number;
3245
+ cost_output_per_1m?: number;
3246
+ notes?: string | null;
3247
+ verified_against_docs?: string | null;
3248
+ archetype_perf?: Record<string, number> | null;
3249
+ version_added?: string;
3250
+ version_removed?: string | null;
3251
+ active?: boolean;
3252
+ /** alpha.41 — model-family tag (migration 024 column). */
3253
+ family?: string | null;
3254
+ /** alpha.49 — explicit latency bucket (migration 028 column). */
3255
+ latency_tier?: string | null;
3256
+ /** alpha.49 — per-archetype prompt-shape conventions (migration 028 column). */
3257
+ archetype_conventions?: ArchetypeConvention[] | null;
3258
+ }
3259
+ interface ProfileToRowOptions {
3260
+ /** e.g. `'2.0.0-alpha.12'` — leave undefined to omit from row. */
3261
+ versionAdded?: string;
3262
+ /** Pass `null` to clear; omit to leave field unset. */
3263
+ versionRemoved?: string | null;
3264
+ /** Defaults to true if omitted. */
3265
+ active?: boolean;
3266
+ /**
3267
+ * Override verifiedAgainstDocs (e.g. set to `null` for auto-onboard).
3268
+ * When omitted, the profile's own value is used. Pass `null` explicitly
3269
+ * to write a SQL NULL (e.g. unverified auto-onboard rows).
3270
+ */
3271
+ verifiedAgainstDocs?: string | null;
3272
+ }
3273
+ /**
3274
+ * Inverse of `rowToProfile` — serialize a `ModelProfile` to a `kgauto_models`
3275
+ * row payload for INSERT/UPSERT. Used by operator scripts that write to
3276
+ * brain (auto-onboard pipeline, promote-model verification CLI).
3277
+ *
3278
+ * Row-level fields (`version_added`, `version_removed`, `active`) are
3279
+ * operator-controlled and pass through `opts`. `verifiedAgainstDocs` can
3280
+ * also be overridden via `opts` — auto-onboard explicitly passes `null` to
3281
+ * mark unverified rows (the column is DATE, doesn't accept the
3282
+ * `'UNVERIFIED-AUTO-ONBOARD'` sentinel used in PROFILES_RAW).
3283
+ */
3284
+ declare function profileToRow(profile: ModelProfile, opts?: ProfileToRowOptions): ModelBrainRow;
3285
+ /**
3286
+ * Sync reader for the brain-driven model registry. Returns bundled
3287
+ * PROFILES_RAW when brain-query is disabled, cold, or unreachable.
3288
+ */
3289
+ declare const loadModelsFromBrain: () => Map<string, ModelProfile>;
3290
+ /**
3291
+ * Sync reader for the brain-driven aliases map. Returns bundled ALIASES
3292
+ * when brain-query is disabled, cold, or unreachable.
3293
+ *
3294
+ * D5: this map carries both active and inactive canonical mappings —
3295
+ * alias resolution is stable regardless of canonical's `active` state.
3296
+ */
3297
+ declare const loadAliasesFromBrain: () => Record<string, string>;
3298
+
3299
+ /**
3300
+ * exclusion-findings-brain — alpha.38 KG-19 adapter.
3301
+ *
3302
+ * Per-tenant SWR cache for the `exclusion_findings` table populated by the
3303
+ * `kgauto-exclusion-re-evaluation-watch` cron (alpha.37 substrate). Distinct
3304
+ * from the cross-tenant `brain-query.ts` snapshot because exclusion findings
3305
+ * are scoped per `app_id` — one process = one consumer = one appId, but the
3306
+ * cache key supports multi-app processes by keying snapshots by appId.
3307
+ *
3308
+ * Architecture mirrors `brain-query.ts` but with a per-(appId) snapshot:
3309
+ *
3310
+ * - **Sync API surface.** `getStaleExclusionFindings({ appId, archetype })`
3311
+ * returns `ExclusionFindingRow[]` immediately. First call returns the
3312
+ * bundled fallback (empty array); async refresh fires in background;
3313
+ * subsequent calls within TTL return brain data.
3314
+ *
3315
+ * - **Per-appId snapshot.** Each appId gets its own cache entry. One fetch
3316
+ * per appId per TTL window. Tests can reset between cases.
3317
+ *
3318
+ * - **Tolerant.** Brain down / endpoint misconfigured / unexpected shape →
3319
+ * silent bundled fallback (empty array). Never throws. Warns once per
3320
+ * process per error to avoid log spam.
3321
+ *
3322
+ * - **Opt-in.** Activation gated on `configureExclusionFindingsBrain()`
3323
+ * having been called with a runtime. The public `configureBrain()` in
3324
+ * brain.ts wires this up automatically when `BrainConfig.brainQuery
3325
+ * .findingsExclusions !== false`.
3326
+ *
3327
+ * Default endpoint:
3328
+ * `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions`
3329
+ * The route accepts `?app_id=X` and returns a JSON array of findings
3330
+ * for that app filtered to `resolved_at IS NULL`. Public read; data
3331
+ * carries no consumer PII (app id, archetype, model id, cost ratio,
3332
+ * savings estimate).
3333
+ */
3334
+ /**
3335
+ * Shape of one row from the `exclusion_findings` cache table. Mirrors the
3336
+ * snake_case JSONB returned by the brain RPC + the dashboard endpoint.
3337
+ * Camel-case mapping happens at the boundary (rowToFinding) so the in-memory
3338
+ * shape stays consistent with the rest of the library.
3339
+ */
3340
+ interface ExclusionFindingRow {
3341
+ /** Intent archetype the finding applies to (e.g. 'hunt', 'classify'). */
3342
+ archetype: string;
3343
+ /** Canonical model id that the consumer has excluded (zero traffic in window). */
3344
+ excludedModel: string;
3345
+ /** Provider of the excluded model (e.g. 'deepseek', 'openai'). */
3346
+ excludedProvider: string;
3347
+ /** Detection verdict — alpha.37 ships 'recommend-probe' only. */
3348
+ verdict: 'recommend-probe' | 'unblock' | 'stay-excluded' | 'inconclusive';
3349
+ /**
3350
+ * Estimated 30-day savings in USD if the excluded model becomes primary
3351
+ * on this archetype. Null when pricing is incomplete or excluded model is
3352
+ * more expensive than the leader.
3353
+ */
3354
+ estimatedSavingsUsd30d: number | null;
3355
+ /** Renderable summary; produced by the detector / RPC. */
3356
+ message: string;
3357
+ /** Actionable recommendation; produced by the detector / RPC. */
3358
+ suggestion: string;
3359
+ /** Detector confidence tier. */
3360
+ confidence: 'high' | 'medium' | 'low';
3361
+ /**
3362
+ * Free-form evidence pack (cost ratio, leader info, promo flags, parallel-
3363
+ * tool hint, etc.). Surfaced verbatim to advisor rules for richer messages.
3364
+ * Optional — older detector runs may not populate every field.
3365
+ */
3366
+ evidence?: Record<string, unknown>;
3367
+ }
3368
+ /**
3369
+ * Default endpoint hosted on the kgauto-dashboard. Public read — data carries
3370
+ * no PII (app id, archetype, model id, cost ratio, savings estimate). Mirrors
3371
+ * the cross-tenant `/api/kgauto-v2/config` pattern.
3372
+ */
3373
+ declare const DEFAULT_FINDINGS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions";
3374
+ /**
3375
+ * Sync introspection — is the findings-brain active? Used by advisor rules
3376
+ * to decide whether to even attempt a read.
3377
+ */
3378
+ declare function isExclusionFindingsBrainActive(): boolean;
3379
+ interface GetExclusionFindingsOpts {
3380
+ /** App id to read findings for. Required. */
3381
+ appId: string;
3382
+ /**
3383
+ * Optional archetype filter. When set, returns only findings where
3384
+ * `archetype` matches. When omitted, returns all findings for the app.
3385
+ */
3386
+ archetype?: string;
3387
+ }
3388
+ /**
3389
+ * Sync reader. Returns the cached findings for `appId`, optionally filtered
3390
+ * to a single archetype. First call returns empty array and triggers async
3391
+ * refresh; subsequent calls within TTL return brain data.
3392
+ *
3393
+ * NEVER throws. Brain down / endpoint misconfigured / mapper exception →
3394
+ * empty array.
3395
+ */
3396
+ declare function getStaleExclusionFindings(opts: GetExclusionFindingsOpts): ExclusionFindingRow[];
3397
+
3398
+ /**
3399
+ * Family resolution — alpha.41.
3400
+ *
3401
+ * "I want the latest Opus" → kgauto picks the current+active model in the
3402
+ * `claude-opus` family. Closes the loop where consumer code carries hardcoded
3403
+ * `claude-opus-4-6` literals long after `claude-opus-4-7` ships and goes
3404
+ * current — the s47 trigger (IC's `generate` chain still routing 43 calls to
3405
+ * legacy 4-6 in production).
3406
+ *
3407
+ * Two surfaces:
3408
+ * - `getRecommendedPrimary({ family, ..., fallback })` — public, sync,
3409
+ * used at IR-construction time when the consumer wants a literal id back
3410
+ * (with a fallback floor for cold-start brain).
3411
+ * - `resolveFamilyEntry({ family, archetype?, appId? })` — internal,
3412
+ * called from compile() when an IR's `models[]` entry is shaped
3413
+ * `{ family: string }`. Throws `FamilyResolutionError` on failure.
3414
+ *
3415
+ * Both routes share the same algorithm (locked in the alpha.41 Phase 0
3416
+ * design contract); they differ only in the fallback ergonomics. The
3417
+ * public route accepts a required `fallback: string`; the IR route throws.
3418
+ *
3419
+ * Pure resolution. No network. No async. Brain-registry reads go through
3420
+ * the existing SWR cache (`loadModelsFromBrain` from `models-brain.ts`) —
3421
+ * cold-start returns bundled profiles, which still resolve via the
3422
+ * `deriveFamilyFromModelId` fallback when the brain row's `family` column
3423
+ * is null (G1 contract: graceful pre-migration behavior).
3424
+ *
3425
+ * @see command-center/advisory/kgauto/2026-05-26_alpha-41-model-family-aliases-and-promotion-probe-watcher.md
3426
+ */
3427
+
3428
+ interface GetRecommendedPrimaryOptions {
3429
+ /**
3430
+ * Family tag (e.g. `'claude-opus'`, `'gemini-flash'`). See the Phase 0
3431
+ * design contract's family taxonomy table for the locked initial set;
3432
+ * extensible via brain migrations.
3433
+ */
3434
+ family: string;
3435
+ /**
3436
+ * Optional archetype gate. When provided, candidates must clear
3437
+ * {@link ARCHETYPE_FLOOR_DEFAULT} on `archetypePerf[archetype]`. Also used
3438
+ * as the primary sort key (DESC) when multiple candidates qualify.
3439
+ */
3440
+ archetype?: IntentArchetypeName;
3441
+ /**
3442
+ * Optional consumer-app id. When provided, candidates matching a
3443
+ * `stay-excluded` finding for `(appId, archetype)` in the
3444
+ * exclusion-findings cache (alpha.38 substrate) are filtered out.
3445
+ */
3446
+ appId?: string;
3447
+ /**
3448
+ * Consumer-posture tag. `'locked'` short-circuits resolution and returns
3449
+ * the literal `fallback` unconditionally — useful for compliance /
3450
+ * contract / brand-promise flows where the consumer doesn't want kgauto
3451
+ * picking the model on their behalf.
3452
+ */
3453
+ posture?: 'preferred' | 'open' | 'locked';
3454
+ /**
3455
+ * Last-resort literal model id. REQUIRED. Returned when (a) brain
3456
+ * registry is cold / no candidates exist, (b) `posture === 'locked'`,
3457
+ * (c) every candidate was filtered out by archetype / exclusion gates.
3458
+ *
3459
+ * The fallback is NOT validated against the family — kgauto trusts the
3460
+ * consumer to pass a meaningful floor. The contract intent is "even when
3461
+ * everything below is on fire, you still get a model id back."
3462
+ */
3463
+ fallback: string;
3464
+ }
3465
+ /**
3466
+ * Thrown by `resolveFamilyEntry` (the internal compile-time twin) when a
3467
+ * `{ family: string }` IR entry can't resolve to any current+active model.
3468
+ * Surfaces with the family string + a one-line cause so consumer error
3469
+ * handling can distinguish "you typo'd the family tag" from "brain is cold
3470
+ * and nothing matches."
3471
+ *
3472
+ * The public `getRecommendedPrimary` does NOT throw — it returns
3473
+ * `fallback` instead.
3474
+ */
3475
+ declare class FamilyResolutionError extends Error {
3476
+ readonly family: string;
3477
+ readonly cause: string;
3478
+ constructor(family: string, cause: string);
3479
+ }
3480
+ /**
3481
+ * Deterministic model_id → family inference. Pure function; no brain
3482
+ * lookup. Used as the runtime fallback when a brain row's `family` column
3483
+ * is null (pre-migration 024) and as the canonical mapping that migration
3484
+ * 024's CASE statement mirrors.
3485
+ *
3486
+ * Returns null for unrecognized ids — caller must handle (typically by
3487
+ * skipping the row in family resolution).
3488
+ *
3489
+ * Order matters: more specific patterns first (e.g. `flash-lite` before
3490
+ * `flash`; `pro` before `chat`). The brain-side CASE statement uses the
3491
+ * same priority.
3492
+ */
3493
+ declare function deriveFamilyFromModelId(modelId: string): string | null;
3494
+ /**
3495
+ * Public sync resolver. Pure (modulo brain snapshot read). Returns the
3496
+ * literal model id of the best candidate, or `fallback` when resolution
3497
+ * yields nothing.
3498
+ */
3499
+ declare function getRecommendedPrimary(opts: GetRecommendedPrimaryOptions): string;
3500
+
3501
+ /**
3502
+ * promotions-brain — alpha.64 Stage-2 substrate.
3503
+ *
3504
+ * Per-tenant SWR cache for the `kgauto_promotions` table populated by the
3505
+ * golden-eval trigger's auto-promote actor (Stage 2 of the eval trust
3506
+ * ladder: auto-promote downswaps behind the 7-day rollback guard). Mirrors
3507
+ * `promote-ready-brain.ts` shape where applicable; this is the read-side
3508
+ * substrate for the compile-time promotion boost in `passScoreTargets`.
3509
+ *
3510
+ * Design contract:
3511
+ * command-center/advisory/kgauto/2026-07-18_stage2-auto-promote-design.md
3512
+ *
3513
+ * Consent posture: the routing effect is OPT-IN, default OFF. The cache is
3514
+ * only activated by `configureBrain()` when the consumer opted in via
3515
+ * `BrainConfig.autoPromote: true` or the `KGAUTO_AUTO_PROMOTE` env var
3516
+ * (config field wins when both are present — mirror of the
3517
+ * `KGAUTO_GOLDEN_CAPTURE` env-as-consent precedent). Not opted in ⇒ this
3518
+ * module never fetches and `getApplicablePromotion` returns undefined ⇒
3519
+ * zero behavior change anywhere in compile().
3520
+ *
3521
+ * Architecture (mirror of promote-ready-brain):
3522
+ * - Sync API surface: `getApplicablePromotion({ appId, archetype })`
3523
+ * returns immediately. First call returns undefined (cold) and fires an
3524
+ * async refresh; subsequent calls within TTL return brain data.
3525
+ * - Per-appId snapshot; one fetch per appId per TTL window.
3526
+ * - Tolerant: brain down / misconfigured / unexpected shape → undefined.
3527
+ * Never throws. Warns once per process.
3528
+ *
3529
+ * A rollback (`status='rolled_back'` PATCHed by the promotion-guard
3530
+ * watcher) drops the row from the endpoint's `status=active` filter, so
3531
+ * routing reverts within one TTL window — the mechanism the 7-day guard's
3532
+ * auto-revert rests on.
3533
+ */
3534
+
3535
+ /**
3536
+ * One active surface promotion, camelCase-mapped at the boundary from the
3537
+ * snake_case endpoint row (typed-boundary-transformer convention).
3538
+ */
3539
+ /**
3540
+ * Release B (alpha.75): `kgauto_promotions` carries two logical channels
3541
+ * sharing one table and one lifecycle (migration 047). `mode` is the
3542
+ * discriminator, and each mode has exactly ONE consumption site:
3543
+ *
3544
+ * mode reader effect
3545
+ * ---------- ---------------------------------- -------------------
3546
+ * downswap passScoreTargets (compile pass 5) which MODEL runs
3547
+ * strategy applySectionRewrites (pass 6.5) which IR runs
3548
+ *
3549
+ * The resolver is mode-filtered and no unfiltered accessor exists — an
3550
+ * unfiltered `.find()` was the §7 read-path bug: a strategy row has
3551
+ * promoted_model === incumbent_model, so one reaching the model-boost code
3552
+ * would boost the incumbent and could suppress the alpha.49 quality gate on
3553
+ * evidence that was never about quality-gating.
3554
+ */
3555
+ type PromotionMode = 'downswap' | 'strategy';
3556
+ interface PromotionRow {
3557
+ /** Brain row id — cited in the `promotion-applied` mutation for Glass-Box. */
3558
+ id: number;
3559
+ /** Intent archetype the promotion applies to. */
3560
+ archetype: string;
3561
+ /**
3562
+ * Channel discriminator (migration 047). Rows from a pre-047 endpoint
3563
+ * carry no `mode` on the wire and map to 'downswap' — every pre-047 row
3564
+ * IS a downswap, and strategy rows can only be written by post-047 code
3565
+ * whose endpoint serves the column.
3566
+ */
3567
+ mode: PromotionMode;
3568
+ /**
3569
+ * The strategy id for mode='strategy' rows (e.g. 'discipline-gates-v1');
3570
+ * null on downswaps. DB CHECK: (mode='strategy') = (strategy IS NOT NULL).
3571
+ */
3572
+ strategy: string | null;
3573
+ /** The model this surface now routes to. */
3574
+ promotedModel: string;
3575
+ /** The model it replaced (the eval's incumbent). */
3576
+ incumbentModel: string;
3577
+ /** The promote-ready kgauto_golden_eval_runs row this rests on. */
3578
+ evalRunId: number | null;
3579
+ /**
3580
+ * Evidence-supersedes-judgment: skip the alpha.49 schema-weak
3581
+ * quality-gate penalty for the promoted model on this surface (the eval
3582
+ * measured the schema floor holding on real workload). Always false on
3583
+ * strategy rows (DB CHECK kgauto_promotions_strategy_no_suppress).
3584
+ */
3585
+ suppressQualityGate: boolean;
3586
+ /** ISO timestamp the promotion went active. */
3587
+ promotedAt: string;
3588
+ /**
3589
+ * alpha.78 — lifecycle status. The endpoint serves rolled_back rows only
3590
+ * when the library asks (`with_rollbacks=1`), so pre-.78 clients can
3591
+ * never receive one. Every reader that APPLIES a promotion must filter
3592
+ * to 'active'; rolled_back rows exist so advisors can see what the guard
3593
+ * already adjudicated instead of re-recommending it (PB Finding 3).
3594
+ */
3595
+ status: 'active' | 'rolled_back';
3596
+ /** ISO timestamp of the guard's revert, rolled_back rows only. */
3597
+ rolledBackAt?: string;
3598
+ /** Guard's classification ('latency' | 'economics' | 'strategy' | …). */
3599
+ rollbackClass?: string;
3600
+ }
3601
+ interface PromotionsRuntime {
3602
+ /** Endpoint base URL. The library appends `?app_id=<id>`. */
3603
+ endpoint: string;
3604
+ /** Stale-while-revalidate window in ms. */
3605
+ ttlMs: number;
3606
+ /** Pluggable fetch. */
3607
+ fetchImpl: typeof fetch;
3608
+ /** Optional warn hook. */
3609
+ onError?: (err: unknown) => void;
3610
+ }
3611
+ /**
3612
+ * Default endpoint hosted on the kgauto-dashboard. Serves `status='active'`
3613
+ * kgauto_promotions rows for one app_id. Mirrors the findings convention.
3614
+ */
3615
+ declare const DEFAULT_PROMOTIONS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/promotions";
3616
+ /**
3617
+ * True when the KGAUTO_AUTO_PROMOTE env var opts this process in.
3618
+ * Accepted truthy forms: '1', 'true' (case-insensitive). Everything else —
3619
+ * unset, '', '0', 'false' — is OFF. Read at configureBrain() time, not per
3620
+ * call.
3621
+ */
3622
+ declare function isAutoPromoteEnabledFromEnv(envSource?: Record<string, string | undefined>): boolean;
3623
+ /**
3624
+ * Wire (or rewire) the runtime. Pass undefined to disable. Resets all
3625
+ * snapshots. Called from `configureBrain()` ONLY when the consumer opted in.
3626
+ */
3627
+ declare function configurePromotionsBrain(rt: PromotionsRuntime | undefined): void;
3628
+ /** Sync introspection — is the promotions brain active (i.e. opted in)? */
3629
+ declare function isPromotionsBrainActive(): boolean;
3630
+ interface GetApplicablePromotionOpts {
3631
+ /** App id to read promotions for. Required. */
3632
+ appId: string;
3633
+ /** Archetype of the compile in flight. Required. */
3634
+ archetype: IntentArchetypeName | string;
3635
+ /**
3636
+ * Channel to read (migration 047). Required — there is deliberately no
3637
+ * unfiltered accessor: with one active row per (surface, mode) legal, an
3638
+ * unfiltered first-match-wins `.find()` returns an arbitrary channel's
3639
+ * row, and a strategy row reaching the model-boost reader is the §7
3640
+ * read-path bug.
3641
+ */
3642
+ mode: PromotionMode;
3643
+ }
3644
+ /**
3645
+ * Sync reader. Returns the active promotion for `(appId, archetype, mode)`
3646
+ * or undefined. First call returns undefined and triggers async refresh;
3647
+ * subsequent calls within TTL return brain data. The brain enforces one
3648
+ * active promotion per (surface, mode) (partial unique index), so at most
3649
+ * one row matches.
3650
+ *
3651
+ * NEVER throws. Not configured / brain down / cold → undefined.
3652
+ */
3653
+ declare function getApplicablePromotion(opts: GetApplicablePromotionOpts): PromotionRow | undefined;
3654
+ /**
3655
+ * alpha.78 — how long a guard rollback suppresses re-recommending the same
3656
+ * model on the same surface. Matches the measured-failure evidence window:
3657
+ * a `rollback_class='latency'` revert deliberately keeps the model ELIGIBLE
3658
+ * long-term (traffic patterns change), so the suppression is windowed, not
3659
+ * permanent.
3660
+ */
3661
+ declare const ROLLBACK_SUPPRESSION_WINDOW_DAYS = 28;
3662
+ /**
3663
+ * alpha.78 (PB Finding 3) — sync reader: did the promotion guard recently
3664
+ * roll back `model` on `(appId, archetype)`? The cost advisor consults this
3665
+ * so it stops recommending "exactly the downswap your own machinery
3666
+ * auto-reverted three days ago" — an advisory acting on it would
3667
+ * re-litigate a decision the guard already made correctly. Same SWR
3668
+ * posture as `getApplicablePromotion`: cold/unconfigured → undefined
3669
+ * (advisor proceeds without rollback knowledge, as before alpha.78).
3670
+ */
3671
+ declare function getRecentRollback(opts: {
3672
+ appId: string;
3673
+ archetype: IntentArchetypeName | string;
3674
+ model: string;
3675
+ windowDays?: number;
3676
+ nowMs?: number;
3677
+ }): PromotionRow | undefined;
3678
+ /**
3679
+ * alpha.86 — cold-start prefetch, the promotions twin of alpha.73's
3680
+ * `prefetchMeasuredFailure`.
3681
+ *
3682
+ * alpha.73 fixed cold-isolate blindness for the measured-failure gate and
3683
+ * did not cover this sibling subsystem: `compile()` is synchronous, so on a
3684
+ * cold isolate `getApplicablePromotion` reads an empty snapshot and an
3685
+ * ACTIVE promotion silently does not apply — hitting low-traffic consumers
3686
+ * (whose isolates are cold most of the time) hardest, directly under
3687
+ * trust-artifact #3. Found s81 via the smoke's own cold-cache bug; grep
3688
+ * confirmed zero prefetch call sites existed.
3689
+ *
3690
+ * Also the fix for the s81 smoke incident's root shape: this starts the SWR
3691
+ * refresh directly, so it cannot be defeated by `getApplicablePromotion`'s
3692
+ * argument validation early-returns.
3693
+ *
3694
+ * Returns the in-flight promise (or undefined when not configured / already
3695
+ * fresh) so a caller can await it. NEVER throws.
3696
+ */
3697
+ declare function prefetchPromotions(appId: string): Promise<void> | undefined;
3698
+ /**
3699
+ * alpha.86 — bounded await on the promotions warm-up, for async callers
3700
+ * only (`call()`); `compile()` stays synchronous. Same contract as
3701
+ * `awaitMeasuredFailureReady`: bounded, silent on timeout, protective
3702
+ * never required — a slow or down brain delays a call by at most
3703
+ * `timeoutMs` and can never fail one. A zero budget still kicks the
3704
+ * prefetch (the opt-out is "do not make me wait", not "do not warm up").
3705
+ *
3706
+ * NEVER throws.
3707
+ */
3708
+ declare function awaitPromotionsReady(appId: string, timeoutMs: number): Promise<void>;
3709
+ /** Reset module state. Tests must call between cases. */
3710
+ declare function _testResetPromotions(): void;
3711
+ /** Wait for any in-flight refresh to settle. */
3712
+ declare function _testWaitForPromotionsRefresh(): Promise<void>;
3713
+
3714
+ /**
3715
+ * measured-failure-brain — the CREATE-a-gate direction of
3716
+ * measured-supersedes-judgment (alpha.70).
3717
+ *
3718
+ * alpha.49 gives kgauto a quality gate that fires off a model profile's
3719
+ * DECLARED conventions (`archetypeConventions.structuredOutputHint: 'avoid'`).
3720
+ * alpha.64 let a MEASURED eval verdict SUPPRESS that gate
3721
+ * (`kgauto_promotions.suppress_quality_gate`). Nothing could go the other
3722
+ * way — a model whose declarations are wrong could not have a gate CREATED
3723
+ * for it, which is precisely the case where declarations cannot be trusted.
3724
+ *
3725
+ * The originating evidence: `claude-haiku-4-5` on playbacksam/summarize
3726
+ * declares `structuredOutput: 'grammar'` + `archetypePerf.summarize: 8`, so
3727
+ * every quality signal reads green and it wins the surface on price — while
3728
+ * failing **12 of 12 in-window attempts** (2026-07-14..25, seven in one
3729
+ * day). The brain held that evidence and nothing could act on it.
3730
+ *
3731
+ * ── Design notes ───────────────────────────────────────────────────────
3732
+ *
3733
+ * **No stored decision.** The gate is DERIVED from a rolling 28d window
3734
+ * (`kgauto_surface_model_failure_v`), never written down. That kills the
3735
+ * flap problem by construction — there is no state to flap — and it means
3736
+ * a gated model un-gates itself once its failures age out. Combined with
3737
+ * the gate being a DE-RANK (out of leadership, retained as graceful
3738
+ * fallback) rather than a hard block, the model keeps earning evidence, so
3739
+ * this cannot become the exclusion-lock-in trap where a blocked model can
3740
+ * never prove itself again.
3741
+ *
3742
+ * **The threshold is a confidence bound, not a fixed sample floor.** A flat
3743
+ * `minSample: 20` (promotion-guard's rate floor) would NOT have fired on
3744
+ * haiku's n=12 — the consumer would keep paying while we waited for a
3745
+ * rounder number. But distinguishing 100% from 5% needs far fewer trials
3746
+ * than distinguishing 2% from 6%. Gating on the Wilson score lower bound
3747
+ * makes the sample requirement adapt to the effect size automatically,
3748
+ * which is the alpha.67 insight ("the sample floor for a median can be far
3749
+ * lower than for a rate") generalised properly.
3750
+ *
3751
+ * **Direct app-scoped read, not the config-endpoint cache.** Modelled on
3752
+ * `promotions-brain.ts`, deliberately NOT `createBrainQueryCache` — that
3753
+ * routes through the dashboard `/v2/config` projection, which is the third
3754
+ * layer in the L-073 "executable knowledge is dropped at every transport
3755
+ * boundary" chain. One fewer place to forget a field.
3756
+ */
3757
+
3758
+ /**
3759
+ * One row of the rolling-window evidence view, per (app, archetype, model).
3760
+ * Raw counts only — the brain serves facts, this module decides.
3761
+ */
3762
+ interface SurfaceFailureRow {
3763
+ archetype: string;
3764
+ model: string;
3765
+ /** Total attempts in-window (served + quality walkaways). */
3766
+ n: number;
3767
+ /** Attempts that failed on the quality axis. */
3768
+ nFail: number;
3769
+ }
3770
+ declare const MEASURED_FAILURE_CFG: {
3771
+ /**
3772
+ * Hard minimum attempts before ANY gate may be created. Guards against
3773
+ * pathological tiny samples that the confidence bound alone would let
3774
+ * through in edge cases. At 5-for-5 the bound clears the threshold; at
3775
+ * 3-for-3 it does not, which is the behaviour we want (three failures is
3776
+ * a bad day, five in a row is a pattern).
3777
+ */
3778
+ readonly minSample: 5;
3779
+ /**
3780
+ * Gate when we are 95% confident the model fails MORE OFTEN THAN IT
3781
+ * SUCCEEDS on this surface. Deliberately unarguable rather than tuned —
3782
+ * a model that probably fails the majority of the time has no business
3783
+ * leading a surface, whatever its declared scores say.
3784
+ */
3785
+ readonly lowerBoundThreshold: 0.5;
3786
+ /** 95% one-sided-ish confidence (standard two-sided z at α=0.05). */
3787
+ readonly z: 1.96;
3788
+ /** Must match the view's window. Documented here for the advisory text. */
3789
+ readonly windowDays: 28;
3790
+ };
3791
+ /**
3792
+ * Wilson score interval, lower bound. Preferred over the normal
3793
+ * approximation because it stays sane at the extremes — at p̂ = 1 the
3794
+ * normal approximation gives a zero-width interval (it would gate on a
3795
+ * single failure), while Wilson correctly returns a bound that tightens
3796
+ * with n.
3797
+ *
3798
+ * Returns 0 for n <= 0.
3799
+ */
3800
+ declare function wilsonLowerBound(failures: number, n: number, z?: number): number;
3801
+ interface MeasuredFailureVerdict {
3802
+ /** Whether the measured-failure quality gate fires for this tuple. */
3803
+ gated: boolean;
3804
+ /** Observed failure rate in-window. */
3805
+ rate: number;
3806
+ /** 95% lower confidence bound on that rate — what the gate tests. */
3807
+ lowerBound: number;
3808
+ /** Attempts backing the verdict. */
3809
+ n: number;
3810
+ nFail: number;
3811
+ }
3812
+ /**
3813
+ * alpha.78 — public row normalizer (PB 2026-07-25 trap): the counts
3814
+ * endpoint speaks snake_case (`intent_archetype`, `n_fail`) and this module
3815
+ * speaks camelCase. A consumer reproducing a gate decision by hand from the
3816
+ * endpoint previously got a silent `gated: false` — `wilsonLowerBound(
3817
+ * undefined, 13)` returns a clean 0 rather than throwing. Exported so the
3818
+ * bridge exists exactly once.
3819
+ */
3820
+ declare function mapMeasuredFailureRows(rows: unknown[]): SurfaceFailureRow[];
3821
+ /**
3822
+ * Pure decision, exported for tests and for the advisory text. Separated
3823
+ * from the I/O so the policy can be exercised without a brain.
3824
+ *
3825
+ * alpha.78 — accepts BOTH row shapes: the module's camelCase
3826
+ * `SurfaceFailureRow` and the counts endpoint's raw snake_case row. A
3827
+ * snake_case row previously slipped through the type system (all fields
3828
+ * `undefined`) and judged `gated: false` silently.
3829
+ */
3830
+ declare function judgeMeasuredFailure(row: SurfaceFailureRow | {
3831
+ intent_archetype: string;
3832
+ model: string;
3833
+ n: number | string;
3834
+ n_fail: number | string;
3835
+ } | undefined, cfg?: typeof MEASURED_FAILURE_CFG): MeasuredFailureVerdict | undefined;
3836
+ interface MeasuredFailureRuntime {
3837
+ /** Endpoint base URL. The library appends `?app_id=<id>`. */
3838
+ endpoint: string;
3839
+ /** Stale-while-revalidate window in ms. */
3840
+ ttlMs: number;
3841
+ fetchImpl: typeof fetch;
3842
+ onError?: (err: unknown) => void;
3843
+ }
3844
+ /** Default endpoint on the kgauto-dashboard. Mirrors the promotions convention. */
3845
+ declare const DEFAULT_MEASURED_FAILURE_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/measured-failure";
3846
+ /**
3847
+ * Opt-out env switch. UNLIKE auto-promote this defaults ON wherever the
3848
+ * brain is configured, because the gate is protective: it only ever
3849
+ * de-ranks a model the consumer's OWN traffic shows to be failing them, and
3850
+ * the failure is already being paid for. Set `KGAUTO_MEASURED_FAILURE_GATE=0`
3851
+ * (or 'false') to disable.
3852
+ */
3853
+ declare function isMeasuredFailureGateEnabledFromEnv(envSource?: Record<string, string | undefined>): boolean;
3854
+ declare function configureMeasuredFailureBrain(rt: MeasuredFailureRuntime | undefined): void;
3855
+ declare function isMeasuredFailureBrainActive(): boolean;
3856
+ interface GetMeasuredFailureOpts {
3857
+ appId: string;
3858
+ archetype: IntentArchetypeName | string;
3859
+ model: string;
3860
+ }
3861
+ /**
3862
+ * alpha.73 — start the warm-up WITHOUT needing a compile to trigger it.
3863
+ *
3864
+ * The SWR posture below ("cold start returns undefined and warms in the
3865
+ * background") is right for a long-lived process and wrong for a
3866
+ * short-lived isolate, where the first compile IS most compiles. Measured on
3867
+ * playbacksam: on a cold isolate the gate was absent, `claude-haiku-4-5` led,
3868
+ * cliffed, was same-model retried and fell over to gemini — two billed
3869
+ * inferences and ~27–34s, every time an isolate is new. PB has ~1 user, so
3870
+ * its isolates are cold most of the time, which inverts the usual severity
3871
+ * ordering: this hits the LOWEST-traffic consumers hardest, and they are the
3872
+ * ones least able to absorb it.
3873
+ *
3874
+ * Kicking the fetch off at `configureBrain()` moves the refresh into the time
3875
+ * the isolate spends on everything else it does before its first compile.
3876
+ * Fire-and-forget and non-blocking: on its own this narrows the window rather
3877
+ * than closing it, which is why `awaitMeasuredFailureReady()` exists too.
3878
+ *
3879
+ * Returns the in-flight promise (or undefined when not configured / already
3880
+ * fresh) so a caller can await it. NEVER throws.
3881
+ */
3882
+ declare function prefetchMeasuredFailure(appId: string): Promise<void> | undefined;
3883
+ /**
3884
+ * alpha.73 — bounded await on the warm-up, for async callers only.
3885
+ *
3886
+ * `compile()` is synchronous and must stay so, so it cannot block on a fetch;
3887
+ * `call()` is async and is about to spend seconds on an inference, which makes
3888
+ * a few hundred milliseconds here a trivially good trade against the ~27–34s
3889
+ * and second billed inference a cold-blind gate costs.
3890
+ *
3891
+ * Deliberately bounded and deliberately silent on timeout: the gate is
3892
+ * protective, never required. If the brain is slow or down, the caller
3893
+ * proceeds un-gated exactly as it does today — this can delay a call by at
3894
+ * most `timeoutMs`, and can never fail one.
3895
+ *
3896
+ * NEVER throws.
3897
+ */
3898
+ declare function awaitMeasuredFailureReady(appId: string, timeoutMs: number): Promise<void>;
3899
+ /**
3900
+ * Sync reader. Returns the verdict for `(appId, archetype, model)` or
3901
+ * undefined (not configured / cold / below minSample / brain down).
3902
+ *
3903
+ * NEVER throws. Cold start returns undefined and warms in the background —
3904
+ * same posture as every other brain-driven lever in compile(). Async callers
3905
+ * that can afford a bounded wait should call `awaitMeasuredFailureReady()`
3906
+ * first; `call()` does.
3907
+ */
3908
+ declare function getMeasuredFailureVerdict(opts: GetMeasuredFailureOpts): MeasuredFailureVerdict | undefined;
3909
+ declare function _testResetMeasuredFailure(): void;
3910
+ declare function _testWaitForMeasuredFailureRefresh(): Promise<void>;
3911
+
3912
+ /**
3913
+ * Release C (Rung 1) — the decomposition coach's planning engine.
3914
+ *
3915
+ * Design contract §5.1: evidence-backed advisories on the existing surface —
3916
+ * "you're paying frontier prices for grunt work; here's the measured split."
3917
+ * No contract change; nothing here executes a fan-out. This module is PURE:
3918
+ * templates + arithmetic. The operator script feeds it measured surface
3919
+ * stats and evidence-picked executors; Release D's `delegate` primitive will
3920
+ * consume the SAME templates, so they live in the library, versioned.
3921
+ *
3922
+ * Honesty posture (the roster-with-receipts rule, applied to ourselves):
3923
+ *
3924
+ * - The per-step token SHARES are JUDGMENT v1 numbers — labelled as such
3925
+ * in every plan (`assumptions[]`), versioned so a future measured
3926
+ * replacement invalidates nothing silently. No consumer has fan-out
3927
+ * traffic yet (R0 shipped alpha.68, zero adopters), so there is nothing
3928
+ * to measure them from; the moment branch traffic exists, these
3929
+ * graduate per surface.
3930
+ * - Executor grounding is carried per step: 'measured' when the portfolio
3931
+ * corpus has real outcomes for (model, sub-archetype), 'judgment' when
3932
+ * the roster's archetypePerf is all we have.
3933
+ * - The coach's most credible output at low volume is "KEEP THE MONOLITH"
3934
+ * with the break-even volume stated — the never-worse floor in coach
3935
+ * form. The advisory only files when the split is MATERIAL (same $5/mo
3936
+ * felt-utility floor as promotions); the demo report renders every
3937
+ * analysis either way.
3938
+ */
3939
+
3940
+ declare const DECOMPOSITION_TEMPLATES_VERSION = "decomposition-templates-v1";
3941
+ interface DecompositionStep {
3942
+ /** Human-readable step name (stable — appears in advisories/recipes). */
3943
+ role: string;
3944
+ /** The sub-archetype this step runs as (its own learning_key downstream). */
3945
+ archetype: IntentArchetypeName;
3946
+ /**
3947
+ * Which tier runs the step. 'delegate' steps are the grunt work the coach
3948
+ * proposes moving to a cheap executor; 'anchor' steps stay on the
3949
+ * incumbent (composition is where fan-outs die — §7a — so the composer
3950
+ * anchors on the strong model by design).
3951
+ */
3952
+ tier: 'delegate' | 'anchor';
3953
+ /** Share of the monolith's INPUT tokens this step reads. JUDGMENT v1. */
3954
+ inputShare: number;
3955
+ /**
3956
+ * Tokens this step EMITS, as a share of the monolith's input (for
3957
+ * intermediate artifacts like extraction notes) — the next anchor step
3958
+ * reads these instead of the raw input. JUDGMENT v1.
3959
+ */
3960
+ emitsShareOfInput: number;
3961
+ /** Share of the monolith's OUTPUT tokens this step produces (0 for
3962
+ * intermediate steps; the anchor composer typically carries 1). */
3963
+ outputShare: number;
3964
+ }
3965
+ interface DecompositionTemplate {
3966
+ archetype: IntentArchetypeName;
3967
+ steps: DecompositionStep[];
3968
+ rationale: string;
3969
+ version: typeof DECOMPOSITION_TEMPLATES_VERSION;
3970
+ }
3971
+ /**
3972
+ * v1 covers the three judgment-heavy archetypes with a clear split shape.
3973
+ * Every share number below is a judgment estimate, stated in the plan's
3974
+ * assumptions — they exist to make the ARITHMETIC honest, not to claim
3975
+ * precision the corpus doesn't have yet.
3976
+ */
3977
+ declare const DECOMPOSITION_TEMPLATES: Partial<Record<IntentArchetypeName, DecompositionTemplate>>;
3978
+ interface SurfaceStats {
3979
+ appId: string;
3980
+ archetype: IntentArchetypeName | string;
3981
+ /** The model serving the monolith today (most-served in the window). */
3982
+ incumbentModel: string;
3983
+ nCalls: number;
3984
+ windowDays: number;
3985
+ avgTokensIn: number;
3986
+ avgTokensOut: number;
3987
+ }
3988
+ interface ExecutorCandidate {
3989
+ modelId: string;
3990
+ /** archetypePerf score on the STEP's archetype. */
3991
+ perfScore: number;
3992
+ grounding: 'measured' | 'judgment';
3993
+ costInputPer1m: number;
3994
+ costOutputPer1m: number;
3995
+ }
3996
+ interface ModelPricing {
3997
+ costInputPer1m: number;
3998
+ costOutputPer1m: number;
3999
+ }
4000
+ interface PlannedStep extends DecompositionStep {
4001
+ /** The picked executor ('delegate' steps) or the incumbent ('anchor'). */
4002
+ executorModel: string;
4003
+ executorGrounding: 'measured' | 'judgment';
4004
+ executorPerfScore: number | null;
4005
+ projectedCostPerCallUsd: number;
4006
+ }
4007
+ interface DecompositionPlan {
4008
+ appId: string;
4009
+ archetype: string;
4010
+ incumbentModel: string;
4011
+ template: DecompositionTemplate;
4012
+ steps: PlannedStep[];
4013
+ monolithCostPerCallUsd: number;
4014
+ splitCostPerCallUsd: number;
4015
+ savingPerCallUsd: number;
4016
+ monthlyCalls: number;
4017
+ projectedMonthlySavingUsd: number;
4018
+ /** Monthly calls at which the split clears the materiality floor. null
4019
+ * when the split doesn't save per-call at all (then no volume helps). */
4020
+ breakEvenMonthlyCalls: number | null;
4021
+ verdict: 'split-pays' | 'keep-monolith';
4022
+ verdictReason: string;
4023
+ /** Judgment inputs, stated. Every number that is not measured is here. */
4024
+ assumptions: string[];
4025
+ }
4026
+ declare const COACH_CFG: {
4027
+ /** Same felt-utility floor as promotions (alpha.67 family). */
4028
+ minMonthlySavingUsd: number;
4029
+ /** Executor must clear this archetypePerf on the step's archetype —
4030
+ * same floor as the translator/advisor (ARCHETYPE_FLOOR_DEFAULT). */
4031
+ executorPerfFloor: number;
4032
+ daysPerMonth: number;
4033
+ };
4034
+ interface PlanDecompositionArgs {
4035
+ stats: SurfaceStats;
4036
+ incumbentPricing: ModelPricing;
4037
+ /**
4038
+ * Evidence-picked executor per step archetype. Return undefined when no
4039
+ * candidate clears the perf floor — the plan then keeps that step on the
4040
+ * incumbent and says so (a coach must not route grunt work to a model
4041
+ * that can't do it just because it is cheap).
4042
+ */
4043
+ pickExecutor: (archetype: IntentArchetypeName) => ExecutorCandidate | undefined;
4044
+ cfg?: Partial<typeof COACH_CFG>;
4045
+ }
4046
+ declare function planDecomposition(args: PlanDecompositionArgs): DecompositionPlan | undefined;
364
4047
 
365
4048
  /**
366
4049
  * @warmdrift/kgauto v2 — prompt compiler + central learning brain.
@@ -408,4 +4091,4 @@ declare function getAllStarterChains(): Record<IntentArchetypeName, string[]>;
408
4091
  */
409
4092
  declare function compile(ir: PromptIR, opts?: CompileOptions): CompileResult;
410
4093
 
411
- export { ApiKeys, type AppOracle, BestPracticeAdvisory, type BrainConfig, CallOptions, CallResult, type CompileOptions, CompilePolicy, CompileResult, CompiledRequest, type ExecuteErr, type ExecuteOk, type ExecuteOptions, type ExecuteResult, type FallbackPosture, type GetDefaultFallbackChainOpts, IntentArchetypeName, type LLMJudgeOptions, ModelProfile, NormalizedResponse, type OracleContext, OracleScore, type OutcomePayload, PromptIR, ProviderOverrides, RecordInput, buildLLMJudge, call, clearBrain, compile, configureBrain, countTokens, execute, getAllStarterChains, getDefaultFallbackChain, getStarterChain, record, resetTokenizer, runAdvisor, setTokenizer };
4094
+ export { ABSOLUTE_FLOOR, type AISDKConvertedMessage, ALT_BLIND_TOKEN_BUDGET_BREACH, ALT_STRATEGY_IDS, ARCHETYPE_FAMILY_FITS, ARCHETYPE_FLOOR_DEFAULT, type ActionableAdvisory, Adapter, type AdvisoryEvidenceWindow, 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, BLOCKED_MODEL_FAMILY_SIBLING_SERVED_CODE, BLOCKED_MODEL_NOT_IN_ROSTER_CODE, BRAIN_READ_ENV_NAMES, BURST_SPAN_MS, BestPracticeAdvisory, type BrainConfig, type BrainDeadLetterEntry, type BrainHealthSnapshot, type BrainQueryConfig, type BrainReadEnv, COACH_CFG, COST_RANKING_REFERENCE_SHAPE, CallOptions, CallResult, ChainEntry, type CompatibilityIntent, type CompileForAISDKv6Result, type CompileOptions, CompilePolicy, CompileResult, CompiledRequest, type CreateDelegateOpts, DECOMPOSITION_TEMPLATES, DECOMPOSITION_TEMPLATES_VERSION, DEFAULT_FINDINGS_ENDPOINT, DEFAULT_JUDGE_MODEL, DEFAULT_MEASURED_FAILURE_ENDPOINT, DEFAULT_PROMOTIONS_ENDPOINT, DELEGATE_TOOL_DEFINITION, DISCIPLINE_GATES_V1_ALT_BLIND_HEADER, DISCIPLINE_GATES_V1_ALT_HEADER, type DecompositionPlan, type DecompositionStep, type DecompositionTemplate, type DelegateHandle, type DelegateRefusalReason, type DelegateResult, type DelegateToolArgs, type ExclusionFindingRow, type ExclusionResolutionSource, type ExecuteErr, type ExecuteOk, type ExecuteOptions, type ExecuteResult, type ExecutorCandidate, type FallbackPosture, FallbackReason, FamilyResolutionError, type GetActionableAdvisoriesOptions, type GetApplicablePromotionOpts, type GetDefaultFallbackChainOpts, type GetMeasuredFailureOpts, type GetPerAxisMetricsOpts, type GetRecommendedPrimaryOptions, type GoldenEvalAxis, type GoldenEvalCase, type GoldenEvalOptions, type GoldenEvalRunResult, type GoldenEvalStrategyId, type GoldenIrRecordInput, Grounding, IntentArchetypeName, JUDGE_RUBRICS, LIBRARY_VERSION, type LLMJudgeOptions, MEASURED_FAILURE_CFG, MEASURED_GROUNDING_MIN_N, type MarkAdvisoryResolvedOptions, type MarkExclusionFindingHandledOptions, type MarkPromoteReadyHandledOptions, type MeasuredFailureRuntime, type MeasuredFailureVerdict, type ModelBrainRow, type ModelCompatibility, ModelProfile, NormalizedResponse, type OracleContext, OracleScore, type OutcomePayload, OutcomeResult, OutputMode, PRODUCER_OWNED_RULE_CODES, PROVIDER_ENV_KEYS, PerAxisMetrics, type PlannedStep, type PricingRow, type ProbeShadowOptions, type ProbeShadowServed, type ProfileToRowOptions, type PromoteReadyFindingRow, type PromoteReadyResolution, type PromotionRow, type PromotionsRuntime, PromptIR, Provider, ProviderOverrides, type ProviderReachability, ROLLBACK_SUPPRESSION_WINDOW_DAYS, RULE_DISCIPLINE_GATES_V1, RULE_DISCIPLINE_GATES_V1_STRUCTURED, RULE_SEQUENTIAL_TOOL_CLIFF, type ReachabilityOpts, RecordInput, RecordOutcomeInput, type RunAdvisorPhase2Context, STRATEGY_AUTHORSHIP_INDEPENDENT, STRATEGY_AUTHORSHIP_LIMITATION, SectionRewrite, type ShadowProbeRecordInput, type StrategyAttribution, type StrategyAttributionResult, type StrategyOutcome, type SupportedProvider, type SurfaceFailureRow, type SurfaceStats, SystemModelMessage, TRANSLATOR_FLOOR, _testResetMeasuredFailure, _testResetOutcomeSourceWarning, _testResetPromotions, _testWaitForMeasuredFailureRefresh, _testWaitForPromotionsRefresh, altBlindGatesBlockFor, altGatesBlockFor, applyArchetypeConvention, applySectionRewrites, attachCacheControlToStreamTextInput, awaitMeasuredFailureReady, awaitPromotionsReady, brainHealth, buildGoldenIrRow, buildLLMJudge, buildPairwiseJudgePrompt, buildShadowProbeRow, burstCaveat, call, chainProviderSpread, classifyEvidenceWindow, classifyStrategyOutcome, clearBrain, combineOrderSwappedVerdicts, compile, compileForAISDKv6, configureBrain, configureMeasuredFailureBrain, configurePromotionsBrain, countTokens, createDelegate, deriveFamilyFromModelId, deriveOwnership, estimateChainCostUsd, estimateModelCostUsd, execute, findBetterFit, flushBrainDeadLetter, formatEvidenceSpan, getActionableAdvisories, getAllStarterChains, getAllStarterChainsWithGrounding, getApplicablePromotion, getArchetypePerfScore, getDefaultFallbackChain, getDefaultFallbackChainWithGrounding, getMeasuredFailureVerdict, getModelCompatibility, getPerAxisMetrics, getReachabilityDiagnostic, getRecentRollback, getRecommendedPrimary, getSequentialStarterChain, getSequentialStarterChainWithGrounding, getStaleExclusionFindings, getStarterChain, getStarterChainWithGrounding, isAltStrategy, isAutoPromoteEnabledFromEnv, isBrainQueryActiveFor, isBrainSync, isDelegateEnabledFromEnv, isExclusionFindingsBrainActive, isMeasuredFailureBrainActive, isMeasuredFailureGateEnabledFromEnv, isModelReachable, isPromotionsBrainActive, isProviderReachable, judgeMeasuredFailure, loadAliasesFromBrain, loadArchetypePerfFromBrain, loadArchetypePerfNFromBrain, loadChainsFromBrain, loadModelsFromBrain, loadPricingFromBrain, mapMeasuredFailureRows, markAdvisoryResolved, markExclusionFindingHandled, markPromoteReadyHandled, parseJudgeVerdict, peekBrainDeadLetter, planDecomposition, prefetchMeasuredFailure, prefetchPromotions, probeShadow, profileToRow, readBrainReadEnv, record, recordGoldenIr, recordOutcome, recordShadowProbe, renderIrForJudge, resetTokenizer, resolveConventionsForProfile, resolveOutcomeSource, resolvePricingAt, resolveProviderKey, rowToAdvisory, rubricFor, runAdvisor, runGoldenEval, runStrategyEvalWithAttribution, setTokenizer, wilsonLowerBound, withAltBlindDisciplineContract, withAltDisciplineContract, withDisciplineContract };