2026-11-06 20:27:38 +04:00

204 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# КФО: §8, DBML v5.26, контракт API — план
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** к утру 09.11.2026 дать Цыганкову (AURORA-1546) и Степанову (AURORA-1547) правила §8 «КФО», модель v5.26 и
контракт API КФО, по которым расчёт и экран строятся параллельно.
**Architecture:** только документы репозитория `arm-ka-docs`. §8 — алгоритм; DBML — что хранится; контракт — что
отдаёт и принимает API; OpenSpec-delta — требования в форме SHALL/сценариев. Числа сквозного примера §8 и `examples`
контракта — одни и те же, считаются одним скриптом в scratchpad, чтобы не разойтись.
**Tech Stack:** Markdown, DBML, OpenAPI 3.1 (YAML), OpenSpec 1.13.1, `make check`.
**Spec:** `openspec/changes/kfo-calculation-contract/design.md`, `proposal.md`.
Все пути — от корня worktree `/Users/andrey.epifancev/projects/awp-ca/.wt/kfo-contract/docs`; команды — из него.
## Global Constraints
- Результат КФО — тыс. руб., строки с двумя знаками; ОСВ и агрегаты — рубли; float нет.
- `cleaned_amount = client_amount − vgo_amount`; `bank_amount = sum_amount − vgo_amount + goodwill_adjust` — на всех строках.
- Строки расходов, приводимые к `−|x|`: 2120, 2210, 2220, 2330, 2350.
- Новый режим правила: `min_or_full`; правило 2 seed v1: `article_2_line: "1310/1350/1370"`.
- Новые поля: `kfo_result_line_company.client_amount`, `.vgo_amount`; `kfo_result.warnings`, `corrections_count_bb`,
`corrections_count_ofr`, `corrections_amount_bb`, `corrections_amount_ofr`; `audit_action.KFO_EDIT`.
- Коды предупреждений: `FORM_MISSING`, `FORM_AMBIGUOUS`, `FORM_UNITS_UNKNOWN`, `LINE_OUTSIDE_BLANK`, `UNALLOCATED_ROWS`,
`INCOME_RULES_MISSING`, `GOODWILL_NOT_APPLIED`, `GOODWILL_ROW_REASSIGNED`.
- Эндпоинты: `GET /api/v1/consolidations/versions/{version_id}/kfo` (`KFO_VIEW`),
`PUT …/kfo/annotations` (`CONSOLIDATION_EDIT`); ошибка `UNKNOWN_LINE`; `units = "thousand_rub"`.
- Новые открытые вопросы — с OQ-180 (177 и 179 заняты открытыми PR #195 и #203).
- Версия модели — v5.26; v5.25 — PR #203 (если слит до нас — строим поверх него, см. design §3).
- `docs/source/**` не трогать. Язык — русский; маркеры решений — `R-n` с номером design-таблицы.
## Review Focus
1. Агрегат с корректировкой, у которого и автосумма > 0 — исключение ровно одно (корректировка), не сумма двух.
2. Пара гудвилла с `G ≤ 0` или выключенным `goodwill_enabled` — обычный агрегат правила 2, строка `GOODWILL` = 0.
3. Расходная строка 2120 положительной в форме одной компании и отрицательной в другой — после приведения Σ по 2120 и
итог 2100 сходятся.
4. Каскад правила 2 при нехватке остатка 1310 и 1350 — остаток целиком на 1370, Σ исключений ДО = исключению ГО 1170.
5. Версия без форм у части компаний — КФО считается, компания с нулями, `FORM_MISSING` в `warnings`.
Каждый пункт — числом в сквозном примере §8 (Task 1) и в одном из `examples` контракта (Task 3).
---
### Task 1: §8 «КФО», §8 «Корректировка», открытые вопросы
**Files:**
- Modify: `context/05-domain-rules.md` — §8: блок «КФО» заменить; блоки «Корректировка», «Гудвилл» («КФО» в конце),
«Пороги» — привести; §5 п. 1 — строка о режиме `min_or_full`.
- Modify: `context/07-open-questions.md` — OQ-180…: открытые вопросы КФО.
- Create (scratchpad, не в репо): `/private/tmp/claude-501/-Users-andrey-epifancev-projects-awp-ca/38dca83c-0de5-4c8e-b11b-50b6f660f3f7/scratchpad/kfo_example.py`
**Interfaces:**
- Produces: числа сквозного примера (компании «Альфа», «Бета», «Гамма»; таблица исключений, строки 1170, 1230, 1310,
1350, 1370, 1520, 1100, 1300, 1600, 1700, `GOODWILL`, 2110, 2120, 2100; пороги) — Task 3 копирует их в `examples`.
- [ ] **Step 1: Скрипт сквозного примера.** `kfo_example.py` на `Decimal`: три компании, агрегаты — правило 6
(«Альфа» → «Бета» в допуске 2 %; «Бета» → «Альфа» 20 % с корректировкой, у которой автосумма была бы 0, и ещё один
агрегат 6 в допуске 3 % с корректировкой, где итоги сторон 100/90 — проверка «меньшего»); правило 2 «Альфа» → «Бета»
с гудвиллом (ФВ, УК, d, P, G > 0); правило 2 «Альфа» → «Гамма» без пары на стороне 2 (`min_or_full` → `amount_1`)
с нехваткой 1310/1350 — каскад на 1370; ОФР-агрегат 2110 «Альфа» / 2120 «Бета» (у «Беты» 2120 положительное в форме);
«Гамма» без ОФР — `FORM_MISSING`. Скрипт печатает таблицы строк по компаниям и итоги, пороги ББ/ОФР.
Assert внутри скрипта: `bank(1600) == bank(1700)`; Σ исключений ДО по правилу 2 = исключению ГО 1170; Σ `vgo`
строки 2100 = 0; у агрегата с корректировкой в `vgo` нет автосуммы.
- [ ] **Step 2: Прогнать скрипт.** Run: `python3 -I <scratchpad>/kfo_example.py` — Expected: таблицы печатаются, ни
одного `AssertionError`.
- [ ] **Step 3: Переписать блок «КФО» §8** по design §4.1 п. 1–12 (единицы, строки и редакция бланка, «по данным
клиента» и знак расходов, агрегаты, таблица режимов и каскад, корректировка вместо автосуммы, `vgo` и округление,
строка и итоги, гудвилл, расхождения, пороги, реквизиты, пересчёт и заморозка, предупреждения и их хранение), со
ссылками на источники (DOC-274230, DOC-259025, DOC-272613, DOC-274636) и пометками «на старте — вариант N, решает
заказчик (OQ-nnn)». Сквозной пример — числами из Step 2. Отдельным абзацем — прогон на РБ 01.10.2024 (66н) и
ожидаемое расхождение с эталоном по OQ-155.
- [ ] **Step 4: Привести соседние блоки §8 и §5.** «Корректировка»: агрегат `min_or_full` — `eliminated_amount`,
`exceeds_threshold = false`, статусы `AUTO` / `ONE_SIDED`; одна функция автосуммы для таблицы корректировок и КФО;
«в КФО по выбранным статьям уходит меньшая сумма» — раскрыть по design п. 5. «Гудвилл», абзац «КФО» — ссылка на
новый блок, ветка по паре независимо от агрегата, `GOODWILL` в 1100/1600. «Пороги» — заменить ссылкой на новый блок
(дубли формул убрать). §5 п. 1 — `mode = min_or_full` в псевдокоде.
- [ ] **Step 5: OQ-180… в `07-open-questions.md`.** По одному вопросу на развилку design, которую решает заказчик:
строки вне бланка; состав колонок; значение без формы; итоговая строка; округление; место строки гудвилла;
совокупный объём расхождений; ЧА — 1300 или расчёт; нулевая база порога; действие при превышении; «подход» по
Методике; согласование клиентом; пересчёт автоматически или по кнопке; правило 1 автоматически (follow-up seed). В
каждом — источник, «допущение принято: вариант …», ссылка на §8.
- [ ] **Step 6: Проверка.** Run: `grep -n "eliminated_auto (Σ сумм элиминации троек" context/05-domain-rules.md` —
Expected: пусто (старая формула удалена). Run: `grep -c "OQ-18[0-9]" context/07-open-questions.md` — Expected: ≥ 10.
- [ ] **Step 7: Commit**
```bash
git add context/05-domain-rules.md context/07-open-questions.md
git commit -m "КФО: §8 под DOC-274230/259025/272613, открытые вопросы OQ-180… (#206)"
```
### Task 2: DBML v5.26 и ссылки на версию
**Files:**
- Create: `model/data-model-v5.26.dbml` (копия v5.24 или v5.25 — см. Global Constraints), `model/entities-v5.26.md`.
- Modify: `Makefile:9`, `openspec/config.yaml:4,9`, `context/00-workspace-layout.md`, `context/03-architecture.md`,
`context/04-data-model-guide.md`, `context/08-source-docs-index.md`, `context/KICKOFF-PROMPT.md`,
`repo-templates/arm-core.CLAUDE.md`, `analyst/eliminations-vgo.md` — ссылки v5.24 → v5.26, где речь о текущей версии.
- Modify (если `npx` есть): `model/diagrams/part08_corrections_kfo.{svg,png}` через `make diagrams`.
**Interfaces:**
- Consumes: формулировки полей из Task 1 (§8).
- Produces: имена колонок и enum — ровно как в Global Constraints; Task 3 на них ссылается.
- [ ] **Step 1: Скопировать модель и записать changelog v5.26** в шапку: 1) `kfo_result_line_company` + `client_amount`,
`vgo_amount`; 2) `kfo_result` + `warnings jsonb`, четыре поля сводки корректировок; 3) `audit_action.KFO_EDIT`;
4) `elimination_mode` — значение `min_or_full`; 5) пояснения `kfo_result_line` по §8 (без изменения структуры);
6) миграция — одна в arm-core, AURORA-1546, все новые колонки nullable, откат удаляет колонки, `KFO_EDIT` при
наличии событий не откатывается (как `FILE_REPROCESS` в v5.21).
- [ ] **Step 2: Правки таблиц и enum** по design §4.2 — `note` каждого поля ссылается на §8 п. N.
- [ ] **Step 3: `entities-v5.26.md`** — копия с правками разделов `kfo_result`, `kfo_result_line`,
`kfo_result_line_company`, `audit_event`, `elimination_rule`; шапка — v5.26.
- [ ] **Step 4: Ссылки на текущую версию** в файлах из списка; в `04-data-model-guide.md` — абзац «v5.26».
- [ ] **Step 5: Проверка.** Run: `grep -rn "v5\.24" Makefile openspec/config.yaml context/00-workspace-layout.md context/04-data-model-guide.md`
— Expected: только исторические упоминания («v5.24: таблица vgo_assignment»), не «текущая». Run:
`grep -n "client_amount\|KFO_EDIT\|min_or_full\|corrections_count_bb" model/data-model-v5.26.dbml` — Expected: все
четыре найдены. Если есть `npx`: `make diagrams` — Expected: без ошибок, diff `part08_*`.
- [ ] **Step 6: Commit**
```bash
git add model/ Makefile openspec/config.yaml context/ repo-templates/ analyst/
git commit -m "DBML v5.26: разрез КФО по компании, предупреждения и аудит КФО, режим min_or_full (#206)"
```
### Task 3: Контракт API КФО и правка контракта корректировок
**Files:**
- Create: `dev/api-contract-kfo.md`, `dev/api-contract-kfo.openapi.yaml`.
- Modify: `dev/api-contract-corrections.md` — агрегат `min_or_full`; `dev/frontend-api-guide.md` — строка-ссылка на
контракт КФО в оглавлении контрактов.
**Interfaces:**
- Consumes: числа Task 1 Step 2; имена полей Task 2.
- Produces: схемы `KfoResultOut`, `KfoLineOut`, `KfoLineCompanyOut`, `KfoSummaryOut`, `KfoRequisitesOut`,
`KfoWarningOut`, `KfoAnnotationsIn`, `KfoCommentIn` — их берёт 1547 как фейк и 1546 как схему ответа.
- [ ] **Step 1: `api-contract-kfo.md`** — структура как у `api-contract-goodwill.md`: 1 «Общее» (права `KFO_VIEW` /
`CONSOLIDATION_EDIT`, тыс. руб. и `units`, порядок проверок правок), 2 «Понятия» (кратко со ссылками на §8 п. N, без
повторения формул), 3 «Эндпоинты» (таблица design §4.3, `GET` и `PUT` подробно: пересчёт при чтении, заморозка,
`null` очищает, лимиты 2000/4000, `UNKNOWN_LINE`, аудит `KFO_EDIT`), 4 «Схемы» (поля с типами и смыслом), 5 «Состояния
экрана DOC-274647 → поля ответа», 6 «Примеры» — три ответа (обычный; превышение порога ББ с гудвиллом; замороженный),
сокращённые до строк сквозного примера, 7 «Открытые вопросы» — ссылки на OQ-180….
- [ ] **Step 2: `api-contract-kfo.openapi.yaml`** — OpenAPI 3.1, два пути, схемы из Interfaces, `examples` из Step 1
(полные JSON), коды ошибок как в design §4.3; деньги — `type: string, pattern: '^-?\d{1,16}\.\d{2}$'`, `nullable`
через `type: [string, "null"]`.
- [ ] **Step 3: Валидация OpenAPI.** Run:
`uv run --with openapi-spec-validator python -I -c "from openapi_spec_validator import validate; from openapi_spec_validator.readers import read_from_filename; validate(read_from_filename('dev/api-contract-kfo.openapi.yaml')[0]); print('ok')"`
— Expected: `ok`. Плюс: каждый `example` проходит свою схему — тот же запуск с `jsonschema` по
`components.schemas.KfoResultOut` (скрипт в scratchpad) — Expected: `ok` для трёх примеров.
- [ ] **Step 4: Контракт корректировок.** В `api-contract-corrections.md` §2/§3.1: для правила с `elimination_mode =
min_or_full` — `eliminated_amount` по §8, `exceeds_threshold = false`, статус `AUTO` / `ONE_SIDED`; сноска «изменение
кода — AURORA-1546». Проверить, что в `api-contract-corrections.openapi.yaml` описание поля `status` / `eliminated_amount`
не противоречит (поправить описание, не схему).
- [ ] **Step 5: Commit**
```bash
git add dev/
git commit -m "КФО: контракт API (dev/api-contract-kfo.*), агрегат min_or_full в контракте корректировок (#206)"
```
### Task 4: OpenSpec-delta, проверка, PR, вложения в Jira
**Files:**
- Create: `openspec/changes/kfo-calculation-contract/specs/arm-core/spec.md`, `openspec/changes/kfo-calculation-contract/tasks.md`.
- [ ] **Step 1: Spec delta** — `## ADDED Requirements` в capability `arm-core`: «Расчёт КФО версии» (сценарии: агрегат
с корректировкой; гудвилл G > 0 и G ≤ 0; каскад правила 2; форма отсутствует; приведение знака расходов),
«Чтение результата КФО» (пересчёт при чтении, заморозка), «Ручные поля КФО» (сохранение, `null` очищает,
`UNKNOWN_LINE`, аудит `KFO_EDIT`), «Автосумма агрегата min_or_full» (таблица корректировок и КФО совпадают).
`tasks.md` — четыре задачи этого плана с отметками.
- [ ] **Step 2: Проверка репозитория.** Run: `make validate-openspec CHANGE=kfo-calculation-contract` — Expected: valid.
Run: `make check` — Expected: все цели зелёные.
- [ ] **Step 3: Финальное ревью ветки** (сабагент opus, только чтение): §8 ↔ DBML ↔ контракт — одни имена и числа;
Review Focus 1–5 покрыты; ни одной развилки заказчика без пометки. Находки `C-n/I-n/M-n` — исправить или
`deferred` в design.md.
- [ ] **Step 4: Push и PR** — `git push -u origin feat/206-kfo-contract`; `tea pulls create --login home --repo
RSHB/arm-ka-docs --head feat/206-kfo-contract --base main` с описанием: что и зачем, Closes #206, порядок с #203,
«Rulings» (design §6), таблица находок. Merge — только по команде владельца.
- [ ] **Step 5: Вложения в Jira** — пакет `batch_create`: AURORA-1546 — `context/05-domain-rules.md`,
`model/data-model-v5.26.dbml`; AURORA-1547 — `dev/api-contract-kfo.md`, `dev/api-contract-kfo.openapi.yaml`;
в обе — комментарий голосом владельца со ссылкой на PR (что смотреть: §8 «КФО» / контракт, открытые вопросы OQ-180…).
Expected: все команды пакета `done`.