docs(#116): сверка консистентности целевой картины после Р-4 и needs_review

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-17 18:33:36 +04:00
parent 0f57ceb5f1
commit 19e185984c

View File

@ -1,7 +1,7 @@
# Единый алгоритм нормализации ББ/ОФР (scan-gateway и tabular-parser) — дизайн
Issue: arm-ka-docs#116. Статус: черновик; текущая цепочка описана, целевая картина по шагам 1–9 — предложение, ждёт
решений владельца Р-1…Р-6 (brainstorming 17.10.2026).
решений владельца Р-1…Р-3, Р-5…Р-7; Р-4 решено (brainstorming 17.10.2026).
## Цель
@ -317,7 +317,7 @@ sheet:<A>,<B>`. `DISCLOSURE` и форма без колонки кодов —
Каждый шаг ниже: **вход = выход предыдущего шага**, единый выход для обоих сервисов, таблица «различие → к чему
приводим → что меняется в scan-gateway → что меняется в tabular-parser». Решения владельца помечены датой; остальное —
предложение (17.10.2026), решения, которые нужны от владельца, собраны в конце (Р-1…Р-6). Имена полей — рабочие,
предложение (17.10.2026), решения, которые нужны от владельца, собраны в конце (Р-1…Р-7). Имена полей — рабочие,
уточняются при написании спеки.
Принципы, из которых выведены решения по строкам:
@ -327,8 +327,9 @@ sheet:<A>,<B>`. `DISCLOSURE` и форма без колонки кодов —
2. **Ничего не выбрасывать молча.** Строка, колонка или ячейка, которую не удалось истолковать, идёт дальше со
статусом, а не превращается в счётчик; пользователь её видит и исправляет.
3. **Качество — структурно и с привязкой к месту:** уверенность ячейки (от источника), `is_recognized` (разбор числа),
статус строки, нарушения §7 по ячейкам, предупреждения с уровнем и привязкой. Статус документа сервис выводит из
них сам; ядро не пересчитывает.
статус строки, нарушения §7 по ячейкам, предупреждения с уровнем и привязкой. Уверенность, `is_recognized` и §7
сервис сводит в один признак ячейки `needs_review` (шаг 8) и из него, статусов строк и предупреждений выводит
статус документа; ядро при загрузке ничего не пересчитывает, после правок аналитика считает тем же общим кодом.
4. **Один словарь — одно место:** строки форм, проверки §7, периоды, заголовки форм, диапазоны кодов.
5. **Очистка OCR (§11.1) — не отдельный шаг, а первая стадия типовых разборов текста** в общем коде, там, где уже
известен смысл ячейки: ИНН и дата шапки (шаг 1), подписи колонок (шаг 2), код строки и разлепление склеенных
@ -425,10 +426,10 @@ sheet:<A>,<B>`. `DISCLOSURE` и форма без колонки кодов —
- **2. Склейка двух строк в одну** — одно правило: ячейка кода содержит N кодов через перевод строки и ячейки значений — N частей → N строк (OQ-156); у Excel не срабатывает
- scan-gateway: как сейчас, через общее правило
- tabular-parser: правило общее, no-op
- **3. Повтор кода** — **решение владельца (17.10.2026):** повтор кода — законный случай (один код, разные наименования), не ошибка и не предупреждение. Все строки сохраняются как есть со статусом `ok`; текстовое предупреждение и `checks.duplicate_line_codes` уходят. Для проверок §7, подтверждения и всего, что идёт после, значения одного кода идут суммой (см. «Что уходит из ядра»; договорённость ДБД в AURORA-1431). Неверно прочитанный код, случайно совпавший с существующим, ловит §7 через сумму
- **3. Повтор кода** — **решение владельца (17.10.2026):** повтор кода — законный случай (один код, разные наименования), не ошибка и не предупреждение. Все строки сохраняются как есть со статусом `ok`; текстовое предупреждение и `checks.duplicate_line_codes` уходят. Для проверок §7, подтверждения и всего, что идёт после, значения одного кода идут суммой (см. «Что уходит из ядра»; договорённость ДБД в AURORA-1431; закрывает AURORA-1406). Неверно прочитанный код, случайно совпавший с существующим, ловит §7 через сумму
- scan-gateway: «оставлена первая» → все строки
- tabular-parser: `duplicates` уходит
- **4. Отброшенная строка** — строки не отбрасываются: `unreadable` / `missing` идут дальше со статусом (AURORA-1634, 1462, 1406); ядро не достраивает вместо них пустую шаблонную строку молча
- **4. Отброшенная строка** — строки не отбрасываются: `unreadable` / `missing` идут дальше со статусом (AURORA-1634, 1462); ядро не достраивает вместо них пустую шаблонную строку молча
- scan-gateway: счётчики → статусы
- tabular-parser: счётчики → статусы
@ -439,10 +440,10 @@ sheet:<A>,<B>`. `DISCLOSURE` и форма без колонки кодов —
**Единый выход:** `StatementValue {column_index, amount, string_value, confidence, is_recognized}` — как в контракте,
с одним смыслом полей у обоих.
- **1. Предобработка текста** — у ячейки после шага 1 либо есть `value`, либо только `text`. `value` есть → `amount = value` (2 знака), `is_recognized = true`. `value` нет → один `parse_amount(text)` для обоих: двойники, разделители тысяч, скобки → минус, прочерк → `null`; Excel-ячейки «число текстом» идут тем же путём
- **1. Предобработка текста** — у ячейки после шага 1 либо есть `value`, либо только `text`. `value` — число → `amount = value` (2 знака), `is_recognized = true`. `value` нет или не число (дата, логическое) → один `parse_amount(text)` для обоих: двойники, разделители тысяч, скобки → минус, прочерк → `null`; Excel-ячейки «число текстом» идут тем же путём
- scan-gateway: `parse_amount` переезжает в общий код
- tabular-parser: `to_money` заменяется общим `parse_amount`
- **2. Смысл `is_recognized`** — один: текст разобран как число без выброшенных и исправленных символов; `confidence` — отдельно, от источника; экран подсвечивает по любому из двух (как сейчас)
- **2. Смысл `is_recognized`** — один: текст разобран как число без выброшенных и исправленных символов; `confidence` — отдельно, от источника; оба признака сервис сводит в `needs_review` (шаг 8, «Подтверждение проверкой»), экран подсвечивает по нему
- scan-gateway: отвязывает от `confidence`
- tabular-parser: как сейчас
- **3. «42831 1»** — в `parse_amount` пробел допустим только как разделитель тысяч (группы ровно по три цифры); иначе `amount` — лучшая догадка (цифры подряд), `is_recognized = false`, `string_value` — сырой текст (AURORA-1511, 1519)
@ -464,7 +465,7 @@ line_name_confidence, values}`: `line_code` — разобранный код (4
`line_code_text` — сырой текст ячейки кода; `line_status` = `code_status` шага 3 (`ok` | `unreadable` | `missing`).
Несколько строк с одним кодом — обычные строки `ok`, порядок как в файле.
- **1. Источник наименования** — одно правило: наименование — из файла, с уверенностью источника; справочник наименование не подменяет. Справочное имя по коду и редакции добавляет ядро из своего (единственного) словаря, экран показывает справочное, файловое — рядом (Р-3; AURORA-1406, 1522)
- **1. Источник наименования** — одно правило: наименование — из файла, с уверенностью источника; справочник наименование не подменяет. Справочное имя по коду и редакции добавляет ядро из единственного словаря строк (общий код, п. 3), экран показывает справочное, файловое — рядом (Р-3; AURORA-1406, 1522)
- scan-gateway: имя из `statement_lines.yaml` → имя из OCR
- tabular-parser: как сейчас
- **2. Редакция (66н / ФСБУ 4)** — в сервисах не определяется; редакция — свойство словаря строк (по дате отчёта), используется в шаге 7 (проверка «код не из редакции формы») и в ядре при достройке шаблонных строк
@ -516,10 +517,10 @@ line_name_confidence, values}`: `line_code` — разобранный код (4
статус конверта — агрегат. Предупреждение — структура `{code, severity: error | info, message, line_ref?,
column_index?}`, а не строка.
- **1. Критерий `done`** — один критерий из самого результата: раскладка найдена ∧ (организация или ИНН) ∧ дата отчёта ∧ все строки `ok` ∧ нет значений `needs_review` (см. «Подтверждение проверкой» ниже) ∧ жёсткие проверки §7 сошлись ∧ нет предупреждений уровня `error`. Excel выполняет условия уверенности автоматически
- **1. Критерий `done`** — один критерий из самого результата: раскладка найдена ∧ (организация или ИНН) ∧ дата отчёта ∧ все строки `ok` ∧ нет значений `needs_review` (см. «Подтверждение проверкой» ниже) ∧ жёсткие проверки §7 сошлись ∧ нет предупреждений уровня `error`. `DISCLOSURE` — `done` без условий о раскладке, строках и проверках (как сейчас). Excel выполняет условия уверенности автоматически
- scan-gateway: «ничего не выброшено и уверенность 100» → общий критерий
- tabular-parser: `_is_ok` → общий критерий; добавляются строки и значения
- **2. Влияние предупреждений** — по уровню: `error` → `needs_check`, `info` — не влияет; у обоих одинаково
- **2. Влияние предупреждений** — по уровню: `error` → `needs_check`, `info` — не влияет; у обоих одинаково; уровень каждого предупреждения задаётся в спеке (например, «строка заголовка не найдена», «колонка без даты», «тип по кодам противоречит заголовку» — `error`; «подпись из словаря исключений пропущена», «дробные при тыс. руб.» — `info`)
- scan-gateway: «любое → `needs_check`» уходит
- tabular-parser: предупреждения начинают влиять
- **3. Статус документа** — в контракте: `document.status`; конверт `done` ⇔ все документы `done` ∧ нет предупреждений файла уровня `error`; иначе `needs_check`; документов нет — `error` (как сейчас)
@ -535,8 +536,9 @@ column_index?}`, а не строка.
**Подтверждение проверкой (вопрос владельца 17.10.2026).** Проверка §7 — арбитр, уверенность — подсказка там, где
проверки нет. По каждому значению сервис считает `needs_review`:
- `true`, если `is_recognized = false` или `confidence` ниже порога (Р-5) **и** значение не покрыто сошедшимся жёстким
соотношением §7 в своей колонке (не входит ни в одно, соотношение не сошлось или оно мягкое);
- `true`, если `confidence` ниже порога (Р-5) **и** значение не покрыто сошедшимся жёстким соотношением §7 в своей
колонке (не входит ни в одно, соотношение не сошлось или оно мягкое); для `is_recognized = false` — то же правило,
если Р-7 = да, иначе всегда `true`;
- `true` у всех ячеек соотношения в колонке, где оно не сошлось, независимо от уверенности;
- иначе `false`: значение подтверждено проверкой, не подсвечивается и статус не трогает; сырой текст и уверенность
остаются в подсказке ячейки.
@ -550,8 +552,9 @@ column_index?}`, а не строка.
### Шаг 9 — Результат
Одинаково, как сейчас; контракт `recognition-result.schema.json` → **v1.3**: `line_status`, `line_code` nullable,
`line_code_text`; `document.status`; `document.warnings[]` и `metrics.warnings[]` структурные; `checks` обязателен для
`BALANCE` / `INCOME` у обоих конвейеров, нарушения с кодами слагаемых; `line_warnings`.
`line_code_text`; `needs_review` у значения; `document.status`; `document.warnings[]` и `metrics.warnings[]`
структурные (уровень, привязка); `checks` обязателен для `BALANCE` / `INCOME` со строками у обоих конвейеров (у
документа без строк отсутствует), нарушения с кодами слагаемых, без `duplicate_line_codes`; `line_warnings`.
### Что уходит из ядра
@ -582,8 +585,9 @@ column_index?}`, а не строка.
- **Р-4** (шаг 3, п. 3) — **решено владельцем 17.10.2026:** повторы кодов законны; все строки сохраняются и
показываются, для проверок и всех операций после подтверждения или автоподтверждения — суммой по коду. Следствие:
снять уникальность `(meta_id, line_code)` в DBML.
- **Р-5** (шаг 8, п. 1) — порог уверенности для `done` (= решение № 7 по спринту 2, AURORA-1519 / 1524); предложение —
100, как сейчас.
- **Р-5** (шаг 8, «Подтверждение проверкой») — порог уверенности, ниже которого значение попадает в `needs_review`,
если не подтверждено проверкой §7 (= решение № 7 по спринту 2, AURORA-1519 / 1524); предложение — 100, как сейчас:
ложных подсветок станет меньше за счёт подтверждения проверкой, а не за счёт порога.
- **Р-6** (шаг 2, п. 6) — неизвестная числовая колонка без периода: оставлять без даты с предупреждением (`needs_check`)
или пропускать, как парсер сейчас.
- **Р-7** (шаг 8, «Подтверждение проверкой») — снимать ли подсветку сошедшимся соотношением §7 и с `is_recognized =