openspec(#116): sync-statements — режим --in-place, подключение копии к хостам, решения P2-n и R-n плана 2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
bb1b761c46
commit
7194b16471
@ -55,20 +55,20 @@ docker compose -f ../docs/dev/docker-compose.yml --project-name arm-ka run --rm
|
||||
| `tabular-parser` | `check` → `statements-check` → `test-integration` → `docker-build` (образ `tabular-parser`) |
|
||||
| `arm-core` | `check` → `statements-check` → `dbml-check` → `check-infra` → `test-integration` → `docker-build` → `web-check` |
|
||||
|
||||
`statements-check` появляется в сервисе вместе с копией пакета `arm_statements` (change `unified-statement-normalization`,
|
||||
шаги 3 и 5 выкладки); до этого цели нет.
|
||||
`statements-check` появляется в сервисе вместе с копией пакета (PR подключения хоста); до этого цели нет.
|
||||
|
||||
### Копия общего кода `arm_statements` и `sync-statements`
|
||||
|
||||
Общий код нормализации ББ/ОФР (`05-domain-rules.md` §11) живёт в репозитории `arm-statements` пакетом `arm_statements/`;
|
||||
в `arm-core`, `tabular-parser` и `scan-gateway` он лежит **копией** — прямые правки копии запрещены (Р-1, design
|
||||
`openspec/changes/unified-statement-normalization/design.md`). **Пока не реализовано:** скрипт, цель `make -C docs
|
||||
sync-statements` и цель `statements-check` сервисов появляются на шагах 1, 3 и 5 выкладки change
|
||||
`unified-statement-normalization`; раздел описывает целевое поведение (спека `statement-normalization`, требование
|
||||
«`sync-statements`…»).
|
||||
`openspec/changes/unified-statement-normalization/design.md`). Скрипт и цели docs (`make -C docs sync-statements`,
|
||||
`statements-check`, `test-sync-statements`) — arm-ka-docs#120; `statements-check` сервисов появляется с PR подключения
|
||||
копии в каждом хосте (план 2, задачи 7–9) — до шага 3 выкладки. Раздел описывает поведение по спеке
|
||||
`statement-normalization` (требование «`sync-statements`…»).
|
||||
|
||||
- **Где копия:** `api/arm_statements/` (рядом с `api/src/`; импорт `import arm_statements` — `api/` в `sys.path`, как для
|
||||
`src`). Пакет приносит свои тесты (`api/arm_statements/tests/`) и конфиг линтеров; `ruff`, `pytest` и `mypy` хоста
|
||||
`src`). Пакет приносит свои тесты (`api/arm_statements/tests/`); конфиг линтеров пакета в копию не кладётся — хост держит
|
||||
`arm_statements` в строгом блоке `mypy` и в `testpaths` (P2-1, P2-3); `ruff`, `pytest` и `mypy` хоста
|
||||
охватывают копию: `ruff` и `pytest` — по каталогу `api/` (тесты пакета подключены как `testpaths`), `mypy` — `MYPY_PATHS`
|
||||
хоста дополняется `arm_statements` (`mypy src arm_statements`, в `arm-core` — `mypy src scripts arm_statements`).
|
||||
- **Маркер версии:** `api/arm_statements/VERSION` — полный хэш коммита `arm-statements`, из которого разложена копия;
|
||||
@ -78,7 +78,11 @@ sync-statements` и цель `statements-check` сервисов появляю
|
||||
sync-statements SYNC_ARGS=…`. Источник — локальный checkout `arm-statements` рядом (`../arm-statements`) или
|
||||
`--source <dir>`, ссылка — `origin/main` или `--ref <ref>`; хост — `--host arm-core|tabular-parser|scan-gateway` или
|
||||
`--host-dir <dir>`. Без `--check` — раскладывает копию нужного коммита в новый worktree хоста на ветке фичи и пишет
|
||||
`VERSION`; issue и PR — как у `sync-web.sh`.
|
||||
`VERSION`; issue и PR — как у `sync-web.sh`; `--dry-run` — то же без issue, проверок, коммита и PR. С `--in-place` —
|
||||
раскладывает копию в рабочее дерево существующего worktree хоста без git-операций (подключение хоста; PR фичи,
|
||||
которой нужна новая версия пакета; при прямой правке копии или недостающей зависимости — отказ `20`, ничего не
|
||||
пишется). Обзор по трём хостам рядом — `make -C docs statements-check`; сборка снимка для контура
|
||||
(`prepare-contour-snapshot.sh`) вызывает `--check` для хостов, где копия уже есть (Р-42).
|
||||
- **`--check`, коды возврата** (файл `VERSION` в сравнении не участвует — в источнике его нет): `0` — копия равна дереву
|
||||
`arm_statements/` коммита из `VERSION`, это коммит `--ref`, и копия перечня кодов равна docs; `10` — копия равна дереву
|
||||
коммита из `VERSION`, но в `--ref` есть более новый (копия отстала), или байтовая копия перечня кодов
|
||||
|
||||
@ -1363,3 +1363,31 @@ line_name, line_name_confidence, parent_ref, values}`: `line_code` — разо
|
||||
140. **R-6 (план 1). История ветки feat/1-arm-statements-package переписана `git filter-branch --msg-filter`**: один коммит имел трейлер «Claude Sonnet 5.5» вместо требуемого «Claude Opus 5.5»; ветка не публиковалась. Цена: SHA коммитов в ledger/отчётах до переписи устарели.
|
||||
141. **R-7 (план 1). Решения исполнителей задач при пробелах спеки**: T6.2 (смешанные/повторные разделители суммы → цифры подряд ≤ 16 и `is_recognized=false`; excel допускает ≥ 3 знака после разделителя); T10.1–T10.4 (`SEGMENT_WITHOUT_CODES` только если столбец кодов найден хотя бы у одного сегмента; ослабленный поиск включается, когда строгий не нашёл и отрезок известен; сегмент двухстрочной повторной шапки открывается строкой с подписью кода; сопоставление по датам требует разных целевых колонок); T11.2 (сегмент без столбца кодов — наименование слева, значения по `value_cols` или правее наименования); T14.3–T14.4 (ничья без даты — `edition=None`, подтверждено в обеих; родитель пятизначного — ближайшая выше строка с нужным кодом, уверенная или подтверждённая); T15.2 («строгое большинство» знака = более 50 %). Ревью задач: со спекой не расходятся. Цена: перечисленные трактовки при пробелах спеки; пересмотр — правкой кода пакета и словарей.
|
||||
142. **R-8 (план 1). Расширение публичного API сверх раздела плана**: в `__all__` добавлены `Rules` (нужен хостам в сигнатурах) и `RulesError` (обработка `load_rules`); абзац про них — в README пакета. Цена: хосты могут зависеть от двух лишних имён.
|
||||
|
||||
**Решения плана 2 (sync-statements), 18.10.2026** (дорожка плана 2, ветка docs `feat/120-sync-statements`, arm-ka-docs#120; решения P2-n — автор плана, R-n — контроллер):
|
||||
|
||||
143. **P2-1 (O-1 плана 1).** Файл конфига линтеров в копию не кладётся; «конфиг пакета подключён к хосту» — это: ruff хоста уже совпадает с пакетом (`line-length = 120`, `py311`, `E F I UP B PL`), в isort `known-first-party` добавлен `arm_statements`; в `mypy` хоста модули `arm_statements.*` входят в строгий блок (те же флаги, что `strict = true` пакета). Цена: блок флагов повторён в трёх хостах; если хост когда-нибудь станет строже пакета, копия покраснеет в хосте — чинить в `arm-statements`.
|
||||
144. **P2-2 (O-2).** Пины `ruff==0.16.10`, `mypy==2.4.0`, `types-PyYAML==6.0.12.20260906` во всех хостах (у tabular-parser и arm-core были `>=`; в их окружениях уже стоят эти версии — пины ничего не переформатируют). `pytest` не закрепляется: тесты пакета не зависят от его версии. Цена: обновление ruff/mypy — согласованно, сначала пакет.
|
||||
145. **P2-3 (O-3).** `testpaths = tests arm_statements/tests` в `pytest.ini` хостов; `conftest` хостов не меняется: у них нет `api/conftest.py`, а `tests/conftest.py` действует только на `tests/`; `env`, `asyncio_mode`, `--strict-markers` тестам пакета не мешают. Проверка — равное число собранных тестов пакета в хосте и в `arm-statements`.
|
||||
146. **P2-4 (O-4).** Dockerfile хостов не меняется: `COPY api/ ./` уже кладёт `api/arm_statements/rules/*.yaml`, `.dockerignore` их не исключает; платформа уже возит `api/rules/*.yaml` и `api/contracts/` (сервисы читают их с диска в контуре). Проверка — запуск `default_rules()` в собранном образе (задачи 7–9).
|
||||
147. **P2-5.** Подключение хостов — три bounded PR этого плана (задачи 7–9), а не части планов 3/4/5: правки одинаковые и механические, план 3 уже ждёт «PR плана 2 в arm-core», первая раскладка проверяет скрипт на настоящих хостах, а планы 4/5 стартуют от `main` с копией. Цена: ещё три PR и копия в `main` хостов до того, как её вызывает код сервиса.
|
||||
148. **P2-6.** Режим `--in-place` (раскладка в существующий worktree без issue, коммита и PR) — для подключения хоста и для PR фичи, которой нужна новая версия пакета; спека дополнена (задача 6). Цена: второй путь раскладки, мимо отдельного PR синхронизации.
|
||||
149. **P2-7.** Скрипт — bash по образцу `sync-web.sh` (spec называет `sync-statements.sh`), разбор TOML/YAML — помощник `statements_check.py` (Python 3.11 + PyYAML); интерпретатор — `STATEMENTS_PY` → `docs/.venv` → `api/.venv` хоста → `python3`; подходящего нет — код `2`. Цена: `make venv` docs ставит PyYAML (как и в PR #117).
|
||||
150. **P2-8.** В `--check` отсутствие копии — `20` («копии нет»): хост, в котором вызывают проверку, обязан держать копию. В обычном режиме хост без копии — `2` с указанием на `--in-place`: подключение хоста — ручная задача с правкой конфигов.
|
||||
151. **P2-9.** Нет `contracts/statement-code-orders.yaml` в docs — `10` (docs старше пакета; так до слияния PR #117).
|
||||
152. **P2-10.** Зависимости сверяются по имени (PEP 503) с `api/requirements.txt` хоста (его ставит образ); разные версии — примечание, код не меняют. Цена: несовпадение версии PyYAML ловят только тесты пакета в хосте.
|
||||
153. **P2-11.** «Копия отстала» — буквально по спеке: `VERSION` ≠ `--ref`, даже если новые коммиты источника не трогают `arm_statements/` (README, Makefile). Цена: лишние предупреждения `10` после таких коммитов (см. O-1).
|
||||
154. **P2-12.** Ошибка `fetch` в `--check` не фатальна (предупреждение, сравнение с локальными ссылками): проверка перед PR не должна краснеть без сети, если копия на месте.
|
||||
155. **P2-13.** Сравнение — по файлам рабочего дерева (`diff -rq`), без `VERSION` и кэшей (`__pycache__`, `*.pyc`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.DS_Store`); биты режима не сравниваются. Незакоммиченная правка — тоже `20`.
|
||||
156. **P2-14.** Обычный режим перед коммитом гоняет `make venv` и `make check` хоста в новом worktree (как `sync-web.sh` — проверки фронта). Цена: минута на окружение.
|
||||
157. **P2-15.** «Сначала ядро» при синхронизации сервиса — предупреждение (в выводе и в описании PR), не отказ: порядок важен для смены формата результата, а не для каждой правки пакета.
|
||||
158. **P2-16.** `make -C docs statements-check` — обзор по трём хостам рядом (`0`/`10` — зелёные); в `make check` docs не входит: читает соседние репозитории.
|
||||
159. **P2-17.** Имя хоста — `--host` или последний компонент `origin` (`arm-core`, `arm-tabular-parser`, `arm-scan-gateway`), иначе имя каталога; сверка словаря имён — только у `arm-core`.
|
||||
160. **P2-18.** Раскладка отказывает (код 1), если файлы копии игнорируются `.gitignore` хоста или содержат то, на чём остановится снимок для контура (`/Users/`, `/home/…`, `git.aepif.ru`, `uv venv`, `uv pip`).
|
||||
161. **P2-19.** Строки `make venv` docs — дословно как в ветке `feat/116-unified-normalization`, строки таблицы `dev/checks.md`, которые меняет PR #117, не трогаются: два PR сливаются в любом порядке без конфликта.
|
||||
162. **P2-20.** В `CLAUDE.md` каждого хоста — правило «копию не править, обновлять скриптом»: агенты читают его первым. Шаблоны `docs/repo-templates/` не меняются (разошлись с репозиториями давно).
|
||||
163. **P2-21.** Ветка docs плана — от `origin/main` (шаг 1 выкладки раньше PR #117); спека, `design.md` и раздел «Копия» `dev/checks.md` правятся в `feat/116-unified-normalization` (задача 6).
|
||||
164. **R-1 (план 2). `make check` в docs красный по `validate-openspec`**: в Makefile `CHANGE ?= slice-0-skeleton`, change в архиве (O-1 плана 0); план 2 это не чинит. Цели проверялись по отдельности (`validate-contracts`, `test-snapshot`, `test-sync-web`, `test-sync-statements` — зелёные), в PR красный `validate-openspec` назван. Цена: `make check` остаётся красным до отдельной правки Makefile.
|
||||
165. **R-2 (план 2). Р-42 исполнен в этом плане (задача 5b)**: `prepare-contour-snapshot.sh` для каждого из трёх сервисов запускает `sync-statements.sh --check` по дереву `api` коммита `$REF` (`git archive` во временный каталог, `--host <имя>`): `0` — тихо; `10` — предупреждение и абзац в `SNAPSHOT.md`; `20` — стоп, код 1; `2` (нет источника или интерпретатора) — предупреждение, снимок делается; если в `$REF` нет `api/arm_statements` — проверка пропускается (пакет в хост ещё не подключён: иначе `20` «копии нет» блокировал бы снимок до задач 7–9). Цена: пока хост без копии, снимок о ней не напомнит; тест снимка требует Python ≥ 3.11 с PyYAML (`STATEMENTS_PY=$(PY)` в `test-snapshot`).
|
||||
166. **R-3 (план 2). Спека: «и его конфигом линтеров» убрано**: предложение спеки о копии «вместе с … конфигом линтеров» противоречило P2-1 (конфиг пакета в копию не кладётся, применяется конфиг хоста); исправлена спека и раздел «Копия общего кода» `dev/checks.md`. Цена: нет.
|
||||
167. **R-4 (план 2). Защиты раскладки липкие, копия при отказе защиты остаётся в дереве**: игнорируемые `.gitignore` файлы и пути контура (P2-18) проверяются и после раскладки, и при повторе `--in-place` с той же версией («раскладывать нечего» код 1, если копию нельзя коммитить); при коде 1 копия остаётся в дереве хоста, об этом сказано в сообщении. После `make check` хоста в обычном режиме `evaluate` повторяется (форматтеры могли переписать копию) — `20` блокирует коммит. Цена: после отказа защиты оператор сам убирает копию (`git checkout`/`clean`).
|
||||
|
||||
@ -62,7 +62,8 @@
|
||||
`examples/v<M>/<имя>.json`, если он есть, иначе с `examples/<имя>.json`; файлы другого MAJOR не сверяются. Правило
|
||||
проходит и до слияния шага 2 (файлов `.v1` ещё нет), и после; без него `make check` всех трёх краснеет между шагами 2
|
||||
и 3 (ядро) или 2 и 5 (сервисы).
|
||||
1. `arm-statements` — пакет с тестами; `sync-statements` в docs.
|
||||
1. `arm-statements` — пакет с тестами; `sync-statements` в docs; копия пакета подключается к хостам (линтеры,
|
||||
`testpaths`, `statements-check`) — код сервисов её ещё не вызывает.
|
||||
2. docs: контракт v2.0, DBML v5.19, правила (этот change).
|
||||
3. arm-core: **сначала очистка форм ББ/ОФР на контуре** (Р-24: владелец или платформенная команда по его заявке,
|
||||
после резервной копии БД — скрипт ядра `scripts/purge_statements.py`: `--dry-run` с отчётом, затем `--apply`; удаляются
|
||||
|
||||
@ -23,8 +23,8 @@ json dataclass-ы), шаги 2–8, общие разборы текста (дв
|
||||
|
||||
### Requirement: `sync-statements` — копии пакета в потребителях
|
||||
Копия пакета в хосте (`arm-core`, `tabular-parser`, `scan-gateway`) SHALL лежать в `api/arm_statements/` (рядом с
|
||||
`api/src/`, импорт `import arm_statements`) вместе с тестами пакета (`api/arm_statements/tests/`) и его конфигом
|
||||
линтеров; `ruff` и `pytest` хоста SHALL охватывать копию (тесты пакета — в `testpaths`), `mypy` хоста — запускаться и по
|
||||
`api/src/`, импорт `import arm_statements`) вместе с тестами пакета (`api/arm_statements/tests/`); конфиг линтеров пакета в копию не кладётся (применяется конфиг
|
||||
хоста); `ruff` и `pytest` хоста SHALL охватывать копию (тесты пакета — в `testpaths`), `mypy` хоста — запускаться и по
|
||||
ней (`mypy src arm_statements`, у `arm-core` — `mypy src scripts arm_statements`). Маркер версии — файл
|
||||
`api/arm_statements/VERSION` с полным хэшем коммита репозитория `arm-statements`, из которого разложена копия; его пишет
|
||||
только скрипт, сервис читает при старте и пишет в результат как `service.statements_version`. Прямые правки копии MUST
|
||||
@ -33,7 +33,10 @@ NOT делаться.
|
||||
Копию SHALL раскладывать и проверять скрипт `docs/scripts/sync-statements.sh` (по образцу `sync-web.sh`; цель `make -C
|
||||
docs sync-statements`). Источник — локальный checkout `arm-statements` рядом с workspace или `--source <dir>`, ссылка —
|
||||
`origin/main` или `--ref`; хост — `--host <имя>` или `--host-dir <dir>`. Без `--check` скрипт раскладывает копию коммита
|
||||
`--ref` в новый worktree хоста на ветке фичи, пишет `VERSION` и готовит issue и PR (как `sync-web.sh`). Копия
|
||||
`--ref` в новый worktree хоста на ветке фичи, пишет `VERSION` и готовит issue и PR (как `sync-web.sh`). С `--in-place` скрипт SHALL раскладывать
|
||||
копию коммита `--ref` в рабочее дерево указанного хоста (существующий worktree) без issue, коммита и PR — для
|
||||
подключения хоста и для PR фичи, которой нужна новая версия пакета; при прямой правке копии или недостающей зависимости —
|
||||
отказ с кодом `20`, ничего не пишется. Копия
|
||||
сравнивается с деревом `arm_statements/` источника без файла `VERSION` (его в источнике нет). `--check` SHALL
|
||||
возвращать: `0` — копия равна дереву `arm_statements/` коммита из `VERSION`, это коммит `--ref`, и копия перечня кодов
|
||||
в пакете равна `docs/contracts/statement-code-orders.yaml`; `10` — копия равна дереву коммита из `VERSION`, но в
|
||||
@ -78,6 +81,11 @@ PR в `arm-statements` (байтовая копия yaml) → `sync-statements`
|
||||
- **WHEN** в `arm-core/api/rules/statement_lines.yaml` редакции `fsbu4` есть код 1120, а в перечне `fsbu4` его нет
|
||||
- **THEN** `--check` в `arm-core` завершается с кодом 20 и называет код и редакцию
|
||||
|
||||
#### Scenario: Копия в PR фичи
|
||||
- **WHEN** PR scan-gateway нужна версия пакета новее, чем в `main` хоста
|
||||
- **THEN** `sync-statements.sh --in-place --host-dir .` в worktree фичи раскладывает копию и пишет `VERSION`, копия
|
||||
коммитится отдельным коммитом этого PR; `--check` после раскладки — `0`
|
||||
|
||||
#### Scenario: Версия общего кода в результате
|
||||
- **WHEN** сервис собирает результат копией пакета, у которой в `VERSION` коммит `abc1234` репозитория `arm-statements`
|
||||
- **THEN** в результате `service.statements_version = "abc1234"`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user