arm-ka-docs/dev/checks.md
2026-10-27 17:06:45 +04:00

24 KiB
Raw Permalink Blame History

Проверки качества: цели make и порядок перед PR

Конфигураций CI в репозиториях нет (в Gitea CI не используется, пайплайн платформы банка вне зоны проекта), поэтому проверки выполняются локально одной командой перед каждым PR. Требования — spec quality-checks (openspec/specs/quality-checks/spec.md), решение D-8 (openspec/changes/archive/2026-10-04-slice-0-skeleton/design.md).

Все цели запускаются из корня репозитория сервиса (arm-core, tabular-parser, scan-gateway); рецепты сами переходят в api/ и используют окружение api/.venv. Инфраструктура compose — docs/dev/docker-compose.yml (см. README.md); в workspace и в worktree .wt/<срез>/ она лежит рядом как ../docs/dev/.

Общие цели

Одинаковый набор целей во всех трёх сервисных репозиториях; семантика, описанная ниже, — эталонная (реализации расходятся в деталях, см. «Известные расхождения реализаций»). Репозиторий вправе добавлять свои цели (см. ниже), но не меняет смысл общих.

Цель Что делает Нужен Docker / compose
make venv api/.venv на Python 3.11 через uv; ставит requirements.txt без строк raisa_* и pylib_ai* (пакеты Nexus банка вне банка недоступны, D-10), requirements-dev.txt и библиотеку arm_statements из STATEMENTS_DIR нет
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; останавливается на первой упавшей проверке (только при последовательном запуске: lint и test — пререквизиты, при make -j они идут параллельно) нет
make check-full make check + make test-integration + сборка docker-образа (docker build, с библиотекой arm_statements из STATEMENTS_DIR, см. ниже); для 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". Любой ненулевой код останавливает цель на этом шаге, следующие не выполняются. Запускайте без -j: при параллельной сборке шаги идут одновременно. make check не требует Docker, PostgreSQL, NATS и сети.

make up

Поднимает compose-проект arm-ka (имя зафиксировано в compose, поэтому тома общие для любого worktree):

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 --profile services down, при сбросе данных down -v с тем же --profile services, иначе контейнеры сервисов останутся), см. 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_statements

Общий код нормализации ББ/ОФР (05-domain-rules.md §11) — Python-библиотека в репозитории RSHB/pylib_ai_arm_statements: дистрибутив pylib-ai-arm-statements, импорт arm_statements (AURORA-1677; до 27.10.2026 — копии api/arm_statements/ в сервисах и скрипт sync-statements, история — архив change unified-statement-normalization). Раздел описывает поведение по спеке statement-normalization (требование «Поставка библиотеки потребителям»).

  • Версия: семантическая, файл VERSION в корне библиотеки и тег v<версия> на коммите выпуска; опубликованная версия не пересобирается с другим содержимым. В Nexus библиотеку публикует платформа.
  • Подключение: в api/requirements.txt каждого сервиса — pylib_ai_arm_statements==<версия>; на платформе ставится из Nexus. Вне банка make venv пропускает строки pylib_ai* (как raisa_*) и ставит библиотеку из checkout STATEMENTS_DIR (по умолчанию ../pylib_ai_arm_statements); после правки библиотеки — make install. Обе цели сначала выполняют statements-version: VERSION checkout ≠ версии в requirements.txt — ошибка, checkout не на теге v<версия> — предупреждение. STATEMENTS_TAG по умолчанию берётся из requirements.txt.
  • Сборка образа: make docker-build передаёт checkout контекстом statements и отказывает, если HEAD checkout не на теге STATEMENTS_TAG. compose (dev/docker-compose.yml) собирает все три сервиса с STATEMENTS_DIR из dev/.env (по умолчанию ../../pylib_ai_arm_statements от docs/dev).
  • Линтеры и тесты: библиотека проверяется своим make check (ruff, mypy, pytest) в своём репозитории; make check сервиса её исходники не обходит, arm_statements для ruff сервиса — сторонний пакет.
  • Маркер версии: service.statements_version результата — версия установленного дистрибутива (importlib.metadata); ядро сравнивает её с statements_version задания при пересчёте после правки (STATEMENTS_VERSION_MISMATCH, info). У заданий до перехода в версии хэш коммита копии — расхождение ожидаемо (решение владельца 26.10.2026).
  • Перечень кодов форм: источник — contracts/statement-code-orders.yaml, в библиотеке — байтовая копия arm_statements/rules/statement_code_orders.yaml. Порядок правки: PR в docs → PR в библиотеку и новая версия → подъём версии в сервисах («сначала ядро»). Сверку docs с библиотекой делает make -C docs statements-orders-check (входит в make -C docs check, расхождение — предупреждение); что все коды словаря имён ядра есть в перечне — тест ядра test_name_dictionary_codes_in_code_orders.

