/** * The single finding-identity-signature authority for the whole pipeline * (drift-plan R2). Before this module, three independent "is this the same * finding?" rules existed: audit's `reporting/findingIdentity.ts` (this 3-tier * ladder), remediate's `dedup/crossLensDedup.ts` (path + category + title * Jaccard + path overlap), and remediate's `coverage/findingLedger.ts` (bare id * string). They disagreed, so a finding could be one identity to the auditor and * another to the remediator. This module owns the deterministic signature; the * auditor re-keys findings off it, the remediator's dedup uses it as the exact * -match collapse (its Jaccard/overlap heuristic is a fuzzy layer on top), and a * finding's stable id (the coverage-ledger denominator key) is derived from it. * * It is a pure module — no IO, no hashing, no model identity — so the same * semantic finding always yields the same signature across passes, runs, and * both orchestrators. */ import type { Finding } from "./types/finding.js"; /** * The stable semantic fields a finding's identity may be derived from. * * Volatile, content-derived values — unit ids, line numbers, pass * ordinals/pass_id, timestamps — are deliberately absent from this shape so * they can never reach the signature at any ladder tier. The raw title is * accepted but only ever influences identity after aggressive normalization * (tier 3), and only when no stronger tier applies. */ export interface FindingIdentityFields { /** Repo-relative primary file path of the structural anchor, if any. */ anchor_path?: string; /** Symbol/scope identifier at the anchor (the anchor's unit/scope). */ anchor_symbol?: string; /** Rule/category identifier. */ category?: string; /** Lens — paired with category at tier 2 (the existing category convention). */ lens?: string; /** Title; aggressively normalized before it can influence identity. */ title?: string; } /** Separator-normalized (always `/`), case-folded, repo-relative path. */ export declare function normalizeAnchorPath(path: string | undefined): string; /** * Aggressively normalize a title so volatile content cannot influence * identity: case-folded; embedded file paths (with optional `:line[:col]` * suffixes) stripped; counts, line numbers, and all other numerals stripped; * punctuation collapsed; whitespace collapsed to single spaces. */ export declare function normalizeTitle(title: string | undefined): string; /** * The single, explicit, deterministic fallback ladder for finding identity. * The same semantic finding always yields the same signature across passes * and runs; the ladder consults stable semantic fields only: * * 1. **Structural anchor** — the repo-relative primary file path * (separator-normalized, case-folded) together with the anchor's * symbol/scope. The unit/scope is part of the signature, so two findings at * the same path but different scopes get distinct signatures. * 2. **Rule/category** — when no structural anchor is available, the * rule/category identifier paired with the lens (the existing category * convention). * 3. **Normalized title** — when neither anchor nor rule/category exists, an * aggressively normalized title (see {@link normalizeTitle}). * * Content-derived unit ids, line numbers, pass ordinals/pass_id, timestamps, * and raw (unnormalized) titles are never part of the signature: they do not * appear in {@link FindingIdentityFields}, so no tier can hash them. * * The signature is also independent of a finding's merged affected-file * *list*: at most the single structural anchor (primary path + scope) can * contribute, never the full file set, so a finding's identity stays put as * additional re-emitted files are unioned into it across passes and runs. */ export declare function findingIdentitySignature(fields: FindingIdentityFields): string; /** Extract only the stable identity-bearing fields from a {@link Finding}. */ export declare function findingIdentityFields(finding: Finding): FindingIdentityFields; /** * The deterministic identity signature of a {@link Finding} — the exact-match * key consumers use to decide whether two findings are the same defect. Shared * by the auditor's id re-keying, the remediator's cross-lens dedup (exact-match * layer), and the coverage ledger. */ export declare function findingIdentityKey(finding: Finding): string; //# sourceMappingURL=findingIdentitySignature.d.ts.map