arm-ka-docs/dev/checks.md
2026-10-04 05:27:21 +04:00

180 lines
17 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.

# Проверки качества: цели `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`. Инфраструктура compose — `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` (в `arm-core` — `mypy src scripts`) →
`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`.
## Эталонный фрагмент `dev/Makefile.common`
Рецепты общих целей вынесены в [`Makefile.common`](Makefile.common) — это эталон (источник — `Makefile` `scan-gateway`),
с которым сервис сверяется `diff`ом или который подключает напрямую:
```make
# Makefile сервиса: свои переменные и цели; include — после первой цели (иначе целью по умолчанию станет venv)
MYPY_PATHS := src scripts # arm-core; по умолчанию src
CHECK_FULL_STEPS := check dbml-check check-infra test-integration docker-build web-check # arm-core
include ../docs/dev/Makefile.common
```
Переменные (все `?=`): `VENV`, `BIN`, `MYPY_PATHS`, `COMPOSE_FILE`, `COMPOSE_PROJECT`, `IMAGE` (по умолчанию имя каталога
сервиса; у `scan-gateway` — `scan-gateway:dev`), `CHECK_FULL_STEPS` (по умолчанию `check test-integration docker-build`).
Определяет цели `venv`, `lint`, `test`, `test-integration`, `check`, `docker-build`, `check-full`, `up`.
Цели, специфичные для сервиса (`migrate`, `seed`, `dbml-check`, `check-infra`, `web-check`, `emulator`, `help`),
остаются в его `Makefile`.
Проверка «`make check` вызывает одинаковые команды»: `make -n <цель>` в каждом сервисе и в Makefile, подключающем
`Makefile.common` с теми же переменными, даёт одинаковый вывод. Текущее состояние (Срез 0, сервисы не менялись):
`scan-gateway` совпадает с эталоном полностью; `arm-core` и `tabular-parser` — по `venv`, `lint`, `test`,
`test-integration`, `check`, `docker-build` и составу команд `check-full`, но не по `up` и по структуре `check-full`
(пререквизиты вместо вызовов `$(MAKE)`); см. «Известные расхождения реализаций». Сервисы переходят на `include` в
следующих срезах (решение 24 в `design.md`).
## Внешние ресурсы: 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` (в `arm-core`; в остальных сервисах — см. «Известные расхождения реализаций») | тесты с маркером `fixtures` (реальные данные, внутренний доступ): причина пропуска — «ARM_KA_FIXTURES недоступен …» (в `arm-core`) |
Пример (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=<id>`) |
| `make check` | обе проверки выше |
Без `make`: `python scripts/validate_contracts.py` (нужен `jsonschema`) и `openspec validate <id> --strict`.
Менять `contracts/**` нужно осознанно: байтовые копии схем лежат в `api/contracts/` каждого сервиса, после правки их
нужно пересинхронизировать (`cp`), иначе тест идентичности в сервисах упадёт.
## Порядок перед PR
1. Поднять инфраструктуру: `make up` (в репозитории сервиса). Убедиться, что `docs` и `fixtures` доступны (рядом или через
`ARM_KA_DOCS`, `ARM_KA_FIXTURES` — последняя поддерживается только в `arm-core`, см. «Известные расхождения
реализаций»).
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` (и `npm install` в `web-check` у `arm-core`) падает без сети** — это шаги `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 нужно класть рядом.