/** * log10x_baseline — establish the X% commitment baseline. * * Hero pre-requisite for any commitment-grade configuration. Before an * agent can wire a target reduction percent into `log10x_configure_engine`, * we need three things to be true: * * 1. Reporter has been emitting metrics for at least 7 days. Anything * shorter and the cap derivation rests on cold-start noise. * 2. The metrics we see cover at least 80% of the customer's stated * destination volume. If we're only seeing 30% of the SIEM's daily * ingest, the cap will under-attribute spend and over-promise savings. * 3. The 30-day history is not visibly contaminated by an anomaly * window (deploy storms, incident floods). Any single day > 4× the * rolling 7d median poisons the percentile math. * * When any gate fails we return `status: 'not_ready'` with a structured * `not_ready_reason` and a remediation string. When all gates pass, we * return the current spend, the no-action 90d projection (organic growth * extrapolated from the 30d window), the top contributors, and a * recommended `target_percent` band derived from how much of the top is * actually compactable on the destination. * * Reads only existing Reporter metrics (`all_events_summaryBytes_total`, * `all_events_summaryVolume_total`). Zero engine ask. * * Open questions resolved by spec (defaults chosen, flagged inline): * - Reporter age threshold: 7d. Overridable via LOG10X_BASELINE_MIN_DAYS * for testing fixtures with shorter histories. * - Coverage threshold: 80% of stated_daily_gb (caller-supplied; absent * → coverage gate is informational, not blocking). * - Anomaly threshold: 4× rolling 7d median on any day in the 30d * window. Single-day windows below 1% of trailing 7d are skipped * (treated as missing data, not zeros, so a forwarder outage doesn't * trip the anomaly gate). */ import { z } from 'zod'; import type { EnvConfig } from '../lib/environments.js'; import { type Action, type DisclosedDollarValue } from '../lib/cost.js'; import { type SiemId } from '../lib/siem/pricing.js'; import { type StructuredOutput } from '../lib/output-types.js'; import { type VolumeLensResolution } from '../lib/volume-lens.js'; export type BaselineHorizon = '30d' | '90d'; export type BaselineStatus = 'ready' | 'not_ready'; export type NotReadyReason = 'reporter_too_new' | 'coverage_low' | 'anomaly_window' | 'no_destination' | 'no_data'; export type RateSource = 'list_price' | 'customer_supplied' | 'unset'; export interface BaselineTopContributor { pattern_hash: string; pattern: string; service: string; severity: string; share_pct: number; /** * Projected monthly $ for this contributor at the resolved `rate_source`. * `null` when `rate_source === 'unset'` (no destination + no customer * override). Aliased by `monthly_usd_at_list` for one release per the * percent-first dual-field rule. */ monthly_usd: number | null; /** Alias of `monthly_usd` carried for one release while callers migrate. */ monthly_usd_at_list: number | null; avg_event_size_bytes: number; compactable: boolean; } export interface BaselineEnvelopeData { status: BaselineStatus; not_ready_reason?: NotReadyReason; reporter_age_days: number; coverage_pct: number; destination: SiemId | null; horizon: BaselineHorizon; /** * Origin of the $/GB used for all dollar math in this envelope. `unset` * means no destination was resolved and no `effective_ingest_per_gb` was * supplied — dollar fields are then `null` and the headline / markdown go * percent-first. */ rate_source: RateSource; /** * The resolved ingest $/GB actually used for all dollar math, stated * explicitly so readers don't have to back it out of monthly_usd / bytes. * `null` when rate_source === 'unset'. (services exposes the same via * `cost_per_gb`; baseline carries it here for symmetry.) Optional: the * not_ready envelope omits it (no rate computed before the gates pass). */ effective_per_gb?: number | null; /** * The rate resolver's own disclosure for `effective_per_gb`, verbatim. Every * sibling tool renders this; baseline resolved the rate through the same * chain and then dropped the sentence, so a ClickHouse envelope quoted a * $/GB figure with nothing saying it is a storage rate and not the bill. * `null` when rate_source === 'unset' or the resolver had nothing to say. */ rate_disclosure?: string | null; /** * True when these dollars rest on a model rather than on the destination's * own meter. ClickHouse only, today: there the bill is compute. */ modeled?: boolean; /** Why the dollars are modeled, in one line. Present only when modeled. */ modeled_note?: string; current: { bytes_window: number; bytes_window_display: string; bytes_per_day_p50: number; bytes_per_day_p50_display: string; bytes_per_day_p90: number; bytes_per_day_p90_display: string; /** `null` when `rate_source === 'unset'`. */ monthly_usd: number | null; /** Alias of `monthly_usd` carried for one release. */ monthly_usd_at_list: number | null; /** Disclosed-value mirror of `monthly_usd`. `null` when `rate_source === 'unset'`. */ monthly_usd_disclosed: DisclosedDollarValue | null; }; projection_no_action_90d: { /** `null` when `rate_source === 'unset'`. */ monthly_usd_in_90d: number | null; monthly_usd_in_90d_at_list: number | null; /** Disclosed-value mirror of `monthly_usd_in_90d`. `null` when `rate_source === 'unset'`. */ monthly_usd_in_90d_disclosed: DisclosedDollarValue | null; /** * @deprecated Ambiguous unit. Use `monthly_compound_growth_pct` (same * value) for clarity, or `horizon_total_growth_pct` for the 90d total. * Kept for back-compat. The naming was flagged as a CFO 46% under-read * risk. */ growth_pct: number; /** * Monthly compound growth rate as a DECIMAL RATIO (0.36 = 36%/mo). * NOT a true percent — the `_pct` suffix is historical. For the * field whose value matches a "percent" reading (36, not 0.36) use * `monthly_compound_growth_percent`. */ monthly_compound_growth_pct: number; /** * Same value × 100 for readers who trust the `_pct` naming convention * used by sibling `share_pct` fields in the same envelope (where * share_pct=16.09 means 16.09%). monthly_compound_growth_percent=36 * means "36% growth per month compounded" with no ambiguity. */ monthly_compound_growth_percent: number; /** * Total growth over the 90d horizon as a DECIMAL RATIO (1.52 = * +152% total = 2.52× the starting cost). NOT a true percent — * use `horizon_total_growth_percent` for the percent-shaped value. */ horizon_total_growth_pct: number; /** Same value × 100. 152 means "+152% total growth over horizon". */ horizon_total_growth_percent: number; }; top_contributors: BaselineTopContributor[]; /** * Volume projection lens resolution. {lensed:false,factor:1} on a normal * (measured) run — the source_disclosure stamp + headline prefix only fire * when lensed. Always present so callers can read it without a guard. */ volume_lens: VolumeLensResolution; recommended_target_range?: { low_pct: number; expected_pct: number; high_pct: number; /** * Provenance for the band so consumers can tell a calibrated heuristic * from the hand-picked drop-only fallback. `drop_only_fallback` = no * compactable contributors, range is the hardcoded {10/15/25}. * `compactable_share_heuristic` = expected = share_top5_compactable_pct * × 0.7. */ basis: 'drop_only_fallback' | 'compactable_share_heuristic'; /** The exact formula that produced (low_pct, expected_pct, high_pct). */ formula: string; /** Inputs the formula consumed. */ inputs: { share_top5_compactable_pct: number; }; }; remediation?: string; } export declare const baselineSchema: { horizon: z.ZodDefault>; destination: z.ZodOptional>; statedDailyGb: z.ZodOptional; effectiveIngestPerGb: z.ZodOptional; environment: z.ZodOptional; monthly_volume_gb: z.ZodOptional; view: z.ZodOptional>>; }; export declare function executeBaseline(args: { horizon?: BaselineHorizon; destination?: SiemId; statedDailyGb?: number; effectiveIngestPerGb?: number; monthly_volume_gb?: number; view?: 'summary'; }, env: EnvConfig): Promise; declare function autoDetectDestination(env: EnvConfig): SiemId | undefined; export type { Action }; /** * Test hook. `autoDetectDestination` decides which cost model a tenant is * billed against from a free-text `analyzer` string, and its CLAUSE ORDER is * load-bearing: a bare `elastic` test would swallow "elastic serverless" and * price a Serverless tenant at the self-hosted rate. Exported so that ordering * is covered rather than assumed. */ export declare const _internals: { autoDetectDestination: typeof autoDetectDestination; };