/** * Reachability & Dead-Code Analysis (spec-20) — cross-language mark-and-sweep * over the unified call graph. * * "Is this reachable from any entry point?", "what is dead?", and "what becomes * dead if I delete X?" — graph reachability questions grep can't answer (it sees * text, not reach) and the model burns tokens guessing at. Reachability is forward * BFS from roots; candidate-dead is the unreached remainder; "dead if I delete X" * is the set reachable only through X. * * Prior art: knip / ts-prune do mark-and-sweep, but TS/JS-only. This is the * cross-language version over the tree-sitter graph (15+ languages). * * HONEST LIMITS — output is *candidates*, never deletion authority. Callback / * event-channel and route→handler dispatch is now PARTIALLY recovered via * synthesized edges (single-language, statically-paired registration+dispatch; * spec: add-synthesized-dynamic-dispatch-edges), and polymorphic dispatch through * inheritance/interfaces is recovered via Class Hierarchy Analysis (name+arity, * declared-type-narrowed where the receiver type is statically recoverable; spec: * add-type-hierarchy-resolved-dispatch). A symbol reachable only through such an * edge is no longer reported as high-confidence dead. What remains a blind spot: * reflection, computed/string-built dispatch (`obj[name]()`), cross-language * bridges and cross-language polymorphism, DI/plugin registries with no * statically-visible binding, RTA/VTA-level pruning of the CHA name+arity * over-approximation, and externally-consumed public exports — these can still * produce false "dead" positives. Roots include tests, imported symbols, and * detected framework entries; every candidate carries a confidence level and a * reason; nothing is ever auto-deleted. Pass `directResolvedOnly` to ignore * synthesized edges and get the strict directly-resolved reachability instead. */ import type { SerializedCallGraph } from '../../analyzer/call-graph.js'; export interface FindDeadCodeInput { directory: string; /** "What becomes dead if I delete this symbol?" — switches to delete-impact mode. */ ifDeleted?: string; /** Limit candidate-dead results (default 100). */ maxResults?: number; /** Only report candidates whose file path contains this substring. */ filePattern?: string; /** * Restrict reachability to directly-resolved edges only: synthesized * dynamic-dispatch edges are not traversed (spec: add-synthesized-dynamic-dispatch-edges). * Trades completeness for certainty — a symbol reachable only through a * synthesized edge is then treated as unreached. Default false. */ directResolvedOnly?: boolean; /** * Opt in to federation scope: a symbol with no consumer in THIS repo may still * be live across the fleet. When set, candidates consumed by another indexed * repo are pulled out of candidate-dead and reported as live-via-federation. * (change: add-multi-repo-federation) */ federation?: boolean; /** Restrict the federation scope to these registry repo names (default: all). */ federationRepos?: string[]; } /** * The candidate dead-code id set: code nodes (excluding tests) not reachable from * any liveness root (tests, by-name imports, HTTP handlers, main-like). Shares the * documented roots definition with {@link handleFindDeadCode} so `find_dead_code` * and landmark signals agree on what "dead" means. Candidate ids only — deadness * is a signal, never deletion authority (see module header). */ export declare function deadCodeIds(absDir: string, cg: SerializedCallGraph): Promise>; export declare function handleFindDeadCode(input: FindDeadCodeInput): Promise; //# sourceMappingURL=reachability.d.ts.map