From 18b7eb23710500b9b70c9c4b896d4a7cc17b6aea Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 17 Oct 2026 18:39:15 +0400 Subject: [PATCH] =?UTF-8?q?docs(#116):=20=D0=A0-3=20=D1=80=D0=B5=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=E2=80=94=20=D1=81=D0=BB=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=80=D1=8C=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B2=20=D1=8F=D0=B4=D1=80=D0=B5,?= =?UTF-8?q?=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D1=8B=20=D0=BE=D1=82?= =?UTF-8?q?=D0=B4=D0=B0=D1=8E=D1=82=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=B7?= =?UTF-8?q?=D0=BD=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=82=D0=B5=D0=BA=D1=81?= =?UTF-8?q?=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .../unified-statement-normalization/design.md | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/openspec/changes/unified-statement-normalization/design.md b/openspec/changes/unified-statement-normalization/design.md index a2f34f7..4bafbde 100644 --- a/openspec/changes/unified-statement-normalization/design.md +++ b/openspec/changes/unified-statement-normalization/design.md @@ -1,7 +1,7 @@ # Единый алгоритм нормализации ББ/ОФР (scan-gateway и tabular-parser) — дизайн Issue: arm-ka-docs#116. Статус: черновик; текущая цепочка описана, целевая картина по шагам 1–9 — предложение, ждёт -решений владельца Р-1…Р-3, Р-5…Р-7; Р-4 решено (brainstorming 17.10.2026). +решений владельца Р-1, Р-2, Р-5…Р-7; Р-3 и Р-4 решены (brainstorming 17.10.2026). ## Цель @@ -330,7 +330,9 @@ sheet:,`. `DISCLOSURE` и форма без колонки кодов — статус строки, нарушения §7 по ячейкам, предупреждения с уровнем и привязкой. Уверенность, `is_recognized` и §7 сервис сводит в один признак ячейки `needs_review` (шаг 8) и из него, статусов строк и предупреждений выводит статус документа; ядро при загрузке ничего не пересчитывает, после правок аналитика считает тем же общим кодом. -4. **Один словарь — одно место:** строки форм, проверки §7, периоды, заголовки форм, диапазоны кодов. +4. **Один словарь — одно место:** проверки §7, периоды, заголовки форм, диапазоны кодов — в общем коде сервисов; + соответствие «код → наименование» (словарь строк с редакциями) — только в ядре, сервисы его не знают и отдают + распознанный текст (решение владельца 17.10.2026, Р-3). 5. **Очистка OCR (§11.1) — не отдельный шаг, а первая стадия типовых разборов текста** в общем коде, там, где уже известен смысл ячейки: ИНН и дата шапки (шаг 1), подписи колонок (шаг 2), код строки и разлепление склеенных строк (шаг 3), сумма (шаг 4). Разбор вызывается для любой ячейки без `value`; у Excel он срабатывает только на @@ -465,16 +467,16 @@ line_name_confidence, values}`: `line_code` — разобранный код (4 `line_code_text` — сырой текст ячейки кода; `line_status` = `code_status` шага 3 (`ok` | `unreadable` | `missing`). Несколько строк с одним кодом — обычные строки `ok`, порядок как в файле. -- **1. Источник наименования** — одно правило: наименование — из файла, с уверенностью источника; справочник наименование не подменяет. Справочное имя по коду и редакции добавляет ядро из единственного словаря строк (общий код, п. 3), экран показывает справочное, файловое — рядом (Р-3; AURORA-1406, 1522) +- **1. Источник наименования** — **решение владельца (17.10.2026):** сервисы отдают распознанный текст наименования как есть, с уверенностью источника; соответствие «код → наименование» — только в ядре и только когда нужно (показ справочного имени, достройка шаблонных строк). Экран показывает справочное имя, файловое — рядом (Р-3; AURORA-1406, 1522) - scan-gateway: имя из `statement_lines.yaml` → имя из OCR - tabular-parser: как сейчас -- **2. Редакция (66н / ФСБУ 4)** — в сервисах не определяется; редакция — свойство словаря строк (по дате отчёта), используется в шаге 7 (проверка «код не из редакции формы») и в ядре при достройке шаблонных строк +- **2. Редакция (66н / ФСБУ 4)** — в сервисах не определяется; редакция — свойство словаря строк ядра (по дате отчёта), ядро использует её при достройке шаблонных строк, показе справочного имени и проверке «код не из редакции формы» - scan-gateway: `_choose_edition` уходит - tabular-parser: без изменений -- **3. Справочник строк** — один словарь строк (в общем коде, Р-1); копия в шлюзе удаляется +- **3. Справочник строк** — только в ядре; в общий код сервисов не входит; копия в шлюзе удаляется - scan-gateway: удаляет `api/rules/statement_lines.yaml` - tabular-parser: без изменений -- **4. Уверенность кода** — от источника (ИС / 100), без срезания до 99 по справочнику; «не в справочнике» — предупреждение к строке в шаге 7 +- **4. Уверенность кода** — от источника (ИС / 100), без срезания до 99 по справочнику; «код не в справочнике» — проверка ядра по его словарю, не сервисов - scan-gateway: убирает `min(conf, 99)` - tabular-parser: как сейчас @@ -501,8 +503,9 @@ line_name_confidence, values}`: `line_code` — разобранный код (4 **Вход:** `StatementDocument`. **Единый выход:** `StatementChecks` у обоих: `relations_failed[]`, `soft_relations_failed[]` (каждое нарушение — с -кодами слагаемых и `column_index`, чтобы экран подсветил ячейки), `line_warnings[]` (код не из редакции формы по дате -отчёта, код не в словаре). `duplicate_line_codes` уходит: соотношения считаются по сумме значений одного кода в +кодами слагаемых и `column_index`, чтобы экран подсветил ячейки). Проверки по словарю строк (код не в словаре, код не +из редакции формы по дате отчёта) — в ядре, сервисы словаря строк не знают (Р-3). `duplicate_line_codes` уходит: +соотношения считаются по сумме значений одного кода в колонке (повтор кода — законный случай, шаг 3 п. 3); нарушение подсвечивает все строки этого кода. - **1. Проверки только у парсера; словарь §7 в двух копиях; ядро результат не читает** — проверки — общий код с одним словарём `statement_checks.yaml` у обоих сервисов; для OCR нарушение §7 — главный признак неверно прочитанной цифры; ядро читает `checks` из результата и пересчитывает тем же кодом только после правок аналитика (PATCH) @@ -554,7 +557,7 @@ column_index?}`, а не строка. Одинаково, как сейчас; контракт `recognition-result.schema.json` → **v1.3**: `line_status`, `line_code` nullable, `line_code_text`; `needs_review` у значения; `document.status`; `document.warnings[]` и `metrics.warnings[]` структурные (уровень, привязка); `checks` обязателен для `BALANCE` / `INCOME` со строками у обоих конвейеров (у -документа без строк отсутствует), нарушения с кодами слагаемых, без `duplicate_line_codes`; `line_warnings`. +документа без строк отсутствует), нарушения с кодами слагаемых, без `duplicate_line_codes`. ### Что уходит из ядра @@ -567,8 +570,10 @@ column_index?}`, а не строка. - `statement_status` (D-6): `RECOGNIZED` ⇔ `document.status = done` ∧ ИНН ≠ `MISMATCH` (единственное знание ядра); остальные признаки D-6 не пересчитываются. - §7 при загрузке: `checks` берутся из результата; пересчёт общим кодом — только после PATCH. -- Словарь строк и словарь §7: единственный экземпляр в общем коде (Р-1); копии ядра и шлюза удаляются. -- Достройка шаблонных строк: по тому же словарю; строки `missing` / `unreadable` показываются как пришли, с +- Словарь §7: единственный экземпляр в общем коде (Р-1), копия ядра удаляется. Словарь строк (код → наименование, + редакции) остаётся только в ядре, копия шлюза удаляется; проверки по нему (код не в словаре, код не из редакции по + дате отчёта) ядро делает само при загрузке и после PATCH, как предупреждения к строке. +- Достройка шаблонных строк: по словарю ядра; строки `missing` / `unreadable` показываются как пришли, с подсветкой; код, у которого есть хотя бы одна строка из файла, шаблоном не достраивается. - Экран: подсветка ячеек только по `needs_review` (уверенность, `is_recognized` и нарушения §7 уже сведены сервисом); строк — по `line_status`; предупреждения документа — с привязкой к месту. @@ -576,12 +581,14 @@ column_index?}`, а не строка. ### Решения, которые нужны от владельца - **Р-1** (шаг 1, п. 2) — форма общего кода: общий Python-пакет с dataclass-ами (сериализуемыми в json — golden-файлы - выхода шага 1 в fixtures), шагами 2–8 и словарями, который подключают оба сервиса и ядро (рекомендация); запасной + выхода шага 1 в fixtures), шагами 2–8 и словарями (§7, периоды, заголовки форм, диапазоны кодов; без словаря + строк), который подключают оба сервиса и ядро (рекомендация); запасной вариант, если платформа не даст ставить пакет из git или зеркала, — копия по скрипту, как `sync-web.sh`. - **Р-2** (шаг 4, п. 5) — отсутствующая OCR-ячейка под колонкой: чистый `null` (предложение; потерю ловит §7) или подсветка «не распознано», как сейчас (больше ложных подсветок, AURORA-1524). -- **Р-3** (шаг 5, п. 1) — наименование: из файла в сервисах, справочное — в ядре (= решение № 2 по спринту 2, - AURORA-1406 / 1522; договорённость ДБД «из справочника» выполняется на экране). +- **Р-3** (шаг 5, п. 1) — **решено владельцем 17.10.2026:** сервисы отдают распознанный текст наименования; + соответствие «код → наименование» — только в ядре, при необходимости (= решение № 2 по спринту 2, AURORA-1406 / + 1522; договорённость ДБД «из справочника» выполняется на экране). - **Р-4** (шаг 3, п. 3) — **решено владельцем 17.10.2026:** повторы кодов законны; все строки сохраняются и показываются, для проверок и всех операций после подтверждения или автоподтверждения — суммой по коду. Следствие: снять уникальность `(meta_id, line_code)` в DBML.