19 KiB
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.jsonv2.0 (MAJOR, Р-9) и конвертrecognition-result-message.schema.jsonv2.0 (структурныеmetrics.warnings); запросrecognition-requestостаётся v1.0. Путь ОСВ в tabular-parser меняется только в части структуры предупреждений иdocument.status. На окне перехода схемы 1.x лежат рядом (*.v1.schema.json, примерыexamples/v1/); тест идентичности копии у ядра и сервисов сверяет файл копии с файлом docs своего MAJOR, если он есть, иначе с основным (схемы и примеры; правило — спекаrecognition-contract). - Упорядоченные перечни кодов форм — данные
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; 409LINES_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).
Порядок выкладки — «сначала ядро» (обязателен)
- arm-core, tabular-parser и scan-gateway: тест идентичности копии контракта по новому правилу — схема копии
сверяется с
<имя>.v<M>.schema.jsonсвоего MAJOR, если такой файл есть в docs, иначе с основным; пример — сexamples/v<M>/<имя>.json, если он есть, иначе сexamples/<имя>.json; файлы другого MAJOR не сверяются. Правило проходит и до слияния шага 2 (файлов.v1ещё нет), и после; без негоmake checkвсех трёх краснеет между шагами 2 и 3 (ядро) или 2 и 5 (сервисы). arm-statements— пакет с тестами;sync-statementsв docs; копия пакета подключается к хостам (линтеры,testpaths,statements-check) — код сервисов её ещё не вызывает.- docs: контракт v2.0, DBML v5.19, правила (этот change).
- arm-core: сначала очистка форм ББ/ОФР на контуре (Р-24: владелец или платформенная команда по его заявке,
после резервной копии БД — скрипт ядра
scripts/purge_statements.py:--dry-runс отчётом, затем--apply; удаляются документыBALANCE/INCOME, ихfinancial_statement_*, комментарии и привязки к версиям «в работе», а файлы, где кроме форм нет ОСВ, — целиком с заданиями; смешанные файлы «ОСВ + формы» — по решению владельца по отчёту; при формах в верифицированных версиях скрипт отказывает; ОСВ, консолидации, справочники не трогаются — спекаarm-core, «Очистка форм перед выкладкой»), затем миграция v5.19 (только колонки, индексы и значения по умолчанию; §7 для старых форм не считается), маппер 2.0 рядом с маппером 1.x, приём ack и конвертов 1.x и 2.0, PATCH, экранные поля API. Формы пересоздаются повторной загрузкой файлов. До этого шага ни один сервис не шлёт 2.0: первый жеline_code = nullдал бы файлуERROR. - arm-web: экран по новым полям (поля 1.x-документов заполнены по умолчанию — экран работает и на них).
- tabular-parser и scan-gateway переходят на 2.0 в любом порядке относительно друг друга.
- После перехода обоих сервисов маппер 1.x удаляется из ядра отдельным PR (не в этом change).
Копии схем в сервисах (api/contracts/, тест идентичности в make check) после слияния контракта v2.0 в docs
сверяются с *.v1.schema.json и examples/v1/ (правило шага 0; у запроса файла .v1 нет — с основным); каждый сервис
обновляет копию до v2.0 в своём PR шага 5, ядро держит копии обоих MAJOR с PR шага 3. Схемы *.v1.schema.json и
examples/v1/ удаляются вместе с маппером 1.x (шаг 6): сначала PR ядра убирает свои копии .v1, затем docs.
Чего ждать на реальных сканах. Значения строк detail в needs_review и в статус не входят (Р-23), законные
повторы кода и мягкие строки ОФР документ не держат (Р-20, Р-21). Поэтому ББ и ОФР РБ («Бухгалтерская отчетность 1
кв.25») и Счастливочной («БО 1 кв 2025») могут стать done: по прогону ревью все их неуверенные значения строк с кодом
покрыты сошедшимися соотношениями, неуверенные коды подтверждаются перечнем fsbu4, а держали их только ячейки
расшифровок. aep_3 и aep_6 остаются needs_check (строки unreadable / missing с суммами, несошедшиеся
соотношения). Фактическая доля 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: очистка форм ББ/ОФР перед выкладкой (
scripts/purge_statements.py, Р-24); миграция v5.19 (financial_statement_*,document,document_issue,recognition_job,related_group; только колонки, индексы и значения по умолчанию, §7 по старым формам не считается — на неочищенной базе их нарушения до первой правки не показываются);JobBrief.warnings— структуры,DocumentOut.issues(в том числе ОСВ);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 по умолчанию — экран и подтверждение работают, новых сигналов качества нет.