Andrey Epifancev 248f8b0c74 openspec(#116): спека по ревью K-1…K-25 и решениям владельца Р-20…Р-22; решения S-26…S-52
- design.md: Р-20 (законные повторы кода в перечне, синонимы в словаре имён), Р-21 (мягкое соотношение, сошедшееся
  точно, подтверждает неуверенное значение), Р-22 (S-1…S-25 приняты с оговорками; отмечены утверждённые владельцем);
  решения при доработке S-26…S-52 с ценой ошибки
- statement-normalization: отдельное требование sync-statements (пути, VERSION, коды 0 / 10 / 20 / 2), словарь
  единиц и ОКЕИ, ref Excel с кавычками, нумерация с двойниками и пропуском, номер колонки, содержимое строки, столбец
  кодов у DISCLOSURE, упрощённый 2400 мягкий, Р-20 / Р-21 со сценариями, обе редакции перечня, интерфейс функции
  статуса, TABLE_PARSE_ERROR / SHEET_OTHER уровня файла
- arm-core: признак строки правки row_index IS NULL, header_source, формы без checks (1.x и миграция) — §7 ядром в
  document_issue, codes / column_index, RESULT_STATUS_INCONSISTENT, синонимы и «итого по разделу», PATCH
  organization_name / confirmed: false / подтверждение даты, LINE_CODE_TAKEN, акцепт и подтверждения, LINES_UNRESOLVED
  с текстом, «того же периода», откат миграции
- recognition-contract: MODIFIED «Копия контракта … идентична» — сверка по MAJOR копии, *.v1.schema.json на окне;
  1.x — MAPPING_WARNING / LEGACY_WARNING; okei, column_index, пустые массивы DISCLOSURE, статус ОСВ одной формулировкой
- quality-checks (новая дельта): make check охватывает копию arm_statements, make check-full — statements-check
- tabular-recognition-service: манифест statements_manifest.yaml — failed_relations страниц 2 баланса (K-25)
- scan-gateway, arm-web: TABLE_PARSE_ERROR файла; подсказки шапки, снятие подтверждений, LINE_CODE_TAKEN
- proposal: шаг 0 выкладки, перечни кодов, ожидания на реальных сканах, Impact

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
2026-10-18 02:17:36 +04:00

134 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Why
Формы ББ/ОФР сегодня нормализуются двумя разными конвейерами: scan-gateway (PDF → ИС Сканирование) и tabular-parser
(Excel). У них разные правила раскладки таблицы, отбора строк, разбора сумм, проверок §7 и статуса; ядро не доверяет
ни одному из них и пересчитывает проверки и статус заново по косвенным признакам, дважды дедуплицирует строки и держит
третью и четвёртую копии словарей (§7 и «код → наименование»). Пользователь видит последствия как отдельные «ошибки
распознавания» — AURORA-1406, 1462, 1511, 1517, 1519, 1522, 1523, 1524, 1634: строки молча пропадают, повтор кода
теряет сумму, «чистая» ячейка с потерянной цифрой не подсвечивается, предупреждения сервисов нигде не видны.
Дизайн `design.md` (финальная версия, решения владельца Р-1…Р-19 от 17.10.2026, три раунда ревью) приводит оба
сервиса к одной цепочке шагов 1–9 с единым выходом каждого шага и общим кодом шагов 2–8; ядро хранит результат как
пришёл и пересчитывает его тем же общим кодом только после правок аналитика.
Срез: вне плана срезов `09-delivery-plan.md` — переработка Среза 2b (Excel-формы), Среза 3a (OCR-нормализатор) и
Среза 3b (формы в ядре). Issue RSHB/arm-ka-docs#116.
## What Changes
- **Общий код нормализации** — новый репозиторий `arm-statements`, пакет `arm_statements/` (Р-1): типы шага 1
(`FormCandidate`, `Cell`), шаги 2–8 (раскладка, отбор строк, значения, код и наименование, сборка документа,
самопроверки §7, статус и `needs_review`), словари §7 (полный и упрощённый наборы), периодов, заголовков форм,
подписей колонок, упорядоченные перечни кодов форм по редакциям и вариантам, диапазоны кодов. Словаря «код →
наименование» в пакете нет (Р-3). В tabular-parser, scan-gateway и arm-core пакет лежит копией, которую раскладывает
и проверяет скрипт `sync-statements` репозитория docs (по образцу `sync-web.sh`).
- **Строки не выбрасываются молча:** статусы строк `ok` | `unreadable` | `missing` | `detail`, `row_index`, `ref`,
сырой текст кода и ячейки (`text`) доезжают до БД и экрана; повтор кода — законный случай, все строки сохраняются
(Р-4, Р-8). **BREAKING** для потребителей: `line_code` становится nullable.
- **Качество структурно и с привязкой к месту:** `needs_review` у значения, строки и полей шапки; «подтверждение
проверкой» §7 вместо порога уверенности (Р-5, Р-7, Р-11, Р-12, Р-16, Р-17); `document.status` у каждого документа;
предупреждения — структуры `{code, severity, message, line_refs, column_index, field}` вместо строк.
- **Контракт `recognition-result.schema.json` v2.0** (MAJOR, Р-9) и конверт `recognition-result-message.schema.json`
v2.0 (структурные `metrics.warnings`); запрос `recognition-request` остаётся v1.0. Путь ОСВ в tabular-parser
меняется только в части структуры предупреждений и `document.status`. На окне перехода схемы 1.x лежат рядом
(`*.v1.schema.json`, примеры `examples/v1/`), тест идентичности сервиса сверяет копию со схемой своего MAJOR.
- **Упорядоченные перечни кодов форм** — данные `contracts/statement-code-orders.yaml` (66н / ФСБУ 4, полная /
упрощённая, законные повторы кода — Р-20); в пакет `arm_statements` — байтовой копией.
- **arm-core:** DBML v5.19 и одна миграция (статусы и порядок строк, `needs_review`, `is_confirmed`, `source_text`,
`period_kind`, `form_variant`, таблица `document_issue`, снятие уникальности `(meta_id, line_code)` и — для ББ/ОФР —
`document (stored_file_id, document_type, osv_account_code)`, `recognition_job.statements_version`,
`related_group.crm_id` по arm-core#112); «агрегат формы по коду» вместо «одна строка на код»; приём 1.x и 2.0 на
время перехода; новое условие `RECOGNIZED`; PATCH `…/statement` с `lines`, `columns`, `values[].confirmed`; 409
`LINES_UNRESOLVED` и `DUPLICATE_FORM` при подтверждении.
- **arm-web:** экран проверки формы — строки со статусами на своих местах, расшифровки под переключателем, подсветка
только по `needs_review`, предупреждения и нарушения у места, назначение кода, «Это расшифровка», подтверждение кода
и ячейки, дата колонки.
- **Документы:** `05-domain-rules.md` — §11 становится общей главой нормализации ББ/ОФР с подразделами по
источникам, §12 — заголовок-редирект; §7 — «посчитанное» соотношение, `abs_terms` и знак, упрощённый набор; §9.3,
§9.5 — статус, маппинг и подтверждение формы по v2.0. `07-open-questions.md` — закрыты OQ-36, OQ-141 (Р-8) и
вопросы, снятые решениями дизайна; новые вопросы — склейка половинок формы (Р-15) и открытое в дизайне.
`frontend-api-guide.md` — новые поля формы и PATCH (после реализации).
Читают и пишут контракт: `arm-core` (читает результат и конверт, публикует запрос), `tabular-parser` и `scan-gateway`
(читают запрос, пишут результат и конверт). Дочерние change'и (заводятся при планировании, по одному на репозиторий):
`arm-statements` (новый), RSHB/arm-core, RSHB/arm-tabular-parser, RSHB/arm-scan-gateway, RSHB/arm-web; связанная
задача — RSHB/arm-core#112 (`related_group.crm_id` входит в ту же миграцию, Р-10).
### Порядок выкладки — «сначала ядро» (обязателен)
0. tabular-parser и scan-gateway: тест идентичности копии контракта выбирает файл docs по MAJOR копии (`$id` `…/v1` →
`*.v1.schema.json`) — до слияния шага 2, иначе их `make check` краснеет на окне перехода.
1. `arm-statements` — пакет с тестами; `sync-statements` в docs.
2. docs: контракт v2.0, DBML v5.19, правила (этот change).
3. arm-core: миграция v5.19, маппер 2.0 рядом с маппером 1.x, приём ack и конвертов 1.x и 2.0, PATCH, экранные поля
API. До этого шага ни один сервис не шлёт 2.0: первый же `line_code = null` дал бы файлу `ERROR`.
4. arm-web: экран по новым полям (поля 1.x-документов заполнены по умолчанию — экран работает и на них).
5. tabular-parser и scan-gateway переходят на 2.0 в любом порядке относительно друг друга.
6. После перехода обоих сервисов маппер 1.x удаляется из ядра отдельным PR (не в этом change).
Копии схем в сервисах (`api/contracts/`, тест идентичности в `make check`) после слияния контракта v2.0 в docs
сверяются с `*.v1.schema.json` (шаг 0); каждый сервис обновляет копию до v2.0 в своём PR шага 5, ядро держит копии обоих
MAJOR с PR шага 3. Схемы `*.v1.schema.json` и `examples/v1/` удаляются вместе с маппером 1.x (шаг 6).
**Чего ждать на реальных сканах.** На шести OCR-документах `fixtures/ocr` после перехода большинство форм останутся
`needs_check` (строки без кода с суммами, неуверенные значения вне соотношений, неуверенная дата); законные повторы кода
и мягкие строки ОФР перестают держать документ (Р-20, Р-21). Доля `done` фиксируется в PR scan-gateway.
## Non-goals
- Разбор ОСВ (`classify.py`, `to_money` ОСВ, правила §1) не меняется; путь ОСВ в tabular-parser меняется только в
структуре предупреждений и `document.status`.
- Переключатель «как в файле» (порядок строк по `row_index`) на экране — не в этой работе (Р-14).
- Склейка двух половинок формы из одного файла в ядре не предоставляется — файл перезагружают; вопрос в
`07-open-questions.md` (Р-15). Склейка страниц из разных файлов (OQ-140) — тоже нет.
- Восстановление строк по наименованию (OQ-149) и сопоставление формы без колонки кодов по именам строк (OQ-139) — нет.
- Запрос `recognition-request` остаётся v1.0; subject'ы NATS, `Nats-Msg-Id`, ack и повторы не меняются по механике.
- Межформенная проверка `1370 − 1370(нач. года) = 2400` остаётся в ядре и мягкой; формулы §7 по редакциям (OQ-146) и
знаки 2410/2420 (OQ-12) не пересматриваются.
- Замена пакета-копии на зависимость из Nexus платформы — не сейчас (платформа Python-пакеты не собирает, Р-1).
- Приведение единиц измерения сверх числового формата ячейки (OQ-138) — нет.
## Capabilities
### New Capabilities
- `statement-normalization`: общая цепочка нормализации ББ/ОФР (шаги 1–8) — пакет `arm_statements`, его типы,
правила и словари, `sync-statements`.
- `tabular-recognition-service`: адаптер Excel шага 1 в tabular-parser и что остаётся в сервисе (чтение книги, листы
ОСВ, сборка конверта v2.0).
- `scan-gateway`: адаптер json ИС шага 1 в scan-gateway и что остаётся в сервисе (горячие папки, склейка набора json,
`raw/`, сборка конверта v2.0).
- `arm-core`: хранение результата v2.0 (DBML v5.19), агрегат по коду, `document_issue`, условие `RECOGNIZED`, PATCH
формы, порядок 409 подтверждения, приём 1.x и 2.0.
- `arm-web`: экран проверки формы ББ/ОФР по новым полям.
### Modified Capabilities
- `recognition-contract`: файл результата и конверт — v2.0; правила перехода (ядро принимает 1.x и 2.0, «сначала
ядро»); статус и структурные предупреждения у всех документов, включая ОСВ; тест идентичности копии — по MAJOR.
- `quality-checks`: `make check` охватывает копию `arm_statements` (тесты, `mypy`), `make check-full` — `statements-check`
(`sync-statements --check`).
## Impact
- Новый репозиторий `arm-statements`; скрипт `sync-statements` и цель Makefile в docs (вызывается из `make check-full`
потребителей, не из `make check`; коды 0 / 10 / 20 / 2).
- docs: `contracts/statement-code-orders.yaml`, схемы `*.v1.schema.json` и `examples/v1/` на окне перехода;
`scripts/validate_contracts.py` проверяет оба MAJOR и перечни кодов, `make venv` ставит PyYAML.
- tabular-parser: `parser/statements/*` (кроме разбора книги и адаптера шага 1) уходит в общий код; словари
`statement_checks.yaml`, `statement_periods.yaml`, `statement_headers.yaml` переезжают в пакет; путь ОСВ — структура
предупреждений и `document.status`; манифест `api/tests/statements_manifest.yaml` обновляется: `failed_relations`
страниц 2 баланса (`unagrande-co/2024-FY/Б.Б. Лист 2.xls`, `unagrande-group/2024-FY/ББ. Лист 2 (2).xls`,
`unagrande-group/2025-Q3/ББ. Лист 2 3кв.25.xls`) получают `1600 = 1700` («посчитанное» соотношение, пустая цель),
статусы `done` не меняются.
- scan-gateway: `normalizer/ocr/text|dates|amounts` становятся общими разборами, `layout|rows|header|document` — шагами
2–6 общего кода; `api/rules/statement_lines.yaml` удаляется, `statement_labels.yaml` и `ocr_lookalikes.yaml` уходят в
словари пакета.
- arm-core: миграция v5.19 (`financial_statement_*`, `document`, `document_issue`, `recognition_job`,
`related_group`; `document_issue` существующих форм — §7 копией пакета), `result_mapping`, `statement_mapping`,
`statements`, `documents`, `auto_confirm`, схемы API формы; признак строки правки — `row_index IS NULL`;
`api/rules/statement_checks.yaml` удаляется (копия словаря §7), `statement_lines.yaml` остаётся только словарём имён
(несколько имён на код, загрузчик повтор кода не запрещает); PATCH шапки принимает `organization_name`.
- arm-web: `widgets/DocumentReview` (экран [41]), типы API.
- Решение v5.13 «`needs_review` считается, не хранится» пересматривается (design, Decisions № 17).
- Риск окна выкладки: пока сервис шлёт 1.x, документы его конвейера получают статус по прежнему правилу D-6 и поля
v2.0 по умолчанию — экран и подтверждение работают, новых сигналов качества нет.