OpenSpec: change slice-2a-osv-parser (контракт v1.1 rows[].extra, декомпозиция Среза 2, уточнения §1 — спека)

Issue: RSHB/arm-ka-docs#9

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
This commit is contained in:
Andrey Epifancev 2026-10-05 11:42:09 +04:00
parent 611db7fa41
commit d57b5bc378
5 changed files with 107 additions and 0 deletions

View File

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-05

View File

@ -0,0 +1,27 @@
# Design: Срез 2a (сквозное, docs)
## Context
См. proposal. Дизайн парсера — в дочернем change `tabular-parser/openspec/changes/slice-2a-osv-parser/design.md` (D-1…D-10).
## Decisions
### D-1. MINOR 1.1 вместо «складывать extra в columns»
`columns` — диагностика документа, а не строки; `extra` нужен построчно. Новое необязательное поле — MINOR по правилу
версионирования, схема v1.0 остаётся валидной для старых файлов. *Альтернатива* — ждать 2.0: парсер потеряет данные.
### D-2. Декомпозиция Среза 2 фиксируется в плане срезов
2a парсер ОСВ → 2b ББ/ОФР из Excel → 2c загрузка и маппинг в ядре (включая решения OQ-01/02/45/67/69/70) → 2d UI.
Каждый подсрез — свой набор change'ей и PR.
### D-3. Golden-снимки живут в fixtures, формат — файл результата без volatile-полей
Так снимки обновляются вместе с данными и видны всем сервисам; `job_id`, `file_id`, `service.version`, `duration_ms`
исключены, чтобы снимок зависел только от файла и кода парсера.
## Decisions made without discussion
| № | Дата | Решение | Обоснование | Цена ошибки |
|---|---|---|---|---|
| 1 | 2026-10-05 | D-1: контракт MINOR 1.1 с `rows[].extra` | §1.2; обратно совместимо | откат поля |
| 2 | 2026-10-05 | D-2: обозначения подсрезов 2a–2d в плане | владелец утвердил объём 2a, остальное — порядок по плану | переименовать |
| 3 | 2026-10-05 | D-3: формат и место golden | см. выше | перенос каталога |
| 4 | 2026-10-05 | Копия схемы v1.1 в arm-core — bounded-PR без логики, после merge docs и tabular-parser | тест идентичности в arm-core | нет |

View File

