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.