_reverse_map был identity-map (faiss_id == doc_id для IndexIDMap2) —
использовался только как doc.faiss_id = _reverse_map[doc_id], т.е. = doc_id.
Убрал поле, метод _rebuild_reverse_map и его обслуживание в 5 местах;
_use_gpu нигде не читался. -30 строк, функционал тот же.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Две связанные проблемы, ломавшие качество детекции:
1. Уровень 1 (Winnowing) репортил весь документ одним совпадением на позиции
0..длина — в отчёте нельзя было понять, ГДЕ плагиат. Теперь winnow'им
каждый фрагмент и находим источник + позицию для каждого, так отчёт
показывает "символы A-B скопированы из источника X".
2. MAX_FINGERPRINTS_PER_DOC=500 обрезал отпечатки статьи (у типичной статьи
их ~3600), причём произвольную выборку. Из-за этого скопированный фрагмент
почти не разделял отпечатки с источником (проверено: хранилось ~14%,
фрагмент находил 17% своих хэшей → не срабатывало). Winnowing рассчитан на
ПОЛНОЕ хранение; поднял лимит до 20000.
Также overall_similarity считается по числу уникальных помеченных позиций,
а не совпадений — фрагмент, совпавший с несколькими источниками, больше не
раздувает процент выше 100.
Проверено end-to-end: документ с дословной вставкой из статьи корпуса →
вставка локализована (chars 1027-2385 = 100%, источник атрибутирован);
чисто оригинальный текст → 0% (нет ложных срабатываний).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>