@ -0,0 +1,46 @@
# Proposal: Срез 2a (сквозное) — контракт результата v1.1, уточнения §1, фикстуры, OQ
**Срез:** 2, подсрез 2a «парсер ОСВ» (решение владельца 05.10.2026: сначала только парсер, без ББ/ОФР из Excel, ядра и UI).
**Репозиторий:** arm-ka-docs. **Issue:** RSHB/arm-ka-docs#9. **Дочерний change:** `tabular-parser/openspec/changes/slice-2a-osv-parser`
(RSHB/arm-tabular-parser#5). Фикстуры: RSHB/arm-ka-fixtures#4.
## Why
§1.2 требует «неизвестные колонки сохранять в `extra`, не терять», а в контракте v1.0 у строки ОСВ такого поля нет —
парсер не может выполнить правило без MINOR-версии контракта. Кроме того, после реального прогона на 66 файлах §1 и
06-test-data нужно привести к факту, а план срезов — к принятой декомпозиции Среза 2.
## What Changes
- **Контракт v1.1** (`docs/contracts/recognition-result.schema.json`): `osvDocument.rows[].extra` — объект
«заголовок колонки → текст ячейки или null» для колонок внутри таблицы, не сопоставленных с суммами и ИНН; `title`
и `description` `schema_version` — «1.1»; пример `examples/result-osv-minimal.json` дополняется `extra`; новый пример
`examples/result-osv-needs-check.json` (нарушение §1.4). Сообщение и запрос не меняются. Спека `recognition-contract`:
требование «Файл результата» — v1.1.
- **`05-domain-rules.md` §1**: уточнения по факту реализации (статусы и коды D-6, формула «стратегия иерархии в
`metrics.warnings` как `hierarchy=<имя>`», TOTAL в `rows`, лимиты парсера, словари по именам файлов), §1.5 — пометка
`ASSUMPTION(OQ-02)`.
- **`06-test-data.md`**: синтетика `osv/synthetic/` (перечень файлов и что проверяет каждый), golden `expected_osv_parse/`
(формат снимка, процесс обновления), xlsb вручную.
- **`09-delivery-plan.md`**: Срез 2 разбит на 2a (парсер ОСВ), 2b (ББ/ОФР из Excel), 2c (загрузка и маппинг в ядре),
2d (UI «Первичные документы»); `08-source-docs-index.md`/README без изменений.
- **`07-open-questions.md`**: новые OQ (коды валют для строк CURRENCY; поведение при нескольких ОСВ одного счёта в одной
книге), статус OQ-81 (закрыт хелпером), OQ-45/OQ-01/OQ-02 — пометка «допущение парсера, решение в 2c».
## Capabilities
### Modified Capabilities
- `recognition-contract`: «Файл результата» — v1.1 с `rows[].extra`; «Версионирование контракта» — без изменений
(MINOR по правилу).
## Impact
- Контракт: MINOR, обратно совместимо; копии обновляются в `tabular-parser` (в дочернем change) и `arm-core` (отдельный
bounded-PR: только файл схемы и `OsvRow.extra`, логики нет). Порядок merge: docs → tabular-parser → arm-core.
- Таблицы DBML: нет. Правила: §1 (уточнения без смены смысла), §1.5 (допущение).
## Non-goals
- §12 (ББ/ОФР из Excel) и `statementDocument` — не трогаются.
- Изменение семантики `is_cumulative`, `TOTAL`, `NU` в ядре — подсрез 2c (OQ-02, OQ-01, OQ-45).
- `audit_action` для статусов задания (OQ-55), дедуп по attempt (OQ-73).

View File

@ -0,0 +1,21 @@
# Spec Delta: recognition-contract
## MODIFIED Requirements
### Requirement: Файл результата
Файл результата SHALL соответствовать `docs/contracts/recognition-result.schema.json` v1.1: один файл (`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` остаются валидными.
#### Scenario: Результат валидируется примерами
- **WHEN** CI сервиса запускает тесты контракта
- **THEN** все файлы `docs/contracts/examples/result-*.json` проходят схему файла результата, а все
`request-*.json` / `result-message-*.json` — схемы сообщений
#### Scenario: Лишняя колонка сохранена
- **WHEN** в ОСВ между ИНН и суммами есть колонка «КПП»
- **THEN** у строк контрагентов `extra = {"КПП": "<значение>"}`, файл проходит схему v1.1 и схему v1.0 (поле
игнорируется)

View File

@ -0,0 +1,11 @@
# Tasks: Срез 2a (docs)
- [ ] 1.1 Контракт v1.1: `contracts/recognition-result.schema.json` (`rows[].extra`, title/description 1.1), примеры
`result-osv-minimal.json` (+`extra`, `schema_version 1.1`) и новый `result-osv-needs-check.json`; `openspec validate --strict`;
проверка схемой через `jsonschema` (скрипт в `dev/checks.md`, если есть, иначе вручную в отчёте).
- [ ] 1.2 `09-delivery-plan.md`: Срез 2 → подсрезы 2a–2d с составом каждого; `07-open-questions.md`: новые OQ (коды валют
CURRENCY-строк; несколько ОСВ одного счёта в книге), OQ-81 закрыт, пометки «допущение парсера» у OQ-01/02/45.
- [ ] 2.1 После реализации парсера (дочерний change, задачи 3.1–4.3): §1 `05-domain-rules.md` — статусы/коды, `hierarchy=<имя>`
в warnings, TOTAL в rows, лимиты, имена словарей; §1.5 — `ASSUMPTION(OQ-02)`; `06-test-data.md` — синтетика, golden,
xlsb; сверка: сценарии спеки `osv-parsing` ↔ пункты §1 (таблица в отчёте).
- [ ] 2.2 После merge дочернего change: `openspec archive slice-2a-osv-parser`; напоминание про bounded-PR копии схемы в arm-core.