/** * Summaries-sourced rollups for retriever query results. * * The engine writes per-slice pre-aggregated summaries under * `qrs/{queryId}/{sliceFrom}_{sliceTo}/{worker}.jsonl` — each row carries * `summaryVolume` (event count), `summaryBytes`, and the deployment's named * enrichment fields (severity_level, tenx_user_service, ...). Summing those * rows yields WHOLE-MATCH rollups at a cost independent of match size, * unlike the event-derived rollups which only see the capped download * (the >limit-match wart). * * Honesty rules enforced by the CALLER (retriever-query.ts): * - Summaries are only used when the query had NO filters[] — whether the * engine's summary writer applies filters before aggregating is * unverified, so filtered queries keep event-derived rollups rather * than risk overcounting. * - Per-dimension coverage fallback: a deployment whose enrichmentFields * omit severity/service produces summary rows WITHOUT those keys * (absent, not empty). Such a dimension falls back to event-derived * counts (raw events always carry the fields). `coverage` reports * which dimensions the summaries can actually serve. * - The envelope stamps `rollup_basis` so a receipt reader knows whether * by_* reflects the whole match (qrs_summaries) or the capped download * (events_capped), or a per-dimension mix. */ import type { RetrieverSummary } from './retriever-api.js'; export interface SummaryRollups { by_severity: Record; by_service: Record; by_day: Record; /** Sum of summaryVolume across all rows = whole-match event count. */ total_volume: number; /** Sum of summaryBytes across all rows. */ total_bytes: number; /** * Which dimensions the summary rows can serve: true when at least one * row carries the field. False = the deployment's enrichmentFields do * not include it — fall back to event-derived counts for that dimension. */ coverage: { severity: boolean; service: boolean; }; } export type RollupBasis = 'qrs_summaries' | 'events_capped' | 'mixed'; export declare function computeSummaryRollups(summaries: readonly RetrieverSummary[]): SummaryRollups; export interface RollupSelection { by_severity: Record; by_service: Record; by_day: Record; rollup_basis: RollupBasis; } /** * Pick the rollup maps + provenance stamp. Pure so the gating (the part * that decides whether the agent sees whole-match or capped counts) is * unit-testable without the tool harness. * * Rules: summaries are never used under filters[] (the engine summary * writer's filter behavior is unverified — overcount risk). A dimension * the summaries cannot serve falls back to the event-derived map. * 'qrs_summaries' is stamped ONLY when all three dimensions came from * summaries; any blend stamps 'mixed'. */ export declare function selectRollups(args: { eventDerived: { by_severity: Record; by_service: Record; by_day: Record; }; summaries: readonly RetrieverSummary[] | undefined; filtersActive: boolean; }): RollupSelection;