ОСВ: xls без CODEPAGE → cp1251, «Кол-во»/«Вал», таблица кончается на первой «Итого» (#47, AURORA-1662, 1663, 1664) #48

Merged
aep merged 4 commits from feat/47-osv-encoding-labels-tail into main 2026-10-18 11:15:43 +03:00
Owner

Closes #47. Bounded-задача: три бага разбора ОСВ из прогона выгрузки контура (AURORA-1639, находки O-1, O-5, O-6, O-12 свода admin/1639-contour-run). Реворк нормализации ББ/ОФР (arm-ka-docs#116) разбор ОСВ не меняет.

Связанные PR (сливать в порядке): RSHB/arm-ka-fixtures — golden и синтетика s29–s32 (первым), этот PR, RSHB/arm-ka-docs — §1 правил.

Что изменено

AURORA-1662 — xls без CODEPAGE. readers/xls.py: книга BIFF5/7 без записи CODEPAGE открывается с encoding_override="cp1251", предупреждение книги «xls без кодовой страницы — строки прочитаны как cp1251». BIFF8 и книги с CODEPAGE — как прежде, кодировка по содержимому не угадывается.

AURORA-1663 — «Кол-во» и «Вал». rules/data_types.yaml: «Кол-во» → QUANTITY; «Вал» без точки — не метка валюты (материал на сч. 10), метка — «Вал.» и коды валют. Реальных валютных строк «Вал» без точки в 126 фикстурах нет.

AURORA-1664 — строки ниже таблицы. classify.py: таблица кончается на первой «Итого» корневого уровня (+ «Итого развернутое» сразу за ней); сначала ищется строка ровно «Итого» (total_row_exact), без неё — первая «Итого …». Числа ниже таблицы в колонках таблицы — предупреждение «строки N–M: ниже таблицы (после «Итого») есть числа …», статус не меняется. Закрывает tp#7 M-2.

Проверка

  • make check: 2564 passed, ruff/mypy чистые; make test-integration: 10 passed; make docker-build: ok.
  • Golden: новые снимки s29–s32; 123 прежних снимка без изменений.
  • Реальные файлы контура (ручная проверка, в git не кладутся):
    • 10 xls Компании 4 (GK-000015): было 10 × INVALID_DOCUMENT «в книге нет листов ОСВ»; стало 2 done (сч. 20, 52), 2 needs_check (сч. 02, 10), 6 error «иерархия строк не определена» — плоская форма «Субконто», это AURORA-1661, здесь не чинится.
    • «ОСВ сч. 10»: 322 строки «Кол-во» стали QUANTITY, «Вал» — обычная номенклатура.
    • «76_01.10.2025_ЗК Новопетровская (ЗКН) (4).xlsx»: было needs_check, 1336 строк, итог — «Итого компании ГК…», настоящая «Итого» (2 492 527 631,81) — контрагентом; стало done, 1333 строки, итог верный, total_row_matches_root=True, предупреждение о хвосте строк 2667–2674.

Rulings I made

  • R-1. Фолбэк cp1251 только для BIFF5/7 без CODEPAGE (в BIFF8 строки в Unicode); проба через on_demand, ошибка пробы не мешает читателю. Цена ошибки: xls в иной однобайтовой кодировке без CODEPAGE прочитается неверно — в выгрузках 1С/Excel РФ не встречалось.
  • R-2. Предупреждение о хвосте — одна строка на весь хвост, только числовые ячейки в колонках таблицы (от колонки текста до правого края сумм); статус не меняет. Цена: числа хвоста правее таблицы не видны предупреждением (контрольные суммы банка в rb/2024-Q1 — именно такие).
  • R-3. Точное «Итого» ищется раньше «Итого …» (новый ключ total_row_exact). Остаточный риск: если точного «Итого» нет, а на листе нет outline/отступов, контрагент «Итого-…» станет TOTAL — ловит проверка TOTAL = корень (тест test_known_risk_…).
  • R-4. Строки «Итого» не на корневом уровне оформления поиск итога пропускают, а не обрывают (сохраняет защиту T3.3).
  • R-5. Синтетический xls без CODEPAGE — собственный минимальный писатель BIFF5 в OLE2 (tests/synthetic/xls_writer.py): Excel и LibreOffice CODEPAGE пишут всегда.
  • R-6. Реальные файлы контура в fixtures не кладутся (данные клиента) — только ручная проверка, регрессия — синтетикой s29–s32.

Находки

Маркер Суть Статус
I-1 Первая «Итого» по ^итого\b: контрагент «Итого-Сервис» на плоском листе обрезал бы таблицу fixed 195720c
M-1 Предупреждение о хвосте срабатывало на контрольные суммы правее таблицы (rb/2024-Q1) fixed 195720c
O-1 make -C docs validate-openspec падает на архивном slice-0-skeleton (давнее) deferred
O-2 make check в docs требует jsonschema без своего venv rejected — уже tp#44 O-2
O-3 «ОСВ сч. 10» Компании 4 остаётся needs_check (нарушения строк 547, 658; в шапке нет БУ/НУ и валюты) — не разбиралось deferred
O-4 «ОСВ сч. 02» Компании 4: needs_check, TOTAL ≠ корень, hierarchy=sums, шапка без счёта — не разбиралось deferred
O-5 «ОСВ сч. 20/52» Компании 4 — done с 1–2 строками: убедиться, что это не нераспознанные данные deferred
O-6 6 xls Компании 4 — плоская форма «Субконто» rejected — AURORA-1661
O-7 В fixtures синтетика и её golden — одним коммитом, не отдельным golden-коммитом rejected — новые файлы и их снимки неразделимы, прежние снимки не менялись

После слияния: AURORA-1662, 1663, 1664 → «Готово к тестированию» (через arm-ka-docs#118, Jira сейчас недоступна).

🤖 Generated with Claude Code

Closes #47. Bounded-задача: три бага разбора ОСВ из прогона выгрузки контура (AURORA-1639, находки O-1, O-5, O-6, O-12 свода `admin/1639-contour-run`). Реворк нормализации ББ/ОФР (arm-ka-docs#116) разбор ОСВ не меняет. Связанные PR (сливать в порядке): RSHB/arm-ka-fixtures — golden и синтетика s29–s32 (**первым**), этот PR, RSHB/arm-ka-docs — §1 правил. ## Что изменено **AURORA-1662 — xls без CODEPAGE.** `readers/xls.py`: книга BIFF5/7 без записи CODEPAGE открывается с `encoding_override="cp1251"`, предупреждение книги «xls без кодовой страницы — строки прочитаны как cp1251». BIFF8 и книги с CODEPAGE — как прежде, кодировка по содержимому не угадывается. **AURORA-1663 — «Кол-во» и «Вал».** `rules/data_types.yaml`: «Кол-во» → QUANTITY; «Вал» без точки — не метка валюты (материал на сч. 10), метка — «Вал.» и коды валют. Реальных валютных строк «Вал» без точки в 126 фикстурах нет. **AURORA-1664 — строки ниже таблицы.** `classify.py`: таблица кончается на первой «Итого» корневого уровня (+ «Итого развернутое» сразу за ней); сначала ищется строка ровно «Итого» (`total_row_exact`), без неё — первая «Итого …». Числа ниже таблицы в колонках таблицы — предупреждение «строки N–M: ниже таблицы (после «Итого») есть числа …», статус не меняется. Закрывает tp#7 M-2. ## Проверка - `make check`: 2564 passed, ruff/mypy чистые; `make test-integration`: 10 passed; `make docker-build`: ok. - Golden: новые снимки s29–s32; 123 прежних снимка без изменений. - Реальные файлы контура (ручная проверка, в git не кладутся): - 10 xls Компании 4 (GK-000015): было 10 × INVALID_DOCUMENT «в книге нет листов ОСВ»; стало 2 done (сч. 20, 52), 2 needs_check (сч. 02, 10), 6 error «иерархия строк не определена» — плоская форма «Субконто», это AURORA-1661, здесь не чинится. - «ОСВ сч. 10»: 322 строки «Кол-во» стали QUANTITY, «Вал» — обычная номенклатура. - «76_01.10.2025_ЗК Новопетровская (ЗКН) (4).xlsx»: было needs_check, 1336 строк, итог — «Итого компании ГК…», настоящая «Итого» (2 492 527 631,81) — контрагентом; стало done, 1333 строки, итог верный, `total_row_matches_root=True`, предупреждение о хвосте строк 2667–2674. ## Rulings I made - R-1. Фолбэк cp1251 только для BIFF5/7 без CODEPAGE (в BIFF8 строки в Unicode); проба через `on_demand`, ошибка пробы не мешает читателю. Цена ошибки: xls в иной однобайтовой кодировке без CODEPAGE прочитается неверно — в выгрузках 1С/Excel РФ не встречалось. - R-2. Предупреждение о хвосте — одна строка на весь хвост, только числовые ячейки в колонках таблицы (от колонки текста до правого края сумм); статус не меняет. Цена: числа хвоста правее таблицы не видны предупреждением (контрольные суммы банка в rb/2024-Q1 — именно такие). - R-3. Точное «Итого» ищется раньше «Итого …» (новый ключ `total_row_exact`). Остаточный риск: если точного «Итого» нет, а на листе нет outline/отступов, контрагент «Итого-…» станет TOTAL — ловит проверка TOTAL = корень (тест `test_known_risk_…`). - R-4. Строки «Итого» не на корневом уровне оформления поиск итога пропускают, а не обрывают (сохраняет защиту T3.3). - R-5. Синтетический xls без CODEPAGE — собственный минимальный писатель BIFF5 в OLE2 (`tests/synthetic/xls_writer.py`): Excel и LibreOffice CODEPAGE пишут всегда. - R-6. Реальные файлы контура в fixtures не кладутся (данные клиента) — только ручная проверка, регрессия — синтетикой s29–s32. ## Находки | Маркер | Суть | Статус | |---|---|---| | I-1 | Первая «Итого» по `^итого\b`: контрагент «Итого-Сервис» на плоском листе обрезал бы таблицу | fixed 195720c | | M-1 | Предупреждение о хвосте срабатывало на контрольные суммы правее таблицы (rb/2024-Q1) | fixed 195720c | | O-1 | `make -C docs validate-openspec` падает на архивном `slice-0-skeleton` (давнее) | deferred | | O-2 | `make check` в docs требует `jsonschema` без своего venv | rejected — уже tp#44 O-2 | | O-3 | «ОСВ сч. 10» Компании 4 остаётся needs_check (нарушения строк 547, 658; в шапке нет БУ/НУ и валюты) — не разбиралось | deferred | | O-4 | «ОСВ сч. 02» Компании 4: needs_check, TOTAL ≠ корень, `hierarchy=sums`, шапка без счёта — не разбиралось | deferred | | O-5 | «ОСВ сч. 20/52» Компании 4 — done с 1–2 строками: убедиться, что это не нераспознанные данные | deferred | | O-6 | 6 xls Компании 4 — плоская форма «Субконто» | rejected — AURORA-1661 | | O-7 | В fixtures синтетика и её golden — одним коммитом, не отдельным golden-коммитом | rejected — новые файлы и их снимки неразделимы, прежние снимки не менялись | После слияния: AURORA-1662, 1663, 1664 → «Готово к тестированию» (через arm-ka-docs#118, Jira сейчас недоступна). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 4 commits 2026-10-18 11:09:22 +03:00
В BIFF5/7 без CODEPAGE xlrd декодировал байтовые строки как latin-1: кириллица
превращалась в мусор, лист ОСВ не находился (INVALID_DOCUMENT). Теперь такая
книга читается с encoding_override=cp1251 и получает предупреждение уровня книги
«xls без кодовой страницы — строки прочитаны как cp1251». Книги с CODEPAGE и
BIFF8 читаются как прежде. Проба CODEPAGE — on_demand-открытие (только globals).

Для теста добавлен минимальный писатель BIFF5 в контейнере OLE2
(tests/synthetic/xls_writer.py), умеющий не писать CODEPAGE.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
AURORA-1663: словарь строк data_types.yaml — «Кол-во» даёт QUANTITY, «Вал» без
точки больше не CURRENCY (материал «Вал» на счёте 10); метка — «Вал.» и код
валюты.

AURORA-1664: _find_total берёт первую «Итого» на корневом уровне оформления
(раньше — последнюю), вторая итоговая строка сразу за ней по-прежнему часть
таблицы; всё ниже вне документа. Числа в хвосте дают предупреждение «ниже
таблицы (после «Итого») есть числа» без смены статуса. Закрывает tp#7 M-2.
Предупреждение появляется и у реальной фикстуры rb/2024-Q1 (контрольные суммы
правее таблицы под «Итого») — тест property допускает его.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
I-1: _find_total сначала берёт первую строку корневого уровня с текстом ровно «Итого»
(новый ключ total_row_exact в osv_headers.yaml) и лишь без неё — первую по total_row.
Контрагент «Итого-Сервис» на плоском листе без outline и отступов больше не обрезает таблицу.
O-3: предупреждение о хвосте считает числа только в колонках таблицы (text_col…right_edge
из TableHeader); контрольные суммы правее таблицы (rb/2024-Q1) его не дают, ослабление
в test_classify_real откачено. Синтетика s32: итог «Итого по счету 60» без точного «Итого»
(нужна тесту покрытия для запасного паттерна total_row).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
aep merged commit 623794936c into main 2026-10-18 11:15:43 +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#48
No description provided.