/** * Action-intent writer — serialises the MCP's per-pattern action plan to * `data/action-intent.json` in the customer gitops repo. * * The INTENT of what the engine should do with each pattern lives HERE, * separate from the numeric floor the rate receiver enforces. * * File shape: * { * "schema_version": "1.0", * "updated_at_iso": "", * "entries": [ * { * "pattern_hash": "abc123", * "service": "frontend", * "action": "drop", * "reason": "high-volume noise; no audit value", * "set_at_iso": "", * "until_epoch_sec": 0 * }, * ... * ] * } * * Deterministic field ordering in the serialised JSON keeps git diffs * readable. Entries are sorted by (service ASC, pattern_hash ASC) so * a refresh PR that adds a single pattern inserts exactly one line. * * `until_epoch_sec = 0` means "no expiry" (permanent until the next * configure_engine run replaces the file). Non-zero values are an ISO * epoch in seconds. */ import type { Action } from './cost.js'; export interface ActionIntentEntry { /** Stable pattern identity (tenx_hash / symbolMessage hash). */ pattern_hash: string; /** * Service name (k8s_service / k8s_container label from TSDB). * Used as the primary sort key and for human readability. May be * empty string when the engine label is absent. */ service: string; /** The intended engine action for this pattern. */ action: Action; /** Human-readable explanation of why this action was chosen. */ reason: string; /** ISO-8601 timestamp when this entry was written by the MCP. */ set_at_iso: string; /** * Unix epoch seconds after which the engine should revert to the * container-default behaviour. `0` means no expiry. */ until_epoch_sec: number; } export interface ActionIntentFile { schema_version: '1.0'; updated_at_iso: string; entries: ActionIntentEntry[]; } /** * Serialise action-intent entries to a JSON string suitable for writing * to `data/action-intent.json`. * * Guarantees: * - Entries sorted by (service ASC, pattern_hash ASC) for stable diffs. * - Each entry serialised with fields in canonical order so line-level * git diffs are predictable. * - Two-space indentation for readability. * - `updated_at_iso` defaults to current UTC time when not supplied. */ export declare function writeActionIntent(entries: ActionIntentEntry[], opts?: { updated_at_iso?: string; }): string; /** * Derive the engine's per-service `actions.csv` body from the same * per-pattern action-intent entries that feed `action-intent.json`. * * The engine's receiver reads this file keyed by k8s container (== the * service) and stamps `route()` on that service's regulator-excess * slice. ONE row per service. A service absent from the file defaults to * `drop` engine-side, so only services with entries are emitted. * * File shape: * container,action ← header * frontend,compact * checkout,drop * payment,offload * * Per-service action rule: * 1. Group entries by `service`. * 2. Pick the MODE — the most frequent `action` among that service's * patterns. * 3. Tie-break by the MOST AGGRESSIVE action in the order * drop > offload > tier_down > compact > sample > pass. * * Rows are sorted by service ASC for stable git diffs (same convention as * writeActionIntent). Entries with an empty `service` are skipped — the * engine keys this file by container and an empty key is meaningless (those * patterns still carry their action in action-intent.json). */ export declare function deriveActionsCsv(entries: ActionIntentEntry[], authoritativeByService?: Map): string; /** * Convenience builder. Converts a flat map of * `pattern_hash → { action, service?, reason?, untilEpoch? }` to a * list of `ActionIntentEntry` objects ready for `writeActionIntent`. * * `set_at_iso` is stamped with the current UTC time unless overridden * via the `set_at_iso` field in the per-pattern override object. */ export declare function buildActionIntentEntries(patterns: Array<{ pattern_hash: string; action: Action; service?: string; reason?: string; until_epoch_sec?: number; set_at_iso?: string; }>, defaults?: { set_at_iso?: string; }): ActionIntentEntry[];