ouroboros/Makefile
Anton Razzhigaev 915f93604d Add scripts/run_tests.py, the one fast local test battery
The documented local command (`make test`, CONTRIBUTING §4, README) was
`pytest tests/ -q --tb=short`: the whole default suite (23k tests) in a
single process, behind a stale "smoke tests" comment. An Ouroboros task
followed it, hit its 1200 s timeout and withheld its PR. The correct
recipe — a parallel `not serial` xdist pass, then the serial pass — lived
only inside the hermetic commit gate.

scripts/run_tests.py is the single entry point for every actor. A bare
call always runs the FULL battery: the node lane (a missing or too-old
node is a red NOT_RUN, never a silent skip), then every default-lane
test in ONE xdist run under `--dist loadgroup --serial-shards=N`.
tests/conftest.py gains that option: each serial FILE is pinned to one of
N file-sharded groups (one per four workers, at most four; four cores
keep a single group), so serial tests overlap the parallel ones while a
serial file still never splits across workers or runs beside another
file of its shard; other tests keep the scope loadscope uses. The option
defaults to 0 and is inert for CI and the commit gate, which keep the
two-pass split and stay the authority. `--sequential` keeps the gate's
marker split and xdist flags in two passes; extra arguments forward a
focused run. Marker exclusions and xdist flags are imported from
ouroboros.preflight_runner, never restated.

Measured on an 18-core Mac shared with other agents: the two-pass
battery took 649 s (parallel 203 s + serial 446 s); the one-run battery
took 217–287 s with identical verdicts (22 950 passed).

Also: `make test` now calls the script; CONTRIBUTING, README, the Build
& CI chapter, the architecture map and one sentence of prompts/SYSTEM.md
point at it and say which opt-in lanes it leaves out and what to record
when a full run could not finish; tests/test_plan_author_presentation.py
resolves node through ouroboros.preflight_node like the rest of the
suite instead of a bare PATH `node`; tests/test_run_tests_script.py pins
the recipe parity, the bounded shard count, bare call = full battery,
node NOT_RUN = red, and the grouping semantics.

Not changed: the commit gate and .github/workflows/ci.yml; the three
gate self-tests that wait out real 30/20 s timeouts (their slack exists
for nested-xdist startup on slow runners); no version carrier.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-19 02:13:01 +03:00

31 lines
1.2 KiB
Makefile

# Ouroboros — common development commands
# Usage: make test, make lint, make health
.PHONY: test lint health clean
# Full local battery: node lane + every default-lane test in one xdist run
# (modes and focused runs: scripts/run_tests.py)
test:
uv run --locked python scripts/run_tests.py
# Single-process verbose run (slow: the whole default suite in one process)
test-v:
uv run --locked python -m pytest tests/ -v --tb=long
# Lint: deterministic F-rule gate (NameError class); matches the CI quick-test step
lint:
uv run --locked python -m ruff check . --select F
# Run codebase health check (requires ouroboros importable)
health:
uv run --locked python -c "from ouroboros.review import collect_sections, compute_complexity_metrics; \
import pathlib, json; \
sections, stats = collect_sections(pathlib.Path('.'), pathlib.Path('../data')); \
m = compute_complexity_metrics(sections); \
print(json.dumps({'repo': stats, **m}, indent=2, default=str))"
# Clean Python cache files
clean:
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find . -type f -name "*.pyc" -delete 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true