19 KiB
ADDED Requirements
Requirement: Шаг 2 — разрез кандидата по смене формы
Перед шагами 2–8 кандидат SHALL разрезаться на части по смене формы (AURORA-1734, решение владельца 06.11.2026).
Сегменты кандидата ищутся по правилу «Шаг 2 — сегменты, повторная шапка и границы листов». Тип формы сегмента — по
первым min_codes кодам (порог словаря диапазонов): все они одной формы (отрезок → document_type, как на шаге 6) —
это тип, которым сегмент открывается; иначе тип не определён. Новая часть SHALL начинаться с первой строки сегмента,
если у сегмента своя строка-шапка и он открывается формой, отличной от типа текущей части (тип части — по большинству
кодов её первого сегмента с кодами; после разреза — тип, которым открылась часть). Сегменты без шапки, с числом кодов
меньше порога или той же формы остаются в текущей части; строки другой формы, приклеенные к сегменту без своей шапки
(сегмент открывается кодами текущей формы), разреза не дают.
Часть — обычный FormCandidate для шагов 2–8: строки сетки с первой строки сегмента до начала следующей части,
segment_breaks — сдвинутые на начало части; header — тот же, что у исходного кандидата (шапка файла ИС одна на
таблицу); source тот же. Первая часть сохраняет locator, type_hint, evidence и warnings исходного кандидата;
следующая часть k (с 1) получает locator = "<locator исходного>;form:<k>", type_hint = null, пустые evidence и
warnings — её тип определяется на шаге 6 только по кодам, без TYPE_CONFLICT от заголовка таблицы. Кандидат без
смены формы SHALL оставаться одним кандидатом без изменений.
Пакет SHALL экспортировать функцию разреза (split_by_form(candidate, rules) → tuple[FormCandidate, ...]); хост
вызывает её на каждый кандидат и передаёт части в normalize_candidate по порядку. Документы частей — отдельные
документы результата (ядро различает их по file_ordinal, Р-10); модель данных и контракт не меняются. Правило общее
для OCR и Excel.
Scenario: ББ и ОФР одной таблицей ИС (АК-ЮЛ)
- WHEN таблица ИС «Бухгалтерский баланс» содержит строки 1110…1700 (две страницы ББ с повторной шапкой на строке 19), а со строки 41 — шапку «Наименование показателя | Коды | За I полугодие 2026 года | …» и строки 2110…2400
- THEN две части: ББ — строки 0–40,
locator = "file:<json>;table:0", колонки ББ; ОФР — строки 41–60,locator = "file:<json>;table:0;form:1", колонки и периоды по своей шапке,TYPE_CONFLICTнет; повторная шапка строки 19 разреза не даёт (тот же тип)
Scenario: Раздел 25xx после ОФР
- WHEN в таблице ОФР повторная шапка открывает сегмент со строками 2510…2910
- THEN разреза нет: тип сегмента тот же (
INCOME), сегмент — продолжение ОФР
Scenario: ОФР без своей шапки после пассива
- WHEN после повторной шапки ББ идут строки 1310, 1300, 1700, а следом без шапки — 2110, 2120, 2100, 2400
- THEN разреза нет: сегмент открывается кодами ББ (как и до изменения)
Scenario: Пара строк другой формы
- WHEN после строк ББ повторная шапка открывает сегмент с двумя кодами 2xxx (меньше порога
min_codes) - THEN разреза нет, сегмент остаётся в части ББ (как раньше)
MODIFIED Requirements
Requirement: Шаг 1 — многостраничная форма
Требование относится к адаптеру Excel: у OCR каждая таблица ИС — отдельный кандидат, склейки таблиц нет (повторная
шапка внутри таблицы ИС — сегмент шага 2; смена формы внутри таблицы — разрез кандидата, требование «Шаг 2 — разрез
кандидата по смене формы»). У Excel одна форма SHALL быть одной сеткой на выходе шага 1. Строки продолжения дописываются в конец сетки по маркеру
«Форма … с.2» или по позиции листа; граница листа записывается в segment_breaks. Тип из маркера продолжения SHALL
сверяться с type_hint формы: расхождение — отдельный кандидат и предупреждение CONTINUATION_TYPE_CONFLICT
(error). Лист без маркера и без шапки присоединяется, только если его коды в диапазоне открытой формы и, при трёх и
более кодах, число колонок сумм совпадает с формой; иначе — отдельный кандидат и предупреждение
SHEET_NOT_JOINED (error).
Scenario: Лист-продолжение с одной строкой
- WHEN после листа ОФР идёт лист без шапки с единственной строкой 2400
- THEN лист присоединяется к ОФР (код в диапазоне формы, кодов меньше трёх — число колонок не сверяется), граница
листа — в
segment_breaks
Scenario: Лист другой ширины с тремя кодами
- WHEN лист без маркера и шапки содержит три кода ББ и четыре колонки сумм при трёх у открытой формы
- THEN лист — отдельный кандидат, предупреждение
SHEET_NOT_JOINEDуровняerror
Requirement: Шаг 2 — подпись и дата колонки
Подпись колонки SHALL разбираться одним словарём периодов statement_periods.yaml, объединяющим словарь
tabular-parser и шаблоны dates.py scan-gateway; строки test_dates.py::test_parses_real_forms scan-gateway —
обязательные тесты словаря. Результат — period_date (конец периода колонки) и period_kind:
- абсолютная подпись («На 31 марта 2025 г.», «31.12.2024», «30/09/25», «30092025», «За 9 месяцев 2025 г.», «с
01.01.2025 по 31.03.2025», «2024», хвост «0:00:00», клетки «2|0|2|4|») →
absolute; - относительная: «На отчётную дату», «За отчётный период» →
relative:current(= эффективная дата); «На 31 декабря предыдущего года» →relative:prev_year_end(31.12 года эффективной даты − 1); «На 31 декабря года, предшествующего предыдущему» →relative:prev_prev_year_end(31.12 года − 2); «За аналогичный период предыдущего года» →relative:prev_period(эффективная дата − 1 год, 29 февраля → 28 февраля); - подписи нет →
none.
Эффективная дата документа SHALL быть датой отчёта из шапки, иначе самой поздней абсолютной датой колонок; нет ни
той, ни другой → у относительных колонок period_date = null, period_kind остаётся относительным.
Подпись из словаря исключений («Изменение», «Отклонение», «%», «Темп», «Доля», «Примечание») SHALL пропускаться с
предупреждением COLUMN_SKIPPED (info). Подпись, не разобранная ни как период, ни как исключение, при числах в
столбце в строках с кодами SHALL оставлять колонку с подписью как есть, period_date = null, period_kind = none и
предупреждением COLUMN_WITHOUT_DATE (error, column_index); без чисел — пропуск. Подпись OCR с уверенностью ниже
100, разобранная в дату, подтверждается, если дата входит в ожидаемые: эффективная дата, она же минус один и минус два
года, 31 декабря предыдущего и предшествующего ему года; иначе предупреждение COLUMN_DATE_UNCERTAIN (error,
column_index). Уверенность подписи — label_confidence (у Excel 100; подписи нет — null).
Если среди колонок значений сегмента есть хотя бы одна с подписью периода (абсолютной или относительной), столбец без
текста подписи правее последней такой колонки SHALL НЕ считаться колонкой сумм: его числа не попадают в значения
строк, COLUMN_WITHOUT_DATE не выдаётся, вместо этого выдаётся одно предупреждение NUMBERS_OUTSIDE_TABLE (info) с
адресами ячеек, собранными по всем сегментам формы (в тексте — первые 10, дальше «и ещё N»). Предупреждение SHALL НЕ
влиять на статус документа. Решение владельца 18.10.2026 (Р-44). Правило общее для Excel и OCR и живёт в пакете.
У сегмента без подписанных колонок (лист-продолжение без шапки) столбцы без текста подписи сверх числа колонок документа
SHALL считаться числами правее таблицы. Подписанный столбец без чисел в строках с кодами границей таблицы не служит.
Адрес ячейки — <лист>!<A1> у Excel и row:<n> у OCR. Без подписанных колонок, а также для столбца без подписи между
подписанными и для столбца с любым текстом подписи, не разобранным как период или исключение, поведение прежнее (COLUMN_WITHOUT_DATE),
кроме редкого столбца ниже.
Редкий столбец с неразобранной подписью (AURORA-1735, решение владельца 06.11.2026) SHALL НЕ считаться колонкой
сумм, если одновременно: у столбца есть текст подписи, не разобранный ни как период, ни как исключение; левее и правее
него в сегменте есть колонки значений с подписью периода; число стоит не более чем в одной строке с кодом этого
столбца, а в каждой колонке значений сегмента с подписью периода — не менее чем в трёх. Его числа не попадают в значения
строк, COLUMN_WITHOUT_DATE не выдаётся; адреса его чисел добавляются в то же предупреждение NUMBERS_OUTSIDE_TABLE
(info). Если среди адресов предупреждения есть адреса такого столбца, текст — «числа вне колонок формы не
учитываются: …», иначе прежний «числа правее таблицы формы не учитываются: …». Это разорванная OCR подпись периода
(«31» + «а I полугодие 2025 года») с посторонним числом под обрывком; столбец с числами в двух и более строках с кодом
остаётся колонкой с COLUMN_WITHOUT_DATE.
Подтверждение SHALL опираться только на уверенные источники, чтобы неуверенное не подтверждало само себя: для
неуверенной подписи эффективная дата — дата отчёта с уверенностью 100, иначе самая поздняя абсолютная дата колонок с
уверенной подписью (label_confidence = 100); такой нет — подпись не подтверждена. Неуверенная дата отчёта (шаг 8, поля
шапки) подтверждается только самой поздней абсолютной датой колонок с уверенной подписью. Для периода документа и
относительных подписей эффективная дата считается, как выше, по всем источникам.
Scenario: Бланк 66н без впечатанных дат
- WHEN подписи колонок ББ — «На отчетную дату», «На 31 декабря предыдущего года», «На 31 декабря года, предшествующего предыдущему», дата отчёта шапки 30.09.2025
- THEN
period_dateколонок 2025-09-30, 2024-12-31, 2023-12-31,period_kind—relative:current,relative:prev_year_end,relative:prev_prev_year_end; предупреждений о дате колонок нет
Scenario: Неуверенная подпись не подтверждает сама себя
- WHEN даты отчёта в шапке нет, единственная колонка с абсолютной датой — подпись OCR «На 30.09.2О25» с уверенностью 60, остальные колонки без подписи
- THEN эффективная дата для подтверждения строится без этой подписи — уверенных источников нет, подпись не
подтверждена:
COLUMN_DATE_UNCERTAINуровняerror; период документа (period_known) по-прежнему определяется этой датой
Scenario: Мусорная подпись над числами
- WHEN подпись колонки —
"| | г"с уверенностью 17, а в колонке суммы - THEN колонка остаётся,
period_date = null,period_kind = none, предупреждениеCOLUMN_WITHOUT_DATEуровняerrorсcolumn_index, документneeds_check
Scenario: Числа справа от таблицы
- WHEN у ББ подписи периодов стоят над столбцами M, Q, S, а правее таблицы в строках с кодами лежат формулы аналитика (V45, W57, U58, V58, V72, W72) над пустой шапкой (Межениновская 2025-Q3)
- THEN колонок значений три, числа U–W в значения не попадают,
COLUMN_WITHOUT_DATEиSEGMENT_COLUMNS_MISMATCHнет; одно предупреждениеNUMBERS_OUTSIDE_TABLEуровняinfoс адресами этих ячеек; документdone, если нет других причин
Scenario: Столбец без подписи между подписанными
- WHEN между колонками с подписями периода стоит столбец без подписи с числами
- THEN он остаётся колонкой с
COLUMN_WITHOUT_DATEуровняerror,NUMBERS_OUTSIDE_TABLEнет
Scenario: Подписанных колонок нет
- WHEN ни у одного столбца значений нет подписи периода
- THEN правило «числа справа от таблицы» не применяется, столбцы с числами — колонки с
COLUMN_WITHOUT_DATE
Scenario: Обрывок подписи периода (Калтан, AURORA-1735)
- WHEN у ОФР подписи «За 1 полугодие 2026 года» (столбец 4), «31» (столбец 5), «а I полугодие 2025 года» (столбец 6); в столбцах 4 и 6 суммы в десятке строк с кодом, в столбце 5 — одно число «$301 .» в строке 2400 и тире
- THEN колонок значений две (4 и 6),
COLUMN_WITHOUT_DATEнет;NUMBERS_OUTSIDE_TABLEуровняinfoс адресом ячейки строки 2400 столбца 5 и текстом «числа вне колонок формы не учитываются: row:21»; число 301 в значения не попадает
Scenario: Неразобранная подпись над двумя числами
- WHEN между двумя колонками периодов стоит столбец с подписью «Прим.» (не из словаря исключений), числа в нём — в двух строках с кодом
- THEN столбец остаётся колонкой с
COLUMN_WITHOUT_DATEуровняerror
Scenario: Колонка «Изменение»
- WHEN правее периодов колонка «Изменение, %»
- THEN колонка пропускается, предупреждение
COLUMN_SKIPPEDуровняinfo