ОСВ: строки ИНН рядом с контрагентом — восемь раскладок (#35, #34) #39

Merged
aep merged 12 commits from feat/35-inn-rows-around-counterparty into main 2026-10-13 16:24:46 +03:00
Owner

Closes #35, closes #34.

ОСВ, где ИНН контрагента выведен отдельной строкой рядом с наименованием, теперь разбирается во всех восьми раскладках: (ИНН над / под наименованием) × (в дереве / не в дереве) × (с суммами / без сумм).

Спека: openspec/changes/osv-inn-rows-layouts/. План: docs/superpowers/plans/2026-10-13-osv-inn-rows-layouts.md.

Мерджить вместе с PR в arm-ka-docs и arm-ka-fixtures (ветка feat/35-inn-rows-around-counterparty).

Что изменилось

  • Новый модуль api/src/parser/inn_rows.py работает между resolve_levels и classify_rows. Он находит строки ИНН, сопоставляет каждую со своим контрагентом, убирает склеенную строку из дерева и передаёт классификатору ИНН контрагентов.
  • Без подсказки <группировка>.ИНН в шапке строка ИНН принимается, только если контрольная сумма верна. С подсказкой проверки нет, а порядок элементов шапки задаёт направление (оба порядка распознаются).
  • Строка из 10 или 12 цифр с неверной контрольной суммой остаётся как есть. Документ получает предупреждение «похожа на ИНН…» и статус needs_check (s28).
  • Если раскладка противоречит подсказке шапки, строки склеиваются, документ получает предупреждение «стоит под/над…, а шапка указывает…» и статус needs_check (H-2).
  • Строка ИНН без пары становится OTHER и получает needs_check.
  • #34: число из 9 или 11 цифр в строке ИНН дополняется ведущим нулём.
  • Удалены _glue_inn_rows (OQ-130), glue_inn_attributes и InnAttribute (#32).
  • Синтетика s20…s28; s18 теперь с верными ИНН.

Проверка

  • Ветка ребейзнута на origin/main (d0d3c79). make check-full: 2433 unit-теста и 10 интеграционных прошли, ruff и mypy чистые.
  • Сравнение main и ветки на 160 файлах fixtures. На реальных файлах отличий нет, Новопетровская не изменилась. Отличаются только s18 и s20…s28; переходы needs_check → done есть в s21, s22, s24 и s26, обратных нет. Golden: изменились ровно эти 10 снимков, владелец одобрил.

Решения владельца (13.10.2026)

  • H-1 — синтетика s28 «неверная контрольная сумма»: строка остаётся, ИНН у контрагента нет, предупреждение и needs_check. fixed 17986e5 (fixtures 7c69f2e, golden d8241c0).
  • H-2 — противоречие раскладки и подсказки шапки: строки склеиваются, предупреждение и needs_check. fixed 17986e5.

Rulings I made

Номер в скобках — номер решения в design.md, раздел ## Decisions made without discussion. Для каждого указана цена ошибки.

  1. R-1 (design #14) — реквизит «нерез.» при подсказке «под» берётся только у ребёнка-листа. Цена ошибки: наименование со своей строкой ИНН ошибочно помечалось «ИНН не распознан». Позже уточнено в R-6.
  2. R-2 (design #15) — строка ИНН без детей под подразделением не склеивается с подразделением, а идёт в соседи. Цена ошибки: ИНН молча уходит подразделению.
  3. R-3 (design #16) — защита «нет лишнего уровня» не действует при подсказке в шапке. Цена ошибки: ИНН над наименованием остаётся неприсвоенным без предупреждения.
  4. R-4 (design #17) — направление листа без подсказки определяется по суммам и блокам вместе; если они противоречат, направление «неизвестно». Цена ошибки: лишний needs_check вместо склейки.
  5. R-5 (design #18) — тесты s18 остаются красными до Task 5, golden правится только в Task 6. Цены ошибки нет: состояние промежуточное.
  6. R-6 (design #22) — реквизит «нерез.» определяется по позиции COUNTERPARTY в схеме, условие «лист» снято. Цена ошибки: контрагент с единственным договором с теми же суммами и без строки реквизита получает needs_check.
  7. R-7 (design #23) — при подсказке «над» строка ИНН с детьми под контрагентом склеивается с родителем и подсвечивается. Цена ошибки: прежнее молчаливое присвоение ИНН договору.
  8. R-8 (design #24) — страховка в osv.py: если ИНН отнесён строке, которая не стала контрагентом, появляются предупреждение и needs_check. Цена ошибки: возможны ложные needs_check; на реальных файлах отличий нет.
  9. R-9 (design #25) — _without берёт родителя по levels.parent. Цена ошибки: при пропусках уровней outline возможна неверная иерархия.
  10. R-10 (design #26) — порядок _drop_conflicts после _check_sums оставлен, спека поправлена. Цена ошибки: строка ИНН, отвергнутая по суммам, не участвует в конфликте.
  11. H.1 финального ревью (design #27) — пустой кандидат не проверяется на противоречие подсказке, потому что этот случай недостижим (rejected).
  12. Решения исполнителей (design #11–#13, #19–#21): __all__ в numbers; проверка isascii() and isdigit(); переименование локальной переменной в classify.py; направление по номерам строк; s28 остаётся COUNTERPARTY без ИНН; состав golden в CLAUDE.md.

Находки ревью

  • Задачи плана: T1.1–T1.4, T2.1–T2.3, T2.5–T2.7, T2.9–T2.12, T3.1–T3.4, T5.1, T5.2 — fixed. T2.8 rejected (не дефект). T4.3 rejected (эквивалентно брифу, покрытие шире).
  • Финальное ревью (opus): I-1 (регрессия #32: _unrecognised_attributes срабатывал на любое наименование), I-2, I-3, M-1, M-3…M-8 — fixed 6110248, docs fafd96f, fixtures a18a4cf. Пере-ревью fix-волны: всё ADDRESSED.

Deferred

Попадут в follow-up issue при закрытии.

  • T2.4 — побочные эффекты _kind и _unrecognised_attributes.
  • T3.5, T3.6 — докстринги _block_direction.
  • T4.1 — нормализация имени владельца подсказки (пробелы, NBSP).
  • T4.2 — дубль реквизита «Контрагенты.ИНН» в шапке.
  • T4.4 — комментарий в classify.py о порядке веток.
  • M-2 — договор с названием-ИНН при схеме «Контрагенты, Договоры» не защищён.
  • M-9 (остаток) — стратегии indent и sums со строками ИНН не проверены.
  • N.1 — позиция реквизита берётся из _depths до склейки: возможна ошибка на схеме с двумя смежными COUNTERPARTY.
  • N.2 — единственный договор с детьми и теми же суммами без строки реквизита получает «ИНН не распознан».
  • O-1 — флейк интеграционного test_roundtrip (уже в #36).

После merge

Пересобрать контейнер парсера на стенде. Ядро не меняется, контракт тот же.

🤖 Generated with Claude Code

Closes #35, closes #34. ОСВ, где ИНН контрагента выведен отдельной строкой рядом с наименованием, теперь разбирается во всех восьми раскладках: (ИНН над / под наименованием) × (в дереве / не в дереве) × (с суммами / без сумм). Спека: `openspec/changes/osv-inn-rows-layouts/`. План: `docs/superpowers/plans/2026-10-13-osv-inn-rows-layouts.md`. Мерджить вместе с PR в arm-ka-docs и arm-ka-fixtures (ветка `feat/35-inn-rows-around-counterparty`). ## Что изменилось - Новый модуль `api/src/parser/inn_rows.py` работает между `resolve_levels` и `classify_rows`. Он находит строки ИНН, сопоставляет каждую со своим контрагентом, убирает склеенную строку из дерева и передаёт классификатору ИНН контрагентов. - Без подсказки `<группировка>.ИНН` в шапке строка ИНН принимается, только если контрольная сумма верна. С подсказкой проверки нет, а порядок элементов шапки задаёт направление (оба порядка распознаются). - Строка из 10 или 12 цифр с неверной контрольной суммой остаётся как есть. Документ получает предупреждение «похожа на ИНН…» и статус `needs_check` (s28). - Если раскладка противоречит подсказке шапки, строки склеиваются, документ получает предупреждение «стоит под/над…, а шапка указывает…» и статус `needs_check` (H-2). - Строка ИНН без пары становится OTHER и получает `needs_check`. - #34: число из 9 или 11 цифр в строке ИНН дополняется ведущим нулём. - Удалены `_glue_inn_rows` (OQ-130), `glue_inn_attributes` и `InnAttribute` (#32). - Синтетика s20…s28; s18 теперь с верными ИНН. ## Проверка - Ветка ребейзнута на `origin/main` (d0d3c79). `make check-full`: 2433 unit-теста и 10 интеграционных прошли, ruff и mypy чистые. - Сравнение main и ветки на 160 файлах fixtures. На реальных файлах отличий нет, Новопетровская не изменилась. Отличаются только s18 и s20…s28; переходы `needs_check → done` есть в s21, s22, s24 и s26, обратных нет. Golden: изменились ровно эти 10 снимков, владелец одобрил. ## Решения владельца (13.10.2026) - **H-1** — синтетика s28 «неверная контрольная сумма»: строка остаётся, ИНН у контрагента нет, предупреждение и `needs_check`. fixed `17986e5` (fixtures `7c69f2e`, golden `d8241c0`). - **H-2** — противоречие раскладки и подсказки шапки: строки склеиваются, предупреждение и `needs_check`. fixed `17986e5`. ## Rulings I made Номер в скобках — номер решения в `design.md`, раздел `## Decisions made without discussion`. Для каждого указана цена ошибки. 1. **R-1 (design #14)** — реквизит «нерез.» при подсказке «под» берётся только у ребёнка-листа. Цена ошибки: наименование со своей строкой ИНН ошибочно помечалось «ИНН не распознан». Позже уточнено в R-6. 2. **R-2 (design #15)** — строка ИНН без детей под подразделением не склеивается с подразделением, а идёт в соседи. Цена ошибки: ИНН молча уходит подразделению. 3. **R-3 (design #16)** — защита «нет лишнего уровня» не действует при подсказке в шапке. Цена ошибки: ИНН над наименованием остаётся неприсвоенным без предупреждения. 4. **R-4 (design #17)** — направление листа без подсказки определяется по суммам и блокам вместе; если они противоречат, направление «неизвестно». Цена ошибки: лишний `needs_check` вместо склейки. 5. **R-5 (design #18)** — тесты s18 остаются красными до Task 5, golden правится только в Task 6. Цены ошибки нет: состояние промежуточное. 6. **R-6 (design #22)** — реквизит «нерез.» определяется по позиции COUNTERPARTY в схеме, условие «лист» снято. Цена ошибки: контрагент с единственным договором с теми же суммами и без строки реквизита получает `needs_check`. 7. **R-7 (design #23)** — при подсказке «над» строка ИНН с детьми под контрагентом склеивается с родителем и подсвечивается. Цена ошибки: прежнее молчаливое присвоение ИНН договору. 8. **R-8 (design #24)** — страховка в `osv.py`: если ИНН отнесён строке, которая не стала контрагентом, появляются предупреждение и `needs_check`. Цена ошибки: возможны ложные `needs_check`; на реальных файлах отличий нет. 9. **R-9 (design #25)** — `_without` берёт родителя по `levels.parent`. Цена ошибки: при пропусках уровней outline возможна неверная иерархия. 10. **R-10 (design #26)** — порядок `_drop_conflicts` после `_check_sums` оставлен, спека поправлена. Цена ошибки: строка ИНН, отвергнутая по суммам, не участвует в конфликте. 11. **H.1 финального ревью (design #27)** — пустой кандидат не проверяется на противоречие подсказке, потому что этот случай недостижим (rejected). 12. Решения исполнителей (design #11–#13, #19–#21): `__all__` в numbers; проверка `isascii() and isdigit()`; переименование локальной переменной в `classify.py`; направление по номерам строк; s28 остаётся COUNTERPARTY без ИНН; состав golden в CLAUDE.md. ## Находки ревью - Задачи плана: T1.1–T1.4, T2.1–T2.3, T2.5–T2.7, T2.9–T2.12, T3.1–T3.4, T5.1, T5.2 — fixed. T2.8 rejected (не дефект). T4.3 rejected (эквивалентно брифу, покрытие шире). - Финальное ревью (opus): I-1 (регрессия #32: `_unrecognised_attributes` срабатывал на любое наименование), I-2, I-3, M-1, M-3…M-8 — fixed `6110248`, docs `fafd96f`, fixtures `a18a4cf`. Пере-ревью fix-волны: всё ADDRESSED. ## Deferred Попадут в follow-up issue при закрытии. - **T2.4** — побочные эффекты `_kind` и `_unrecognised_attributes`. - **T3.5, T3.6** — докстринги `_block_direction`. - **T4.1** — нормализация имени владельца подсказки (пробелы, NBSP). - **T4.2** — дубль реквизита «Контрагенты.ИНН» в шапке. - **T4.4** — комментарий в `classify.py` о порядке веток. - **M-2** — договор с названием-ИНН при схеме «Контрагенты, Договоры» не защищён. - **M-9 (остаток)** — стратегии `indent` и `sums` со строками ИНН не проверены. - **N.1** — позиция реквизита берётся из `_depths` до склейки: возможна ошибка на схеме с двумя смежными COUNTERPARTY. - **N.2** — единственный договор с детьми и теми же суммами без строки реквизита получает «ИНН не распознан». - **O-1** — флейк интеграционного `test_roundtrip` (уже в #36). ## После merge Пересобрать контейнер парсера на стенде. Ядро не меняется, контракт тот же. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 12 commits 2026-10-13 15:30:51 +03:00
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>
Модуль inn_rows: строка с одним ИНН сопоставляется с наименованием в дереве (родитель или ребёнок), без пары
остаётся с причиной; подсказка шапки InnHint отменяет контрольную сумму. row_data_type стал публичным.
ASCII-проверка ИНН (ревью T1.2), комментарий про zip(strict=False) (T1.3), тест «770123456²» (T1.1).
Решения 12–13 в design.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Строки ИНН не в дереве: с суммами — сосед с теми же суммами (совпали оба — по направлению);
без сумм — сосед по направлению листа: подсказка шапки, иначе единогласные сведения пар по
суммам и однозначных блоков детей. Противоречие или отсутствие сведений — строка без пары.

Хвосты ревью Task 2: тест подразделения переписан на итоговый результат (T2.9); в спеке
уточнены реквизит «нерез.» (только лист, design #14) и защита «над, в дереве» с подсказкой
шапки (design #16) (T2.10); опечатка в докстринге _parent_can_own (T2.11).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Хвосты ревью Task 3: формулировка направления листа в spec/design (T3.1), тесты противоречия сведений и приоритета подсказки (T3.2), assert на glue.ok (T3.4).

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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
R-6 (design #22), R-7 (#23), R-8 (#24), R-9 (#25), R-10 (#26), H.1/H.2 (#27); словарь позиций соседей (T2.6/T3.3);
spec/design/README: текст предупреждения, цена ошибки design #1, ссылки на решение владельца 10 (M-3, M-4, M-5, M-8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Парные PR: RSHB/arm-ka-docs#102, RSHB/arm-ka-fixtures#19. Мерджить вместе.

Парные PR: RSHB/arm-ka-docs#102, RSHB/arm-ka-fixtures#19. Мерджить вместе.
aep merged commit 32090f41d5 into main 2026-10-13 16:24:46 +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-tabular-parser#39
No description provided.