plesty-sdk · Gate 1

module_type — Explicit Module Classification

Replace fragile AST import scanning with a single TOML declaration that tells plesty check exactly what kind of module you are building.

plesty-sdk Gate 1 New in v0.2.1
⚠️ The Problem
🔍 Old approach: AST import scanning

Previously, plesty check decided whether a module was a "device" by walking every .py file with Python's ast module and looking for from plesty.lib.device import … statements. This approach had several critical flaws:

False positives: The SDK's own template files in assets/ import from plesty.lib.device — so the SDK triggered Gate d1 on itself, requiring an ever-growing list of path exclusions (if "assets" in py_file.parts: continue).

Fragile coupling: If a device module restructured its imports, or if the plesty.lib namespace changed, the heuristic silently broke — a device module could stop being detected as one without any error.

Hidden behaviour: Nothing in the repository told you which type of module it was. You had to read the source code to find out.

✅ The Solution
📄 New approach: one TOML field

Add module_type = "device" (or the appropriate value) to [tool.plesty] in your pyproject.toml. That single line is the source of truth.

Explicit: The type is declared, not inferred. No scanning, no path heuristics, no edge cases.

Version-control visible: The type lives in pyproject.toml, alongside the package name and version. Any change is tracked in git.

Validated: Gate 1 rejects unknown values immediately with a clear error message, so typos are caught before the push.

Activating: Setting module_type = "device" automatically activates Gate d1 (Device API Pipeline) — no other configuration needed.

🏷️ The 4 Valid Values
"device"

A HUB device driver. Controls lab hardware via VISA, TCP/IP, or serial. Must expose a consistent API and implement the 8-gate DevicePipeline test suite.

⚡ Activates Gate d1
"experiment"

A HUB experiment module. Orchestrates one or more devices into a complete measurement workflow. Does not control hardware directly.

Gate d1 not activated
"analyzer"

A HUB analyzer module. Processes raw data from device outputs into meaningful results — fitting, reduction, visualisation, or classification.

Gate d1 not activated
"core"

A core PLESTY library or SDK module (plesty-lib, plesty-sdk). Not a HUB contribution. Used internally by the PLESTY team.

Gate d1 not activated
📖 Tutorial — Adding module_type to Your Module
1

Open your module's pyproject.toml

Find the [tool.plesty] section. If it only has standard = "quantum", you are ready to add the type.

# Before — no module_type declared [tool.plesty] standard = "quantum"
2

Add module_type on the next line

Choose the value that matches what your module does. For a device driver, use "device".

# After — device module declared explicitly [tool.plesty] standard = "quantum" module_type = "device" # activates Gate d1
# For an experiment module [tool.plesty] standard = "quantum" module_type = "experiment"
# For a core library (plesty team only) [tool.plesty] standard = "quantum" module_type = "core"
3

Run plesty check and observe Gate 1

Gate 1 now reads and validates the value. For a device module, Gate d1 activates automatically after the standard gates pass.

# Device module — Gate d1 activates automatically $ uv run plesty check --standard quantum Metadata & Namespace Code Hygiene (lint) Code Hygiene (format) Code Hygiene (types) API Interface Matching Data Layer Compliance Documentation Completeness Dependency Coexistence Automated Test Coverage (≥80%) Semantic Versioning Licensing Compliance Vulnerability Audit (no known CVEs) Docs Build Device API Pipeline (d1 — 8 mock gates pass) All checks passed.
# Non-device module — Gate d1 reports N/A Metadata & Namespace ... Device API Pipeline (N/A — not a device module)
4

Unknown values are caught immediately

Gate 1 rejects any value not in the known set. The error tells you exactly what to fix.

# If you write module_type = "instrument" (not a valid value) $ uv run plesty check --standard quantum Metadata & Namespace Error: [Metadata] Unknown module_type 'instrument' in [tool.plesty]. Valid values: 'device', 'experiment', 'analyzer', 'core'.
🔄 Before vs After — Implementation
✗ Before — AST scanning (fragile)
# ~50 lines, grows with every edge case def _is_device_module(project_dir: Path) -> bool: for py_file in project_dir.rglob("*.py"): if "assets" in py_file.parts: continue # exclude SDK templates if "tests" in py_file.parts: continue # exclude test fixtures try: tree = ast.parse(py_file.read_text()) except SyntaxError: continue for node in ast.walk(tree): if isinstance(node, ast.ImportFrom): if (node.module and "plesty.lib.device" in node.module): return True return False
✓ After — TOML field (explicit)
# 3 lines, zero edge cases, always correct def _is_device_module( pyproject_toml: dict ) -> bool: return ( pyproject_toml .get("tool", {}) .get("plesty", {}) .get("module_type") == "device" ) # And in pyproject.toml: # [tool.plesty] # module_type = "device"
🔗 Effect on the Check Pipeline
How module_type flows through plesty check
📄 pyproject.toml
module_type = "device"
Gate 1
validates value
if "device"
Gate d1 activates
8 mock tests run
otherwise

The module_type field is read once, validated by Gate 1, and its value gates subsequent checks. No other configuration is required to enable or disable Gate d1.