Спеки применены: 5 новых capability (arm-core, arm-web, scan-gateway, statement-normalization, tabular-recognition-service) с Purpose, изменения quality-checks и recognition-contract. Ссылки в 05-domain-rules, DBML v5.19, entities, dev/checks.md и dev/qa-statements-v2.md ведут в архив. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
7.7 KiB
Markdown
72 lines
7.7 KiB
Markdown
# tabular-recognition-service Specification
|
||
|
||
## Purpose
|
||
Требования к tabular-parser в единой нормализации ББ/ОФР: адаптер листов Excel (шаг 1) в общую сетку ячеек и выдача результата распознавания контракта 2.0, нормализованного общим кодом `arm_statements`.
|
||
|
||
## Requirements
|
||
|
||
### Requirement: Адаптер Excel шага 1
|
||
tabular-parser SHALL оставить у себя чтение книги (лимиты `PARSE_MAX_BYTES`, `PARSE_TIMEOUT_SECONDS`, формат по
|
||
сигнатуре, лимиты zip и объединённых ячеек, `UNREADABLE`), классификацию листов (ОСВ — отдельный путь; форма;
|
||
продолжение; прочее) и адаптер «блок формы на листе → `FormCandidate`» общего кода; шаги 2–8 по формам SHALL
|
||
выполняться копией пакета `arm_statements`. Адаптер SHALL: выделять блоки форм на листе по заголовку или ОКУД (без
|
||
кодов между ними блоки сливаются, заголовок после кодов — новая форма); собирать шапку каждого блока в его границах
|
||
(организация, ИНН без ИНН аудитора, ОКПО, ОКОПФ, ОКФС, единицы, дата, адрес) как `Cell` с `confidence = 100`;
|
||
заполнять у каждой ячейки `text` по числовому формату (tp#42) и `value`, `ref = <лист>!<A1>` (имя листа в одинарных
|
||
кавычках по правилу Excel, если в нём есть что-то кроме букв, цифр и `_`); дописывать
|
||
листы-продолжения в сетку открытой формы до раскладки (маркер «Форма … с.2» или позиция листа; проверки типа,
|
||
диапазона кодов и, при трёх и более кодах, числа колонок — как `join_blocker`), записывая границы листов в
|
||
`segment_breaks`. Несовпадение формата с `file_type` — предупреждение файла `FILE_TYPE_MISMATCH` (`info`). Лист без
|
||
признаков ОСВ и формы, без `type_hint` и кодов — предупреждение файла `SHEET_OTHER` (`info`, `locator = sheet:<имя>`),
|
||
документа нет.
|
||
|
||
#### Scenario: Книга ББ + ОФР
|
||
- **WHEN** книга содержит лист «Баланс» (ОКУД 0710001), лист «Баланс (2)» с маркером «Форма 0710001 с.2» и лист «ОФР»
|
||
- **THEN** адаптер выдаёт два кандидата: `BALANCE` с `locator = sheet:Баланс,Баланс (2)` и одной сеткой из двух листов
|
||
(`segment_breaks` — первая строка второго листа) и `INCOME` с `locator = sheet:ОФР`
|
||
|
||
#### Scenario: Ссылки ячеек
|
||
- **WHEN** код строки стоит в ячейке C27 листа «Баланс»
|
||
- **THEN** `ref` строки — `Баланс!C27`; у листа «Бухгалтерский баланс. Лист 1» — `'Бухгалтерский баланс. Лист 1'!C27`
|
||
|
||
### Requirement: Строки без кода и неизвестные колонки в Excel
|
||
tabular-parser SHALL отдавать строки без кода с содержимым со статусами `detail` / `missing` / `unreadable` (Р-8; ранее
|
||
не отдавались, OQ-36 / OQ-141), числовые колонки с нераспознанной подписью — колонкой без даты и `error` (ранее
|
||
пропускались), повторы кодов — всеми строками без `duplicate_line_codes`.
|
||
|
||
#### Scenario: НПЗ «Реализация иного имущества»
|
||
- **WHEN** в ОФР ФСБУ 4/2023 строка «Реализация иного имущества…» без кода с суммами стоит под строкой 2340
|
||
- **THEN** в результате строка `detail` с `parent_ref` строки 2340; ранее она отбрасывалась со счётчиком
|
||
|
||
### Requirement: Манифест ожиданий на реальных формах
|
||
Манифест `tabular-parser/api/tests/statements_manifest.yaml` SHALL быть обновлён в PR перехода на 2.0 по правилу
|
||
«посчитанного» соотношения §7 (пустая цель при непустых членах — нарушение): `failed_relations` страниц 2 баланса без
|
||
1600 получают `["1600 = 1700"]` — `unagrande-co/2024-FY/Б.Б. Лист 2.xls`, `unagrande-group/2024-FY/ББ. Лист 2 (2).xls`,
|
||
`unagrande-group/2025-Q3/ББ. Лист 2 3кв.25.xls` (было `[]`, причина «страница 2 без шапки» остаётся); страницы 1 «только
|
||
актив» (`Б.Б Лист 1.xls`, `ББ. Лист 1 .xls`, `ББ. Лист 1 3кв.25.xls`) сохраняют `["1600 = 1700"]` (теперь как «непустая
|
||
цель при пустых членах»). Статусы `done` (Межениновская ББ и ОФР, НПЗ ББ и ОФР, ОФР «Лист 1» Унагранде ×2) MUST NOT
|
||
меняться: их строки без кода уходят в `detail`, строки шапки выше заголовка — в `title`. Остальные записи манифеста
|
||
пересчитываются прогоном и правятся только с объяснением в описании PR.
|
||
|
||
#### Scenario: Страница 2 баланса
|
||
- **WHEN** разбирается `unagrande-group/2025-Q3/ББ. Лист 2 3кв.25.xls` (есть 1700, нет 1600)
|
||
- **THEN** документ `needs_check`, в `checks.relations_failed` — `1600 = 1700` с пустой целью
|
||
|
||
### Requirement: Путь ОСВ в контракте v2.0
|
||
У `osvDocument` tabular-parser SHALL выдавать `status` (`done`, когда контрольные суммы §1.4 листа сошлись, иначе
|
||
`needs_check` — прежние условия §1.6, применённые к листу) и `warnings[]` — прежние предупреждения листа структурами с `severity = info` и кодом с
|
||
префиксом `OSV_`; строк вида `sheet=<имя> <текст>` в `metrics.warnings` больше нет. Остальной разбор ОСВ не меняется.
|
||
|
||
#### Scenario: Предупреждение ОСВ
|
||
- **WHEN** на листе ОСВ есть строка без родителя
|
||
- **THEN** у документа ОСВ предупреждение `{code: "OSV_…", severity: "info", message}`, статус документа по §1.6
|
||
|
||
### Requirement: Статус книги
|
||
Статус конверта tabular-parser SHALL вычисляться по общему правилу: `done` ⇔ все документы `done` ∧ нет предупреждений
|
||
файла уровня `error`; книга без листов ОСВ и форм — `error INVALID_DOCUMENT`. Порядок документов — сначала ОСВ в
|
||
порядке листов, затем формы.
|
||
|
||
#### Scenario: Книга только из пояснений
|
||
- **WHEN** книга содержит только листы пояснений (0710003, «Пояснения»)
|
||
- **THEN** документы `DISCLOSURE` со статусом `done`, конверт `done`
|