From 42af56263523e776afddd2c895c1ebb3ac1e27e0 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Tue, 6 Oct 2026 22:41:10 +0400 Subject: [PATCH] =?UTF-8?q?openspec:=20=D0=B0=D1=80=D1=85=D0=B8=D0=B2=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=BD=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20change=20slice-2b-statement-parser=20(2026-10-06?= =?UTF-8?q?),=20recognition-contract=20=C2=AB=D0=A4=D0=B0=D0=B9=D0=BB=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82=D0=B0?= =?UTF-8?q?=C2=BB=20v1.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #26 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3 --- .../design.md | 0 .../proposal.md | 0 .../specs/recognition-contract/spec.md | 0 .../tasks.md | 0 openspec/specs/recognition-contract/spec.md | 26 ++++++++++++++++--- 5 files changed, 22 insertions(+), 4 deletions(-) rename openspec/changes/{slice-2b-statement-parser => archive/2026-10-06-slice-2b-statement-parser}/design.md (100%) rename openspec/changes/{slice-2b-statement-parser => archive/2026-10-06-slice-2b-statement-parser}/proposal.md (100%) rename openspec/changes/{slice-2b-statement-parser => archive/2026-10-06-slice-2b-statement-parser}/specs/recognition-contract/spec.md (100%) rename openspec/changes/{slice-2b-statement-parser => archive/2026-10-06-slice-2b-statement-parser}/tasks.md (100%) diff --git a/openspec/changes/slice-2b-statement-parser/design.md b/openspec/changes/archive/2026-10-06-slice-2b-statement-parser/design.md similarity index 100% rename from openspec/changes/slice-2b-statement-parser/design.md rename to openspec/changes/archive/2026-10-06-slice-2b-statement-parser/design.md diff --git a/openspec/changes/slice-2b-statement-parser/proposal.md b/openspec/changes/archive/2026-10-06-slice-2b-statement-parser/proposal.md similarity index 100% rename from openspec/changes/slice-2b-statement-parser/proposal.md rename to openspec/changes/archive/2026-10-06-slice-2b-statement-parser/proposal.md diff --git a/openspec/changes/slice-2b-statement-parser/specs/recognition-contract/spec.md b/openspec/changes/archive/2026-10-06-slice-2b-statement-parser/specs/recognition-contract/spec.md similarity index 100% rename from openspec/changes/slice-2b-statement-parser/specs/recognition-contract/spec.md rename to openspec/changes/archive/2026-10-06-slice-2b-statement-parser/specs/recognition-contract/spec.md diff --git a/openspec/changes/slice-2b-statement-parser/tasks.md b/openspec/changes/archive/2026-10-06-slice-2b-statement-parser/tasks.md similarity index 100% rename from openspec/changes/slice-2b-statement-parser/tasks.md rename to openspec/changes/archive/2026-10-06-slice-2b-statement-parser/tasks.md diff --git a/openspec/specs/recognition-contract/spec.md b/openspec/specs/recognition-contract/spec.md index b11c2b9..36c17ef 100644 --- a/openspec/specs/recognition-contract/spec.md +++ b/openspec/specs/recognition-contract/spec.md @@ -86,12 +86,19 @@ v1.0: обязательные поля `schema_version` (`"1.0"`), `job_id`, `f `RECOGNITION_FAILED`, `UNKNOWN_ERROR`); `result_s3` может отсутствовать ### Requirement: Файл результата -Файл результата SHALL соответствовать `docs/contracts/recognition-result.schema.json` v1.1: один файл (`stored_file`) +Файл результата SHALL соответствовать `docs/contracts/recognition-result.schema.json` v1.2: один файл (`stored_file`) → один `job_id` → массив `documents` из `osvDocument` и/или `statementDocument`; денежные значения — строки `^-?\d+(\.\d{1,2})?$`; `confidence` — 0–100. Пустой массив `documents` допустим только при `status = error`. У строки `osvDocument.rows[]` SHALL быть необязательное поле `extra` — объект «заголовок колонки → строка или null» для -колонок внутри таблицы, не сопоставленных с шестью суммами и ИНН (§1.2 «не терять»); потребители, не знающие поля, -игнорируют его (MINOR). Производитель v1.1 пишет `schema_version = "1.1"`; файлы v1.0 без `extra` остаются валидными. +колонок внутри таблицы, не сопоставленных с шестью суммами и ИНН (§1.2 «не терять»). У шапки `osvDocument.header` SHALL +быть необязательные `period_start`, `period_end` (дата или null — границы периода по шапке; для квартала и года — +первое и последнее число, для диапазона месяцев — его границы) и `is_from_year_start` (boolean или null; `is_cumulative` +не переопределяется). `statementDocument.document_type` SHALL допускать `DISCLOSURE` (расшифровка или иная форма +0710xxx: документ без `columns` и `lines`). У `statementDocument` SHALL быть необязательный объект `checks`: +`relations_failed` и `soft_relations_failed` — массивы `{column_index, relation, expected, actual}` (нарушенные +соотношения §7 по колонке; `expected`/`actual` — `money`), `duplicate_line_codes` — массив строк; отсутствие объекта +означает «не проверялось», пустые массивы — «проверено, сошлось». Потребители, не знающие новых полей и значений, +игнорируют их (MINOR). Производитель v1.2 пишет `schema_version = "1.2"`; файлы v1.0 и v1.1 остаются валидными. #### Scenario: Результат валидируется примерами - **WHEN** CI сервиса запускает тесты контракта @@ -100,9 +107,20 @@ v1.0: обязательные поля `schema_version` (`"1.0"`), `job_id`, `f #### Scenario: Лишняя колонка сохранена - **WHEN** в ОСВ между ИНН и суммами есть колонка «КПП» -- **THEN** у строк контрагентов `extra = {"КПП": "<значение>"}`, файл проходит схему v1.1 и схему v1.0 (поле +- **THEN** у строк контрагентов `extra = {"КПП": "<значение>"}`, файл проходит схему v1.2 и схему v1.0 (поле игнорируется) +#### Scenario: Форма из Excel с проверками +- **WHEN** tabular-parser разобрал книгу с балансом на двух листах, ОФР и пояснениями (`examples/result-statement-excel.json`) +- **THEN** файл проходит схему v1.2: `BALANCE` с `locator` из двух имён листов и `checks` с нарушением в + `soft_relations_failed`, `INCOME` с пустыми массивами `checks`, `DISCLOSURE` без `columns`/`lines`; тот же файл + без `checks` и с `document_type = OTHER` вместо `DISCLOSURE` проходит схему v1.1 + +#### Scenario: Границы периода ОСВ +- **WHEN** в шапке ОСВ период «Октябрь 2024 г. – Сентябрь 2025 г.» +- **THEN** `period_start = "2024-10-01"`, `period_end = "2025-09-30"`, `is_from_year_start = false`; файл проходит схему + v1.2, а потребитель v1.1 читает его без ошибок + ### Requirement: Версионирование контракта Поле `schema_version` SHALL быть строкой `MAJOR.MINOR`. Добавление необязательных полей или значений enum — `MINOR` (1.1, обратно совместимо); удаление/переименование полей, смена типов или семантики — `MAJOR` (2.0). -- 2.47.2