Advanced Metal Research
GitHub Contact AMR

Code style and quality checks

On this page
  1. Gate commands
  2. Report commands
  3. Conventions
  4. Every constant carries its evidence
  5. Units are in the name
  6. Docstrings state the contract
  7. Fail closed, with a named reason
  8. Tests assert absolute units
  9. Generated code is never edited
  10. Keep formatting separate

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 check

Each 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.

CommandWhat it does
node quality/quality.mjs checkThe 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 formatRewrites formatting with Oxfmt. The only command that edits files.
node quality/quality.mjs format-checkOxfmt in check mode.
node quality/quality.mjs lintOxlint, plus the tested ast-grep rules in quality/sgconfig.yml.
node quality/quality.mjs typecheckGenerates 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.

CommandScopeTool
node quality/quality.mjs pythonweld_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 gogofmt over tracked steamdeck/real/v4 sources, then golangci-lint 2.13.2 with quality/golangci.ymlGo toolchain of that module
node quality/quality.mjs rustdaemon/v1: cargo fmt --check, then Clippy on all targetsRust 1.95.0 through rustup
node quality/quality.mjs workflowsEvery workflowactionlint 1.7.12
node quality/quality.mjs shelldev-stack.shShellCheck, 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.jsonclang-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:

rt-core/tools/rtctl/hostcheck.gogo
// 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 = 1000

If 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:

rt-core/tools/rtctl/command.gogo
// 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.