/** * log10x_configure_engine * * Converts a `target_percent` (or `budget_usd`) commitment into the engine's * policy files — caps.csv (per-container byte caps) + actions.csv (per-service * over-cap disposition) — plus the MCP-side data/action-intent.json, delivered * as a `gh` PR against the customer gitops repo or a kubectl ConfigMap write. * The engine hot-reloads the files on the next poll; no pipeline restart, no * event drops. * * Solver: greedy v1, ordered by (current_bytes_30d * severity_weight) DESC, * where severity_weight = audit:1.0, error:0.8, standard:0.5, debug:0.2, * synthetic:0.1. Replace with LP only if greedy is materially suboptimal * on a representative customer. * * Per-destination action resolution honors the cost lib's CompactMode: * - splunk (envelope) compact ⇒ encode-in-event * - elasticsearch (index-pruned) compact ⇒ pruned _source * - datadog/cw/azure/gcp/sumo/clickhouse (no-op) * compact is rejected and the solver * falls back to the destination's * FIRST LEGAL SAVING LEVER, never to * drop: cloudwatch ⇒ tier_down, * datadog ⇒ offload (Flex tier_down * is unpriced), clickhouse ⇒ offload, * offload-only destinations ⇒ offload. * * ClickHouse is in the no-op list on a measurement rather than a missing * expander: compaction there was worth about 7% of table bytes, and table * bytes are not the ClickHouse bill. That bill is compute, and compute follows * rows inserted, so offload is the lever. * * drop/sample are opt-in only on the destination-resolution path: they appear * in no DEFAULT_ACTION_BY_DESTINATION entry, so the per-service auto path * never selects a lossy lever. * * Tier defaults are the other half of that contract, and they are caller- * configurable via `action_defaults`: * - audit → always `pass` (not configurable) * - error → `pass` by default. Severity error/warn/warning is kept * verbatim unless the caller sets `action_defaults.error`, * which is the contract the POC report's recommendation * rules render (lib/poc-report-renderer.ts). See the note on * cap semantics in renderCsvDiff for why the per-pattern * action never reaches the engine. * - debug / synthetic → `drop` by default. These two ARE lossy defaults; * a caller who needs them lossless sets `action_defaults`. * * Cross-validation: exactly one of target_percent / budget_usd is required; * else the tool returns a structured not-configured envelope. * * Phases (data.phase in the envelope): * - 'target_resolution' gitops repo / destination could not be resolved * - 'backend' customer metrics backend not configured * - 'resolution_prompt' service matched multiple containers — agent re-calls * with `containers=[...]` * - 'solver_failed' target unreachable without violating floors * - 'pr_rendered' success — `pr_command` ready to paste (or null when * current state already meets target) * * Zero engine ask: every query runs against existing receive-aggregator * metrics (all_events_summaryBytes_total labeled by k8s_container, * tenx_hash, severity_level). The PR machinery is the same `gh` pattern * configure_regulator already uses. * * Not-configured states return structured envelopes * (CustomerMetricsNotConfiguredError + the shapes configure_regulator * uses) rather than throwing. */ import { z } from 'zod'; import type { EnvConfig } from '../lib/environments.js'; import { type StructuredOutput } from '../lib/output-types.js'; import { COST_MODEL_BY_DESTINATION, getDestinationCostModel, type Action } from '../lib/cost.js'; import type { SiemId } from '../lib/siem/pricing.js'; declare const WINDOWS_PER_DAY: number; declare const WINDOWS_PER_MONTH: number; declare const MIN_REPORTER_DAYS = 7; /** * Dual-axis feasibility: a plan hits its target if it sheds enough BYTES or * saves enough DOLLARS. Rate-only actions (tier_down) have bytes_out == * bytes_in, so a byte-only test reports an all-tier_down plan (e.g. the * CloudWatch standard-tier default) infeasible despite real spend savings. * `saved_dollars` per row already captures tier_down's rate delta, so the * caller passes the summed row savings as `achievedSavedUsd`. */ export declare function isPlanFeasible(p: { targetShedBytes: number; remainingBytesToShed: number; currentMonthlyUsd: number; targetPercent: number; achievedSavedUsd: number; }): { feasible: boolean; bytesFeasible: boolean; dollarsFeasible: boolean; }; export type Tier = 'audit' | 'error' | 'standard' | 'debug' | 'synthetic'; /** * The tiers whose action comes from `action_defaults`. `audit` is excluded: * it is unconditionally `pass` and callers cannot change it. */ export type ConfigurableTier = Exclude; /** Actions that discard events. Never a default for any tier but debug/synthetic. */ export declare const LOSSY_ACTIONS: readonly Action[]; export declare const configureEngineSchema: { mode: z.ZodDefault>; delivery: z.ZodDefault>; kubectl_namespace: z.ZodOptional; kubectl_configmap_name: z.ZodOptional; tolerance_pct: z.ZodOptional; service: z.ZodString; containers: z.ZodOptional>; target_percent: z.ZodOptional; budget_usd: z.ZodOptional; destination: z.ZodOptional>; es_pruned: z.ZodOptional; contract_type: z.ZodDefault>; signal_floor: z.ZodDefault; events_per_min_per_pod: z.ZodOptional; }, "strip", z.ZodTypeAny, { pattern_hash: string; reason?: string | undefined; events_per_min_per_pod?: number | undefined; }, { pattern_hash: string; reason?: string | undefined; events_per_min_per_pod?: number | undefined; }>, "many">>; action_defaults: z.ZodDefault>; standard: z.ZodDefault>; debug: z.ZodDefault>; synthetic: z.ZodDefault>; }, "strip", z.ZodTypeAny, { error: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; debug: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; standard: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; synthetic: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; }, { error?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; debug?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; standard?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; synthetic?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; }>>; respect_default_action: z.ZodDefault; reduction: z.ZodDefault>; observationDays: z.ZodDefault; snapshot_id: z.ZodOptional; gitops_repo: z.ZodOptional; gitops_branch: z.ZodDefault; lookup_path: z.ZodDefault; current_csv: z.ZodOptional; from_poc_id: z.ZodOptional; auto_apply: z.ZodDefault; read_only: z.ZodDefault; view: z.ZodDefault>; service_policy: z.ZodOptional>; keep_queryable: z.ZodOptional; }, "strip", z.ZodTypeAny, { standard_action?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; keep_queryable?: boolean | undefined; }, { standard_action?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; keep_queryable?: boolean | undefined; }>>>; auto_recommend: z.ZodDefault; compact_worth_it_ratio: z.ZodDefault; service_compaction: z.ZodOptional>>; }; declare const schemaObj: z.ZodObject<{ mode: z.ZodDefault>; delivery: z.ZodDefault>; kubectl_namespace: z.ZodOptional; kubectl_configmap_name: z.ZodOptional; tolerance_pct: z.ZodOptional; service: z.ZodString; containers: z.ZodOptional>; target_percent: z.ZodOptional; budget_usd: z.ZodOptional; destination: z.ZodOptional>; es_pruned: z.ZodOptional; contract_type: z.ZodDefault>; signal_floor: z.ZodDefault; events_per_min_per_pod: z.ZodOptional; }, "strip", z.ZodTypeAny, { pattern_hash: string; reason?: string | undefined; events_per_min_per_pod?: number | undefined; }, { pattern_hash: string; reason?: string | undefined; events_per_min_per_pod?: number | undefined; }>, "many">>; action_defaults: z.ZodDefault>; standard: z.ZodDefault>; debug: z.ZodDefault>; synthetic: z.ZodDefault>; }, "strip", z.ZodTypeAny, { error: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; debug: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; standard: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; synthetic: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; }, { error?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; debug?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; standard?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; synthetic?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; }>>; respect_default_action: z.ZodDefault; reduction: z.ZodDefault>; observationDays: z.ZodDefault; snapshot_id: z.ZodOptional; gitops_repo: z.ZodOptional; gitops_branch: z.ZodDefault; lookup_path: z.ZodDefault; current_csv: z.ZodOptional; from_poc_id: z.ZodOptional; auto_apply: z.ZodDefault; read_only: z.ZodDefault; view: z.ZodDefault>; service_policy: z.ZodOptional>; keep_queryable: z.ZodOptional; }, "strip", z.ZodTypeAny, { standard_action?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; keep_queryable?: boolean | undefined; }, { standard_action?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; keep_queryable?: boolean | undefined; }>>>; auto_recommend: z.ZodDefault; compact_worth_it_ratio: z.ZodDefault; service_compaction: z.ZodOptional>>; }, "strip", z.ZodTypeAny, { mode: "configure" | "refresh"; service: string; view: "summary" | "detail" | "pr_command_only"; delivery: "gitops" | "kubectl_configmap" | "stdout_only"; contract_type: "committed" | "on_demand"; signal_floor: { pattern_hash: string; reason?: string | undefined; events_per_min_per_pod?: number | undefined; }[]; action_defaults: { error: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; debug: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; standard: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; synthetic: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop"; }; respect_default_action: boolean; reduction: "soft" | "hard"; observationDays: number; gitops_branch: string; lookup_path: string; auto_apply: boolean; read_only: boolean; auto_recommend: boolean; compact_worth_it_ratio: number; destination?: "datadog" | "splunk" | "elasticsearch" | "clickhouse" | "cloudwatch" | "azure-monitor" | "gcp-logging" | "sumo" | undefined; snapshot_id?: string | undefined; target_percent?: number | undefined; kubectl_namespace?: string | undefined; kubectl_configmap_name?: string | undefined; tolerance_pct?: number | undefined; containers?: string[] | undefined; budget_usd?: number | undefined; es_pruned?: boolean | undefined; gitops_repo?: string | undefined; current_csv?: string | undefined; from_poc_id?: string | undefined; service_policy?: Record | undefined; service_compaction?: Record | undefined; }, { service: string; mode?: "configure" | "refresh" | undefined; destination?: "datadog" | "splunk" | "elasticsearch" | "clickhouse" | "cloudwatch" | "azure-monitor" | "gcp-logging" | "sumo" | undefined; view?: "summary" | "detail" | "pr_command_only" | undefined; snapshot_id?: string | undefined; target_percent?: number | undefined; delivery?: "gitops" | "kubectl_configmap" | "stdout_only" | undefined; kubectl_namespace?: string | undefined; kubectl_configmap_name?: string | undefined; tolerance_pct?: number | undefined; containers?: string[] | undefined; budget_usd?: number | undefined; es_pruned?: boolean | undefined; contract_type?: "committed" | "on_demand" | undefined; signal_floor?: { pattern_hash: string; reason?: string | undefined; events_per_min_per_pod?: number | undefined; }[] | undefined; action_defaults?: { error?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; debug?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; standard?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; synthetic?: "pass" | "sample" | "compact" | "tier_down" | "offload" | "drop" | undefined; } | undefined; respect_default_action?: boolean | undefined; reduction?: "soft" | "hard" | undefined; observationDays?: number | undefined; gitops_repo?: string | undefined; gitops_branch?: string | undefined; lookup_path?: string | undefined; current_csv?: string | undefined; from_poc_id?: string | undefined; auto_apply?: boolean | undefined; read_only?: boolean | undefined; service_policy?: Record | undefined; auto_recommend?: boolean | undefined; compact_worth_it_ratio?: number | undefined; service_compaction?: Record | undefined; }>; export type ConfigureEngineArgs = z.infer; export interface PerPatternRow { pattern_hash: string; /** Human pattern name — renderers lead with this, never the hash. */ pattern: string; current_bytes_30d: number; cap_bytes_per_window: number; action: Action; /** k8s_container this slice belongs to (== the engine's actions.csv key). */ container?: string; saved_bytes_monthly: number; saved_dollars_monthly: number; projected_monthly_usd_low: number; projected_monthly_usd_expected: number; projected_monthly_usd_high: number; floor_reason?: string; reason: string; } export declare function executeConfigureEngine(args: ConfigureEngineArgs, env?: EnvConfig): Promise; interface ResolvedTarget { gitops_repo: string; lookup_path: string; gitops_branch: string; destination: SiemId; /** * Active env id resolved from envs.json / env vars (LOG10X_ENV_ID). Used * to anchor Prometheus selectors with `tenx_env=""` so per-pattern * scans don't fan out across every tenant on the shared prom backend. * Undefined for single-tenant prom backends (back-compat fallback). */ envId?: string; } interface ServiceCompressibility { /** optimized/input, clamped to [0.02, 1.0]; null when unmeasurable. */ ratio: number | null; input_bytes: number; optimized_bytes: number; /** * Where the ratio came from. `live` = the engine's realized optimize-mode * output (Prometheus, full production volume). `sample` = an on-demand * log10x_measure_compaction run (real codec on a sampled batch), used before * optimize mode is deployed. Live wins when both exist. Absent is treated as * `live` (the historical default). */ source?: 'live' | 'sample'; } interface ServiceActionDecision { action: Action; source: 'user_pinned' | 'auto' | 'global_default'; reason: string; ratio_source: 'measured_live' | 'measured_sample' | 'static_band'; measured_compression_pct: number | null; keep_queryable: boolean; /** Measured ratio threaded into projectActionRange; cost.ts honors it for compact only on envelope destinations. */ compact_ratio_override?: number; } /** * Resolve the standard-tier action for one service (k8s_container) under the * env's single destination. Precedence: explicit pin (validated legal) -> * the global non-compact action_defaults.standard or auto-off legacy fallback * -> compressibility-driven auto-recommendation (compact when it compresses * well and stays queryable; offload when it compresses poorly). Never emits an * action that is illegal or zero-saving on the destination. */ export declare function _resolveServiceAction(params: { container: string; destination: SiemId; model: ReturnType; compressibility?: ServiceCompressibility; policy?: { standard_action?: Action; keep_queryable?: boolean; }; autoRecommend: boolean; globalStandardAction: Action; compactWorthItRatio: number; warnings: string[]; }): ServiceActionDecision; export declare function inferTier(severity: string): Tier; /** Per-tier actions the solver applies, after `action_defaults` resolution. */ export interface TierActionDefaults { error: Action; standard: Action; debug: Action; synthetic: Action; } /** * Tier → action for a row that is NOT `signal_floor` pinned. * * The floor pin is deliberately NOT handled here. It is checked at the call * site, ahead of this function, so the floor keeps its visible precedence in * the solver loop instead of being buried in a helper. `_resolveTierAction` * therefore describes only what a tier does when nothing pre-empts it. * * Exported so `test/severity-policy-drift.test.ts` can table-test every tier * against the promises the POC report renders, without standing up a metrics * backend. That test is the reason this is a pure function. * * `audit` and `error` are the severity-protected tiers, and both resolve to * `pass` unless the caller opts out via `action_defaults.error`. Keeping * error-class lines verbatim is what poc-report-renderer tells the customer, * and the solver has to agree with the artifact the customer reads. */ export declare function _resolveTierAction(tier: Tier, defaults: TierActionDefaults, standardOverride?: Action): { action: Action; reason: string; defaultTier: ConfigurableTier | null; }; export declare function renderCsvDiff(containers: string[], currentCsv: string | undefined, rows: PerPatternRow[], defaultAction: Action, actionByContainer: ReadonlyMap, reduction: 'soft' | 'hard', commitment?: { targetPercent: number; baselineMonthlyBytes: number; }): string; /** * Render the engine's per-service action file (`actions.csv`) — the sibling * of caps.csv that `rateReceiverActionLookupFile` points at. * * ENGINE GRAMMAR (rate-object-cap.js): * ,[:][:] * A service with no row (or no file) defaults to `drop` for its over-cap * slice, so this file must ship WITH every caps.csv delivery: caps without * actions silently turns compact/offload/tier_down/sample/pass policies * into hard drops. * * BOOT CONTRACT: when the cap variant is active the engine hard-resolves * this file at pipeline init (`rateReceiverCapInput` loads both tables) — * a missing OR EMPTY actions.csv fails the receiver launch. Always emit * the header plus at least one row, and never deliver caps.csv without it. * * Merge semantics mirror the caps merge: rows for other services in the * existing file survive; the configured containers' rows are replaced. */ export declare function renderActionsCsv(containers: string[], actionByContainer: ReadonlyMap, defaultAction: Action, existingActionsCsv: string | undefined, reduction: 'soft' | 'hard'): string; export declare function renderPrCommand(args: ConfigureEngineArgs, resolved: ResolvedTarget, csvDiff: string, siblings?: { actionsCsv?: string; intentJson?: string; }): string; export { COST_MODEL_BY_DESTINATION, MIN_REPORTER_DAYS, WINDOWS_PER_DAY, WINDOWS_PER_MONTH }; /** * Merge a freshly-rendered actions.csv over the ConfigMap's existing one: * rows for other services survive, configured containers' rows win. Same * survival rule as mergeCapsRows; `container,action` header. */ export declare function mergeActionRows(existingCsv: string | undefined, newCsv: string): string;