# Spec Delta ## MODIFIED Requirements ### Requirement: Пересчёт после правки После каждого PATCH формы ядро SHALL пересчитывать `checks`, `needs_review`, `form_variant`, родителей строк `detail` и статус **точкой входа пакета `arm_statements` для пересчёта** по сохранённым данным (`statement-normalization`; конвенция знака — по `source_text`); временного пересчёта ядра MUST NOT быть. Правила: `is_modified` или `is_confirmed` значения ⇒ `needs_review = false`; `line_code_modified` или `is_confirmed` строки ⇒ `needs_review` строки = `false`; значения строк `detail` — `needs_review = false` (Р-23), у строки, выведенной из `detail` назначением кода, `needs_review` её значений считается по общему правилу; акцепт ⇒ жёсткие нарушения не учитываются; правленые ячейки в голосование знака не входят. Результат пишется: `needs_review` строк и значений, `form_variant`, `parent_row_index` всех строк `detail` (ближайшая строка `ok` выше по `row_index`; нет такой — `null`, строка остаётся `detail`), записи `document_issue` видов `relation` / `soft` (заменяются целиком независимо от источника), статус. Относительные даты колонок (`period_kind`, `statement-normalization`) пересчитываются от даты отчёта после правки `header.report_date` и `columns[].period_date`. Отличие `statements_version` задания от версии установленной библиотеки ядра — `document_issue` `STATEMENTS_VERSION_MISMATCH` (`info`); у задания без версии (`1.x`) запись не пишется. Записи `core` `CODE_NOT_IN_DICTIONARY`, `CODE_NOT_IN_EDITION` (только четырёхзначные коды), `NAME_MISMATCH` и `STATEMENTS_VERSION_MISMATCH` пересчитываются заменой; `NAME_MISMATCH` не ставится строке с назначенным аналитиком кодом; `MAPPING_WARNING`, `RESULT_STATUS_INCONSISTENT`, `LEGACY_WARNING` сохраняются. Один PATCH — один пересчёт и одна запись аудита `RECOGNIZED_DATA_EDIT`. Акцепт SHALL сбрасываться правкой данных — суммы, кода или статуса строки, даты колонки, поля шапки; подтверждение или снятие подтверждения (`confirmed`) и подтверждение даты отчёта или даты колонки тем же значением акцепт MUST NOT сбрасывать (Р-25, S-47). #### Scenario: Подтверждение ячейки без правки - **WHEN** аналитик подтверждает ячейку с `needs_review = true` без изменения суммы - **THEN** `is_confirmed = true`, `confirmed_by/at`, `is_modified` не ставится, `needs_review = false`, аудит; акцепт проверок, если был, сохраняется #### Scenario: Снятие подтверждения - **WHEN** аналитик снимает подтверждение с ячейки (`confirmed: false`), которая не покрыта соотношением - **THEN** `is_confirmed = false`, `needs_review = true` после пересчёта, аудит #### Scenario: Родитель уходит в расшифровки - **WHEN** у строки 1150 две расшифровки (`detail`, `parent_row_index` = 1150), аналитик отмечает саму 1150 расшифровкой - **THEN** после пересчёта родитель всех трёх строк `detail` — ближайшая строка `ok` выше 1150; строк над ними нет — `null` (на экране — в начале раздела) #### Scenario: Правка исправляет нарушение - **WHEN** форма принята с `RELATION_FAILED` по `1200 = 1210 + … + 1260`, аналитик правит сумму 1230 так, что соотношение сходится - **THEN** запись `relation` по 1200 заменена (её больше нет), статус пересчитан точкой входа пакета #### Scenario: После PATCH остаётся RELATION_FAILED - **WHEN** аналитик правит сумму, но соотношение всё ещё не сходится - **THEN** запись `RELATION_FAILED` пересоздана с новыми `expected` / `actual`; `POST …/confirm` без акцепта — 409 `CHECKS_NOT_PASSED` #### Scenario: Совпадение версии установленного дистрибутива - **WHEN** форма из существующей фикстуры результата 2.0 принята с `service.statements_version`, равной версии установленной библиотеки без внутреннего `VERSION` - **THEN** поле версии проходит валидацию и `STATEMENTS_VERSION_MISMATCH` не создаётся #### Scenario: Разные версии библиотеки и сервиса - **WHEN** та же форма принята с непустой версией сервиса, отличающейся от версии установленной библиотеки - **THEN** создаётся `STATEMENTS_VERSION_MISMATCH` уровня `info` без ослабления валидации результата ### Requirement: Словари ядра и достройка шаблонных строк Копия словаря §7 ядра (`api/rules/statement_checks.yaml`) SHALL быть удалена: проверки ядро считает установленной библиотекой `arm_statements` (дистрибутив `pylib-ai-arm-statements`). `api/rules/statement_lines.yaml` SHALL оставаться только словарём имён (код → наименования по редакциям): у кода может быть несколько имён (синонимы и законные повторы кода в бланке, Р-20), загрузчик повтор кода в редакции MUST NOT запрещать; сверка наименования — с любым именем кода; шаблонная строка берёт первое имя. Порядок и состав редакций — из перечня кодов установленной библиотеки (`code_orders.editions`); код словаря имён, которого нет в перечне своей редакции, — ошибка проверки (тест согласованности с установленной библиотекой). В редакции `fsbu4` словарь имён SHALL быть дополнен вторыми именами законных повторов 1220 «НДС, начисленный по отгрузке», 1520 «Обязательство по аренде», 2410 «Налог при упрощенной системе налогообложения» (Р-20) и кодами печатной формы 1С 1105 «Гудвил», 1130 «Нематериальные поисковые активы», 1140 «Материальные поисковые активы», 1530 «Доходы будущих периодов», 2460 «Прочее» (имена — по `fixtures/ocr` и шаблонам банка); без этого законные повторы РБ, Счастливочной и aep_6 и любой неуверенный 1105 дают `NAME_MISMATCH`. Шаблонные строки достраиваются по словарю имён (одна на код, первое имя); код, у которого есть хотя бы одна строка `ok` из файла, шаблоном MUST NOT достраиваться; строки `unreadable` / `missing` не заменяются шаблонной строкой молча. #### Scenario: Код словаря вне перечня - **WHEN** в `statement_lines.yaml` у редакции есть код, которого нет в перечне этой редакции установленной библиотеки - **THEN** проверка согласованности словаря с перечнем падает #### Scenario: Код есть только у строки unreadable - **WHEN** у формы нет строки `ok` с кодом 1250, но есть строка `unreadable` «ИЧ,250» - **THEN** шаблонная строка 1250 достраивается пустой, строка `unreadable` показывается отдельно со статусом #### Scenario: Два имени у кода - **WHEN** в редакции `fsbu4` словаря имён код 1520 записан дважды — «Кредиторская задолженность» и «Обязательство по аренде» - **THEN** словарь загружается; шаблонная строка 1520 одна, с именем «Кредиторская задолженность» #### Scenario: Гудвил с заголовком раздела в имени - **WHEN** строка 1105 (уверенность 67) с наименованием «АКТИВ I. Внеоборотные активы Гудвил» - **THEN** справочное «Гудвил» (≥ 5 символов) входит в него — совпало, `NAME_MISMATCH` нет