import { type JoinKeyType } from './JoinKeys.js'; /** Where a seed value enters the search. */ export interface Seed { type: JoinKeyType; value: string; } /** * Why a row is in the timeline: the seed matched it, a key tied it in, or no seed was given and * the whole window was returned. */ export type Attribution = 'seed' | 'window' | JoinKeyType; export interface CorrelatedRow { row: Record; attribution: Attribution; } /** An expansion the engine declined, and the evidence for declining it. */ export interface Refusal { type: JoinKeyType; value: string; cardinality: number; threshold: number; } export interface CorrelateOptions { /** Distinct-actor ceiling above which a key is not expanded. Default 8. */ maxCardinality?: number; /** Expand regardless of cardinality. Off by default; the result reports the consequence. */ allowSharedIdentity?: boolean; } export interface CorrelationResult { rows: CorrelatedRow[]; refusals: Refusal[]; /** Key values actually expanded through, in visit order — the provenance of the result. */ expandedThrough: Array<{ type: JoinKeyType; value: string; }>; } /** * A judgement call from one incident, recorded rather than buried: a request id was 1:1, and a * shared community identity was 1:1371. Eight sits far above the former and far below the * latter. Worth revisiting against a second dataset. */ export declare const DEFAULT_MAX_CARDINALITY = 8; /** * Expand from seed values to every row belonging to the same actor. * * Salesforce splits one actor's activity across event types that share no common identifier. * Some carry a client address, some carry only a request id, and one carries the address column * but leaves it empty. Filtering on any single field finds a fraction of the activity, so the * search has to walk between keys — and walking between keys is exactly where correlation * invents relationships that are not there. * * Two guards keep it honest, and neither lives here by accident: * * Blank values cannot reach the frontier because {@link joinKeysOf} never yields one. A blank * admitted as a key matches every other row whose value is also blank, which is how a two-row * answer became a twenty-five-row one during the original hand reconstruction. * * Shared identities are refused by cardinality. A key standing for many actors is not an * identifier, and expanding through it presents a crowd's activity as one actor's. Refusals are * returned rather than applied quietly: a bounded timeline that does not say it was bounded is * as misleading as an over-attributed one. */ export declare function correlate(rows: ReadonlyArray>, seeds: ReadonlyArray, options: CorrelateOptions): CorrelationResult; //# sourceMappingURL=CorrelationEngine.d.ts.map