/** One minute is the base rollup granularity. */
export declare const ROLLUP_BUCKET_MS = 60000;
/**
 * Upper boundaries (inclusive, in ms) for the pre-aggregated latency histogram.
 * Bucket `i` counts durations `d` where `d <= LATENCY_BOUNDARIES_MS[i]` and
 * `d > LATENCY_BOUNDARIES_MS[i-1]`. A final OVERFLOW bucket (index
 * `LATENCY_BOUNDARIES_MS.length`) counts everything greater than the last
 * boundary, so a histogram always has `LATENCY_BOUNDARIES_MS.length + 1` cells.
 */
export declare const LATENCY_BOUNDARIES_MS: readonly number[];
/** The fixed cell count of every latency histogram (boundaries + 1 overflow). */
export declare const HISTOGRAM_BUCKET_COUNT: number;
/** A fresh, all-zeros histogram of the canonical fixed length. */
export declare function emptyHistogram(): number[];
/**
 * The histogram cell a duration falls in: the first index `i` where
 * `durationMs <= LATENCY_BOUNDARIES_MS[i]`, else the overflow index. Negative or
 * zero durations land in cell 0.
 */
export declare function histogramBucketIndex(durationMs: number): number;
/**
 * Increments the histogram cell for `durationMs` by one, in place. Safe against
 * the index typing (always a valid in-range cell of a fixed-length array).
 */
export declare function incrementHistogram(histogram: number[], durationMs: number): void;
/**
 * Normalizes a (possibly legacy/undefined) stored histogram into a fixed-length
 * zero-padded array. Legacy rollup rows with no histogram read back as all-zeros
 * of the canonical length — never NaN, never a wrong width.
 */
export declare function normalizeHistogram(histogram: number[] | null | undefined): number[];
/**
 * Element-wise additive merge of `addend` into `target` (mutates and returns
 * `target`). Both are normalized first, so legacy/short arrays are safe.
 */
export declare function mergeHistograms(target: number[], addend: number[] | null | undefined): number[];
/** Floors an epoch-ms timestamp to the start of its 1-minute rollup bucket. */
export declare function floorToBucket(epochMs: number): number;
/** An additive aggregate for (metric, bucketStart). metric = the entry `type` for now. */
export interface RollupDelta {
    metric: string;
    bucketStart: number;
    count: number;
    sum: number;
    max: number;
    /** Fixed-length ({@link HISTOGRAM_BUCKET_COUNT}) latency histogram for this group. */
    histogram: number[];
}
/** A materialized rollup row for (metric, bucketStart). */
export interface RollupBucket {
    metric: string;
    bucketStart: number;
    count: number;
    sum: number;
    max: number;
    /** Fixed-length ({@link HISTOGRAM_BUCKET_COUNT}) latency histogram for this bucket. */
    histogram: number[];
}
/**
 * Optional SPI a {@link StorageProvider} MAY also implement to support
 * pre-aggregated rollups. Detected at runtime via {@link isRollupStore}; it is
 * deliberately NOT part of the StorageProvider interface, so stores that do not
 * implement it keep working via the raw-scan fallback.
 */
export interface RollupStore {
    /**
     * Additively merge deltas into the rollup table (accumulate count/sum, keep a
     * running max). Idempotent per (metric, bucketStart) via upsert + increment.
     */
    recordRollups(deltas: RollupDelta[]): Promise<void>;
    /**
     * Buckets for the given metrics whose bucketStart is in [fromBucket, toBucket].
     * Order unspecified.
     */
    queryRollups(metrics: string[], fromBucket: number, toBucket: number): Promise<RollupBucket[]>;
}
/** Duck-types `s` as a {@link RollupStore} (recordRollups & queryRollups present). */
export declare function isRollupStore(s: object): s is RollupStore;
//# sourceMappingURL=rollup-store.d.ts.map