plesty check

Validate a project against the Plesty compliance standard. Runs a suite of static analysis and runtime gates organised into two enforcement tiers.

plesty check [--standard LEVEL] [--no-report]

Options

Option

Default

Description

--standard

derived

Compliance level: pixel, nebula, or quantum (see below)

--no-report

off

Skip writing reports/check.json (see Report artifacts)

Standard resolution

Without --standard, the level is resolved in this order:

  1. Explicit: [tool.plesty] standard in pyproject.toml (core repos pin quantum this way).

  2. Derived from the release version — shared prototypes ramp up automatically:

    Version

    Standard

    < 0.1.0 — or no release tag yet

    pixel

    >= 0.1.0, < 1.0.0

    nebula

    >= 1.0.0

    quantum

    Projects with a dynamic version (versioningit) derive from the latest git tag.

  3. Fallback: quantum (conservative) when no version information exists.

plesty check echoes which rule applied. Publishing to PyPI always requires quantum (see SCOPE_v1.0.0.md in governance).

Enforcement tiers

Gates are divided into two tiers depending on where they are enforced:

  • [SDK+CI] — enforced locally by plesty check and repeated by CI in a clean environment as the authoritative final gate (gates 1–10).

  • [SDK] — enforced locally and in merge-request pipelines; skipped in branch pipelines, where the dedicated hub-deploy-docs job builds the docs instead. Currently just the Docs Build gate (11).

The pre-push git hook installed by plesty init runs plesty check before every push, enforcing whichever standard resolves for the project (see Standard resolution above).

Compliance levels

Pixel

Metadata and code hygiene only — fast check suitable for pre-commit hooks.

Gate

Tier

What is checked

Metadata & Namespace

[SDK+CI]

pyproject.toml has required fields; package name matches plesty-<module>; plesty/<module>/ directory exists

Code Hygiene

[SDK+CI]

ruff lint (E, F, W, D rules); ruff format --check; mypy type checking

Nebula

All Pixel gates plus the remaining static gates (3–6) — no network access required.

Gate

Tier

What is checked

API Interface Matching

[SDK+CI]

Classes that import from plesty.lib.* must inherit from the imported base class (e.g. BaseDeviceSyncModel)

Data Layer Compliance

[SDK+CI]

All public methods have explicit return type annotations; no class redefines a plesty-lib schema model (ResultDocument, DeviceStatus, TelemetryEvent, ConfigParameter, FuncMeta, Plan, …)

Documentation Completeness

[SDK+CI]

docs/index.md (or index.rst) exists; CHANGELOG.md exists and has been updated since the last git tag

Dependency Coexistence

[SDK+CI]

No exact pins (==x.y.z) in pyproject.toml; use >=x.y,<x+1

Quantum

Everything in Nebula plus the [SDK+CI] gates, run locally for full verification before a release. Required for every PyPI release, and the derived default from version 1.0.0 on.

Gate

Tier

What is checked

Automated Test Coverage

[SDK+CI]

pytest --cov with a minimum threshold of 80%

Semantic Versioning

[SDK+CI]

Diffs the public API against the newest PyPI release on the tree’s own major.minor line (so a maintain/0.N branch is compared with 0.N, not with a later line) and requires a version bump that matches: a minor bump for a breaking change before 1.0.0, a major bump from then on. Advisory locally, fails in CI. When the package is unpublished or PyPI is unreachable, falls back to a reminder to tag a release when commits exist since the last tag

Licensing Compliance

[SDK+CI]

REUSE compliance (reuse lint) and authorship currency of the SPDX headers; license field declared in pyproject.toml

Vulnerability Audit

[SDK+CI]

No known CVEs in declared dependencies; queries the OSV database via pip-audit

Docs Build

[SDK]

Full Sphinx build must complete with zero errors and zero warnings. Runs locally and in merge-request pipelines, so a docs-breaking change fails before it merges; skipped in branch pipelines, where the dedicated hub-deploy-docs job builds the docs

Module-type gates

Quantum additionally runs gates scoped to the module_type declared in [tool.plesty]; they report N/A for every other module type.

Gate

Applies to

What is checked

d1 — Device API Pipeline

module_type = "device"

