/**
 * ParallelWorkOverlap — the pure cross-topic overlap detector that the
 * ParallelWorkSentinel (Phase B) runs on a cadence (docs/specs/parallel-activity-coherence.md).
 *
 * Convergence hardened this against false-positive nudges (a noisy councilor gets
 * muted, which is worse than silence). The containment lives HERE, in pure logic:
 *  - ACTIVITY GATE: only topics worked within a recent window are compared (a dormant
 *    overlap is not a live duplication risk — mirrors BurnDetector's activity gate).
 *  - SPECIFICITY: overlap rests on shared HIGH-SPECIFICITY tags (entities/files/identifiers,
 *    already filtered of boilerplate by extractTags) and requires ≥ minSharedSpecific of
 *    them — never on generic words. Rarer shared tags weigh more (IDF over the candidate set).
 *  - SELF-EXCLUSION: a topic never matches itself.
 *  - SIGNATURE: the sorted shared-tag SET — the dedup key the sentinel uses (with hysteresis)
 *    so a slowly-evolving focus does not re-nag and a genuinely new overlap is not suppressed.
 *
 * This module is PURE (no I/O, no time except the injected nowMs) so it is exhaustively
 * unit-testable. The stateful dedup/cooldown/cadence/nudge lives in the sentinel.
 */
/** The subset of a TopicActivity this detector needs (structurally compatible with ParallelActivityIndex output). */
export interface OverlapCandidate {
    topicId: number;
    tags: string[];
    updatedAt: number | null;
    running?: boolean;
}
export interface OverlapPair {
    /** Lower topicId first (stable pair key). */
    topicA: number;
    topicB: number;
    /** The high-specificity tokens both topics share (the genuine overlap). */
    sharedTags: string[];
    /** IDF-weighted overlap strength over the candidate set; higher = rarer shared tokens. */
    score: number;
    /** Sorted sharedTags joined — the dedup signature (the sentinel keys cooldown on the PAIR, hysteresis on this). */
    signature: string;
}
export interface DetectOverlapsOptions {
    nowMs: number;
    /** Only compare topics whose updatedAt is within this window (default 4h). Null updatedAt ⇒ excluded. */
    activityWindowMs?: number;
    /** Require at least this many shared high-specificity tags (default 1). */
    minSharedSpecific?: number;
    /** When true, at least ONE side of each pair must be currently running (default true — we nudge live work). */
    requireRunning?: boolean;
}
/**
 * Detect overlapping work across topics. Returns one OverlapPair per genuinely-overlapping
 * pair, strongest first. Pure: same inputs → same output.
 */
export declare function detectOverlaps(candidates: OverlapCandidate[], opts: DetectOverlapsOptions): OverlapPair[];
/** Stable pair key for sentinel-side cooldown (survives focus edits / signature drift). */
export declare function pairKey(topicA: number, topicB: number): string;
/**
 * Hysteresis: should a NEW overlap signature for an already-nudged pair re-fire? Only when
 * the shared-tag set has changed materially (Jaccard(old,new) < threshold) — so a one-token
 * focus tweak does not re-nag, but a genuinely different overlap does.
 */
export declare function signatureChangedMaterially(oldSig: string, newSig: string, jaccardThreshold?: number): boolean;
//# sourceMappingURL=ParallelWorkOverlap.d.ts.map