From a9a57319916b55e079762d3c6454e0247d9ca62d Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Mon, 17 Aug 2026 12:06:08 +0200 Subject: [PATCH] build(setup): prove the venv works instead of trusting pip's exit code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `make setup` exited 0 whether or not the environment it produced was usable — per D-24, a step whose job is to not fail has a passing state indistinguishable from its broken state. Adds two cheap checks at the end: `pip check` for version drift between installed packages, and `pytest --collect-only` to walk the full src/ import graph and catch a missing declared dependency, which is what core-api's undetected missing sqlalchemy looked like (T-47). Neither needs any of the five backing services running — dependencies.py only constructs clients inside lru_cache getters, never at import/collection time. Also fixes `setup` to install requirements-dev.txt rather than requirements.txt. It only ever installed the latter since the Makefile's introduction, so `make test` and `make lint` — both of which need pytest and ruff — were never actually reachable from a clean `make setup`. requirements-dev.txt pulls in requirements.txt via -r, so the runtime set installed is unchanged; only the tooling to prove it is added. Found because the new check failed honestly on its first clean-tree run, before this fix. Verified: clean-tree run installs everything and passes (455 tests collected); a second run is a fast no-op; uninstalling a declared runtime dependency (asyncpg) makes the check fail with ModuleNotFoundError, and rerunning setup restores and re-passes it. Co-Authored-By: Claude --- Makefile | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 045a731..9629771 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,32 @@ help: ## Show this help | awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}' .PHONY: setup -setup: ## Create the venv and install dependencies +setup: ## Create the venv, install dependencies, and prove the result works $(PYTHON) -m venv .venv - $(VENV)/bin/pip install -r requirements.txt + # requirements-dev.txt pulls in requirements.txt via -r, so this is still + # the full runtime set plus pytest/ruff. Installing only requirements.txt + # here (as this line originally did) left `make test` and `make lint` + # unreachable from a clean `make setup` since the Makefile's introduction + # in b9f55cb — pytest was never installed by setup at all. Found by the + # check below failing on its first clean-tree run; fixed in the same + # commit rather than filed separately, since the new check cannot pass + # honestly against the old line. + $(VENV)/bin/pip install -r requirements-dev.txt + # Exit 0 from pip install is not evidence (D-24) — it is the same exit code + # whether requirements.txt matches what's on disk or a dependency silently + # failed to install. Two cheap checks, for two different drift modes: + # pip check - installed packages satisfy each other's declared + # version constraints (a stale/partial install). + # pytest --collect-only - every test module actually imports, which + # walks the full src/ import graph and is exactly + # what catches a *missing* declared dependency + # (core-api's sqlalchemy case in T-47). It builds + # no client and opens no socket - dependencies.py + # wraps client construction in lru_cache getters, + # never called at collection time - so this needs + # none of the five backing services running. + $(VENV)/bin/pip check + $(VENV)/bin/python -m pytest tests/ --collect-only -q .PHONY: run run: ## Dev server on :8778 with reload (8089 is the container, not this)