Раскладка Output/<job_id>/*.json (склеиваются все файлы), SCAN_TMP_DIR, SCAN_SETTLE_SECONDS, структура raw/{job_id}.json,
успех = error.code == "", ошибочные файлы в metrics.warnings, правило набора эмулятора. D-5: не строковый error.code
тоже ошибка (UNKNOWN_ERROR, R-32). Решения R-36 (design #76). Тест TestAnswerSet на реальных фикстурах помечен fixtures.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Для `<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>
- HotFolder.poll(job_id) -> list[AnswerFile] | None: все *.json каталога <output>/<job_id>/ по возрастанию
имени, когда набор не пуст и имена/размеры не менялись SCAN_SETTLE_SECONDS (SettleTracker: состояние по
job_id, внедряемые часы, сброс при выдаче/опустении, предел 1024 задания, потокобезопасно);
- put: временный .<name>.part в <корень>/<SCAN_TMP_DIR>/ (создаётся), rename в Input (Local и SMB);
- настройки SCAN_TMP_DIR (Tmp) и SCAN_SETTLE_SECONDS (2, >= 0); в .env.test settle = 0 (R-23);
- воркер: переходная прослойка — берётся первый файл набора (склейка всех — Task 3, R-22).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`api/src/__init__.py` оставлен только с docstring: `python -m src.scan_emulator` больше не импортирует `src.app`
и не требует `OPENBAO__*`. `run_server.py` импортирует `app` из `src.app`, `get_settings` — из `src.core.config`.
Регрессионный тест: subprocess эмулятора с окружением только PATH/ENV_FILE/SCAN_HOTFOLDER_PATH -> код 2,
сообщение про корень горячей папки, без ValidationError.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Пара фикстур a_b-1.json / a_b.json: префикс по алфавиту раньше точного имени, поэтому тест падает,
если шаг «сначала <name>.json» убран. Убран посторонний комментарий в соседнем тесте.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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>