Check the installed packages against the lockfiles

A clean lockfile does not mean a clean workstation. pip-audit reported
vulnerabilities here while requirements.txt was already pinned to fixed
versions - the installed environment had drifted from the pins, and nothing
compared the two. The same drift had left requirements-dev.txt uninstalled, so
pytest.ini's -n auto failed for want of pytest-xdist.

Add scripts/check-dependency-drift.py, comparing installed distributions
against both lockfiles. MISSING is reported separately from MISMATCHED: a
package that was never installed and a package at the wrong version need
different fixes, and folding them together hid the missing dev requirements.

Wire it into the style gate advisorially, with DEPENDENCY_DRIFT_ENFORCE=1 for
CI. A developer mid-upgrade should not be blocked by a gate that is telling
them something they already know.

The gate now probes python, python3 and py by executing them rather than by
looking them up on PATH. On Windows, python3 resolves to the Microsoft Store
alias stub, which is present on PATH and does nothing when run.

CONTRIBUTING.md gains the Windows-specific traps this exposed: npm.cmd rather
than npm under a Restricted execution policy, the explicit Git Bash path
because bare bash finds the WSL shim, and npm test rather than npx vitest run
because only the pretest hook stages plugin frontends.
This commit is contained in:
benjamin.baker
2026-09-20 13:22:55 -04:00
parent 8d6e5db347
commit 0288587522
3 changed files with 266 additions and 0 deletions

View File

@@ -206,6 +206,74 @@ Tests are required for:
- New plugin hooks (contract test)
- Schema migrations (before/after data integrity)
### Running the gates on Windows
Three commands in this repository resolve to the wrong program on a Windows dev
box. Each one fails in a way that looks like a code fault, which is why all
three are written out here rather than left to be rediscovered.
```bash
& "C:\Program Files\Git\bin\bash.exe" scripts/check-naming-and-style.sh
cd frontend; npm.cmd test; npm.cmd run build; cd ..
python -m pytest tests/ -q
```
- **`bash` resolves to WSL.** `C:\Windows\System32\bash.exe` is on PATH by
default. With no distribution installed it fails with
`execvpe(/bin/bash) failed: No such file or directory`, and with one installed
it cannot read the Windows path you handed it. Always give the Git Bash path
in full. The same trap bit the test suite: `tests/test_naming_gate_migrations.py`
used bare `bash`, and its 13 failures were miscategorised as "environmental"
for weeks. It now resolves Git Bash explicitly and probes it before use.
- **`npm` resolves to `npm.ps1`.** PowerShell prefers the `.ps1` over the
`.cmd`, and the default execution policy is `Restricted`, so bare `npm` dies
with "npm.ps1 cannot be loaded because running scripts is disabled on this
system" before any test runs. Use `npm.cmd`. Nothing in the repo causes this
and nothing in the repo can fix it; it is machine policy. If you would rather
fix it once, `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` also works,
but that is a machine-level change and `npm.cmd` is free.
- **`npm test`, not `npx vitest run`.** The `pretest` hook runs
`stage-frontend.mjs`; bare vitest never stages plugin frontends and silently
skips their specs.
### Keeping the environment matched to the lockfiles
```bash
python scripts/check-dependency-drift.py
```
Editing a lockfile changes what a FUTURE install produces. It does not touch an
already-populated `site-packages`. Commit `a8f8580` raised eight pins carrying
advisories; no install was re-run afterwards, so that workstation kept the old
libraries for three weeks while `requirements.txt` said otherwise. Every local
test run in that window exercised different libraries than a container build
would have.
Run this after any pull that touches `requirements.txt` or
`requirements-dev.txt`, and fix drift with:
```bash
python -m pip install --require-hashes -r requirements.txt
python -m pip install --require-hashes -r requirements-dev.txt
```
The check reports MISSING separately from MISMATCHED, because absent packages
are the class that gets missed: `pytest-xdist` was simply not installed, which
surfaced only as `pytest: error: unrecognized arguments: -n` - a message that
reads as a broken `pytest.ini` and invites deleting `-n auto` instead of
installing the plugin.
`scripts/check-naming-and-style.sh` runs this check too, advisory by default.
CI sets `DEPENDENCY_DRIFT_ENFORCE=1` to make it fail the build.
If you use the repo-local `env/` virtualenv, check it specifically - it drifts
independently of the global interpreter, and both were stale in the incident
above:
```bash
env/Scripts/python.exe scripts/check-dependency-drift.py
```
## Branches: what belongs on main, and what does not
`main` is the product every site runs and the publication mirror exports.