# 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.