Документация: признаки листа ОСВ, синтетика s48–s57, итог регрессии (#81)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-28 21:09:27 +04:00
parent dc3d7c8ce9
commit f7cb32e3d4
3 changed files with 25 additions and 4 deletions

View File

@ -75,7 +75,10 @@ CORS, регистрация SMB-сессии, импорт `raisa_fastapi_prote
обращения к ячейке константами. Значения enum контракта вычисляются из `src.contract` и под линтер не попадают.
- Каждая запись словаря должна срабатывать хотя бы на одном реальном или синтетическом файле
(`tests/fixtures/test_rules_coverage.py`); мёртвый синоним удаляется, пробел в фикстурах закрывается синтетикой.
- Golden-снимки (`../fixtures/golden/expected_osv_parse/`, 136 файлов: 72 реальных + 23 пакета ДКБ (`osv-dkb/**` до 1 МиБ, снимки в `osv-dkb/`) + 41 синтетический) — регрессия, а не
- Признак листа ОСВ шире названия ведомости — запасной признак по заголовку таблицы (`detect.has_osv_table`, #81).
Его ограничения (три группы, Дт и Кт рядом, первые 30 строк, без свёрнутого сальдо) держат негативы синтетики
s55–s57: ослабили ограничение — падает свой негатив. Новое ослабление — только с новым негативом.
- Golden-снимки (`../fixtures/golden/expected_osv_parse/`, 149 файлов: 72 реальных + 23 пакета ДКБ (`osv-dkb/**` до 1 МиБ, снимки в `osv-dkb/`) + 54 синтетических) — регрессия, а не
оракул; правятся только `make golden-update` с просмотром diff и отдельным коммитом в `fixtures`. Корректность
проверяют property-тест и ручная сверка «Итого».
- Деньги — `Decimal`, `float` в домене нет; `needs_check` — только по контрольным суммам, структуру под сходимость не

View File

@ -121,7 +121,7 @@ ParseOutcome`. Структура ОСВ ищется **по содержимо
| `grid.py` | модель листа: `Cell`, `Sheet`, `MergedRange`, `column_letter` (буква колонки — только для диагностики) |
| `readers/` | чтение книги в `Sheet`: `read_book(data, file_type) -> (листы, предупреждения)`; формат определяется по сигнатуре байтов (xlsx — openpyxl; части архива, отличающиеся от ссылок `[Content_Types].xml`/`*.rels` только регистром (`xl/SharedStrings.xml`), до openpyxl переименовываются по ссылкам, как их находит Excel — AURORA-1707; xls — xlrd с `formatting_info`, xlsb — pyxlsb, без outline level); несовпадение с `file_type` — предупреждение; до библиотеки чтения — лимиты чтения (`_limits.py`, см. «Лимиты») |
| `rules.py` | загрузчик словарей `rules/*.yaml` в frozen-модели (pydantic), `normalize_text`, `Pattern`; ошибка словаря — `RuntimeError` с файлом и ключом при старте |
| `detect.py` | вид листа (`classify_sheet`: ОСВ / форма ББ-ОФР / прочее), блок заголовка таблицы (`find_table_header`: 1–4 строки, шесть колонок сумм, колонка текста, ИНН, дополнительные колонки, правая граница, повтор заголовка внутри данных) |
| `detect.py` | вид листа (`classify_sheet`: ОСВ / форма ББ-ОФР / прочее; ОСВ — по названию ведомости `sheet_markers` или, если лист не форма, по полному заголовку таблицы `has_osv_table`: три группы, у каждой «Дебет» и «Кредит» рядом, в первых 30 строках, #81), блок заголовка таблицы (`find_table_header`: 1–4 строки, шесть колонок сумм, колонка текста, ИНН, дополнительные колонки, правая граница, повтор заголовка внутри данных) |
| `header.py` | шапка документа (организация, счёт, период, тип данных, валюта) и схема группировок `group_schema` (варианты шапки 1 и 2) |
| `hierarchy.py` | каскад стратегий уровней строк: `outline` → `indent` → `account_pattern` → `header_account` → `sums`; `trivial` — меньше двух строк данных; `header_account` — плоский список под счётом шапки (код счёта в шапке, строк-счетов в теле нет; плоская форма 1С, #59); выбранная стратегия пишется в `warnings[]` документа листа как `OSV_HIERARCHY_BY_<СТРАТЕГИЯ>` (`info`) |
| `numbers.py` | суммы в `Decimal` с двумя знаками (`to_money`), ИНН из текста ячейки (`inn_digits`); `float` в домене нет |

View File

@ -52,9 +52,10 @@
### D1. Запасной признак листа — последним шагом (решение владельца 28.10.2026)
Порядок классификации: признак ОСВ по названию (`sheet_markers`) → форма / продолжение / прочее (пакет). Только если
пакет вернул «прочее», лист проверяется запасным признаком: в первых `SHEET_MARKER_ROWS` строках есть строка групп, где
пакет вернул «прочее», лист проверяется запасным признаком — раньше слабого продолжения формы (R-12): в первых `SHEET_MARKER_ROWS` строках есть строка групп, где
найдены **все три** группы (начало, обороты, конец), и у каждой группы найдены **обе** стороны — Дебет и Кредит
(в ячейках под группой или в самой ячейке группы). Свёрнутое сальдо (одна колонка в группе) запасной признак не даёт.
(в ячейках под группой или в самой ячейке группы), и между ними в строках заголовка нет других подписей (R-11).
Свёрнутое сальдо (одна колонка в группе) запасной признак не даёт.
Нашёлся — лист `OSV`, дальше обычный конвейер ОСВ; нет — `SHEET_OTHER`, как сейчас.
Почему так: расшифровки ББ с колонками «Остаток на начало / … / Остаток на конец» забирает классификатор форм раньше,
@ -105,6 +106,17 @@ xlsb) на main `a8c9605` и на ветке. Сравнение по каждо
и сторон дополняются написаниями из D2. PR в arm-ka-docs из ветки `feat/81-osv-other-systems` worktree
`.wt/osv-dict/docs`, ссылка на tabular-parser#81.
## Итог регрессии (28.10.2026)
Банк первички, 2152 файла (`admin/osv-other-systems-regress/report.md` workspace): 60 файлов из ошибки → ОСВ «Готово»,
70 → «Требует проверки», 40 узнаны как ОСВ, но стоят на 1720–1723; ни один лист формы или прочий лист книги с формами
не стал ОСВ; ухудшения — только R-14. Файлы списков 1717/1719 (175): 60 «Готово», 60 «Требует проверки», 50 ошибка
формата, 4 ложных «Готово» безымянных ведомостей 009, которые забирает конвейер форм (D1), 1 — неполный заголовок.
Контрольный набор синтетики s48–s57: позитивы на базе падали, негативы проходили; на ветке проходят все. Мутации
запасного признака (без R-11, без лимита 30 строк, со свёрнутым сальдо, с двумя группами) и снятие якоря `^` у названий
ловит каждая свой негатив (s55, s56, s57).
## Risks / Trade-offs
- [`^осв\b` и «оборотн… ведомост» в тексте формы] → проверка ОСВ идёт первой; регрессия D3 ловит листы форм, ставшие
@ -126,4 +138,10 @@ xlsb) на main `a8c9605` и на ветке. Сравнение по каждо
| 2026-10-28 | R-6. Запасной признак переиспользует поиск строки групп и колонок обычного заголовка (`_find_group_row`, `_columns_of_group`) в строгом режиме, а не отдельную функцию | запасной признак и конвейер не должны расходиться в том, что считать заголовком | — |
| 2026-10-28 | R-7. Порядок PR: `fixtures` (golden синтетики, отдельный коммит `make golden-update`) → tabular-parser → docs | golden-тесты tabular-parser читают `../fixtures` | — |
| 2026-10-28 | R-8. Приёмка — синтетика + `make check-full` + нет ухудшений D3; число исправленных файлов банка — отчёт, не порог | эксперимент автора задач — ориентир, а не обязательство; остаток держат 1720–1723 | — |
| 2026-10-28 | R-9. Написание «Остаток по дебету/кредиту на начало/конец» (6 файлов КТЗ/ЧАЗ) включено в словарь: группа «остаток» с опережающей проверкой, сторона — из остатка ячейки | та же семья «Остаток на начало/конец» (1719), решается записью словаря | лишняя запись, удаляется |
| 2026-10-28 | R-10. В синтетике s50 у SAP-листа обороты «Оборот Дт / Оборот Кт», а не реальное «Дт оборот» | сторона перед группой — AURORA-1722, вне объёма (R-4) | файлы Виолы остаются с ошибкой до 1722 |
| 2026-10-28 | R-11. Запасной признак требует, чтобы между колонками «Дебет» и «Кредит» каждой группы в строках заголовка не было других подписей | иначе 1С «Обороты счета» (Дт/Кт оборота разделены колонками корр. счетов) проходит как ОСВ вопреки R-1; держит негатив s55 | безымянная ОСВ с колонкой между Дт и Кт не распознаётся |
| 2026-10-28 | R-12. Запасной признак проверяется раньше слабого продолжения формы (лист из 1–2 кодов сразу после формы), но после сильных признаков формы и продолжения | на базе лист Navision после формы ББ пакет присоединял к ней как слабое продолжение (синтетика s52); полная таблица ОСВ — сильнее эвристики «1–2 кода» | лист-продолжение формы с полной таблицей ОСВ отделится от формы (у продолжения формы таких групп нет) |
| 2026-10-28 | R-13. Признак «ОСВ …» сужен до `^осв\s+по\s+(\w+\s+по\s+)?сч\b` вместо `^осв\b` | первый прогон банка: строка «ОСВ за квартал по счетам …» перечня документов на листе «Входные данные_ИП» шаблона банка делала лист ОСВ, его разбор падал, и вся книга расшифровок становилась ошибкой (86 файлов); все 20 реальных названий начинаются с «ОСВ по сч.» / «ОСВ по ДЗ по сч.»; держит негатив s55 | «ОСВ» с другим продолжением по названию не узнаётся (остаётся запасной признак) |
| 2026-10-28 | R-14. Два файла «Сводная ОСВ … (забаланс)»: ложное «Готово» расшифровки на базе → ошибка иерархии ОСВ на ветке принято, а не исправлено | это цель изменения (ведомость «Оборотный баланс / Оборотная ведомость» перестаёт быть расшифровкой, 1718); дальше файл держит иерархия «002.01: Название» — AURORA-1721 | у двух книг «Ошибка» вместо фальшивого «Готово» до 1721 |
| 2026-10-28 | R-4. AURORA-1722 (SAP со стороной перед группой, НОВО-МАР) не входит | в задачах указан порядок: после 1717/1719; причина варианта НОВО-МАР не разобрана | эти файлы остаются с ошибкой до 1722 |