17 KiB
17 KiB
Design: unified-normalization-tp
Контекст
Change переносит в tabular-parser требования общей нормализации ББ/ОФР: шаг 1 (кандидат в форму из книги Excel)
пишет адаптер сервиса, шаги 2–8 выполняет копия пакета arm_statements, результат и конверт — контракт v2.0.
Дизайн и решения Р-1…Р-24 — change unified-statement-normalization в arm-ka-docs (issue RSHB/arm-ka-docs#116);
реализация — план 4 (plans/2026-10-18-plan-4-tabular-parser.md в docs), issue RSHB/arm-tabular-parser#54, ветка
feat/54-statements-v2.
Номера P4-n — решения автора плана, R-n — рулинги контроллера при исполнении (нумерация сквозная, R-3 не присваивался). Дата всех решений ниже — 18.10.2026.
Decisions made without discussion
Решения автора плана (P4-n)
- P4-1. Переход на общий код и на контракт v2.0 — одна задача (7): модели, копия схем, сборка книги, путь ОСВ и
воркер меняются вместе; «контракт v2.0 в копии» отдельной последней задачей не вынесен — модели 2.0 без копии 2.0 (или
наоборот) валят
result_contractи тест идентичности. Golden и манифест — сразу за переключением (задача 8), до удаления старого кода; между задачами 7 и 8 проверка идёт сARM_KA_FIXTURES=/nonexistent. Цена: одна крупная задача и окно в одну задачу без проверки на реальных файлах. - P4-2. Адаптер пишется новыми модулями рядом со старыми (
cells,forms,header_cells,adapter,contract,pipeline); старыеstatements/*не правятся и удаляются целиком задачей 9. Цена: временное дублирование логики поиска блоков и шапки. - P4-3.
Cell.textчисла Excel — как в русской локали: группы по три через пробел, если в формате есть разделитель групп; десятичная запятая; литералы секции (скобки) сохраняются; «-» добавляется только у односекционного формата;General/неразобранный формат/xlsb — число без групп и экспоненты, целое без дробной части; дата —dd.mm.yyyy; логическое — «ИСТИНА»/«ЛОЖЬ». Цена: у экзотических форматов текст может отличаться от экрана Excel;valueи статус от этого не зависят (у Excel значение берётся изvalue). Совпадает с примером docsresult-statement-excel.json("586 260,26"). - P4-4. Показываемое число вне
numeric(18,2)больше не делает формат «неразобранным»: адаптер отдаётDecimal, аVALUE_OUT_OF_RANGEиamount = nullвыдаёт пакет (спека «Шаг 4»). Цена: правка поведения #42 для чисел больше 16 целых цифр (на реальных файлах их нет). - P4-5. Сетка кандидата: строки блока целиком, включая пустые; объединённая ячейка — только в позиции левой верхней,
прочие позиции
None; ширина — наибольшая среди листов кандидата. Цена: подпись, объединённая на два столбца, видна пакету только в левом. - P4-6. Шапка ищется в строках блока выше первой строки с кодом его столбца кодов (столбец —
code_columnпакета: то же правило (а)/(б) шага 2 с защитой от блока «Коды», своего правила у адаптера нет), без кодов — во всём блоке: так титульный блок «Коды» (ОКОПФ 12267) не мешает, а подписи под формой (ИНН и ФИО в блоке подписей) не попадают в шапку. Цена: метка шапки ниже начала таблицы не найдётся. - P4-7. Шаблоны словаря пакета адаптер применяет к тексту, нормализованному функцией пакета по таблице «Словари»
раздела API плана 1: метки шапки, заголовки, ОКУД,
auditor,legal_form—normalize_label(= прежнийnormalize_texttabular-parser, P1-22); подпись «Код» и относительные периоды —normalize_caption; маркер продолжения —is_continuation. Цена: нет — смена нормализации в пакете меняет иtype_hint, и адаптер. - P4-8. Склейка: открытая форма — последний кандидат с
type_hintBALANCE/INCOME; лист с маркером сверяется только по типу; лист без маркера (сильное продолжение — столбец кодов по правилу шага 2 или своя строка заголовка; слабое — столбец кодов ослабленным поискомcode_column(…, relaxed=<тип формы>), минимумmin_codes_continuationкодов, сразу после листа формы) —sheet_joinsс числом колонок суммlen(amount_columns(...))пакета («столбцы правее столбца кодов, где в строках с кодами есть число»); открытой формы нет — отдельный кандидат без предупреждения (пакет дастNO_ORGANIZATION_NO_INN). Цена: «Изменение, %» с числами считается колонкой сумм с обеих сторон сравнения; лист с иной шапкой, но тем же числом колонок, присоединится и будет сопоставлен пакетом по датам. - P4-9.
SHEET_OTHERдля листов «прочее» выдаёт книга сама (документа и кандидата нет), а не пакет по кандидату безtype_hint. Цена: два места порождения одного кода (у пакета — для кандидатов, не нашедших ни типа, ни кодов). - P4-10.
XLSB_NO_FORMATS— у каждого кандидата книги xlsb (P1-5);NUMBER_FORMAT_UNPARSED— одно на кандидата с перечнем форматов всех его листов. Цена: у пояснений xlsb тоже естьXLSB_NO_FORMATS(info). - P4-11. Книга вызывает
normalize_candidateпо одному кандидату, а неnormalize: так проверяется дедлайн между кандидатами (header.form_nameпакет ставит сам изevidence.title, пара «кандидат → документ» не нужна). Исключение пакета на кандидате —RECOGNITION_FAILEDвсей книги, как сейчас (TABLE_PARSE_ERROR— код таблицы ИС). Цена: одна сломанная форма роняет книгу с ОСВ. - P4-12. Коды ОСВ — по источнику предупреждения, не по тексту:
OSV_HIERARCHY_BY_<СТРАТЕГИЯ>,OSV_HEADER,OSV_ROWS,OSV_INN_ROWS,OSV_NO_DATA_ROWS,OSV_BALANCE_IDENTITY,OSV_PARENT_SUM,OSV_TOTAL,OSV_XLSB_NO_OUTLINE; тексты сообщений прежние, кроме иерархии. Цена: внутриOSV_HEADERиOSV_ROWSразные случаи различаются только текстом. - P4-13. Заметки читателя: несовпадение формата —
FILE_TYPE_MISMATCHфайла; «xls без кодовой страницы» —XLS_NO_CODEPAGEфайла (info, код пакета, P1-23) в любой книге xls — касается и форм, и ОСВ; «xlsb без outline» — в каждый документ ОСВ книги (OSV_XLSB_NO_OUTLINE), в книге без ОСВ только логируется (иерархия строк — только у ОСВ). Цена: предупреждение о кодировке видно в карточке файла, а не у листа ОСВ. - P4-14. Предупреждение «форма не разобрана: книга завершилась ошибкой листа ОСВ» снято: в v2.0 для него нет кода, а текст ошибки и так называет лист ОСВ. Цена: аналитик не видит списка листов форм, оставшихся неразобранными.
- P4-15. Статус документа ОСВ — прежние условия листа: контрольные суммы §1.4 сошлись и строки ИНН без нарушений
(
glue.ok, #35). Цена: формулировка спеки «когда контрольные суммы сошлись» читается шире. - P4-16. Нет
api/arm_statements/VERSION— сервис не стартует (RuntimeError), как при ошибке словаря; в goldenservice.statements_version— volatile-поле. Цена: копия безVERSIONне запустится даже локально. - P4-17. Новые синтетические случаи (форма xlsb, книга из пояснений, конфликты продолжений) — в памяти в юнит-тестах
(
sheet_from_rows,write_xlsb), новых файлов вfixtures/statements-xlsx/syntheticнет; PR fixtures — только golden. - P4-18. Манифест получает необязательное поле
error_warnings(точное множество кодовerrorдокумента); проверка уникальности кодов строк снята (повторы законны, Р-4). Цена: при правке пакета, меняющей набор предупреждений, манифест правится вместе с golden. - P4-19. Тест покрытия словарей tabular-parser больше не охватывает словари форм — они в пакете. Цена: «мёртвый» синоним заголовка или метки шапки на реальных файлах не ловится (O-8).
- P4-20. В tabular-parser — свой change
unified-normalization-tpс дельтамиstatement-parsing,tabular-recognition-service,osv-parsing(по образцу P0-5); требование «Копия контракта идентична источнику» правит план 0, здесь не трогается. - P4-21. Golden — отдельные issue, ветка и PR в RSHB/arm-ka-fixtures (один PR на репозиторий); сливается сразу за PR
tabular-parser. Цена: короткое окно, когда
make checkmainодного из них красный на golden. - P4-22. Две формы на одном листе дают два документа с одинаковым
locator(спека уникальностиlocatorне требует;refстрок различаются).
Рулинги контроллера при исполнении (R-n)
- R-1. docs-worktree отсоединён на origin/main (docs #117 слит), а не на feat/116 (П-1/П-5 плана). Цена ошибки: нет.
- R-2. Предупреждение tp #47 «xls без кодовой страницы…» —
XLS_NO_CODEPAGEпакета (info, файл, без locator); новогоOSV_*-кода нет; текст сообщения reader'а tp #47 сохранён; передаётся флагомBookRead.no_codepage. Цена: правкаbook.pyи golden. - R-4. Задача 1 (markdown-дельты) без отдельного task-ревью — проверена
openspec validate --strictи финальным ревью ветки. Цена: неточность формулировки дельты. - R-5. Проверка диапазона numeric(18,2) в
display_amountне возвращается (P4-4); диапазон иVALUE_OUT_OF_RANGEвыдаёт пакет; старый конвейер удалён задачей 9. Цена: нет после удаления. - R-6. Для |raw| ≥ 1e15 текст/значение числа без округления до 15 значащих цифр (иначе число из 17 цифр теряет
цифры); пробел групп — обычный U+0020 как в примере docs
result-statement-excel.json. Цена: расхождение с NBSP русского Excel, на value/статус не влияет. - R-7. Ячейки из одних цифр не считаются подзаголовком даты
report_date(иначе год из тройки «число|месяц|год» принимается за подзаголовок), как в прежнемheader.py. Цена: подзаголовок из голого числа «2025» не распознаётся. - R-8. Ячейка в строке-шапке таблицы (в строке есть подпись «Код» по словарю пакета
code_caption) не заголовок формы: подпись колонки «Пояснения» ('^пояснени'вform_titlesпакета) делала лист-продолжение НПЗ ещё одной формой DISCLOSURE. Дефект адаптера (спека называет «Пояснения» подписью колонки), пакет не правится. Решение владельца: оставить, посмотреть позже. Цена: компактная шапка, где заголовок формы и «Код» в одной строке, потеряет заголовок. - R-9. Предупреждения адаптера при кандидате без документа — предупреждения файла со своим
locator; порядокmetrics.warnings— сначала reader, затем по номеру первого листа;XLS_NO_CODEPAGEиOSV_XLSB_NO_OUTLINE— флагиBookRead(no_codepage,no_outline). Цена: правкаbook.pyи golden. - R-10. НПЗ, ОФР, строки «Реализация иного имущества, прав требования, прочих работ и услуг» (F34, F44): значения 0
с форматом
[=0]"-"— только прочерки, суммы нет; по спеке «строка без кода и без содержимого — не строка данных», пакет её не выдаёт; значение прочерка не превращаем в 0 (сломало бы различие null/0 и соотношения §7).test_npz_documentsне требует detail/parent_ref 2340. Вопрос владельцу O-8.2: сценарий спеки «Реализация иного имущества… с суммами» не соответствует файлу. Цена: строки из прочерков не видны аналитику. - R-11. Задача 9 (удаление по списку) без отдельного task-ревью — покрыта финальным ревью ветки.
- R-12. Остановка Р-31 по Межениновской (посторонние формулы аналитика в столбцах U–W) снята владельцем 18.10.2026:
правило в пакете (docs #123, Р-44; arm-statements #6, 3390f92) — столбец без подписи правее последней подписанной
колонки с числами не колонка сумм, предупреждение
NUMBERS_OUTSIDE_TABLE(info). Копия пакета обновлена коммитомf5d071f. Цена: нет. - R-13. Ложная склейка/дедлайн:
plan_sheetsполучаетdeadline(финальное ревью I-1, регрессия таймаута против main). Цена: нет.