feat(statements): единая нормализация ББ/ОФР, часть Б — ядро (#131) #132

Merged
aep merged 13 commits from feat/131-normalization-core-b into main 2026-10-18 21:50:23 +03:00
Owner

Closes часть Б плана 3 «единая нормализация ББ/ОФР» (arm-ka-docs#116). Issue: RSHB/arm-core#131. Часть А уже в main.

Что сделано

  • B0: дельты OpenSpec unified-normalization-core-b.
  • B1: адаптер arm_statements за протоколом StatementsEngine, вход пересчёта из БД.
  • B2: пересчёт после правки точкой входа пакета, §7 только из document_issue.
  • B3: §7 и вариант формы при приёме 1.x копией пакета.
  • B4: маппер результата 2.0 для форм.
  • B5: ОСВ по контракту 2.0 (Р-28), выбор маппера по MAJOR, нечитаемый JSON результата — MappingFatal (T5.2 части А).
  • B6: удалена копия словаря §7 ядра (statement_checks.yaml, run_checks, load_check_rules).
  • Копия arm_statements обновлена до 3390f92 (Р-44, NUMBERS_OUTSIDE_TABLE).

На контур — одним снимком с фронтом (план 6) после очистки форм purge_statements.py. Формы, принятые кодом части А, до первой правки теряют проверку CHECKS_NOT_PASSED (M-5).

make check-full (зелёный, exit 0)

  • make check: 1820 passed (ruff, mypy чистые)
  • statements-check: копия синхронна с arm-statements@origin/main (3390f92)
  • dbml-check против data-model-v5.19.dbml: ок
  • check-infra: ок
  • test-integration: 1113 passed (7:34)
  • e2e: 1 passed
  • docker-build: ок
  • web-check: biome, tsc, сборка — ок

Ревью

Пары B1+B2 (sonnet), B3+B4 (sonnet), B5+B6 (sonnet), финальное ревью всей ветки (opus), scoped re-review после каждой fix-волны (sonnet). B0 отдельно не ревьюировался (R-4), проверен финальным ревью; дельта проверена openspec archive А затем Б на копии каталога.

Findings

Маркер Суть Статус
T13.3 (часть А) settle_edited_values затирал needs_review у detail fixed 065153e
T13.4 (часть А) P3-8 пересчёт core info после смены кода fixed 065153e
T5.2 (часть А) ValueError от parse_result на битом JSON fixed 2b8fafc
M-6 (часть А) code_amount отдельным SUM deferred
T8.3, T8.4, T8.5 (часть А) мелкие рефакторинги deferred
T2.1 аудит теряет смену parent_row_index fixed 0285126
T2.2 окно между B2 и B3 rejected — R-6
T2.3 P3-30: пустая цель при непустых членах = нарушение deferred (вопрос владельцу, O-2)
T1.1 паритет редакции fixed 0285126
T1.2 str(None) в stored_form fixed 0285126
T2.4 column_index из issue vs column_id fixed 0285126
T2.5 edition ответа по дате vs пакета rejected — соответствует спеке docs
T2.6 мёртвое дублирование needs_review fixed 0285126
T2.7 _line игнорирует status в тесте deferred
T2.8 PeriodKind(...) ValueError -> 500 (+ _stored_column) fixed 0285126
T2.9 трейлер Sonnet 5.5 вместо Opus 5.5 в коммите B2 rejected — историю не переписываем
T3.1 лишний load_form колонок в form_blocker deferred (minor)
T4.1 DISCLOSURE 2.0 всегда RECOGNIZED (= P3-41) deferred (вопрос владельцу)
T4.2 utc_now() вмест�� now в checks_on_intake_1x fixed e6292a2
T4.3 дубль row_index/ref отбрасывается с MAPPING_WARNING fixed e6292a2 (P3-43, тесты)
T4.4 непокрытые ветки приёма 2.0 fixed e6292a2
T4.5 запросы на форму в insert_forms_v2 rejected — 2–3 формы на файл
T4.6 column_id и column_index вместе в relation/soft rejected — совпадает с B2
T6.1 нет теста: OSV-лист severity=error не блокирует fixed e6292a2
T6.2 RecursionError на глубоком JSON уходит в повторяемую ветку deferred (minor)
T6.3 CLAUDE.md: нет описания приёма 2.0 fixed e6292a2
C-1 дельта B0 не архивируется, теряет требования А fixed e944565
I-1 спека statement-checks vs P3-30 fixed e944565, e6292a2
I-2 is_recognized NULL -> False fixed e6292a2
I-3 разные источники ошибки файла fixed e6292a2 (R-11, P3-53)
I-4 нет тестов правки/акцепта формы 2.0 fixed e6292a2
I-5 nullable expected/actual; индекс колонки -1 vs null fixed e944565 (спека); выравнивание -1/null — deferred (P3-60, план 6)
M-1, M-2, M-5, M-6, M-7 (финальное) дубли ADDED, tasks.md, README, CLAUDE.md, формулировка P3-39 fixed e944565, e6292a2, 0f84088
M-3 (финальное) parent_row_index перезаписывается без аудита при правке шапки deferred
M-4 (финальное) row_by_ref по пропущенным дублям fixed e6292a2
N-1 statement_recompute импортирует из statement_intake_v2 deferred (minor)
O-1 коммит B2 подписан Sonnet 5.5, не Opus 5.5 rejected — история
O-3 в B5 два блока тестов дописаны cat >> вместо Edit/Write rejected — в коммите корректны

Rulings I made

  • R-1: Р-40 приоритетнее P3-7: CODE_NOT_IN_DICTIONARY / CODE_NOT_IN_EDITION только для кодов ровно из четырёх цифр.
  • R-2: Р-34 уже внесено в планы (P3-16), отдельных действий нет.
  • R-3: вместо REMOVED «копия словаря §7 ядра» в дельте — MODIFIED (REMOVED несуществующего требования упал бы при archive). Уточнено P3-61: MODIFIED несёт полный текст требований А.
  • R-4: отдельное ревью B0 не проводится, проверяется финальным.
  • R-5: ревью пар задач (B1+B2, B3+B4, B5+B6) вместо поодиночке.
  • R-6: окно «§7 не считается на лету, приём не пишет записи» между B2 и B3 допустимо (B2..B6 в одном PR).
  • R-7: P3-30 следует пакету (P1-21) и спеке; открыт вопросом владельцу.
  • R-8: fix-волна B1/B2 одним исполнителем после B3, до B4.
  • R-9: блокировка require-plan на B4: правки откачены, копия плана положена в docs/superpowers/plans/ (ff11542) по решению владельца; код правится только Edit/Write.
  • R-10: T4.2/T4.4 правятся в общей fix-волне после B6.
  • R-11: единый источник предупреждений файла: при приёме 2.0 они сохраняются в recognition_job.metrics.file_warnings, recompute_form читает его (фолбэк — metrics.warnings конверта).

Решения без обсуждения P3-25…P3-61 — в openspec/changes/unified-normalization-core-b/design.md.

Открытые вопросы владель��у

  • O-2 / P3-30: пустая цель при непустых членах — нарушение с expected = NULL, форма без итоговой строки блокирует confirm до правки/акцепта.
  • FailedCheckOut.expected / actual теперь nullable (P3-60); индекс колонки: -1 в GET и null в 409 — выровнять в плане 6.
  • P3-34: NAME_MISMATCH не ограничен четырёхзначными кодами.
  • P3-36: 1.x с пустой целью даёт NEEDS_CHECK строже прежнего.
  • P3-41 / T4.1: DISCLOSURE 2.0 — один документ RECOGNIZED, статус сервиса и ошибки файла игнорируются; спека молчит.
  • P3-52: edition_for (по дате, для экрана) и engine.edition могут расходиться на формах без даты.
  • Наблюдение процесса (в нумерации ledger O-2 занято вопросом выше, здесь — O-4): исполнители части А и B1–B3, по-видимому, правили src через Bash, который хук require-plan не проверяет; хук сработал только на Write нового файла в B4.

Что ждёт человека

Ревью и merge; решения по вопросам выше; выкладка на контур — одним снимком с фронтом (план 6) после purge_statements.py; типы фронта (src/types/api.ts: expected/actual — nullable) — в плане 6.

🤖 Generated with Claude Code

Closes часть Б плана 3 «единая нормализация ББ/ОФР» (arm-ka-docs#116). Issue: RSHB/arm-core#131. Часть А уже в main. ## Что сделано - B0: дельты OpenSpec `unified-normalization-core-b`. - B1: адаптер `arm_statements` за протоколом `StatementsEngine`, вход пересчёта из БД. - B2: пересчёт после правки точкой входа пакета, §7 только из `document_issue`. - B3: §7 и вариант формы при приёме 1.x копией пакета. - B4: маппер результата 2.0 для форм. - B5: ОСВ по контракту 2.0 (Р-28), выбор маппера по MAJOR, нечитаемый JSON результата — `MappingFatal` (T5.2 части А). - B6: удалена копия словаря §7 ядра (`statement_checks.yaml`, `run_checks`, `load_check_rules`). - Копия `arm_statements` обновлена до 3390f92 (Р-44, `NUMBERS_OUTSIDE_TABLE`). **На контур — одним снимком с фронтом (план 6) после очистки форм `purge_statements.py`.** Формы, принятые кодом части А, до первой правки теряют проверку `CHECKS_NOT_PASSED` (M-5). ## make check-full (зелёный, exit 0) - `make check`: 1820 passed (ruff, mypy чистые) - `statements-check`: копия синхронна с arm-statements@origin/main (3390f92) - `dbml-check` против data-model-v5.19.dbml: ок - `check-infra`: ок - `test-integration`: 1113 passed (7:34) - `e2e`: 1 passed - `docker-build`: ок - `web-check`: biome, tsc, сборка — ок ## Ревью Пары B1+B2 (sonnet), B3+B4 (sonnet), B5+B6 (sonnet), финальное ревью всей ветки (opus), scoped re-review после каждой fix-волны (sonnet). B0 отдельно не ревьюировался (R-4), проверен финальным ревью; дельта проверена `openspec archive` А затем Б на копии каталога. ## Findings | Маркер | Суть | Статус | |---|---|---| | T13.3 (часть А) | `settle_edited_values` затирал `needs_review` у detail | fixed 065153e | | T13.4 (часть А) | P3-8 пересчёт core info после смены кода | fixed 065153e | | T5.2 (часть А) | `ValueError` от `parse_result` на битом JSON | fixed 2b8fafc | | M-6 (часть А) | `code_amount` отдельным SUM | deferred | | T8.3, T8.4, T8.5 (часть А) | мелкие рефакторинги | deferred | | T2.1 | аудит теряет смену `parent_row_index` | fixed 0285126 | | T2.2 | окно между B2 и B3 | rejected — R-6 | | T2.3 | P3-30: пустая цель при непустых членах = нарушение | deferred (вопрос владельцу, O-2) | | T1.1 | паритет редакции | fixed 0285126 | | T1.2 | `str(None)` в `stored_form` | fixed 0285126 | | T2.4 | `column_index` из issue vs `column_id` | fixed 0285126 | | T2.5 | edition ответа по дате vs пакета | rejected — соответствует спеке docs | | T2.6 | мёртвое дублирование `needs_review` | fixed 0285126 | | T2.7 | `_line` игнорирует status в тесте | deferred | | T2.8 | `PeriodKind(...)` ValueError -> 500 (+ `_stored_column`) | fixed 0285126 | | T2.9 | трейлер Sonnet 5.5 вместо Opus 5.5 в коммите B2 | rejected — историю не переписываем | | T3.1 | лишний `load_form` колонок в `form_blocker` | deferred (minor) | | T4.1 | DISCLOSURE 2.0 всегда RECOGNIZED (= P3-41) | deferred (вопрос владельцу) | | T4.2 | `utc_now()` вмест�� `now` в `checks_on_intake_1x` | fixed e6292a2 | | T4.3 | дубль `row_index`/`ref` отбрасывается с `MAPPING_WARNING` | fixed e6292a2 (P3-43, тесты) | | T4.4 | непокрытые ветки приёма 2.0 | fixed e6292a2 | | T4.5 | запросы на форму в `insert_forms_v2` | rejected — 2–3 формы на файл | | T4.6 | `column_id` и `column_index` вместе в relation/soft | rejected — совпадает с B2 | | T6.1 | нет теста: OSV-лист severity=error не блокирует | fixed e6292a2 | | T6.2 | `RecursionError` на глубоком JSON уходит в повторяемую ветку | deferred (minor) | | T6.3 | CLAUDE.md: нет описания приёма 2.0 | fixed e6292a2 | | C-1 | дельта B0 не архивируется, теряет требования А | fixed e944565 | | I-1 | спека statement-checks vs P3-30 | fixed e944565, e6292a2 | | I-2 | `is_recognized` NULL -> False | fixed e6292a2 | | I-3 | разные источники ошибки файла | fixed e6292a2 (R-11, P3-53) | | I-4 | нет тестов правки/акцепта формы 2.0 | fixed e6292a2 | | I-5 | nullable `expected`/`actual`; индекс колонки -1 vs null | fixed e944565 (спека); выравнивание -1/null — deferred (P3-60, план 6) | | M-1, M-2, M-5, M-6, M-7 (финальное) | дубли ADDED, tasks.md, README, CLAUDE.md, формулировка P3-39 | fixed e944565, e6292a2, 0f84088 | | M-3 (финальное) | `parent_row_index` перезаписывается без аудита при правке шапки | deferred | | M-4 (финальное) | `row_by_ref` по пропущенным дублям | fixed e6292a2 | | N-1 | `statement_recompute` импортирует из `statement_intake_v2` | deferred (minor) | | O-1 | коммит B2 подписан Sonnet 5.5, не Opus 5.5 | rejected — история | | O-3 | в B5 два блока тестов дописаны `cat >>` вместо Edit/Write | rejected — в коммите корректны | ## Rulings I made - R-1: Р-40 приоритетнее P3-7: `CODE_NOT_IN_DICTIONARY` / `CODE_NOT_IN_EDITION` только для кодов ровно из четырёх цифр. - R-2: Р-34 уже внесено в планы (P3-16), отдельных действий нет. - R-3: вместо REMOVED «копия словаря §7 ядра» в дельте — MODIFIED (REMOVED несуществующего требования упал бы при archive). Уточнено P3-61: MODIFIED несёт полный текст требований А. - R-4: отдельное ревью B0 не проводится, проверяется финальным. - R-5: ревью пар задач (B1+B2, B3+B4, B5+B6) вместо поодиночке. - R-6: окно «§7 не считается на лету, приём не пишет записи» между B2 и B3 допустимо (B2..B6 в одном PR). - R-7: P3-30 следует пакету (P1-21) и спеке; открыт вопросом владельцу. - R-8: fix-волна B1/B2 одним исполнителем после B3, до B4. - R-9: блокировка require-plan на B4: правки откачены, копия плана положена в `docs/superpowers/plans/` (ff11542) по решению владельца; код правится только Edit/Write. - R-10: T4.2/T4.4 правятся в общей fix-волне после B6. - R-11: единый источник предупреждений файла: при приёме 2.0 они сохраняются в `recognition_job.metrics.file_warnings`, `recompute_form` читает его (фолбэк — `metrics.warnings` конверта). Решения без обсуждения P3-25…P3-61 — в `openspec/changes/unified-normalization-core-b/design.md`. ## Открытые вопросы владель��у - O-2 / P3-30: пустая цель при непустых членах — нарушение с `expected = NULL`, форма без итоговой строки блокирует confirm до правки/акцепта. - `FailedCheckOut.expected` / `actual` теперь nullable (P3-60); индекс колонки: `-1` в GET и `null` в 409 — выровнять в плане 6. - P3-34: `NAME_MISMATCH` не ограничен четырёхзначными кодами. - P3-36: 1.x с пустой целью даёт NEEDS_CHECK строже прежнего. - P3-41 / T4.1: DISCLOSURE 2.0 — один документ RECOGNIZED, статус сервиса и ошибки файла игнорируются; спека молчит. - P3-52: `edition_for` (по дате, для экрана) и `engine.edition` могут расходиться на формах без даты. - Наблюдение процесса (в нумерации ledger O-2 занято вопросом выше, здесь — O-4): исполнители части А и B1–B3, по-видимому, правили `src` через Bash, который хук `require-plan` не проверяет; хук сработал только на Write нового файла в B4. ## Что ждёт человека Ревью и merge; решения по вопросам выше; выкладка на контур — одним снимком с фронтом (план 6) после `purge_statements.py`; типы фронта (`src/types/api.ts`: `expected`/`actual` — nullable) — в плане 6. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 13 commits 2026-10-18 21:49:50 +03:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
recompute_form (services/statement_recompute.py) собирает вход из БД, зовёт engine.recompute и пишет needs_review
строк и значений, form_variant, parent_row_index расшифровок, записи relation/soft и core по P3-8, статус через
form_status_v2. GET/confirm/accept читают нарушения §7 из document_issue. Правка header.report_date пересчитывает
relative:* колонки. Временный код A12/A13 удалён.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
checks_on_intake_1x: один recompute по вставленной форме, запись form_variant и
relation/soft (core); run_checks из приёма убран. P3-36.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
T2.1: аудит lines[] включает итоговую смену parent_row_index после пересчёта.
T1.1: тест паритета редакции приёма и пересчёта для строки с confidence < 100 и code_fixed.
T1.2: edition_codes пропускает строку ok без кода.
T2.4: общий issue_column_index для ответа формы и detail отказа подтверждения.
T2.6: удалено дублирование needs_review в statement_line_edits.
T2.8: неизвестный relative:* не даёт 500 (адаптер stored_form и _resolve_relative_columns).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Приём файла результата выбирает модель по MAJOR (parse_result); нечитаемый JSON и неизвестный
MAJOR — неповторяемая ошибка схемы (T5.2). Статус ОСВ 2.0 — osv_status_v2, предупреждения листа
(OSV_*) — в document_issue. Решения P3-46…P3-49.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Удалены api/rules/statement_checks.yaml, load_check_rules, run_checks и правила соотношений; в
domain/statement_checks.py остались межформенная проверка 1370/2400 и subline_parents. Тест
test_name_dictionary_codes_in_code_orders сверяет справочник имён с перечнями редакций пакета.
CLAUDE.md и README.md: §7 — копия arm_statements, нарушения хранятся в document_issue. Решения P3-50…P3-52.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
I-2: NULL у is_recognized не сомнение (P3-54); I-3: metrics.file_warnings при приёме 2.0 — единый
источник для пересчёта (P3-53, R-11); I-4/T4.4/T6.1: тесты правки, акцепта и веток приёма 2.0;
T4.2: now в checks_on_intake_1x; M-4: row_by_ref по принятым строкам; документация (M-5, M-6, M-7).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit 35a24e7af3 into main 2026-10-18 21:50:23 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/arm-core#132
No description provided.