# Proposal: Срез 3a — горячие папки как у armka_file_worker и нормализатор OCR → `statementDocument` v1.2 **Срез:** 3a, первая половина Среза 3 «ББ/ОФР: scan-gateway, маппинг форм, логические проверки» (`../docs/context/09-delivery-plan.md`). **Репозиторий:** scan-gateway. **Issue:** RSHB/arm-scan-gateway#6. **Соседние:** fixtures — пары PDF+JSON и `ocr/expected_normalize/` (issue заводится при плане); docs — bounded-PR без change (`03-architecture.md`, OQ-137, §11.1 п. 6 и п. 9, новые OQ). Срез 3b (маппинг `statementDocument` в ядре, проверки §7, подтверждение, чек-лист) — отдельный change в arm-core. ## Why Срез 0 оставил scan-gateway с `NullNormalizer`: любой успешный ответ ИС Сканирование превращается в `NOT_IMPLEMENTED`. Срез 2b даёт ядру `statementDocument` v1.2 из Excel; чтобы ядро в 3b маппило формы одним кодом для обоих источников, PDF-путь должен отдавать тот же документ. Второй повод — 06.10.2026 в контуре проверен PDFWorker старого АРМ (`RSHB/armka_file_worker`): его раскладка горячих папок ИС принята владельцем как эталон (OQ-137), а модуль очистки OCR (`ofr_result_conversion`) разрешено переносить (§11.1 `05-domain-rules.md`, единственное исключение для `reference-old-arm`). ## What Changes - **Горячие папки** (`src/gateway/`): входящий файл — `/.` (расширение исходного имени в нижнем регистре) вместо `_`; временный `.part` по-прежнему в `` (решение владельца: в `Input` временных файлов не класть, ИС может их подхватить), rename **без замены** — существующее назначение считается доставленным. Новый метод `cleanup(job_id, ext)` под флагом `SCAN_CLEANUP` (по умолчанию `false`): удаляет `Output//*.json`, каталог, входящий файл (и его `.done`-вариант эмулятора) и осиротевший `.part`; любое удаление только при включённом флаге (на SMB может не быть прав). Ошибка удаления не меняет исход задания. - **Эмулятор** (`src/scan_emulator/`): входящий `.`; пара фикстур ищется по **sha256 содержимого** среди не-JSON файлов `SCAN_FIXTURES_DIR` (`aep_6.pdf` → `aep_6.json` + `aep_6_*.json`); промах → набор `SCAN_EMULATOR_DEFAULT`, если задан, иначе ответ-ошибка `INVALID_DOCUMENT`. `.part`/`.tmp`/`.done` игнорируются. - **Нормализатор** (`src/normalizer/ocr/`): `OcrNormalizer` реализует протокол `Normalizer` Среза 0 — конвейер чистых функций `text` → `dates` → `amounts` → `layout` → `rows` → `header` → `document`; проверенные на стенде функции старого ядра (двойники, `|`, разбор дат, суммы, раскладка с шапкой и без) переносятся дословно по §11.1; выход — pydantic-модели контракта v1.2 (`StatementDocument`), по одному документу на таблицу `table_structure[i]`. `checks` не считаются (их считает ядро в 3b для обоих источников). - **Статусы**: ошибочные файлы — как в Срезе 0; из успешных собираются документы; ни одной таблицы → `error RECOGNITION_FAILED`; всё распознано → `done`, иначе `needs_check`; причины — в `metrics.warnings`. - **Правила как данные** (`api/rules/`): `statement_lines.yaml` с **редакциями** форм (`66n` до отчётности за 2024 включительно — из `codes_mapping` старого ядра; `fsbu4` с 2025 — пустая, данные положит владелец), `ocr_lookalikes.yaml`, `statement_labels.yaml`. Загружаются и валидируются при старте. - **Настройки**: `SCAN_CLEANUP`, `SCAN_RULES_DIR`, `SCAN_EMULATOR_DEFAULT`; `SCAN_TMP_DIR` остаётся. Dev-compose: `SCAN_CLEANUP=true`. - **Тесты**: юнит по функциям, golden на `../fixtures/ocr/aep_3.json`, `aep_6.json` (эталоны `../fixtures/ocr/expected_normalize/`), обновлённые тесты горячих папок, эмулятора, воркера; roundtrip с эмулятором. ## Non-goals - Маппинг `statementDocument` в `financial_statement_*`, проверки §7, подтверждение документа, чек-лист, UI — Срез 3b. - Изменение контракта (v1.2 заморожен): редакция формы в конверт не добавляется (OQ, кандидат в MINOR 1.3). - Расшифровки без кода (OQ-36), склейка одной формы из нескольких таблиц (OQ-77), `DISCLOSURE` из OCR. - Заполнение словаря редакции `fsbu4` и подбор пар PDF+JSON — владелец, отдельный PR в fixtures. - Перенос обвязки старого ядра (`json_to_db_rows`, запись в БД, `pdfworker_results.py`). ## Параграфы `05-domain-rules.md` §11 (структура ответа ИС, маппинг таблица → документ), §11.1 п. 1–9 (очистка OCR-текста), §12 п. 4 (разбор дат — общий смысл с Excel-путём). Правила, которых в `05` нет и которые вводятся этим change'ом: редакции форм в справочнике кодов (ASSUMPTION(OQ-12): состав 2025 года не задан), `is_recognized` колонок шапки. Таблицы DBML не затрагиваются (сервис без БД). ## Открытые вопросы, затрагиваемые change'ом OQ-137 (уточнить: `Tmp` остаётся, очистка под флагом), OQ-36 (строки без кода не отдаются), OQ-77 (одна форма двумя таблицами — два документа с предупреждением), OQ-12 (редакции форм и §7), новые: права на удаление на SMB-шаре; редакция формы в контракте; §7/§12 по редакциям для 2b и 3b.