Skip to content

Test Suites and Runtime

The 2026-08-10 documentation audit collected 596 tests: 591 in the fast tier and five in the slow tier. On the audited checkout, the fast pytest run completed in 70.97 seconds (74.79 seconds including runner startup), and the slow pytest run completed in 44.56 seconds (47.13 seconds including startup). Treat these as a local warm-cache snapshot rather than a performance budget.

The five slow cases are one deterministic-bandit IPPO integration, one Markov Stag Hunt exact-graph build, two IPPO-Lagrangian trainer integrations, and one shielded IPPO integration. Cold JAX and exact-graph caches can make absolute timings longer, but CI runs the fast and slow shards in parallel so those costs are not serialized.

Use the repository runner during development:

# Select non-slow tests from tracked and untracked working-tree changes.
uv run python scripts/run_tests.py changed

# Broad non-slow regression suite.
uv run python scripts/run_tests.py fast

# One ownership group, excluding slow tests by default.
uv run python scripts/run_tests.py world_model

# Include that component's expensive integrations.
uv run python scripts/run_tests.py shield --include-slow

# Expensive tier only, or every test.
uv run python scripts/run_tests.py slow
uv run python scripts/run_tests.py full

changed compares the working tree to HEAD. Pass --base origin/main to include committed branch changes, or repeat --changed-file PATH to use an explicit set. Arguments after -- are forwarded to pytest.

Change-to-suite map

Every test module has one primary marker in tests/suite_manifest.py. Collection fails if a new test_*.py module has not been classified. Manifest keys are relative to tests/, so nested notebook suites are supported.

Changed code Routine suite Include slow when
src/core/ core normally unnecessary
src/environments/ env exact environment graphs or long rollouts change
src/world_model/ world_model model training or a large graph projection changes
src/opponent_model/ opponent_model imagination or policy-improvement loops change
src/joint_graph/ joint_graph exact graph enumeration changes
src/shield/, src/true_shield/ shield shielded trainer integration changes
src/rl/ rl trainer construction or update loops change
notebooks/ experiments real notebook execution or exports change
src/visualisation/ visualisation plot or export behavior changes
a tests/**/test_*.py file that exact file the edited test has the slow marker
dependency, pytest, CI, or unknown implementation configuration fast use full if integrations may change
documentation only no pytest selection run uv run zensical build --strict

Some files are explicitly cross-cutting. In particular, labelled environment logging selects environment, RL, shield, and visualisation tests; graph augmentation selects joint-graph, world-model, and opponent-model tests.

CI runs fast and slow as parallel jobs. Together they preserve complete coverage while allowing ordinary deterministic failures to return earlier. The JAX persistent compilation cache lives under .cache/jax-test-compilation, which is already ignored.

Runtime policy

The slow marker is reserved for measured tests near or above ten seconds, not tests that merely look complex. Slow tests receive a 180-second timeout; normal tests retain the 60-second project default. Re-profile before changing the manifest:

uv run pytest -q --durations=50

Prefer small deterministic contract tests and fixture reuse over adding more slow integrations. Component ownership describes the test's primary purpose, not the absence of dependencies on other components.