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

16 KiB
Raw Blame History

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

Порядок выкладки — «сначала ядро» (обязателен)

  1. tabular-parser и scan-gateway: тест идентичности копии контракта выбирает файл docs по MAJOR копии ($id …/v1 → *.v1.schema.json) — до слияния шага 2, иначе их make check краснеет на окне перехода.
  2. arm-statements — пакет с тестами; sync-statements в docs.
  3. docs: контракт v2.0, DBML v5.19, правила (этот change).
  4. arm-core: миграция v5.19, маппер 2.0 рядом с маппером 1.x, приём ack и конвертов 1.x и 2.0, PATCH, экранные поля API. До этого шага ни один сервис не шлёт 2.0: первый же line_code = null дал бы файлу ERROR.
  5. arm-web: экран по новым полям (поля 1.x-документов заполнены по умолчанию — экран работает и на них).
  6. tabular-parser и scan-gateway переходят на 2.0 в любом порядке относительно друг друга.
  7. После перехода обоих сервисов маппер 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 по умолчанию — экран и подтверждение работают, новых сигналов качества нет.