/** * DOES THIS INSTALL ACTUALLY CLEAR A BAR? -- the question a report cannot answer. * * `token-optimizer-savings` renders what happened. An operator rolling this out * across a team needs the other half: a number to hold it to, and a status code * when it is not met. Without that, "are we getting the savings we were told to * expect" is a question somebody has to answer by reading a table, which means * it is a question nobody answers twice. * * THE TWO HALVES ARE GATED SEPARATELY, NEVER BLENDED. The MCP half counts * materialized tool-payload tokens; the proxy half counts request bytes on the * wire against the bytes we would have sent. They are two measurements of two * things, and one combined percentage would be a headline that hides whichever * half was doing badly -- so each is checked against the target on its own and * the verdict names which one failed. * * AN ABSENT MEASUREMENT IS A FAILURE, NOT A PASS. This is the whole reason the * gate exists rather than a comparison in a shell script: a window with no * measured traffic has no percentage, a client that sent nothing has no * percentage, and `0 >= 0` would let both through as a success. Every check * below therefore carries the operations it was computed over, and a check with * none is reported as unmeasured and fails. * * A HALF THAT WAS NEVER CONFIGURED IS NOT CHECKED AND SAYS SO. An operator who * runs the MCP tools and no proxy has not failed a proxy target; the verdict * lists the scopes it checked, so a pass can never be read as covering * something that was not measured at all. * * READS NOTHING AND WRITES NOTHING. Every input is handed in. */ import type { AnalyticsEntry } from '../analytics/analytics-types.js'; import type { AnalyticsRollup } from '../analytics/analytics-rollup.js'; import { type ProxyInput } from './proxy.js'; /** * The windows an operator can name, and the label each one asks for. * * THE TOKENS ARE NOT THE LABELS. A label is prose that belongs to the report * and may be reworded; a token is an interface that a CI job pins. Mapping one * to the other here means rewording a heading cannot silently change which * period a team's gate is measuring. */ export declare const GATE_WINDOW: Readonly<{ readonly Today: "today"; readonly SevenDays: "7d"; readonly ThirtyDays: "30d"; readonly AllTime: "all"; }>; export type GateWindow = (typeof GATE_WINDOW)[keyof typeof GATE_WINDOW]; export declare const GATE_WINDOW_LABELS: Readonly>; export declare const GATE_WINDOWS: readonly GateWindow[]; /** What a check was measuring, as a value rather than as text to match. */ export declare const GATE_SCOPE: Readonly<{ readonly Mcp: "mcp-tool-traffic"; readonly Proxy: "proxy-wire-traffic"; readonly Client: "client"; }>; export type GateScope = (typeof GATE_SCOPE)[keyof typeof GATE_SCOPE]; /** Why a check failed, from a fixed vocabulary a consumer can switch on. */ export declare const GATE_REASON: Readonly<{ readonly Met: "met"; readonly BelowTarget: "below-target"; readonly NoTraffic: "no-measured-traffic"; readonly NotRecorded: "client-never-recorded"; }>; export type GateReason = (typeof GATE_REASON)[keyof typeof GATE_REASON]; export interface GateCheck { readonly scope: GateScope; /** The client a `Client` check is about; null for the two halves. */ readonly name: string | null; readonly targetPercent: number; /** The measured percentage, or null when nothing was measured. */ readonly measuredPercent: number | null; /** The operations the measurement is over -- the denominator of the claim. */ readonly operations: number; readonly passed: boolean; readonly reason: GateReason; } export interface GateVerdict { readonly window: GateWindow; readonly label: string; readonly targetPercent: number; readonly checks: readonly GateCheck[]; /** * Whether every check passed AND there was at least one. * * A GATE THAT CHECKED NOTHING HAS NOT PASSED. `checks.every(...)` on an empty * list is true, and that is exactly the shape of the defect this gate is for: * a CI job that reports success because no measurement reached it. */ readonly passed: boolean; } export interface GateRequest { readonly targetPercent: number; readonly window: GateWindow; /** Clients that must each have traffic in the window and meet the target. */ readonly clients: readonly string[]; } export interface GateInput { readonly entries: readonly AnalyticsEntry[]; readonly rollups: readonly AnalyticsRollup[]; readonly proxy: ProxyInput; readonly now: Date; } export declare function evaluateGate(input: GateInput, request: GateRequest): GateVerdict; /** * The verdict as text, for a person reading a failed CI job. * * THE FAILING CHECKS ARE NOT BURIED. Every check is printed, in the order they * were made, so a reader can see what passed as well -- but the first line says * whether the gate passed, because that is the only line most readers get. */ export declare function renderGate(verdict: GateVerdict): readonly string[]; /** The verdict as data, for a consumer that is not a person. */ export declare function gateJson(verdict: GateVerdict): Record; //# sourceMappingURL=gate.d.ts.map