These gates complete the full local verification. Run them before tagging a release. Network access is required for Gate 10 (CVE database query).
pytest --cov with a minimum coverage threshold of 80%. Measures line coverage across the entire source package. Tests in tests/ are excluded from the coverage measurement. The same threshold is enforced in CI in a clean install environment.
major.minor line — pre-releases and yanked files skipped. A breaking change requires a version bump beyond that release — a minor bump before 1.0.0, a major bump afterwards — witnessed by a git tag. The gate is advisory locally and authoritative in CI (where CI is set), so a breaking change you have not admitted in the version fails the pipeline rather than the push. When the package is unpublished or PyPI is unreachable, it falls back to reminding you that commits have piled up since the last tag.
LICENSE file must be present, the license field declared in pyproject.toml, and reuse lint clean — every file carries its SPDX licence header. Locally it also checks that the SPDX authorship is current; plesty license author fixes it. All of it is generated by plesty init, set to LGPL-3.0-or-later.
pip-audit for known CVEs in all declared dependencies. A CVE blocks the push. Fix by upgrading the affected package: uv lock --upgrade-package <package> && uv sync.
deploy-docs job of gate 12 instead. Locally it always runs.
DevicePipeline.run_mock_pipeline() and passes — one call runs all eight mock gates and reports every failure it finds. plesty init mock-test generates that test. Activated only when module_type = "device" in [tool.plesty]. Runs without hardware — uses a mock solver that generates schema-valid responses. See Testing devices for the complete test file.
ExperimentPipeline contract test functions to be present in the test suite and passing. Activated only when module_type = "experiment" in [tool.plesty]. Runs without hardware — validates the package against the Experiment ABC contract: single public subclass, deterministic build_plan(), resolvable step operations, JSON-serializable plans, and async lifecycle hooks. See Testing experiments for the complete test file.
The rest of the lettered gates
d1 and e1 are the two you write tests for. The others are checks your
module either satisfies by construction or does not, and each reports N/A
unless its module_type matches:
| Gate | Applies to | Requires |
|---|---|---|
d2 — Device Status Contract |
device | The device reports its state the way every consumer expects, so a client can ask what is wrong without knowing the instrument |
d3 — Device Docs |
device | The package imports, exposes a hardware-free DocDevice/Device factory, and returns a populated doc_model() — so plesty docs needs no hand-written content |
a1 — Analyzer Contract |
analyzer | The analyzer implements the interface an experiment drives it through |
e2 — Experiment Persistence |
experiment | No ad-hoc persistence in the package (np.save, pickle.dump, h5py.File, open for writing) — results go through plesty-lib's save_result / ResultDocument |
e3 — Experiment Manifest |
experiment | python -m <module> --manifest prints the run contract; every setting has a type and a description (and a unit where bounded), and the schema and config/*.yaml declare the same keys |
f1 — Field Test Findings |
any | No published reports/<instrument>/field-test.json holds an error finding. No report published, no gate — see plesty init field-test |
d3 is the one that most often surprises a device author: it fails when the
module cannot be constructed without hardware, because then no documentation
can be generated from it either.
Coverage below 80%
The most common quantum failure on first attempt. Check the coverage report:
uv run pytest --cov=plesty/power_meter --cov-report=term-missing
The MISS column shows uncovered lines. Focus on branches in _write_, _query_, and check_errors — these are often missing from the scaffolded smoke tests.
Gate 11 in CI
In a GitLab branch pipeline, Gate 11 is skipped: the Sphinx build is done by the dedicated deploy-docs job in Gate 12 instead, which has the docs deployment credentials. In a merge-request pipeline it runs, so a change that breaks the docs is caught before it is merged.