build(make): prove make setup actually works before exiting 0 (T-47)

pip install exiting 0 is not evidence the gateway environment is usable
(D-24) — a resolved-but-broken dependency or a stale venv from another
Python both look identical to a clean install at the point setup exits.
End the target with a cheap positive check instead: collect the test
suite (imports every src module each test pulls in) and confirm ruff
and mypy resolve inside the venv, the only place either binary exists.

Also states explicitly, in a comment, that setup covers the gateway
half only — the firmware half needs `source ~/esp-idf/export.sh` in
every shell, which a Makefile recipe cannot leave sourced in the
caller's shell, so build-firmware sources it itself instead.
This commit is contained in:
2026-08-17 12:04:12 +02:00
parent 3f8e4cf593
commit 78d9b276ee
2 changed files with 24 additions and 1 deletions
+3
View File
@@ -14,6 +14,9 @@ until the first tagged release.
removed. `make test` means the same thing from any directory.
- Firmware targets source `~/esp-idf/export.sh` themselves, so `idf.py` resolves without
having to remember. Override the location with `IDF_EXPORT=`.
- `make setup` now proves the gateway environment actually works instead of trusting a
clean `pip install` exit code: it collects the test suite and checks `ruff`/`mypy`
resolve in the venv, and fails the target if any of that is broken (T-47).
## [0.2.2] — 2026-07-19
+21 -1
View File
@@ -44,8 +44,28 @@ lint: lint-gateway ## Lint every component that has a linter
# --- gateway ------------------------------------------------------------------
.PHONY: setup
setup: ## Create the gateway venv and install dev deps (no ML models)
setup: ## Gateway venv + dev deps + prove it works (firmware needs export.sh — see below)
cd $(GATEWAY) && $(PYTHON) -m venv .venv && .venv/bin/pip install -e ".[dev]"
@# This covers the gateway half only, deliberately. The firmware half needs
@# `source ~/esp-idf/export.sh` in every shell (see the firmware gotchas
@# above); a Makefile recipe runs in its own subshell, so it cannot leave
@# that sourced in the caller's shell. A `setup` that appeared to prepare
@# firmware and silently left `idf.py` unresolved would be worse than one
@# that says plainly it does not touch that half — hence `build-firmware`
@# sources export.sh itself, per target, instead.
@#
@# Exit 0 from `pip install` is not evidence (D-24) — pip reports success
@# even when the result is unusable (e.g. a dependency that resolved but
@# doesn't actually import, or a stale .venv left over from a different
@# Python). Prove the environment works instead of trusting the install
@# step: `--collect-only` imports every test module and therefore every
@# src module each one pulls in (T-47). It runs zero tests, so it stays
@# cheap, and it also confirms ruff/mypy landed in .venv/bin — the venv
@# is the only place either binary exists (see gateway gotchas above);
@# `--version` is enough to prove each resolves and runs.
cd $(GATEWAY) && .venv/bin/python -m pytest tests/ --collect-only -q
cd $(GATEWAY) && .venv/bin/ruff --version >/dev/null
cd $(GATEWAY) && .venv/bin/mypy --version >/dev/null
.PHONY: setup-speech
setup-speech: ## Additionally install faster-whisper and piper