6 Commits

Author SHA1 Message Date
Andrey Epifancev
e3353242bd fix(emulator): единственный refresh индекса за проход, реальный тест появления каталога, dot-файл в skip-тесте (round 3)
- T14.1: процесс_once() без refresh если индекс передан; run() refresh перед вызовом, не после
- T14.2a: спай на build_index — не вызывается повторно при неизменных фикстурах
- T14.2b: реальный тест файла, появляющегося на проходе 2: ровно 2 build_index всего
- T14.2c: добавлен dot-файл `.{uuid}.pdf.part` в skip-тест
- Мутационные тесты падают при удалении проверок (не коммичены)
- Typo: «фиксутрах» → «фикстурах»
- 915 тестов проходят, make check зелёный

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 02:21:42 +04:00
Andrey Epifancev
793516fa61 fix(emulator): тесты неперестроения индекса, единственный refresh за проход, различающий тест skip-списка и верхний регистр (T14.2, T14.4)
T14.2(a): Добавлен тест с шпионом на build_index, проверяющий что индекс не пересчитывается повторно на каждом проходе при неизменных фикстурах. 5 проходов — ровно 1 вызов build_index (при инициализации run), остальные используют refresh.

T14.2(b): Добавлен тест корректной обработки появления каталога фикстур после стартапа — run не выбрасывает исключение и может использовать фикстуры после их создания.

T14.1 remainder (double refresh): Исправлено поведение process_once: если index=None, то build_index один раз; если index передан, то только refresh. Обновлена docstring процесса.

T14.2(c): Добавлен мутационный тест test_skip_suffixes_not_logged_as_regex_mismatch, проверяющий что файлы с _SKIP_SUFFIXES пропускаются молча и НЕ логируются как не совпадающие с шаблоном.

T14.4: Переписан test_uppercase_extension_accepted — теперь пишет файл напрямую .PDF и проверяет нормализацию в .pdf.done, вместо использования _drop которая нормализует расширение.

Дополнительно:
- Обновлена docstring run() — точное описание: один refresh в конце каждого прохода
- Удалено "(Review Focus 5)" из docstring test_ignores_part_tmp_done
- Добавлен @pytest.mark.skipif для chmod теста при запуске от root

915 тестов пройдено, 10 деселектировано (10 избранных тестов требуют fixtures).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 02:13:23 +04:00
Andrey Epifancev
31e05955ae fix(emulator): индекс не пересчитывается на каждом проходе, устойчивость к нечитаемому файлу, тесты (T14.1–T14.4)
T14.1: run() ВСЕГДА строит индекс один раз (даже если fixtures_dir отсутствует → пустой индекс), обновляет через refresh() на каждом проходе. process_once() больше не пересчитывает при None, берёт переданный индекс.

T14.3: OSError при чтении входящего файла логируется одной строкой, проход продолжается со следующего файла.

T14.4: Лог сообщений об ошибке использует "по умолчанию" вместо `default`; исправлена опечатка "фиксутрах" → "фикстурах"; удалено "(Review Focus 5)" из docstring модуля.

Новые тесты: test_upload_file_read_error_continues (T14.3), test_uppercase_extension_accepted (M-4), test_ignores_part_tmp_done_robust (T14.2c).

Все 912 тестов зелёные.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 02:02:55 +04:00
Andrey Epifancev
bb56226177 feat(emulator): пара фикстур по sha256 содержимого, SCAN_EMULATOR_DEFAULT, входящий <uuid>.<ext> (D-3)
- Добавлена FixtureIndex с индексированием по sha256 содержимого файлов (не-JSON)
- build_index() строит индекс один раз, refresh() обновляет только при изменении списка файлов
- resolve_stem() находит основу имени по хешу, при промахе возвращает default или (None, "none")
- process_once() принимает параметр index и default, работает с файлами <uuid>.<ext>
- Пропускаются dot-файлы, *.part, *.tmp, *.done (Review Focus 5)
- Сообщение об ошибке: "{sha256[:12]}: нет пары по содержимому в фикстурах"
- EmulatorSettings.default = "" для SCAN_EMULATOR_DEFAULT
- Логирование источника пары: hash / default / none
- Все 909 тестов зелёные, включая 54 новых и переписанных тестов эмулятора

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 01:53:22 +04:00
Andrey Epifancev
24af6f1b9a Срез 0 [7.3]: эмулятор — набор файлов ответа на задание
Для `<uuid>_<name>.<ext>` эмулятор собирает все `<name>.json` и `<name>_*.json` из SCAN_FIXTURES_DIR (не префикс
`<name>*`) и кладёт их в `Output/<uuid>/` как `<uuid>.json` / `<uuid>_<suffix>.json` с `file_uid = <uuid>`. Набор
пишется в `<root>/<SCAN_TMP_DIR>/.<uuid>.answer` и переименовывается в каталог ответа целиком (R-26). Ответ «нет пары» —
`data_ocr` объектом с пустыми полями (R-28). Решения исполнителя — design №75 (R-35).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:48:57 +04:00
Andrey Epifancev
b489f6e0b3 Срез 0 [4.3]: эмулятор ИС Сканирование (src/scan_emulator), unit-тесты, отметка задачи
process_once(root, fixtures, delay): новые <uuid>_<имя> -> ответ из фикстуры (точное имя, затем префикс,
file_uid подставляется) либо INVALID_DOCUMENT, атомарная запись ответа, затем переименование в .done.
Цикл python -m src.scan_emulator с корректной остановкой по SIGINT/SIGTERM.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:10:36 +04:00