/** * Remove the comments the scan says are debt — and prove nothing else moved. * * The actuator is the dangerous half of this feature: a classifier that is 86% * precise only misinforms, but a pruner that is 86% precise deletes. So the * deliverable here is not the deletion, it is the PROOF, and the proof is a * structural check run on every file before it is written: * * - the diff is computed line-by-line against the plan, so a changed line that * the scan never named is a violation, not a surprise; * - every removed line must be a comment line, and a stripped trailing comment * must leave its code byte-identical; * - a line that carries a block-comment delimiter opening or closing ELSEWHERE * is never removed, because deleting it would turn the rest of the comment into * code — the one failure mode that makes this a compile error rather than a * lost sentence; * - a file whose line endings are mixed is left alone, since re-joining it would * rewrite every line and the proof would stop meaning anything. * * Anything that fails the check is reported and NOT written. The ledger records * every line removed, with the rule that fired, so a prune is reviewable after the * fact instead of only before it. */ import type { CommentFinding, CommentFindingKind } from './comment-hygiene.js'; /** What the pruner will do to one line. */ export type PruneAction = { readonly file: string; readonly line: number; readonly kind: CommentFindingKind; readonly matched: string; /** `drop-line` deletes the whole comment line; `strip-trailing` keeps the code. */ readonly mode: 'drop-line' | 'strip-trailing'; /** The full text of the line as it sits on disk right now. */ readonly lineText: string; /** The comment as the SCAN saw it — for a trailing comment, not the whole line. */ readonly comment: string; }; /** A finding the pruner refused to act on, with the reason. */ export type PruneSkip = { readonly file: string; readonly line: number; readonly reason: string; readonly text: string; }; export type PruneOptions = { readonly projectRoot: string; /** Narrow to one category; the default is both, which is the accepted boundary. */ readonly kinds?: readonly CommentFindingKind[]; /** Restrict to one file, repo-relative — how a single-case proof is run. */ readonly onlyFile?: string; /** Write the files. False (the default) plans and proves without touching disk. */ readonly apply?: boolean; }; export type PruneResult = { readonly scannedFiles: number; readonly planned: number; readonly dropped: number; readonly stripped: number; readonly skipped: number; readonly touchedFiles: readonly string[]; readonly notWritten: readonly string[]; readonly ledgerPath: string; readonly actions: readonly PruneAction[]; readonly skips: readonly PruneSkip[]; readonly applied: boolean; }; /** * Decide the fate of every finding. * * The line is re-read here and passed back through `commentLines`, the scan's own * extractor, rather than compared against the whole line: a trailing comment's * recorded text is the comment, not the code before it, and an equality test on the * raw line would reject every one of them. Re-using the extractor is what makes the * plan and the scan agree BY CONSTRUCTION instead of by two copies of a rule — the * defect class this whole feature is a reply to. */ export declare function planPrune(options: PruneOptions, findings: readonly CommentFinding[]): { actions: PruneAction[]; skips: PruneSkip[]; }; /** * Plan, prove, and (on `apply`) write. * * The scan runs through `auditComments`, so a pruned line is one the worklist * already showed a human; the pruner adds no rule of its own about what counts as * debt. */ export declare function pruneComments(options: PruneOptions): PruneResult;