From 2905827c3f17908e74ff422df776ee8b42b8d5e1 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Wed, 17 Jun 2026 07:45:29 -0400 Subject: [PATCH] =?UTF-8?q?CLAUDE.md:=20document=20the=20requirements.py3.?= =?UTF-8?q?txt=20=E2=86=94=20requirements-prod.lock=20relationship?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two-file dependency setup tripped me twice in one session: 1. Added erldistpy to requirements.py3.txt without running make pins-lock. Result: env.tar.gz shipped without erldistpy, prod crypto_watcher hit ModuleNotFoundError at runtime. 2. Added click as a CLI dep that wasn't in any pin file at all. Result: 516 import errors in CI tests across unrelated modules. Documents the two-file model + the obligation to run `make pins-lock` on every requirements.py3.txt edit. Notes the CLI-convention point too (stdlib argparse, not click). --- CLAUDE.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 145ac85..ad80f28 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,6 +87,42 @@ This project uses a Makefile for most development operations. Use `make` command - Clean up environment: `make clean` - Activate environment: `source env/bin/activate` +### Dependencies — two-file source of truth + +Runtime deps live in **two** files; they are NOT redundant. + +- `requirements.py3.txt` — what `setup.py` reads for `install_requires`. + Used by `pip install .` / editable dev installs. Source-of-truth for + what `make_post_sell` declares as its deps. +- `requirements-prod.lock` — hash-pinned, full transitive closure, + generated by `make pins-lock` (uv pip compile). What CI's + `install-source-prod` actually installs into `env.tar.gz` via + `pip install --require-hashes -r requirements-prod.lock`. + +**Whenever you edit `requirements.py3.txt`, you MUST run `make pins-lock` +and commit the regenerated `requirements-prod.lock` in the same PR.** + +If you forget: CI tests will still pass (test stage uses the unpinned +files), and the build artifact will still publish — but the artifact's +venv will be missing whatever dep you added. The deploy to prod will +silently roll out an env without the new dep. The first runtime import +of it is where the world finds out. + +Pattern that has bitten us: +1. Add `erldistpy>=0.1.6` to `requirements.py3.txt`. Tests pass. +2. Forget `make pins-lock`. CI builds env.tar.gz from the stale lock. +3. Highstate ships → `pip show erldistpy` returns empty on prod → + `ModuleNotFoundError` the moment crypto_watcher reaches for it. + +Same shape for any other dep — make a habit of running `make pins-lock` +after every requirements edit, before commit. + +Same trap on the CLI side: if your new module imports a stdlib-adjacent +library that's not yet pinned (e.g. someone reaches for `click` +instead of `argparse`), it triggers `ModuleNotFoundError` in CI tests +because the CI runner's env doesn't carry the transitive. Match repo +convention (stdlib `argparse` for CLIs) before adding deps. + ## Code Structure ### Key Directories