fix(stats): fix duplicate-line cleanup edge cases

- Drain the full write queue before scanning, not just one batch, so pending burst rows aren't missed
- Floor lookback-days before the positivity check so a sub-day value no longer collapses to a zero-day window
- Let the parsed cue list override the streaming dedup heuristic wherever it covers a line
- Reject combining --lifetime with --duplicate-lines and non-positive --lookback-days values
- Widen the burst frame bound to catch heavier typesetting while still sparing longer-spaced runs
- Keep the cleanup modal open until the user closes it so they can read the result before it unmounts
This commit is contained in:
2026-08-10 23:50:48 -07:00
parent 684ab9eaff
commit 039aed79c3
11 changed files with 163 additions and 16 deletions
@@ -43,7 +43,6 @@ export function DuplicateLineCleanup({ onClose, onCleaned }: DuplicateLineCleanu
} else {
setApplied(result);
setPreview(null);
onCleaned();
}
} catch (cause) {
setError(cause instanceof Error ? cause.message : String(cause));
@@ -51,9 +50,18 @@ export function DuplicateLineCleanup({ onClose, onCleaned }: DuplicateLineCleanu
setBusy(null);
}
},
[lookbackDays, onCleaned],
[lookbackDays],
);
// Reloading the vocabulary tables unmounts this modal along with the rest of the tab,
// so it waits for the user to close: they get to read what was removed first.
const close = useCallback(() => {
if (applied && applied.removedLines > 0) {
onCleaned();
}
onClose();
}, [applied, onCleaned, onClose]);
const result = applied ?? preview;
const nothingToDo = preview !== null && preview.removedLines === 0;
@@ -63,7 +71,7 @@ export function DuplicateLineCleanup({ onClose, onCleaned }: DuplicateLineCleanu
type="button"
aria-label="Close duplicate line cleanup"
className="absolute inset-0 bg-ctp-crust/70 backdrop-blur-[2px]"
onClick={onClose}
onClick={close}
/>
<div className="absolute inset-x-0 top-1/2 mx-auto max-w-xl -translate-y-1/2 rounded-xl border border-ctp-surface1 bg-ctp-mantle shadow-2xl">
<div className="flex items-center justify-between border-b border-ctp-surface1 px-5 py-4">
@@ -71,7 +79,7 @@ export function DuplicateLineCleanup({ onClose, onCleaned }: DuplicateLineCleanu
<button
type="button"
className="rounded-md border border-ctp-surface2 px-3 py-1.5 text-xs font-medium text-ctp-subtext0 transition hover:border-ctp-blue hover:text-ctp-blue"
onClick={onClose}
onClick={close}
>
Close
</button>