From 96278e0d02d50f1bdfe28c8f1f15888b703a0b39 Mon Sep 17 00:00:00 2001 From: Willem van den Ende Date: Mon, 26 Oct 2026 17:59:44 +0000 Subject: [PATCH] AGENTS.md: document the fast loop, the Lens pass and its triage classes Records the two loops (make check per commit, make verify per push), how to install the hook (make hooks), the deliberate --no-verify bypass, the Lens practice (separate pass, don't chase nits inline, file a yak), the triage classes (real bug / environment-dependent test / design nit), and how that reconciles with the zero-defects policy. Playwright stays outside the Lens pass pending an explicit decision. --- AGENTS.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7f521a3..2b7ed17 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,7 +28,8 @@ firehose/ ├── mise.toml # Runtime versions (Elixir, Erlang, Node) ├── Dockerfile # Deploy build; ARG pins must match mise.toml ├── scripts/check-pins.sh # Verifies the pin sync; runs in `make check` -└── Makefile # make (test, check) +├── .githooks/pre-push # Lens pass on push; install once with `make hooks` +└── Makefile # make (check, verify, test, hooks) ``` Two blogs are configured: @@ -69,9 +70,70 @@ This is a Phoenix Liveview monorepo, the blogging library is in blogex, the appl Main make targets: -- make test -- make check - runs credo static analysis and suggests refactorings +- `make check` - cheap static gate for both apps (no DB): app `credo --strict` + + format, blogex compile (warnings fatal) + format, then `scripts/check-pins.sh` +- `make precommit` - alias of `check`; fast, safe to run on every commit +- `make test` - both suites (app needs PostgreSQL on localhost:5432) +- `make verify` - the Lens pass: `check`, then per-app heavy sensors and both suites +- `make hooks` - install `.githooks/*` into this clone (once per clone) +# Verification: fast loop vs Lens pass + +Two loops, deliberately split so commits stay cheap and pushes stay honest. + +**Fast loop (every commit).** `make check` is static analysis only: no database, +no coverage, about a second. `make precommit` is the same target. Per app, +`mix precommit` (run inside `app/` or `blogex/`) is the fuller loop: compile with +warnings fatal, format, test. Run these as often as you like while working. + +**Lens pass (every push, and before handing off).** `make verify` runs `check` +first (cheapest), then each app's heavy sensors - sobelow, coverage, CRAP, +mutation, as those yaks land - and finally both test suites. Measured 2026-10-26: +~10s wall (app 178 tests + blogex 156 tests). + +`.githooks/pre-push` runs `make verify` and blocks the push when anything fails. +Install it once per clone: + + make hooks + +It symlinks `.githooks/*` into the clone's hooks directory; `core.hooksPath` is +deliberately left alone so bd's own hooks (pre-commit JSONL flush, post-merge +import) keep firing. On failure the hook prints one summary - last step started, +log path, bypass - and exits non-zero; the full output is in `.git/lens-pass.log`. +Deliberate override (e.g. pushing a branch you know is red): `git push --no-verify`. + +## Lens practice + +The Lens pass is a *separate pass with its own context*. It is not a way to find +work mid-feature: finish and commit what you are building, then run it. + +- Do not chase hook or `credo` output inline while building a feature. If + something interesting surfaces, note it and file a yak; take it up in a Lens + session. +- A failing Lens pass blocks the push, and therefore the hand-off. Triage it; + never re-run until green and never ignore it. +- Adding a sensor: implement it as its own make target, add it to that app's + `VERIFY_SENSORS` in `app/Makefile` / `blogex/Makefile` (cheapest first), and + update the slot comments there. A gate that reports a check it did not run is + worse than no gate - the `VERIFY_SENSORS` list is what gets echoed. + +### Triage classes + +| Class | Looks like | What to do | +|-------|-----------|------------| +| *Real bug* | behavior is wrong; a test fails for a real reason; a sensor reports a real risk | fix inline, with a test that pins the behavior | +| *Environment-dependent test* | passes alone, fails in the pass; depends on ambient state (rows left behind, wall clock, ordering, network, locale) | the test is the bug: make it deterministic by construction - own fixtures, explicit clock, no ambient state as fixtures. Never retry-until-green | +| *Style or design nit* | credo or format suggestion, naming, structure, "this could be smaller" | do not refactor mid-build: note it and file a yak; the Lens session decides | + +Reconciling this with the zero-defects policy: "never continue when there are +errors" governs *what you do with a failure* - report, triage, decide - not +*when* you fix it. Never silently absorb a finding, and never let a pre-existing +failure ride along: if it predates your change, stop and discuss it with the user +rather than working around it. + +Browser tests (`make playwright*`) are *external* verification and are **not** +part of the Lens pass. Whether they ever join it is an open decision (see the yak +"ratchets, deferred decisions, handoff practice"). # Development Always fix failing tests, credo issues and format isseus.