From 401cdbc362cb35ca6234132ed8466e5c250d0552 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sun, 4 Oct 2026 05:20:27 +0400 Subject: [PATCH] =?UTF-8?q?docs(dev):=20checks.md=20=E2=80=94=20=D1=86?= =?UTF-8?q?=D0=B5=D0=BB=D0=B8=20make,=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20PR,=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=20=D0=B1=D0=B5=D0=B7=20docs/fixtures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- dev/checks.md | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 dev/checks.md diff --git a/dev/checks.md b/dev/checks.md new file mode 100644 index 0000000..3262196 --- /dev/null +++ b/dev/checks.md @@ -0,0 +1,151 @@ +# Проверки качества: цели `make` и порядок перед PR + +Конфигураций CI в репозиториях нет (в Gitea CI не используется, пайплайн платформы банка вне зоны проекта), поэтому +проверки выполняются локально одной командой перед каждым PR. Требования — spec `quality-checks` +(`openspec/changes/slice-0-skeleton/specs/quality-checks/spec.md`), решение D-8. + +Все цели запускаются **из корня репозитория сервиса** (`arm-core`, `tabular-parser`, `scan-gateway`); рецепты сами +переходят в `api/` и используют окружение `api/.venv`. Компоуз-инфраструктура — `docs/dev/docker-compose.yml` +(см. [`README.md`](README.md)); в workspace и в worktree `.wt/<срез>/` она лежит рядом как `../docs/dev/`. + +## Общие цели + +Одинаковый набор и одинаковая семантика во всех трёх сервисных репозиториях. Репозиторий вправе добавлять свои цели +(см. ниже), но не меняет смысл общих. + +| Цель | Что делает | Нужен Docker / compose | +|---|---|---| +| `make venv` | `api/.venv` на Python 3.11 через `uv`; ставит `requirements.txt` без строк `raisa_*` (пакеты Nexus банка вне банка недоступны, D-10) и `requirements-dev.txt` | нет | +| `make lint` | `ruff check .`, `ruff format --check .`, `mypy src` (в `arm-core` — `mypy src scripts`) | нет | +| `make test` | `pytest -m "not integration"`: юнит-тесты; **включает тест идентичности вендоренного контракта** `api/contracts/` с `../docs/contracts` | нет | +| `make test-integration` | `pytest -m integration` против инфраструктуры compose (PostgreSQL 16, NATS, MinIO; бакет `arm-ka` должен существовать, его создаёт `make up`) | да, `make up` | +| `make check` | `make lint` затем `make test`; останавливается на первой упавшей проверке | нет | +| `make check-full` | `make check` + `make test-integration` + сборка docker-образа (`docker build`); для `arm-core` — расширенный набор, см. ниже | да, `make up` и Docker | +| `make up` | поднимает инфраструктуру из `../docs/dev/docker-compose.yml`; постоянные сервисы `postgres`, `nats`, `minio` | Docker | + +Сводка шагов `make check`: `ruff check .` → `ruff format --check .` → `mypy src` → `pytest -m "not integration"`. +Любой ненулевой код останавливает цель на этом шаге, следующие не выполняются. `make check` не требует Docker, +PostgreSQL, NATS и сети. + +### `make up` + +Поднимает compose-проект `arm-ka` (имя зафиксировано в compose, поэтому тома общие для любого worktree): + +```bash +docker compose -f ../docs/dev/docker-compose.yml --project-name arm-ka up -d --wait postgres nats minio +docker compose -f ../docs/dev/docker-compose.yml --project-name arm-ka run --rm minio-init # бакет arm-ka (идемпотентно) +``` + +Почему так: голый `docker compose up -d --wait` возвращает код 1 (одноразовый `minio-init` завершается кодом 0, compose +считает это сбоем), поэтому `--wait` даётся со списком долгоживущих сервисов, а бакет создаётся отдельным шагом. Без +бакета интеграционные тесты на свежем томе падают на `NoSuchBucket`. Целей `down`/`stop`/`restart` нет намеренно: проект +`arm-ka` общий для всех сервисов; остановка и сброс — вручную (`docker compose down`, `down -v`), см. `README.md`. + +> Эталонная реализация `make up` — в `scan-gateway`. Реализации в `arm-core` и `tabular-parser` отличаются +> (см. «Известные расхождения реализаций»). + +### Состав `make check-full` по репозиториям + +| Репозиторий | Шаги по порядку | +|---|---| +| `scan-gateway` | `check` → `test-integration` → `docker-build` (образ `scan-gateway:dev`); интеграционный тест поднимает эмулятор ИС Сканирование в процессе теста | +| `tabular-parser` | `check` → `test-integration` → `docker-build` (образ `tabular-parser`) | +| `arm-core` | `check` → `dbml-check` → `check-infra` → `test-integration` → `docker-build` → `web-check` | + +Для `arm-core` дополнительно: + +- `dbml-check` — `python scripts/check_dbml_vs_orm.py ../../docs/model/data-model-v5.13.dbml` (путь от `api/`; + другой — `make dbml-check DBML=<путь относительно api/>`): ORM обязана совпадать с DBML; расхождения печатаются + построчно, код 1. +- Цикл миграций «`alembic upgrade head` → `alembic downgrade base` → `alembic upgrade head`» на чистой БД, пустой + autogenerate и сверка схемы с `create_all` ORM выполняет `tests/test_migrations.py`; он входит в `test-integration`, + поэтому отдельным шагом в `check-full` не гоняется. Для быстрой проверки одних миграций: `make migration-cycle`. +- `check-infra` — TCP-проверка доступности PostgreSQL и NATS из `api/.env.test`; вместо длинного трейсбека pytest + подсказывает «поднимите инфраструктуру: `make up`». +- `web-check` — `npm install`, `biome check src`, `tsc --noEmit`, `npm run build` в `web/`. + +Дополнительные цели репозиториев (не общие): `arm-core` — `migrate`, `seed`, `seed-dev`, `dbml-check`, +`migration-cycle`, `check-infra`, `docker-build`, `web-check`; `scan-gateway` — `help`, `docker-build`, `emulator`; +`tabular-parser` — `docker-build`. + +## Внешние ресурсы: docs и fixtures опциональны + +Проверки сервисов обращаются к соседним репозиториям workspace и **не должны падать**, если их нет: тест +пропускается (`skipped`) с явной причиной, остальные выполняются, `make check` остаётся зелёным. + +| Что | Где ищется | Что пропускается без него | +|---|---|---| +| `docs` | `../docs` или каталог из `ARM_KA_DOCS` | тест идентичности контракта `api/contracts/` с `docs/contracts/`; в `arm-core` ещё сверка с DBML в тестах (`dbml-check` как цель `make` требует DBML и падает без него) | +| `fixtures` | `../fixtures` или каталог из `ARM_KA_FIXTURES` | тесты с маркером `fixtures` (реальные данные, внутренний доступ): причина пропуска — «ARM_KA_FIXTURES недоступен …» | + +Пример (docs и fixtures лежат не рядом): + +```bash +export ARM_KA_DOCS=/path/to/arm-ka-docs +export ARM_KA_FIXTURES=/path/to/arm-ka-fixtures +make check +``` + +Причины пропусков видно в выводе (`pytest --verbose` в `addopts`: строки `SKIPPED (…)`); полный список — +`cd api && .venv/bin/pytest -m "not integration" -rs`. + +Важно: зелёный `make check` с пропусками **не** доказывает идентичность контракта и прохождение на реальных данных. Перед +PR убедитесь, что `docs` и `fixtures` доступны (пропусков по этим причинам нет) либо явно укажите в описании PR, что +пропущено. + +> Фактическая поддержка переменных различается по репозиториям — см. «Известные расхождения реализаций». + +## Проверки этого репозитория (`docs`) + +В репозитории `arm-ka-docs` нет сервисных целей; `Makefile` в его корне содержит только проверки спеки и контракта: + +| Цель | Что делает | +|---|---| +| `make venv` | `.venv` (Python 3.11, `uv`) с `jsonschema` — единственной зависимостью скриптов | +| `make validate-contracts` | `python scripts/validate_contracts.py`: примеры `contracts/examples/` против трёх схем JSON Schema 2020-12 (3 схемы, 8 примеров); код 1 при любой ошибке | +| `make validate-openspec` | `openspec validate slice-0-skeleton --strict` (другое изменение: `make validate-openspec CHANGE=`) | +| `make check` | обе проверки выше | + +Без `make`: `python scripts/validate_contracts.py` (нужен `jsonschema`) и `openspec validate --strict`. +Менять `contracts/**` нужно осознанно: байтовые копии схем лежат в `api/contracts/` каждого сервиса, после правки их +нужно пересинхронизировать (`cp`), иначе тест идентичности в сервисах упадёт. + +## Порядок перед PR + +1. Поднять инфраструктуру: `make up` (в репозитории сервиса). Убедиться, что `docs` и `fixtures` доступны (рядом или через + `ARM_KA_DOCS`, `ARM_KA_FIXTURES`). +2. `make check` — быстрые проверки. Исправлять до зелёного. +3. `make check-full` — полная проверка (интеграционные тесты, образ; для `arm-core` — ещё DBML, миграции, `web`). +4. Если менялись `contracts/`, `model/` или спека в репозитории `docs`: в нём `make check`, затем в каждом затронутом + сервисе — пересинхронизация копий контракта и пункты 2–3. +5. Итог `make check-full` (зелёный/красный, число тестов, **что пропущено и почему**) вписать в описание PR. + +Правила: PR создаётся только после зелёного `make check-full`; один OpenSpec change и один PR — на один репозиторий; +`make check-full` не заменяет ревью. + +## Типичные проблемы + +- **`make test-integration` падает на соединении** — не поднята инфраструктура: `make up`; порты заняты — поменять в + `docs/dev/.env` и в `api/.env.test`/`api/.env` сервиса (`README.md`). +- **`NoSuchBucket`** — бакета нет на свежем томе: `docker compose -f ../docs/dev/docker-compose.yml --project-name arm-ka + run --rm minio-init`. +- **`tabular-parser`: интеграционный тест получает чужие ответы** — на шине compose не должно работать другого + экземпляра сервиса из той же queue group (интеграционный тест поднимает сервис в процессе теста). +- **Нет `uv`/Python 3.11** — `make venv` их требует (версия Python — как на платформе). +- **`docker build` падает без сети** — это единственные шаги `check-full`, которым нужна сеть; `make check` её не требует. + +## Известные расхождения реализаций + +Фактические реализации в `Makefile` трёх сервисов расходятся с описанной выше семантикой. Сервисы в рамках Среза 0 +не менялись; расхождения занесены как находки ревью. + +- **`make up`.** Эталон — `scan-gateway` (`--project-name arm-ka`, `--wait` со списком сервисов, затем `run --rm + minio-init`). `tabular-parser` не создаёт бакет (нет шага `minio-init`) и на свежем томе даёт `NoSuchBucket`; + `arm-core` выполняет `docker compose up -d` без `--wait`, то есть возвращается до готовности сервисов. +- **Структура `check-full`.** В `scan-gateway` шаги вызываются через `$(MAKE)` (порядок и остановка на первой ошибке + гарантированы и при `make -j`); в `arm-core` и `tabular-parser` — пререквизитами (при последовательном запуске + эквивалентно, при `make -j` порядок не гарантирован). Запускайте без `-j`. +- **`ARM_KA_DOCS`/`ARM_KA_FIXTURES`.** `arm-core` учитывает обе переменные; `tabular-parser` — только `ARM_KA_DOCS` + (тестов с маркером `fixtures` пока нет); `scan-gateway` — ни одну (ищет `../docs` и `../fixtures/ocr` по фиксированному + пути; тексты причин пропуска не содержат «ARM_KA_FIXTURES недоступен»). Пока расхождение не устранено, для + `scan-gateway` docs/fixtures нужно класть рядом.