A test in tests/ calls DevicePipeline.run_mock_pipeline() (plesty.lib.test.device_pipeline) and passes without hardware. One call runs all eight mock gates and reports every failure it found; plesty init mock-test generates the test

d2 — Device Status Contract

module_type = "device"

Overrides of status() are annotated to return DeviceStatus and overrides of device_state() to return str — consumers can rely on the plesty-lib telemetry schema

d3 — Device Docs

module_type = "device"

The device is importable, constructs without hardware, and renders a populated doc_model() — the source for the generated reference pages

a1 — Analyzer Contract

module_type = "analyzer"

The five AnalyzerPipeline contract gate tests (plesty.lib.test.analyzer_pipeline) are present in tests/ and pass on schema-generated synthetic inputs: public Analyzer subclass, schema integrity, analyze-signature match, mock round-trip, provenance stamp

e1 — Experiment Contract

module_type = "experiment"

The five ExperimentPipeline contract gate tests (plesty.lib.test.experiment_pipeline) are present in tests/ and pass: public Experiment subclass, deterministic build_plan(), resolvable step ops, JSON-serializable plan, async lifecycle hooks

e2 — Experiment Persistence

module_type = "experiment"

No ad-hoc persistence in the module package (np.save/np.savez, pickle.dump, h5py.File/open with write mode) — results are persisted via plesty.lib.data.save_result/ResultDocument

e3 — Experiment Manifest

module_type = "experiment"

python -m <module> --manifest prints the run contract (plesty.lib.experiment.Manifest): it names this module, every configuration parameter carries a dtype and a description (and a unit where it is bounded), and the schema and the module’s own config/*.yaml declare the same keys — a key only one of them knows about is either uneditable or a setting that does nothing

f1 — Field Test Findings

any module with a published field test report

No reports/<instrument>/field-test.json holds an error finding — a parameter the instrument refuses or will not answer, which the module nonetheless declares

Report artifacts

Every run writes reports/check.json — the gate results as a document, in the same envelope plesty.lib.test.field_test uses for a field test. One envelope means hub.plesty.net renders both with one component, and a module’s quality reads as one story rather than two.

reports/
  check.json                    plesty check            committed
  <instrument>/
    field-test.json             field test              committed
  *.md                          every report            git-ignored
  *.jsonl                       raw per-run records     git-ignored

check.json sits at the top because the standard gates are a property of the module and have no instrument. A field test report belongs to a module and the hardware it ran against, so it lives in a directory named for that hardware — a powermeter with a silicon photodiode reports different limits and different timings than the same module with a thermopile head.

The report says what actually happened. A gate that did not apply is recorded as skip with its reason, not as a pass; a run that stopped at the first failure records every gate it never reached, so a partial run cannot be read as a clean sweep of a shorter sequence. That is why the report is written even when the run fails.

Only the JSON documents are committed. The markdown and JSONL forms a field test also writes carry the host name, the instrument address, its serial and the lab’s file paths — a hub repository is world-readable, and the scaffold git-ignores them.

A module that has never been field-tested publishes no field-test.json, and gate f1 skips. Absence is the honest rendering: “never run” and “ran and found nothing” are different facts, and a placeholder invites a reader to treat them as the same.

Failure guidance

When a gate fails, the raw error is followed by an explanation of what the gate verifies and how to fix it, plus a link back to this page. The guidance text ships in the wheel (plesty/sdk/assets/check/guidance.yaml). Pass the global --quiet flag to suppress the per-gate progress lines — failures and their guidance always print:

  ✗ Automated Test Coverage (gate 7)
    Error: [Coverage] total coverage 62% below threshold
    This gate verifies: the pytest suite passes with at least 80% line coverage.
    How to fix: Reproduce with 'uv run pytest --cov=plesty' and add tests ...
    Reference: https://docs.plesty.net/plesty-sdk/latest/commands/check.html

Examples

# Check the current directory at the standard it resolves to (see Standard resolution)
plesty check

# Quick pixel check (metadata + code hygiene only)
plesty check --standard pixel

# Full quantum check on a project in another directory
plesty --project-dir ../plesty-power-meter check --standard quantum

# Progress lines suppressed; failures and the verdict still print
plesty --quiet check