blogex: coverage floor (74) + test-scaffolding exclusions

`test_coverage` sets the floor the Lens pass enforces, measured first: 74.53%
with test/support excluded (`mix test --cover` and the exported sample give the
same number). The rule — a FLOOR, ratcheted up as behavior yaks land, never
lowered — is written next to the config, along with why each module is excluded
(test scaffolding only: fixtures measure the tests, not the library).

Wiring, per the fast/push split: `test.coverage` runs the suite once with
`--cover --export-coverage default`; the `coverage` sensor then enforces the
floor from that export via `mix test.coverage` (no second suite run). So
`verify` runs the suite first and the sensors after it. The sensor guards on the
export existing: `mix test.coverage` exits 0 when it finds no .coverdata, and a
floor check that did not run must not report success.

blogex/.gitignore: cover/ (generated).
This commit is contained in:
Willem van den Ende
2026-10-26 18:38:35 +00:00
parent a9a02aa9ba
commit 754c8fa1b9
3 changed files with 52 additions and 5 deletions
+26 -5
View File
@@ -3,7 +3,7 @@
MISE_BIN ?= mise
MISE_EXEC = $(MISE_BIN) exec --
.PHONY: check precommit deps compile test format verify
.PHONY: check precommit deps compile test test.coverage coverage format verify
# Cheap static gate for this library (no database, no coverage). Runs from the
# root `make check`, which loops app then blogex.
@@ -30,6 +30,20 @@ compile:
test: deps
$(MISE_EXEC) mix test
# Run the suite once with coverage exported, so the coverage floor check (and,
# later, CRAP) reads the export instead of running the suite a second time.
# Stale exports are removed first: the floor must never report an older run.
test.coverage: deps
rm -f cover/*.coverdata
$(MISE_EXEC) mix test --cover --export-coverage default
# Enforce the coverage floor (mix.exs -> test_coverage) from that export. No
# test run. `mix test.coverage` exits 0 when it finds no export at all, so the
# guard below is load-bearing: a floor check that did not run must not pass.
coverage:
@test -f cover/default.coverdata || { echo "coverage: no exported coverage - run 'make test.coverage' first" >&2; exit 1; }
$(MISE_EXEC) mix test.coverage
# Format code
format:
$(MISE_EXEC) mix format
@@ -42,11 +56,18 @@ format:
# and to VERIFY_SENSORS — that variable is the single source of truth for what
# this target reports as wired.
# - coverage (yak: coverage floors + framework-glue exclusions policy)
# WIRED below (test.coverage + coverage).
# - crap (yak: CRAP scores with ex_crap (both apps))
# - mutation (yak: mutation testing with muex — a sensor, not a gate)
VERIFY_SENSORS :=
#
# The suite runs FIRST: it is what produces the coverage export that the
# sensors below read. (Sampling and reporting are separate steps because
# `mix test --cover --export-coverage` exports instead of printing a summary,
# and reporting through `mix test.coverage` keeps it to one suite run.) Sensors
# still run cheapest-first among themselves.
VERIFY_SENSORS := coverage
verify:
@echo "==> verify(blogex): sensors [$(if $(VERIFY_SENSORS),$(VERIFY_SENSORS),none wired yet)]"
@for sensor in $(VERIFY_SENSORS); do $(MAKE) $$sensor || exit 1; done
@$(MAKE) test
@echo "==> verify(blogex): suite (coverage exported), then sensors [$(VERIFY_SENSORS)]"
@$(MAKE) test.coverage
@for sensor in $(VERIFY_SENSORS); do echo "==> verify(blogex): sensor $$sensor"; $(MAKE) $$sensor || exit 1; done