Для arm-core дополнительно:

  • dbml-check — python scripts/check_dbml_vs_orm.py ../../docs/model/data-model-v5.19.dbml (путь от api/, по умолчанию — переменная DBML Makefile, она указывает на текущую версию модели; другой — 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/. Юнит-тесты и линтер фронта в web-check не входят — их запускают из web/: npm test (vitest) и npm run lint (ESLint + Prettier).

Дополнительные цели репозиториев (не общие): 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 scan-gateway), с которым сервис сверяется diffом или который подключает напрямую:

# Makefile сервиса: свои переменные и цели; цель по умолчанию задана явно, иначе ею станет первая цель include (venv)
.DEFAULT_GOAL := check
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 лежат не рядом):

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 и PyYAML — зависимостями скриптов (после обновления репозитория — перезапустить)
make validate-contracts python scripts/validate_contracts.py: примеры contracts/examples/ против текущих схем JSON Schema 2020-12, примеры contracts/examples/v1/ — против схем прежнего MAJOR *.v1.schema.json (окно перехода на контракт 2.0), форма упорядоченных перечней кодов contracts/statement-code-orders.yaml (коды — 4 цифры формы; в варианте full код стоит 1 + (вхождений в repeats) раз, в simplified — не чаще); код 1 при любой ошибке
make validate-openspec openspec validate --all --strict — все спеки и незаархивированные change'и (один change: make validate-openspec CHANGE=<id>)
make check все проверки выше, test-snapshot и statements-orders-check
make statements-orders-check contracts/statement-code-orders.yaml против байтовой копии в библиотеке (STATEMENTS_DIR, по умолчанию ../pylib_ai_arm_statements); расхождение или нет checkout — предупреждение, код 0

Без make: python scripts/validate_contracts.py (нужны jsonschema и PyYAML) и openspec validate <id> --strict. Менять contracts/** нужно осознанно: байтовые копии схем лежат в api/contracts/ каждого сервиса, после правки их нужно пересинхронизировать (cp), иначе тест идентичности в сервисах упадёт. Правило теста идентичности (у ядра и сервисов одно, верно до, во время и после окна перехода между MAJOR — сейчас 1 → 2): схема копии с $id …/v<M> сверяется с <имя>.v<M>.schema.json, если такой файл есть в docs, иначе с основным (у recognition-request файла .v1 нет — копия v1.0 сверяется с основным); пример examples/<имя>.json копии — с examples/v<M>/<имя>.json, если он есть, иначе с examples/<имя>.json (M — MAJOR копии схемы этого вида, вид — по префиксу имени); прочие файлы копии (*.v<N>.schema.json, examples/v<N>/ у ядра) — с одноимёнными; файлы docs другого MAJOR сервис не сверяет. Правило вводится во все три репозитория до слияния контракта v2.0 в docs (шаг 0 выкладки; спека recognition-contract, требование «Копия контракта в сервисе идентична источнику»). Ядро держит копии обоих MAJOR. Правило реализовано файлом api/tests/contract_identity.py, побайтно одинаковым в трёх репозиториях; правка — сразу во всех трёх. Перечень кодов contracts/statement-code-orders.yaml копируется не в сервисы, а в библиотеку arm_statements (сверяет make statements-orders-check).

Порядок перед 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 учитывает ARM_KA_DOCS в тесте идентичности контракта (с шага 0 #116), а ARM_KA_FIXTURES — нет (ищет ../fixtures/ocr по фиксированному пути; тексты причин пропуска не содержат «ARM_KA_FIXTURES недоступен»). Пока расхождение по fixtures не устранено, для scan-gateway fixtures нужно класть рядом.