Reference
Review Checklist
Every connector best-practice rule in one list, with a stable ID to cite in reviews.
Each rule has a stable ID you can cite in a review comment or merge request, such as op-property-per-value. The Details column links to the page that explains the rule or shows how to apply it.
Naming
| ID | Rule | Details |
|---|---|---|
name-title-case-display-name | Display name in Title Case with spaces | Naming |
name-hyphen-case-project-name | Project name in hyphen-case | Naming |
name-snake-case-package-name | Package name in snake_case | Naming |
name-no-unitelabs-in-project-name | Don't include unitelabs in the project or package name | Naming |
name-no-rename-without-migration-plan | Don't rename a connector without a migration plan | Naming |
name-folder-mirrors-class | Feature folder and module are the snake_case form of the class | Naming |
name-short-file-names | Short file names that don't repeat the package name | Naming |
name-suffix-by-role | Controller, Provider, or Service suffix by role | Naming |
name-service-for-maintenance-features | Service for teaching, calibration, and server settings | Naming |
name-actor-not-artifact | Name the actor, not the artifact | Naming |
name-no-feature-suffix | No Feature in class names | Naming |
name-no-package-in-class-name | Don't repeat the package name in class names | Naming |
name-no-abbreviations | Spell out full words | Naming |
name-get-prefix | get_ prefix on unobservable properties | Naming |
name-subscribe-prefix | subscribe_ prefix on observable properties | Naming |
name-verb-for-commands | Commands start with an action verb | Naming |
name-full-words-for-identifiers | Full words in method names | Naming |
name-explicit-name-for-acronyms | Set name= to keep an acronym uppercase | Naming |
name-no-redundant-context | Don't repeat the feature's context in endpoint names | Naming |
name-no-units-in-identifier | No units in identifiers | Naming |
name-one-name-everywhere | One name for file, class, and identifier | Naming |
name-normalize-vendor-terminology | Use the standard term, not the vendor's | Designing Features |
name-model-the-intent-not-the-mechanism | Name the operation the client cares about | Designing Features |
name-standard-command-vocabulary | Use a standard verb when one matches | Naming |
name-check-sila-base-feature-repo-first | Check the SiLA base feature repository first | Naming |
name-parametrized-multi-instance | One parametrized class per repeated module | Repeated Modules |
name-index-before-suffix | <Noun><Index><Suffix>, index injected via name= | Repeated Modules |
name-slot-id-for-homogeneous-instances | One feature with a slot parameter for interchangeable positions | Repeated Modules |
Docstrings
| ID | Rule | Details |
|---|---|---|
doc-google-style-docstrings | Google style, no RST directives | Docstrings |
doc-no-types-in-docstring | No types in Args:/Returns: | Docstrings |
doc-no-units-in-docstring | No units in docstrings; annotate a Unit | Docstrings |
doc-two-space-indent | 2-space indent under section headers | Docstrings |
doc-describe-what-and-when | Feature docstring says what and in which context | Docstrings |
doc-args-section-pascalcase | Args: entries in PascalCase | Docstrings |
doc-params-match-signature | Document parameters in signature order | Docstrings |
doc-returns-section-pascalcase | Returns: entries in PascalCase | Docstrings |
doc-yields-section-pascalcase | Yields: for intermediate responses | Docstrings |
doc-no-args-on-properties | No Args: on properties | Docstrings |
doc-no-returns-on-properties | No Returns: on properties | Docstrings |
doc-raises-to-override-description | Raises: only to override the default description | Docstrings |
doc-no-generic-error-documentation | Don't document errors that can happen anywhere | Docstrings |
doc-no-pythonic-examples | No doctest examples | Docstrings |
doc-sila-identifiers-in-descriptions | Refer to other endpoints by SiLA identifier | Docstrings |
Features
| ID | Rule | Details |
|---|---|---|
feat-originator-reverse-domain | Reverse domain notation for originator | Feature Metadata |
feat-no-default-originator | Never leave originator unset | Feature Metadata |
feat-namespace-format-for-originator-category | Lowercase, digits, and dots only | Feature Metadata |
feat-category-domain-choice | One functional domain; reuse existing categories | Feature Metadata |
feat-version-default-then-bump | Leave version unset until it bumps; major.minor only | Feature Metadata |
feat-maturity-level-draft-default | Leave maturity_level unset | Feature Metadata |
feat-be-opinionated-about-interface-design | Design for the user, not the vendor's manual | Designing Features |
feat-one-feature-per-concern | One feature per concern | Designing Features |
feat-register-before-yield | Register features before yield app | Connector Architecture |
Endpoints
| ID | Rule | Details |
|---|---|---|
op-observable-property-for-changing-values | Observable for changing values, unobservable for static ones | Designing Endpoints |
op-no-side-effects-in-properties | Properties never change device state | Designing Endpoints |
op-property-per-value | One property per piece of information | Designing Endpoints |
op-no-selector-parameter | No parameters that only select which value to return | Designing Endpoints |
op-long-or-risky-commands-observable | Observable for movement or anything over ~300 ms | Designing Endpoints |
op-no-fake-progress | No fabricated progress | Designing Endpoints |
op-indefinite-duration-start-stop-pair | Start/stop pair for actions with no natural end | Designing Endpoints |
op-cancellable-movement-commands | Movement commands can be cancelled | Designing Endpoints |
op-prefer-idempotent-commands | Calling twice has the same effect as calling once | Designing Endpoints |
op-raise-on-already-in-progress | Raise a clear error if the operation is already running | Designing Endpoints |
op-caller-can-always-tell-outcome | Return normally on success, raise on failure | Designing Endpoints |
op-recovery-through-normal-commands | Every reachable state is recoverable through normal commands | Designing Endpoints |
op-no-boolean-success-response | No Success: bool responses | Designing Endpoints |
op-bool-param-over-split-methods | One bool parameter for a strictly two-state setting | Designing Endpoints |
op-parameter-order-convention | Axes first, then by impact, duration last | Designing Endpoints |
op-execution-mode-by-repeatability | SINGLE for movement; queue only idempotent commands | Execution Modes |
op-expose-stateless-api | Endpoints are stateless | Designing Endpoints |
op-enabled-for-device-variants | enabled= to hide endpoints a variant lacks | Device Variants |
op-enable-as-overload | enabled= plus name= to overload an endpoint per variant | Device Variants |
Data types and constraints
| ID | Rule | Details |
|---|---|---|
dt-constraints-applied-to-all-values | Constrain parameters and return values wherever it applies | Constraints and Units |
dt-static-constraints-via-annotated | Static constraints via typing.Annotated | Constraints and Units |
dt-runtime-constraints-on-startup | Device-dependent constraints in on_before_start | Constraints and Units |
dt-validation-error-for-fully-dynamic-constraints | Validator plus documented range for per-call limits | Constraints and Units |
dt-binary-for-raw-data | bytes for raw payloads | Designing Data Types |
dt-content-type-for-known-binary-format | ContentType for known binary formats | Designing Data Types |
dt-dataclass-for-grouped-data | Dataclass for grouped values | Designing Data Types |
dt-no-raw-xml-json-string | No raw XML or JSON strings | Designing Data Types |
dt-no-nested-lists | No lists of lists | Designing Data Types |
dt-enum-for-status | Enum for status and state values | Designing Data Types |
dt-unit-constants-in-io-units | Define units once in io/units.py | Constraints and Units |
dt-propagate-device-native-units | Expose the unit the device uses | Designing Data Types |
dt-fractional-unit-two-cases | Fractional units: expose as-is, or convert firmware workarounds | Designing Data Types |
dt-liquid-handler-origin-at-tip-bottom | Liquid handler origin at the bottom of the tip | Designing Data Types |
Input-output
| ID | Rule | Details |
|---|---|---|
io-no-movement-on-transport-open | No physical movement when the transport opens | Connector Architecture |
Error handling
| ID | Rule | Details |
|---|---|---|
err-only-execution-errors-in-decorator-or-raises | Only declare execution errors | Error Handling |
err-define-error-per-failure-mode | One exception per expected failure mode | Error Handling |
err-surface-hardware-error-codes | Include the device's error code in the message | Error Handling |
err-actionable-runtime-messages | Say what happened and what to try next | Error Handling |
err-no-all-errors-declared | Only declare errors the caller can react to | Error Handling |
err-start-real-mode-failed | Stay in simulation if real mode can't connect | Testing |
Project structure
| ID | Rule | Details |
|---|---|---|
proj-features-import-from-io-not-reverse | features/ imports from io/, never the reverse | Connector Architecture |
proj-io-has-no-sila-knowledge | io/ has no knowledge of SiLA | Connector Architecture |
proj-no-helpers-in-feature | Business logic lives in io/, not in feature helpers | Connector Architecture |
proj-delegate-protocol-by-module | Split a long protocol into per-module delegates | Project Structure |
proj-protocol-layer-mirrors-vendor-docs | Name io/ commands as the vendor does | Project Structure |
proj-dedicated-config-py | Configuration in config.py | Project Structure |
proj-no-commit-config-json | Don't commit config.json | Project Structure |
proj-hardware-errors-in-io-errors | Hardware exceptions in io/errors.py | Project Structure |
proj-debugging-commands-in-own-feature | Debugging commands in their own feature | Project Structure |
proj-extend-standard-feature-in-place | Add device-specific endpoints to the standard feature | Project Structure |
proj-public-top-private-bottom | Constructor, properties, public, then private methods | Project Structure |
proj-descriptive-private-method-names | Self-descriptive private method names | Project Structure |
Testing
| ID | Rule | Details |
|---|---|---|
test-always-include-simulation-mode | Every connector runs without hardware | Testing |
test-simulate-at-protocol-level-not-feature-level | Simulate in the protocol, not in features | Testing |
test-simulation-true-by-default | Simulation mode defaults to on | Testing |
test-simulation-stubs-in-io | Simulation stubs live in io/ | Testing |
test-mirror-package | tests/ mirrors the package layout | Testing |
test-protocol-with-stubbed-responses | Unit-test every io/ method with stubbed responses | Testing |
Last updated