/**
 * AttentionTopicGuard — a per-source + global circuit breaker for forum-topic
 * creation. NOT a blocker: it is a DELIVERY SHAPER (same class as
 * SentinelNotifier), never a gate. It holds no authority over agent behavior or
 * information flow — it only changes the FORM of delivery (one coalesced topic +
 * a log line) for non-critical, high-volume notices, and never withholds a
 * critical notice or drops an item. See docs/signal-vs-authority.md (the rate-
 * counter / transport-dedup carve-outs).
 *
 * Built in response to the 2026-05-28 topic-spam flood (the SECOND such flood;
 * the first, 2026-05-22, produced the SentinelNotifier fix). Root cause both
 * times: `TelegramAdapter.createAttentionItem` spawns a BRAND-NEW forum topic
 * per attention item, and there was no structural gate stopping a housekeeping
 * feature from raising attention items at volume.
 *
 * It sits at the one chokepoint (createAttentionItem) and caps how many NEW
 * topics may be spawned in a rolling window — BOTH per source AND globally. Past
 * the budget, items are COALESCED into one running notice topic + logged. The
 * GLOBAL cap is load-bearing: a mis-wired feature that varies its `sourceContext`
 * per item would dodge a per-source-only budget, so once total topic creation in
 * the window exceeds the global ceiling, every further non-critical item — of any
 * source — coalesces into ONE shared global bucket. That makes the "a brand-new
 * mis-wired feature gets auto-throttled" guarantee hold regardless of source
 * cardinality.
 *
 * Invariants:
 *  - HIGH / URGENT (case-insensitive; CRITICAL treated as URGENT) ALWAYS get
 *    their own topic and are never counted. Critical messages are never coalesced.
 *  - No item is ever DROPPED. A coalesced item is still recorded in the attention
 *    store and written to the suppression audit log; only its per-item TOPIC is
 *    withheld.
 *
 * Pure logic, injectable clock, bounded memory — unit-testable in isolation.
 */
export interface AttentionTopicGuardConfig {
    /** When false, every item is allowed its own topic (pre-guard behavior). */
    enabled: boolean;
    /** Rolling window over which topic creations are counted. */
    windowMs: number;
    /** Max NEW topics a single source may spawn within `windowMs`. */
    maxTopicsPerSource: number;
    /**
     * Max NEW topics across ALL sources within `windowMs`. Backstop against a
     * source that varies its key per item to dodge the per-source budget. Past
     * this, non-critical items coalesce into one shared global bucket regardless
     * of source. Must be >= maxTopicsPerSource to be meaningful.
     */
    maxTopicsGlobal: number;
    /** Hard cap on distinct source keys tracked (memory bound). */
    maxTrackedSources: number;
}
export declare const DEFAULT_ATTENTION_TOPIC_GUARD: AttentionTopicGuardConfig;
/** The shared key used when the GLOBAL cap (not a per-source cap) trips. */
export declare const GLOBAL_BUCKET = "*";
/**
 * Thrown by the topic-creation chokepoint (`TelegramAdapter.createForumTopic`)
 * when an `origin: 'auto'` creation exceeds the last-resort flood ceiling.
 * Deliberately the same failure shape as a Telegram 429 — every existing
 * caller already survives topic-creation failure (rate limits happen in the
 * wild), so the budget rides battle-tested error paths instead of inventing
 * a new fallback surface.
 */
export declare class TopicFloodBudgetError extends Error {
    readonly topicName: string;
    readonly label: string;
    readonly bucket: string;
    constructor(topicName: string, label: string, bucket: string);
}
export type GuardDecision = {
    action: 'allow';
} | {
    action: 'coalesce';
    firstInEpisode: boolean;
    suppressedCount: number;
    bucket: string;
};
export declare class AttentionTopicGuard {
    private readonly cfg;
    private readonly now;
    /** source key -> timestamps of recent topic-relevant events within the window. */
    private readonly events;
    /** bucket key -> count of items coalesced in the CURRENT (uninterrupted) episode. */
    private readonly episode;
    /** Global rolling timeline of topic-relevant events (all sources). */
    private globalEvents;
    constructor(cfg?: Partial<AttentionTopicGuardConfig>, now?: () => number);
    get config(): Readonly<AttentionTopicGuardConfig>;
    /**
     * Decide whether an item from `source` at `priority` may spawn its own topic.
     * Returns the coalesce `bucket` (the source key, or GLOBAL_BUCKET when only the
     * global cap tripped) so the adapter routes all global-flood notices into ONE
     * shared topic rather than one-per-varying-source.
     */
    decide(source: string | undefined, priority: string | undefined): GuardDecision;
    /** Drop source keys whose events have all aged out, and hard-cap map size. */
    private evictStaleSources;
    /** Test/inspection seam. */
    episodeCount(bucket: string): number;
    /** Test/inspection seam — number of distinct source keys currently tracked. */
    get trackedSourceCount(): number;
}
//# sourceMappingURL=AttentionTopicGuard.d.ts.map