Code style and quality checks
On this page
RosieOS has one quality runner, quality/quality.mjs, plus conventions that the code follows everywhere. Run the gate before you open a pull request:
npm ci --prefix coordination/v1 # installs the pinned npm tools the runner uses
node quality/quality.mjs checkEach step prints a status line: passed, rejected, capability_unavailable (the tool is missing) or report_completed_not_qualified. The runner exits 1 if any step was rejected or unavailable.
Gate commands#
These are the checks CI runs (quality-pilot.yml). They cover the TypeScript sources the runner owns, in coordination/v1, and they use the tools pinned in that directory's lockfile: Oxfmt, Oxlint, ast-grep and tsc.
| Command | What it does |
|---|---|
node quality/quality.mjs check | The CPU-only CI gate: the runner's own tests, then format-check, lint and typecheck, then the unit and schema tests. The default command. |
node quality/quality.mjs format | Rewrites formatting with Oxfmt. The only command that edits files. |
node quality/quality.mjs format-check | Oxfmt in check mode. |
node quality/quality.mjs lint | Oxlint, plus the tested ast-grep rules in quality/sgconfig.yml. |
node quality/quality.mjs typecheck | Generates Worker types, then runs tsc. |
The runner uses explicit allowlists. It never formats evidence, CAD, generated files, vendor code or legacy trees.
Report commands#
These are not CI gates. Run them on the component you change. A missing tool or a nonzero tool exit still fails the run, and none of them applies fixes.
| Command | Scope | Tool |
|---|---|---|
node quality/quality.mjs python | weld_planner/v1 python/, tests/, tools/ | Ruff 0.15.6 through uvx (format check and lint), with the project's Ruff settings |
node quality/quality.mjs go | gofmt over tracked steamdeck/real/v4 sources, then golangci-lint 2.13.2 with quality/golangci.yml | Go toolchain of that module |
node quality/quality.mjs rust | daemon/v1: cargo fmt --check, then Clippy on all targets | Rust 1.95.0 through rustup |
node quality/quality.mjs workflows | Every workflow | actionlint 1.7.12 |
node quality/quality.mjs shell | dev-stack.sh | ShellCheck, installed by you |
node quality/quality.mjs cpp <compile-db-dir> <source> | One .cpp file under motion-server/joint-trajectory/v1/src, with a real compile_commands.json | clang-format and clang-tidy, with quality/clang-format.yml and quality/clang-tidy.yml |
Clippy can exit 0 with warnings, so the Rust step reports report_completed_not_qualified, never passed. Read its output. The C++ configuration is opt-in and is not a repository-wide style.
Conventions#
These are visible throughout the code. Follow them in new code.
Every constant carries its evidence#
A tunable number states, in the comment above it, whether it was measured and where, or that it is unverified:
// Measured repository dependency: host/ethercat-foundation.sh pins IgH 1.6.9.
const hostcheckIgHVersion = "1.6.9"
// Unverified inspection ceiling: 1000 ns CLOCK_MONOTONIC resolution.
const hostcheckTimerResolutionNS = 1000If you change a constant, update its measurement or mark it unverified.
Configuration follows the same rule. Every numeric robot fact and every safety exception in a config file needs a _source ("cited: …") or _unverified ("unverified: …") sibling, and the compiler refuses one without it. See provenance siblings.
Units are in the name#
Fields and variables carry their unit: cycle_ns, lease_ms, velocity_rad_s, acceleration_rad_s2, xyz_m, rpy_rad, following_error_counts_max. The public rt-core API uses rad or m, rad/s or m/s, and ns on the host's CLOCK_MONOTONIC. When a unit changes at a boundary, name both sides.
Docstrings state the contract#
A doc comment says what the code guarantees and the failure it exists to prevent, not what the next line does:
// DefaultRoot finds config/drives beside the build directory or above the
// working directory, preventing unrelated launch directories from selecting a
// different drive config tree.Fail closed, with a named reason#
- Reject unknown fields, duplicate keys, trailing data and malformed values. Do not fall back to a default when an input is invalid.
- Refuse with a stable, named reason (
robot_description_mismatch,resource_unknown) and a detail that says what to change. - Never hide an error by dropping failure handling or weakening a test. A suppression comment must name the rule and the reason.
Tests assert absolute units#
Assert the contract in fixed units, such as "within 0.5 mm" or "under 250 ms". Do not compute a threshold from the thing under test (for example from a trajectory's own time step): a threshold that moves with the behaviour still passes when the behaviour collapses.
Generated code is never edited#
Change the contract in rt-core/protocol/ and regenerate. See generated code.
Keep formatting separate#
Use one formatter per language, and keep formatting-only commits apart from behaviour changes.
Note
Linters and formatters prove none of these: installation, controller admission, collision freedom or physical execution. Do not describe a clean check as qualification.