import { z } from 'zod';
import type { OccEntityFreshness, OccEntityQuery, OccEntityRef } from './api-types.js';
import type { LiveEntityIndex } from './resolve.js';
import type { EntityIndex } from './store.js';
import type { EntityDiagnostic } from './types.js';
import type { EntityEvidenceGapSummary } from './evidence.js';
export declare const ENTITY_COCHANGE_DEFAULT_LIMIT = 20;
export declare const ENTITY_COCHANGE_DEFAULT_MIN_COUNT = 3;
export declare const ENTITY_COCHANGE_DEFAULT_MAX_COMMIT_ENTITIES = 500;
export declare const EntityCochangeOptionsSchema: z.ZodObject<{
    limit: z.ZodOptional<z.ZodNumber>;
    minCount: z.ZodOptional<z.ZodNumber>;
    minConfidence: z.ZodOptional<z.ZodNumber>;
    maxCommitEntities: z.ZodOptional<z.ZodNumber>;
}, z.core.$strip>;
export type EntityCochangeOptions = z.infer<typeof EntityCochangeOptionsSchema>;
export interface EntityCochangeRuntimeOptions extends EntityCochangeOptions {
    signal?: AbortSignal;
}
export interface EntityCochangePair {
    a: OccEntityRef;
    b: OccEntityRef;
    cochangeCount: number;
    /** Number of considered commits in which `a` changed logic. */
    aChangeCount: number;
    /** `cochangeCount / aChangeCount`; `a` is the named target when one was supplied. */
    confidence: number;
    lastCoChange: string;
}
export interface EntityCochangeHonesty {
    freshness: {
        fresh: boolean;
        reasons: OccEntityFreshness['reasons'];
        workingTreeMeasured: boolean;
    };
    truncation: {
        truncated: boolean;
        reasons: EntityDiagnostic[];
        commitsSkipped: number;
        maxCommitEntities: number;
        omitted: number;
    };
    coverage: {
        commitsIndexed: number;
        commitsConsidered: number;
        eventsScanned: number;
        logicEvents: number;
        cosmeticEventsFiltered: number;
        neutralEventsFiltered: number;
        unknownEventsFiltered: number;
        historicalLineagesExcluded: number;
        currentCodeEntities: number;
    };
    ambiguityCount: number;
    evidenceGaps: EntityEvidenceGapSummary;
}
interface EntityCochangePayload {
    pairs: EntityCochangePair[];
    /** Full indexed commit-window denominator, including commits with no eligible entity event. */
    windowCommits: number;
    minCount: number;
    minConfidence: number;
    honesty: EntityCochangeHonesty;
}
export type EntityCochangeResult = ({
    status: 'resolved';
    query?: OccEntityQuery;
    entity?: OccEntityRef;
} & EntityCochangePayload) | {
    status: 'not_found';
    query: OccEntityQuery;
    candidates: OccEntityRef[];
    message: string;
} | {
    status: 'ambiguous';
    query: OccEntityQuery;
    candidates: OccEntityRef[];
    message: string;
} | {
    status: 'error';
    query?: OccEntityQuery;
    code: 'invalid-options' | 'invalid-query' | 'invalid-ref';
    message: string;
};
export interface EntityCochangeContext {
    entityIndex: EntityIndex;
    live: LiveEntityIndex;
    freshness: OccEntityFreshness;
}
/**
 * Aggregate temporal coupling from persisted entity events.
 *
 * Each commit contributes a set of lineage ids, so multiple events for one
 * lineage cannot inflate a pair. Only proved logic changes enter that set.
 * Current refs are joined after aggregation, which is what lets a pair survive
 * file and symbol renames while keeping the result directly addressable.
 */
export declare function entityCochange(query: OccEntityQuery | undefined, options: EntityCochangeOptions, context: EntityCochangeContext): EntityCochangeResult;
export {};
