From dc374a54a4fb5fbd063bfa63d7130b901ba80818 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Fri, 6 Nov 2026 22:57:45 +0400 Subject: [PATCH] =?UTF-8?q?AURORA-1864:=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF?= =?UTF-8?q?=D0=B0=20=D0=B0=D0=BB=D1=8C=D1=82=D0=B5=D1=80=D0=BD=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D0=B2=20=D1=81=D0=BE=D0=BE=D1=82=D0=BD=D0=BE=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=202400,=20=D0=B7=D0=BD=D0=B0=D0=BA=202410=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D0=BC=20(RSHB/pylib=5Fai=5Farm=5Fstatements#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §7: правило group в statement_checks.yaml, соотношения 2400 полного и упрощённого наборов — альтернативы; OQ-12 закрыт в части 2410. Change statement-checks-alternatives: требование «Шаг 7» спеки statement-normalization. Co-Authored-By: Claude Opus 5.5 --- context/05-domain-rules.md | 22 ++++-- context/07-open-questions.md | 2 +- .../.openspec.yaml | 2 + .../statement-checks-alternatives/design.md | 30 ++++++++ .../statement-checks-alternatives/proposal.md | 34 +++++++++ .../specs/statement-normalization/spec.md | 74 +++++++++++++++++++ 6 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 openspec/changes/statement-checks-alternatives/.openspec.yaml create mode 100644 openspec/changes/statement-checks-alternatives/design.md create mode 100644 openspec/changes/statement-checks-alternatives/proposal.md create mode 100644 openspec/changes/statement-checks-alternatives/specs/statement-normalization/spec.md diff --git a/context/05-domain-rules.md b/context/05-domain-rules.md index 6059607..18f02f7 100644 --- a/context/05-domain-rules.md +++ b/context/05-domain-rules.md @@ -828,7 +828,8 @@ one_sided = ровно одна из amount_a, amount_b равна 0 (знак `1200 = 1210 + 1220 + 1230 + 1240 + 1250 + 1260`; `1300 = 1310 + 1320 + 1340 + 1350 + 1360 + 1370`; `1400 = 1410 + 1420 + 1430 + 1450`; `1500 = 1510 + 1520 + 1540 + 1550`; `1600 = 1100 + 1200`; `1700 = 1300 + 1400 + 1500`. ОФР: `2100 = 2110 − 2120`; `2200 = 2100 − 2210 − 2220`; `2300 = 2200 + 2310 + 2320 − 2330 + 2340 − 2350`; -`2400 = 2300 − 2410 + 2420` (знаки 2410/2420/2430 — по ФСБУ 4/2023 уточнить [открыто]). +`2400 = 2300 − 2410 + 2420` или `2400 = 2300 + 2410 + 2460` (знак 2410 не определяется — см. группу альтернатив ниже; +знаки 2420/2430 по ФСБУ 4/2023 — OQ-12 [открыто]). Межформенная: `1370(отчётная дата) − 1370(начало года) = 2400(ОФР за период)` — при расхождении КА может акцептовать с комментарием (`financial_statement_meta.checks_accepted_*`). @@ -839,9 +840,9 @@ one_sided = ровно одна из amount_a, amount_b равна 0 (знак пересчитывает тем же кодом только после правок аналитика; своей копии словаря у ядра нет. Правила счёта: - **Жёсткие** (нарушение → `needs_check`): ББ — `1100`, `1200` (+1215), `1300`, `1400`, `1500`, `1600 = 1100 + 1200`, - `1700 = 1300 + 1400 + 1500`, `1600 = 1700`; ОФР — `2100`, `2200`, `2300`. **Мягкие** (`info`, `ASSUMPTION(OQ-12)`): `2400 = - 2300 − 2410 + 2420` и варианты ФСБУ 4/2023 (`2400 = 2300 + 2410 + 2460`, `2410 = 2411 + 2412`), `2500 = 2400 + 2510 + - 2520 + 2530`, «сумма пятизначных подстрок = родитель» (по колонке — только если хотя бы одна подстрока родителя в ней + `1700 = 1300 + 1400 + 1500`, `1600 = 1700`; ОФР — `2100`, `2200`, `2300`. **Мягкие** (`info`): `2400 = + 2300 − 2410 + 2420` и `2400 = 2300 + 2410 + 2460` (группа альтернатив, ниже), `2410 = 2411 + 2412`, `2500 = 2400 + + 2510 + 2520 + 2530`, «сумма пятизначных подстрок = родитель» (по колонке — только если хотя бы одна подстрока родителя в ней непуста: `amount` не `null`, ноль — значение; AURORA-1527). Мягкое соотношение на статус и подсветку не влияет, но **сошедшееся точно** (расхождение в пределах допуска ±1, без «округления») подтверждает неуверенные значения своих кодов (Р-21, §11.9): так покрываются 2400, 2410, 2411, 2412, 2460, 25xx и пятизначные подстроки. @@ -862,12 +863,21 @@ one_sided = ровно одна из amount_a, amount_b равна 0 (знак с этими членами по модулю (1С выгружает расходы со знаком минус, 66н — в скобках). Такое соотношение сходится при любом знаке члена и потому **подтверждает величину, но не знак**: знак сомнительной ячейки подтверждается конвенцией колонки (§11.9). +- **Группа альтернатив** (`group` в `statement_checks.yaml`; AURORA-1864, решение владельца 27.10.2026). Мягкие + соотношения одной цели одной формы и варианта могут быть альтернативами: в колонке сошлась хоть одна — нарушений + группы нет; не сошлась ни одна — в `soft_relations_failed` одно нарушение, ближайшая к цели альтернатива (при пустой + цели или пустых членах — первая по словарю). `group` только у мягких и с одной целью — иначе словарь не загружается. + Группы — соотношения 2400 обоих наборов: **знак 2410 не определяется**, принимается любой вариант (расход — + `2300 − 2410`, со знаком минус, в скобках или без знака; доход по налогу ФСБУ 4/2023 — `2300 + 2410`). Жёсткие + проверки, подсветка, `needs_check` и подтверждение значений (Р-21) группой не меняются; каждая альтернатива + подтверждает свои коды, как отдельное мягкое соотношение. Формула старого бланка с 2430/2450 не добавляется. - **Упрощённый набор.** Набор выбирается по `form_variant` документа (§11.7): у упрощённой формы нет подытогов 1100 / 1200 (ББ) и 2100 / 2200 / 2300 (ОФР), свои равенства по бланку упрощённой формы (приказ 66н, прил. 5; `ASSUMPTION` до первого образца в fixtures): ББ — `1600 = 1150 + 1170 + 1210 + 1230 + 1250` (жёсткое), `1700 = 1300 + 1350 + 1360 + 1410 + 1450 + 1510 + 1520 + 1550` (жёсткое), `1600 = 1700` (жёсткое); ОФР — `2400 = 2110 − 2120 − 2330 + - 2340 − 2350 − 2410` (**мягкое**, как `2400` полного набора: знак 2410 не определён, OQ-12; `abs_terms` те же; решение - владельца 18.10.2026, Р-22 / S-5). Оба набора — в одном словаре `statement_checks.yaml`. Без упрощённого набора полный + 2340 − 2350 − 2410` и `2400 = 2110 − 2120 − 2330 + 2340 − 2350 + 2410` (**мягкие**, группа альтернатив, как `2400` + полного набора; `abs_terms` — 2120, 2330, 2350, у первого ещё 2410; решение владельца 18.10.2026, Р-22 / S-5; + вторая альтернатива — AURORA-1864). Оба набора — в одном словаре `statement_checks.yaml`. Без упрощённого набора полный дал бы нарушения «пустой цели» на каждой упрощённой форме. `form_variant = null` (документ, оставшийся в БД с времён до v5.19, если база не очищена) — полный набор; у результата 1.x вариант определяется по структуре кодов при приёме. - **Родитель пятизначной подстроки** — ближайшая четырёхзначная строка выше с теми же первыми тремя цифрами, иначе код diff --git a/context/07-open-questions.md b/context/07-open-questions.md index b8cdb4c..0fe24a7 100644 --- a/context/07-open-questions.md +++ b/context/07-open-questions.md @@ -17,7 +17,7 @@ | OQ-09 | Правила элиминации ОФР (2110/2120/2310/2320/2330): точный состав субсчетов, источник средневзвешенной ставки НДС, выбор субсчетов «работником ПА самостоятельно» | FNR03 | срез 6 | не реализовывать авто-элиминацию ОФР до решения; только ручные `correction` | | OQ-10 | Гудвилл: входит ли стр. 1350 (добавочный капитал) в базу участия; УК из ББ (1310) или из ОСВ 80/83 | DBML, DOC-259025, FNR03 | срез 6 | допущение: 1310 из ББ; 1350 — настраиваемый флаг, по умолчанию выключен. **06.11:** DOC-259025 (Лысенко, 03.11) — «для УК используется 1310», 1350 в формулу не входит; так реализовано (arm-core #222), флага нет; подтверждение методологов (AURORA-1369) не получено | | OQ-11 | Строка «ППА» в КФО (правило № 1, когда у А нет ОСВ 03) — что это и куда | FNR03 | срез 6 | не реализовывать | -| OQ-12 | Формулы ОФР: знаки 2410/2420/2430 по ФСБУ 4/2023 vs 66н; состав 1100 (1120–1140) | DOC-221281 | срез 3 | допущение: формулы §7, строки без значения = 0; **расширение 07.10.2026:** формулы и справочники по редакциям форм (`66n` / `fsbu4`) — OQ-146 | +| OQ-12 | Формулы ОФР: знаки 2410/2420/2430 по ФСБУ 4/2023 vs 66н; состав 1100 (1120–1140) | DOC-221281 | срез 3 | допущение: формулы §7, строки без значения = 0; **06.11.2026 закрыт в части 2410** (AURORA-1864, решение владельца 27.10.2026): знак 2410 не определяется, соотношения 2400 — группа альтернатив §7 (`2300 − 2410` и `2300 + 2410`); 2420/2430 и состав 1100 — открыты; **расширение 07.10.2026:** формулы и справочники по редакциям форм (`66n` / `fsbu4`) — OQ-146 | | OQ-13 | `confidence` от ИС Сканирование — доли 0..1 или проценты 0..100; имя поля организации (`full_name` vs `form_name`) | FNR02 vs `aep_*.json` | срез 3 (scan-gateway) | **закрыт для scan-gateway (04.10.2026, по `aep_3.json`, `aep_6.json`):** `confidence` — числа 0–100 (не доли); название организации — `data_ocr.organization.form_name` (шумный OCR-текст), ИНН — `inn.form_name`, единицы — `units.form_name`, дата — `date.form_name` (в `aep_6.json` мусор); `full_name`/`inn.inn`/`units.measurement` из ТЗ в реальных файлах нет. Нормализация — Срез 3 | | OQ-14 | `reporting_date` в JSON ИС Сканирование — «ждём обновлённый JSON» | FNR01 | срез 3 | **уточнено (04.10.2026):** отдельного поля `reporting_date` в ответе нет; `date.form_name` ненадёжен (в `aep_6.json` — «Общество с ограниченной ответственностью», в `aep_3.json` — «2\|0\|2\|4\|»); даты колонок — в строке-шапке `rows[0]` таблицы («На 30 июня 2025 г» в `aep_6.json`), в `aep_3.json` шапки нет. Допущение прежнее: парсить из шапки таблицы, при её отсутствии — `NEEDS_CHECK`; решение — Срез 3 | | OQ-15 | Таймаут OCR 5 мин / 0 повторов (ТЗ 3) vs outbox с повторами (DBML) | DOC-037736 | срез 3 | решено DBML: `max_attempts` OCR = 1, парсер = 3 | diff --git a/openspec/changes/statement-checks-alternatives/.openspec.yaml b/openspec/changes/statement-checks-alternatives/.openspec.yaml new file mode 100644 index 0000000..8a94d76 --- /dev/null +++ b/openspec/changes/statement-checks-alternatives/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-11-06 diff --git a/openspec/changes/statement-checks-alternatives/design.md b/openspec/changes/statement-checks-alternatives/design.md new file mode 100644 index 0000000..b55f1be --- /dev/null +++ b/openspec/changes/statement-checks-alternatives/design.md @@ -0,0 +1,30 @@ +## Context + +Решение согласовано владельцем 27.10.2026 (комментарий в AURORA-1864): мягкие соотношения одной цели объединяются в +группу альтернатив, знак 2410 не определяется. Реализация — `arm_statements/checks.py` (`checks_from`) и загрузчик +словаря (`loader.py`); RSHB/pylib_ai_arm_statements#3. + +## Decisions + +- Группа считается в `checks_from` по паре (колонка, `group`) среди уже посчитанных исходов; `evaluate_relations` и + исходы для шага 8 не меняются — поэтому подсветка и Р-21 остаются прежними (каждая альтернатива подтверждает + значения сама, как раньше). +- «Сошлась» — расхождение в пределах допуска ±1 (`within_tolerance`), как для мягкого соотношения без группы. +- Проверки «`group` только у мягкого» и «у группы одна цель» — в загрузчике: жёсткая группа означала бы, что статус документа зависит от + выбора альтернативы, а этого решение не предусматривает. + +## Decisions made without discussion + +| Дата | Решение | Обоснование | Цена ошибки | +|---|---|---|---| +| 2026-11-06 | Имя группы в словаре — `net_profit` для обоих наборов | Группа — по форме и варианту (`relations_for`), одно имя не смешивает полный и упрощённый наборы; имя описывает цель 2400 | Нулевая: имя только в словаре, наружу не выходит | +| 2026-11-06 | Если у всех несошедшихся альтернатив пуста цель или все члены (сравнить не с чем) — выдаётся первая по словарю | Расхождения нет, «ближайшую» выбрать не по чему; порядок словаря детерминирован | Низкая: текст нарушения другой альтернативы, сам факт нарушения тот же | +| 2026-11-06 | При равном расхождении выдаётся первая по словарю | Детерминированность | Нулевая | +| 2026-11-06 | Тест `test_simplified_income_soft` (2400 = 500 при 1000 − 600 ± 50) теперь ожидает нарушение новой альтернативы `… + 2410` — она ближе к цели (450 против 350) | Прямое следствие правила «ближайшая к цели» | Нулевая: данные теста неверны в обоих вариантах | + +## Risks / Trade-offs + +- Новая альтернатива упрощённого набора (`… + 2410`) при совпадении подтверждает неуверенные значения своих кодов + (Р-21), включая положительный 2410 — это и есть желаемое поведение для дохода по налогу. +- Документы, загруженные до выкладки 0.1.4, сохраняют прежние `checks` до пересчёта (правка аналитика) — ложное + предупреждение у них останется; переразбор не планируется. diff --git a/openspec/changes/statement-checks-alternatives/proposal.md b/openspec/changes/statement-checks-alternatives/proposal.md new file mode 100644 index 0000000..a8ee594 --- /dev/null +++ b/openspec/changes/statement-checks-alternatives/proposal.md @@ -0,0 +1,34 @@ +## Why + +Замечание тестировщика заказчика 23.10.2026 (AURORA-1864, ООО «Фавор плюс», ООО «Фактор»): у ОФР с положительной строкой +2410 «Налог на прибыль» (доход по налогу, ФСБУ 4/2023) появляется мягкое нарушение «2400 = 2300 − 2410 + 2420», хотя +форма верна (2400 = 2300 + 2410). 2410 — член `abs_terms`: правая часть считается и как записано, и с |2410|, но оба +варианта вычитают 2410. Второе соотношение «2400 = 2300 + 2410 + 2460» на таких данных сходится, а первое всё равно +выдаёт предупреждение. Аналитик видит «некорректную проверку». + +## What Changes + +- Словарь `statement_checks.yaml` (библиотека `pylib_ai_arm_statements` 0.1.4, RSHB/pylib_ai_arm_statements#3): + необязательный ключ `group` у мягких соотношений — группа альтернатив одной цели. В колонке сошлась хоть одна — + нарушений группы нет; не сошлась ни одна — одно нарушение, ближайшая к цели. `group` у жёсткого — ошибка загрузки. +- Соотношения 2400 ОФР — одна группа в полном наборе (`2400 = 2300 − 2410 + 2420`, `2400 = 2300 + 2410 + 2460`) и в + упрощённом (существующее + новое `2400 = 2110 − 2120 − 2330 + 2340 − 2350 + 2410`). +- Документы контекста: `05-domain-rules.md` §7 (правило группы, знак 2410 не определяется), `07-open-questions.md` + OQ-12 — закрыт в части знака 2410. +- Контракт `recognition-result` не меняется: формат `soft_relations_failed` прежний, меняется только состав нарушений. + +Подъём версии библиотеки до 0.1.4 в arm-core, tabular-parser, scan-gateway — отдельными PR после merge AURORA-1677 +(переезд на библиотеку; merge придержан владельцем до выкатки гудвилла). + +## Non-goals + +- Жёсткие проверки, подсветка, `needs_check`, подтверждение значений шагом 8 (Р-21) — без изменений. +- Формула старого бланка с 2430/2450 не добавляется. +- Словари по редакциям 66н / ФСБУ 4/2023 (OQ-146, OQ-150, AURORA-1554) — отдельная задача. +- Переразбор уже загруженных документов: новые проверки применяются к новым загрузкам и к пересчёту после правок. + +## Impact + +- Спека `statement-normalization` — требование «Шаг 7 — самопроверки §7». +- Репозитории: pylib_ai_arm_statements (код и словарь), arm-ka-docs (этот change); подъём пина в arm-core, + arm-tabular-parser, arm-scan-gateway — после AURORA-1677. diff --git a/openspec/changes/statement-checks-alternatives/specs/statement-normalization/spec.md b/openspec/changes/statement-checks-alternatives/specs/statement-normalization/spec.md new file mode 100644 index 0000000..69eb11d --- /dev/null +++ b/openspec/changes/statement-checks-alternatives/specs/statement-normalization/spec.md @@ -0,0 +1,74 @@ +## MODIFIED Requirements + +### Requirement: Шаг 7 — самопроверки §7 +Шаг 7 SHALL считаться у обоих источников одним словарём `statement_checks.yaml` и выдавать `StatementChecks +{relations_failed[], soft_relations_failed[]}`; каждое нарушение — `{column_index, relation, codes, expected, +actual}`, где `codes` — коды цели и членов соотношения. Правила: +- значение кода в колонке — сумма по всем строкам `ok` с этим кодом; строки `detail`, `unreadable`, `missing` в + соотношения не входят; нарушение относится ко всем строкам его кодов; +- соотношение **посчитано**, если непуста цель или хотя бы один член (есть строка `ok` с кодом и `amount` не `null`); + пусто всё — соотношение пропускается; пустая цель при непустых членах и непустая цель при пустых членах — нарушение; +- жёсткое соотношение не сошлось, если расхождение больше допуска ±1 в единицах формы **и** больше 0,001 % наибольшего + по модулю числа соотношения — тогда оно в `relations_failed`; расхождение в пределах округления и мягкие + соотношения — в `soft_relations_failed`; +- члены `abs_terms` (2120, 2210, 2220, 2330, 2350, 2410) сравниваются и как записаны, и по модулю; такое соотношение + подтверждает величину, но не знак (шаг 8); +- набор соотношений — по `form_variant` (полный или упрощённый); `form_variant = null` — полный. В упрощённом наборе + соотношения ББ жёсткие, а `2400 = 2110 − 2120 − 2330 + 2340 − 2350 − 2410` и `2400 = 2110 − 2120 − 2330 + 2340 − + 2350 + 2410` ОФР — мягкие, как `2400` полного набора; +- **группа альтернатив** (`group` в словаре, только у мягких соотношений одной формы и варианта): в колонке сошлась + хоть одна альтернатива — ни одна не попадает в `soft_relations_failed`; не сошлась ни одна — в + `soft_relations_failed` одно нарушение, ближайшая к цели альтернатива (меньшее расхождение; при пустой цели или пустых + членах — первая по словарю). `group` у жёсткого соотношения и разные цели в одной группе — ошибка загрузки словаря. Соотношения 2400 каждого + набора — одна группа: полный — `2400 = 2300 − 2410 + 2420` и `2400 = 2300 + 2410 + 2460`, упрощённый — два варианта + выше. Знак 2410 (расход или доход по налогу, ФСБУ 4/2023) не определяется — принимается любая альтернатива (OQ-12). + Группа не меняет жёстких проверок, подсветки, `needs_check` и подтверждения значений (шаг 8, Р-21); +- родитель пятизначной подстроки — ближайшая четырёхзначная строка выше с теми же первыми тремя цифрами, иначе код из + первых четырёх цифр; «сумма подстрок = родитель» (мягкое) — только если хотя бы одна подстрока в колонке непуста. + +`checks` SHALL быть у каждого `BALANCE` / `INCOME` со строками и отсутствовать у документа без строк. +`duplicate_line_codes` MUST NOT выдаваться. + +#### Scenario: «БАЛАНС» без кода +- **WHEN** строка «БАЛАНС» ушла в `detail` (код потерян), в колонке есть 1100 и 1200 +- **THEN** соотношение `1600 = 1100 + 1200` посчитано и нарушено (пустая цель при непустых членах), в + `relations_failed` + +#### Scenario: Лист только с активом +- **WHEN** в ББ заполнены 1100, 1200, 1600, а 1300–1700 отсутствуют +- **THEN** `1600 = 1700` нарушено (непустая цель при пустых членах), документ `needs_check` + +#### Scenario: Повтор кода в соотношении +- **WHEN** две строки 2410 с суммами 100 и 649 +- **THEN** в соотношениях код 2410 равен 749 + +#### Scenario: Упрощённый ОФР с доходом по налогу +- **WHEN** у упрощённого ОФР 2410 записан со знаком дохода, 2400 с ним сходится только по `2400 = 2110 − 2120 − 2330 + + 2340 − 2350 + 2410` +- **THEN** нарушений по 2400 в `soft_relations_failed` нет + +#### Scenario: Доход по налогу в полной форме (AURORA-1864) +- **WHEN** в колонке ОФР 2300 = 100, 2410 = 20 (без минуса и скобок), 2400 = 120 +- **THEN** `2400 = 2300 − 2410 + 2420` не сошлось, но сошлось `2400 = 2300 + 2410 + 2460` из той же группы — нарушений + по 2400 в `soft_relations_failed` нет + +#### Scenario: Расход по налогу в полной форме +- **WHEN** 2300 = 100, 2410 = −20 или (20) или 20, 2400 = 80 +- **THEN** сходится `2400 = 2300 − 2410 + 2420` — нарушений по 2400 в `soft_relations_failed` нет + +#### Scenario: Неверная чистая прибыль — одно нарушение +- **WHEN** 2300 = 100, 2410 = 20, 2400 = 150 — не сходится ни одна альтернатива группы +- **THEN** в `soft_relations_failed` одно нарушение по 2400 — `2400 = 2300 + 2410 + 2460` (`actual` 120 ближе к 150, + чем 80); документ из-за него не `needs_check` + +#### Scenario: Группа считается по колонке +- **WHEN** в первой колонке 2400 сходится с одной из альтернатив, во второй — ни с одной +- **THEN** нарушение по 2400 одно и только у второй колонки + +#### Scenario: Группа у жёсткого соотношения +- **WHEN** в `statement_checks.yaml` у соотношения со `strict: true` указан `group` +- **THEN** словарь не загружается (ошибка загрузки `statement_checks.yaml`) + +#### Scenario: Округление итогов +- **WHEN** `1600 = 1700` расходится на 9,02 при итогах ~17 млрд +- **THEN** нарушение в `soft_relations_failed`, на статус и подсветку не влияет -- 2.47.2