# Spec Delta: tabular-recognition-service ## MODIFIED Requirements ### Requirement: Парсер — заменяемый интерфейс Разбор файла SHALL выполняться через единый интерфейс «байты + тип файла → документы/метрики/ошибка», не знающий о NATS и S3; воркер MUST NOT зависеть от конкретной реализации. Реализация по умолчанию (`get_parser()`) SHALL быть оркестратором книги `BookParser`: он читает книгу один раз, классифицирует листы по содержимому и отдаёт листы ОСВ конвейеру спеки `osv-parsing`, листы форм и их продолжения — конвейеру спеки `statement-parsing`; прочие листы пропускаются с предупреждением. Файл результата SHALL писаться с `schema_version = "1.2"`; документы книги — ОСВ в порядке листов, затем формы в порядке листов. Заглушка `NullParser` (`error NOT_IMPLEMENTED`) SHALL использоваться только в тестах воркера и MUST NOT быть реализацией по умолчанию. Реализация по умолчанию SHALL создаваться один раз при старте приложения (словари читаются и проверяются там же). Каталог `api/rules/` SHALL содержать словари ОСВ (`osv_headers`, `osv_groups`, `periods`, `data_types`), словари форм (`statement_headers`, `statement_periods`, `statement_checks`) и README. #### Scenario: Подмена реализации в тесте - **WHEN** в тесте воркеру передан парсер, возвращающий один `osvDocument` - **THEN** файл результата с этим документом записан в S3, конверт имеет `status = done` и `result_s3` на этот файл #### Scenario: Реальная ОСВ через воркер - **WHEN** в интеграционном тесте в S3 лежит `rb/2024-FY/ОСВ_66 за 2024.xls` и опубликован запрос `file_type = XLS` - **THEN** после ack публикуется конверт `done` с `result_schema_version = "1.2"`, файл результата проходит схему v1.2 и содержит один `osvDocument` с `account_code_raw = "66"` #### Scenario: Реальные формы через воркер - **WHEN** в интеграционном тесте в S3 лежит книга `statements-xlsx/npz/2025-Q3/…xlsx` и опубликован запрос `file_type = XLSX` - **THEN** после ack публикуется конверт `needs_check` с `result_schema_version = "1.2"` (книга НПЗ: `1600 = 1700` расходится на 1.94 / 9.02 / 2.48 руб. — значения в рублях при шапке «тыс. руб.», OQ-137), файл результата содержит два `statementDocument` (`BALANCE`, `INCOME`); `checks.relations_failed` баланса содержит только `1600 = 1700` по трём колонкам #### Scenario: Книга без ОСВ и форм - **WHEN** в S3 лежит книга Excel, ни один лист которой не имеет признаков ОСВ или формы - **THEN** публикуется конверт `error`, `error.code = INVALID_DOCUMENT`, сообщение называет число просмотренных листов