# Design: Срез 2b (сквозное) — контракт v1.2, §12, OQ ## Context Контракт `recognition-result.schema.json` v1.1: `statementDocument` рассчитан на OCR (поля `*_confidence`, `is_recognized`), `document_type ∈ {BALANCE, INCOME, OTHER}`, результатов проверок у форм нет (у `osvDocument` есть `checks`); `osvDocument.header` описывает период текстом, годом и кварталом, границы диапазона месяцев выразить нельзя (OQ-131). Правило версионирования: MINOR — необязательные поля и новые значения enum; потребители обновляют копии раньше производителя. Потребители копий: `tabular-parser` (тест идентичности в `make check`), `arm-core` (тест идентичности, pydantic-модели результата в `services/result_mapping.py`), `scan-gateway` (копия и модели). ## Decisions ### D-1. Состав v1.2 - `$defs.statementDocument.properties.document_type.enum`: `["BALANCE", "INCOME", "DISCLOSURE", "OTHER"]`. - `$defs.statementDocument.properties.checks` (object, необязательное): `relations_failed` и `soft_relations_failed` — массивы объектов `{column_index: integer, relation: string, expected: money, actual: money}` (все четыре обязательны); `duplicate_line_codes` — массив строк. Описание: отсутствие объекта — «не проверялось» (OCR-путь), пустые массивы — «проверено, сошлось». - `$defs.osvDocument.properties.header.properties`: `period_start`, `period_end` — `["string", "null"]`, `format: date`; `is_from_year_start` — `["boolean", "null"]`. Описание: границы периода по шапке; для квартала/года — первое и последнее число; для диапазона месяцев — его границы; `is_from_year_start` = `period_start` — 1 января. - `title`, `description` схемы и `schema_version.description` — «1.2». `$comment` о версионировании не меняется. - `recognition-request.schema.json` и `recognition-result-message.schema.json` не меняются; `result_schema_version` в сообщении — строка, новых значений не требует. ### D-2. Примеры `result-statement-minimal.json` получает `checks: {relations_failed: [], soft_relations_failed: [], duplicate_line_codes: []}` и `schema_version: "1.2"`. Новый `result-statement-excel.json`: `service.name = tabular-parser`, три документа — `BALANCE` с `locator = "sheet:Бухгалтерский баланс. Лист 1,Бухгалтерский баланс. Лист 2"`, тремя колонками, строками 1110/11101/1100/1600 и `checks` с одним нарушением в `soft_relations_failed`; `INCOME` на одном листе; `DISCLOSURE` без `columns`/`lines`; `status = needs_check` с предупреждением о единицах. `result-osv-minimal.json` — `period_start`, `period_end`, `is_from_year_start`. Все примеры валидируются тестами контракта в трёх сервисах. ### D-3. §12 — текст решений владельца §12 переписывается по пунктам 1–8 с сохранением нумерации и добавлением п. 9 «Склейка листов и страниц», п. 10 «Статус документа и книги», п. 11 «Что отложено» (запасной путь по именам, нормализация единиц, признак продолжения). Формулы §7 остаются в §7; в §12 п. 7 — ссылка и правило «жёсткие/мягкие, допуск ±1, двойной расчёт знаков». Текст решений — из brainstorming 06.10.2026 (вопросы 2–6) и design дочернего change (D-2…D-8). ### D-4. Порядок раскатки docs (этот change) → bounded-PR в arm-core и scan-gateway «копия схемы v1.2 + модели, без логики» → tabular-parser (производитель 1.2) → fixtures (golden). Тест идентичности в сервисах пропускается только при недоступном docs, поэтому между мержем docs и мержем копий тесты сервисов на main падают; окно минимизируется одновременным открытием PR. ## Decisions made without discussion | № | Дата | Решение | Обоснование | Цена ошибки | |---|---|---|---|---| | 1 | 2026-10-06 | `checks` форм — отдельная структура, не переиспользование `osvDocument.checks` | у форм нарушения по колонкам и соотношениям, у ОСВ — по строкам | поле остаётся необязательным | | 2 | 2026-10-06 | `expected`/`actual` в нарушении — `money` (строка с двумя знаками), не число | единый тип денег контракта | смена типа — MAJOR, поэтому сразу строка | | 3 | 2026-10-06 | `is_from_year_start` — отдельное поле, `is_cumulative` не переопределяется | `is_cumulative` ядро уже трактует по OQ-02/124; новое поле не ломает семантику | два похожих поля | | 4 | 2026-10-06 | Пример `result-statement-excel.json` со статусом `needs_check` и `DISCLOSURE` | иллюстрирует все новые элементы одним файлом | нет |