diff --git a/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-4-tabular-parser.md b/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-4-tabular-parser.md index e74010a..dc9ae2f 100644 --- a/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-4-tabular-parser.md +++ b/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-4-tabular-parser.md @@ -35,7 +35,7 @@ |---|---|---| | 0 | тест идентичности копий контракта по MAJOR (в т. ч. tabular-parser) | слит в tabular-parser **до** задачи 7: без него копия схем v2.0 не сверяется с docs | | 1 | пакет `arm_statements` (репозиторий `arm-statements`) | API — источник имён этого плана; копия пакета приходит в tabular-parser через план 2 | -| 2 | `sync-statements`: копия в `api/arm_statements/`, подготовка хоста | PR плана 2 в tabular-parser слит **до** задачи 3; задача 2 сверяет и доделывает подготовку хоста | +| 2 | `sync-statements`: копия в `api/arm_statements/`, подготовка хоста (его задача 8) | PR задачи 8 плана 2 в tabular-parser слит **до старта**; задача 2 этого плана только сверяет и при нужде обновляет копию `--in-place` | | 3 | arm-core части А и Б: приём 2.0 | PR этого плана **сливается** только после выкладки ядра, принимающего 2.0 (`proposal.md`, шаг 5) | | docs PR #117 | контракт v2.0, правила | до слияния — отсоединённый worktree docs на `origin/feat/116-unified-normalization`; после — на `origin/main` | @@ -51,7 +51,8 @@ - **П-2.** Зеркальный workspace `$WS/.wt/normalization-tp/` (`$WS` = `/Users/andrey.epifancev/projects/awp-ca`; `00-workspace-layout.md`, «Worktree вместо веток»): worktree `tabular-parser/` (ветка фичи), worktree `fixtures/` (ветка фичи fixtures — golden пишется сюда, поэтому **не** симлинк), отсоединённый worktree `docs/` (в нём не - коммитится), симлинки `reference-old-arm`, `CLAUDE.md`, `.claude`, `arm-statements` (источник для `statements-check`): + коммитится), симлинки `reference-old-arm`, `CLAUDE.md`, `.claude` (источник `arm-statements` скрипт плана 2 находит + сам — `$WS/arm-statements`): ```bash WS=/Users/andrey.epifancev/projects/awp-ca; M=$WS/.wt/normalization-tp @@ -62,7 +63,7 @@ git -C $WS/fixtures fetch origin git -C $WS/fixtures worktree add -b tmp/statements-v2-golden $M/fixtures origin/main git -C $WS/docs fetch origin git -C $WS/docs worktree add --detach $M/docs origin/feat/116-unified-normalization -for l in reference-old-arm CLAUDE.md .claude arm-statements; do ln -s $WS/$l $M/$l; done +for l in reference-old-arm CLAUDE.md .claude; do ln -s $WS/$l $M/$l; done git -C $M/tabular-parser branch -m feat/-statements-v2 git -C $M/fixtures branch -m feat/-statements-v2-golden cd $M/tabular-parser && codegraph init && make venv @@ -71,9 +72,9 @@ cd $M/tabular-parser && codegraph init && make venv - **П-3.** В тексте плана `$T` = `/Users/andrey.epifancev/projects/awp-ca/.wt/normalization-tp/tabular-parser`, `$F` = `…/normalization-tp/fixtures`, `$D` = `…/normalization-tp/docs`. Команды `make` — из `$T`, backend — из `$T/api`, git — `git -C <путь>`. Перед правкой исполнитель вызывает `codegraph_explore` с `projectPath` = `$T`. -- **П-4.** Проверить: в `$T` есть `api/arm_statements/__init__.py` и `api/arm_statements/VERSION` (план 2) и - `api/tests/contract_identity.py` (план 0). Нет копии пакета — стоп и вопрос владельцу (копию раскладывает только - `sync-statements`, не агент руками). Нет плана 0 — задачи 1–6 можно вести, задача 7 ждёт. +- **П-4.** Проверить: в `$T` есть `api/arm_statements/__init__.py` и `api/arm_statements/VERSION` (PR задачи 8 плана 2 + слит) и `api/tests/contract_identity.py` (план 0). Нет копии пакета — стоп и вопрос владельцу (подключение копии — + PR плана 2, не этого плана; руками копию не раскладывать). Нет плана 0 — задачи 1–6 можно вести, задача 7 ждёт. - **П-5.** После слияния docs PR #117: `git -C $D checkout --detach origin/main`. ## Global Constraints @@ -143,8 +144,7 @@ cd $M/tabular-parser && codegraph init && make venv ``` tabular-parser/ ├── openspec/changes/unified-normalization-tp/ # задача 1: proposal, tasks, дельты трёх спек -├── Makefile, api/pyproject.toml, api/pytest.ini, # задача 2: подготовка хоста (план 2) -│ api/requirements-dev.txt, .dockerignore +├── api/arm_statements/** # копия пакета (план 2); задача 2 — только --in-place при нужде ├── api/contracts/** # задача 7: копия docs/contracts v2.0 (без .v1 и examples/v1) ├── api/src/contract/{common,request,result,__init__}.py # задача 7: модели v2.0 ├── api/src/parser/ @@ -217,47 +217,44 @@ git -C $T commit -m "openspec: change unified-normalization-tp — адапте --- -### Task 2: Подготовка хоста (по плану 2 — сверить с планом 2) +### Task 2: Подготовка хоста — сверка с планом 2 и свежесть копии -Модель исполнителя: haiku (конфигурация по списку). +Модель исполнителя: haiku (проверки по списку). -План 2 (`plans/2026-10-18-plan-2-sync-statements.md`) на момент написания этого плана ещё не готов: пункты ниже — -ожидаемый состав. Исполнитель сначала сверяет каждый пункт с планом 2 и с `main` tabular-parser; уже сделанное планом 2 -не повторяет, расхождение формулировок — находка `O-n` в отчёт, решает план 2. +Подготовку хоста делает план 2 (`plans/2026-10-18-plan-2-sync-statements.md`, задача 8 «tabular-parser — подключение +копии»; раздел «Что должны включить планы 3, 4, 5»), и её PR слит до старта (П-4). Эта задача только сверяет `main` +с планом 2 и, если пакету нужна версия новее, обновляет копию скриптом. Недостающее из списка ниже — **не** доделывать +здесь, а остановиться и сообщить контроллеру (находка `O-n`: правка подключения — PR плана 2). **Files:** -- Modify: `$T/Makefile` (`lint`, `check-full`, цель `statements-check`), `$T/api/pytest.ini` (`testpaths`), - `$T/api/pyproject.toml` (`known-first-party`), `$T/api/requirements-dev.txt` (пины), `$T/.dockerignore` +- Modify (только если нужна новая версия пакета): `$T/api/arm_statements/**` — скриптом, руками не править **Interfaces:** -- Produces: `make lint` проверяет `mypy src arm_statements`; `make test` запускает `arm_statements/tests`; - `make statements-check` (`$(ARM_KA_DOCS)/scripts/sync-statements.sh --check --host-dir .`, `ARM_KA_DOCS ?= ../docs`) - входит в `check-full`, не в `check`. +- Consumes (из плана 2): `make lint` → `mypy src arm_statements`; `api/pytest.ini` `testpaths` с `arm_statements/tests`; + `known-first-party = ["src", "arm_statements"]`; строгий блок `[[tool.mypy.overrides]]` для `arm_statements.*`; + пины `ruff==0.16.10`, `mypy==2.4.0`, `types-PyYAML==6.0.12.20260906`; цель `statements-check` в `check-full`, не в + `check`; `.dockerignore` и `Dockerfile` не менялись (словари копии попадают в образ через `COPY api/ ./`). +- Produces: копия, в API которой есть все имена раздела Global Constraints. -- [ ] **Step 1: Сверка** — `api/arm_statements/VERSION` есть и это 40 hex-символов; `PyYAML==6.0.3` в - `api/requirements.txt` (есть); `conftest.py` без `autouse` вне `tests/` (сейчас `autouse` нет — оставить). -- [ ] **Step 2: Правки (только недостающее):** - - `api/pytest.ini`: `testpaths = tests arm_statements/tests`; - - `api/pyproject.toml`: `[tool.ruff.lint.isort] known-first-party = ["src", "arm_statements"]`; - - `Makefile`: в `lint` — `$(BIN)/mypy src arm_statements`; `ARM_KA_DOCS ?= ../docs`; цель `statements-check`; - `check-full: check statements-check test-integration docker-build`; цель в `.PHONY`; - - `api/requirements-dev.txt`: `ruff==0.16.10`, `mypy==2.4.0`, `pytest==9.1.1` (пины пакета, P1-2; если план 2 решил - иначе — как в плане 2); - - `.dockerignore`: `api/arm_statements/tests` (словари `api/arm_statements/rules/*.yaml` в образ попадают — - `COPY api/ ./`). -- [ ] **Step 3: Проверка** +- [ ] **Step 1: Сверка подключения** — каждый пункт Consumes есть в `$T` (`grep` по `Makefile`, `api/pytest.ini`, + `api/pyproject.toml`, `api/requirements-dev.txt`); `api/arm_statements/VERSION` — 40 hex-символов. +- [ ] **Step 2: Свежесть и API копии** -Run: `cd $T && make venv && make check && make statements-check; echo "exit=$?"` -Expected: `make check` зелёный, в выводе pytest есть `arm_statements/tests/…` PASSED; `statements-check` — `exit=0` или -`exit=10` с предупреждением «копия отстала» (зелёная). +Run: `cd $T && make statements-check; cd api && .venv/bin/python -c "import arm_statements as a; print(a.statements_version()); [getattr(a, n) for n in ('Rules','default_rules','Cell','Evidence','HeaderCells','FormCandidate','Source','DocumentType','StatementWarning','normalize_candidate','envelope_status','make_warning','type_hint','continuation_type','sheet_joins','parse_code','parse_date','parse_amount','parse_header','to_jsonable','statements_version')]"` +Expected: `statements-check` — `0` или `10`; хэш печатается, `AttributeError` нет. -- [ ] **Step 4: Commit** +- [ ] **Step 3 (только при `10` «копия отстала» или нехватке имени):** обновить копию в worktree фичи + +Run: `cd $T && ../docs/scripts/sync-statements.sh --in-place --host-dir . && make check` +Expected: `statements-check tabular-parser: 0`; `make check` зелёный. ```bash -git -C $T add Makefile api/pytest.ini api/pyproject.toml api/requirements-dev.txt .dockerignore -git -C $T commit -m "build: копия arm_statements в lint, test и statements-check (#)" +git -C $T add api/arm_statements +git -C $T commit -m "chore(arm_statements): копия пакета arm-statements@ (#)" ``` +- [ ] **Step 4: Базовая проверка** — `cd $T && make check` зелёный, в выводе pytest есть `arm_statements/tests/…`. + --- ### Task 3: Ячейка Excel → `Cell`: ссылка, текст по формату, сетка @@ -1094,8 +1091,9 @@ tea pulls create --login home --repo RSHB/arm-tabular-parser --head feat/ - **O-9.** Порог слабого продолжения (`min_codes_continuation: 1` в словаре tabular-parser) в словарь пакета не перенесён; адаптер использует 1 и `code_ranges.min_codes` как границы «1–2 кода». Если порог должен быть данными — ключ в `statement_code_ranges.yaml`. -- **O-10.** План 2 на момент написания не готов: задача 2 перечисляет ожидаемую подготовку хоста (пины, `testpaths`, - `mypy src arm_statements`, `statements-check`, `.dockerignore`) — сверить с планом 2, решает он. +- **O-10.** Сверено с планом 2 (появился в ветке во время написания): подготовку хоста делает его задача 8, задача 2 + этого плана сведена к сверке и `--in-place`; `.dockerignore` не меняется (план 2: «`api/arm_statements` не добавлять в + `.dockerignore`» — тесты копии попадают в образ, это его решение). Пин `pytest` план 2 не вводит — здесь тоже нет. ## Открытые вопросы владельцу