Tools
Part of the OpenRAL public-symbol inventory. Hand-curated;
(LNN)markers are refreshed bytools/refresh_methods_linenos.py.
tools/lifecycle_autostart.py
Drives a lifecycle node through configure → activate after ros2 launch brings it up. Spawned per node by deploy_e2e.launch.py for the HAL, safety kernel, and reasoner.
--transition-timeout-s— Per-transition spin budget, default300.0; the HAL's budget is derived per scene, not hardcoded — raise the scene'sbackend_options.boot_timeout_sinstead of this flag.- Why the HAL's is derived. The bound must cover the whole
on_configure, including a sidecar's spawn — some backends need far more than 300 s to boot, so the timeout is set per scene rather than fixed. --required(flag) — Treat an absentchange_stateservice as a failure (exit 1) instead of informational, so a missing node cannot come up looking healthy; used for the deadman watchdog so a deploy without it refuses to run.- Transitions carry their label as well as their id. rclpy refuses an invalid labelled
ChangeStatewithsuccess=False, but an id-only one raises out of the target's service callback and kills the node; with the label, a transition another activator already made redundant is refused harmlessly. _STATE_TO_TRANSITION: dict[str, list[int]](L36) —--target→ theTransitionconstants to drive in order (inactive= CONFIGURE;active= CONFIGURE then ACTIVATE).main() -> int(L127) — CLI entry; parses--node/--target/--required/--service-timeout-s/--transition-timeout-s(documented above) and drives the transitions via_drive_transition.
tools/profile_policy_load.py
One-shot wall-time breakdown of a single policy load. Drives openral_sim.factory.make_policy against an in-tree rSkill manifest and prints a phase-by-phase summary. Use when a launch or openral sim run is slow to first action, to see where the seconds go.
Wired as just profile-load <rskill> [args]. Families whose adapter lacks a phase-timer helper report "no phase_timer events captured", but the end-to-end total is still valid.
class _PhaseCapture—structlogprocessor that buffers_start/_doneevents and pairs them by name. Insertion-ordered so the rendered table mirrors the actual load order. (L35)_parse_args(argv) -> argparse.Namespace—--rskill <dir>(required),--device(defaultauto). (L69)_build_env_cfg(rskill_dir, *, device) -> _SimpleEnvCfg— Builds a minimal env_cfg from<rskill_dir>/rskill.yaml; mirrorsrskill_runner_node._SimpleEnvCfg. (L103)_render(pairs, total_s) -> str— Formats the captured pairs asphase / elapsed_s / sharecolumns plus an(unaccounted)row when phase coverage misses >1 s. (L122)main(argv=None) -> int(L149) — Late-importsopenral_sim.factory.make_policyso the import cost lands inside the profiled total; reportsHF_HUB_OFFLINEstatus alongside the result.
tools/viz_collision.py
Overlays a robot's kernel collision primitives — the shapes the C++ safety kernel checks — on its real meshes at any joint pose, for eyeballing whether they clear the robot without running a deploy. Standalone inspection tool, not a pytest test; run with PYTHONPATH=packages/openral_safety.
--viewer— interactive MuJoCo window;--screenshot PATHwrites an offscreen PNG;--rvizpublishes the primitives as markers in RViz.--robot <id>(defaultso101_follower) and--deg <j...>set the pose in degrees.main(argv=None) -> int(L334) — CLI entry; builds the robot's kernel collision primitives and dispatches to the viewer/screenshot/RViz renderer named above.
tools/derive_scene_inputs.py
Derive a deploy scene's safety inputs from the simulator instead of by hand (#349): the declared static geometry and the grasp declaration's search_box / workspace_box. Backend-neutral (Isaac sidecar or MuJoCo); explicit scene values win unless --replace, and both are printed for comparison.
to_declared(box) -> dict(L40) — A backendkind: boxcollider as aStaticBoxentry (quat_xyzw, base frame).mesh_bounds(vertices) -> tuple[list[float], list[float]](L68) — Centre and half-extents of a vertex set's axis-aligned bound.nearest_distance_m(entry) -> float(L80) — Lower bound on an entry's distance from the base-frame origin.aabb(box) -> Bbox(L92) — Base-frame axis-aligned bound(x0, y0, z0, x1, y1, z1)of an oriented{center_m, rotation, half_extents_m}box.source_fixture(obj, colliders, tol_m=0.02, gap_m=0.25) -> tuple[Bbox, str] | None(L114) — The static collider group the object rests on (highest box under the object's centre, then every collider sharing its parent path and connected to it withingap_m— RoboCasa's parked unused panels 10 m up are not) and its bound: a tote's floor + walls + rims, a counter body's geoms.destination_hull(placements, obj_name, anchor, cap_m) -> tuple[Bbox | None, list[str], list[str]](L171) — The hull ofobj_name's candidate destinations (one placement each:target+adjacent) that reach into the pick'sanchor±cap_mwindow, and the names kept / dropped; a candidate wholly outside (a mobile base drives between pick and place) is dropped.maingrounds the workspace from the source fixture and this hull, and falls back to the pick side alone (logged) when the two together exceed the workspace caps.write_static(reply, out, max_distance) -> int(L272) — The backend's colliders as aStaticGeometryYAML (meshes as.npzbeside it).main(argv=None) -> int(L331) — Boots the scene (build_sim_env_from_yaml), resets at its seed, exports static colliders (Isaacstatic_collider_boxes; MuJoComujoco_geometry.static_collider_boxeswith the robot's bodies excluded; none for a mobile base, whose base-frame fixtures hold only at the reset pose),set_task(prompt)+scene_ground_truth, groundssearch_boxwithground_grasp_target(sim objects asDetectedObjects) andworkspace_boxwithground_workspace(source fixture + destination region and its graded-adjacent regions), and writes the derived scene (--out, static geometry beside it).
tools/generate_tight_geometry.py
Derives a robot manifest's tight_geometry blocks from its real collision meshes, for the safety kernel's staged 26-DOP → convex-hull narrow phase. Both stages are proven to contain the mesh by construction, and mesh placement follows the GEOM transform only. Standalone operator/CI tool needing mujoco + scipy + robosuite; see collision-hull-narrow-phase.md.
Two modes: emit --robot <path> prints the YAML fragment to paste into the manifest, annotated per link with vertex counts and margins; check --robot <path> re-derives from the mesh and verifies every declared block still contains it, exiting 3 on any failure.
REPO_ROOT: Path(L46) — Repo root, derived from this file's location.PANDA_GEOM_OF_LINK: dict[str, str](L78) — Panda manifest link name → MJCF collision geom name (panda_link{i}→link{i}_collision).link_mesh_in_box_frame(xml_path, geom_name, origin_xyz_rpy) -> np.ndarray(L112) — Collision-mesh vertices ofgeom_name, expressed in the manifest box's frame. Raises when the geom is missing, isn't a mesh, or whenmesh_pos != geom_pos.link_mesh_faces(xml_path, geom_name) -> Points(L148) — Triangle face indices ofgeom_name's collision mesh, paired withlink_mesh_in_box_frame's vertices for the overhang check.ROBOT_MESH_SOURCES: dict[str, tuple[str, dict[str, str]]](L82) — Robot name → its MJCF asset path and manifest-link → MJCF-geom name map. A new robot must be registered here before either mode will run for it.main(argv=None) -> int(L295) — CLI entry;emit --robot <path>/check --robot <path>subcommands.- Re-exported from
openral_safety.tight_geometry(moved there so the collision lowering can refine links; see06-reasoning-wam-safety-observability.md):derive_tight_geometry,hull_overhang_m,refine_dop_to_budget,_dop_axes, and_round_up_m/_HULL_OVERHANG_SAFETY_MARGINunder their old names. The tool insertspackages/openral_safetyonsys.pathfor a standalone run.
tools/schema_export.py
Generates JSON Schema files for every public openral_core model.
_enum_schema(cls) -> dict[str, Any]— Minimal JSON Schema for astrEnum. (L187)export_schemas(out_dir=_OUT_DIR) -> dict[str, Any]— Export JSON Schema for every public model. (L199)check_drift(out_dir=_OUT_DIR) -> bool— On-disk schemas == regenerated. (L251)
tools/check_repo_state_map.py
Pre-commit drift guard checking the mechanically verifiable half of docs/architecture/repo-state-map.html: that every card field is a well-formed string literal, its pkg: pointers name something real and its asserted counts haven't rotted. Prose on the map stays a human judgement call.
REPO_ROOT(L41) — Repo root, derived from this file's location.MAP_PATH = REPO_ROOT / "docs" / "architecture" / "repo-state-map.html"(L42) — The map file this script checks.- module const
COUNT_TOLERANCE: float(L67) — Counts are held to within 10%, not to the digit — an exact check would go red on every added test file and get disabled. iter_cards(html: str) -> list[tuple[str, str]]— Pair eachpkg:value with thedesc:that follows it in the same card. (L93)_resolves(head: str, token: str) -> bool— Whether apkg:token names a real path under any of the three spellings the map uses: repo-root-relative, relative to the card's leading package under the workspace src layout, or a bare module name. (L102)check_paths(cards) -> list[str]— Reportpkg:tokens that name nothing on disk. (L123)check_counts(cards) -> list[str]— Reportdesccounts that have drifted pastCOUNT_TOLERANCE. (L142)check_literals(html) -> list[str]— Report data lines whose string literals are not well-formed JS strings, each line shape checked whole: cardtitle/pkg/status/descscalars (matched on the field name, so a field missing its opening quote is reported, not skipped), cardinputs/outputs/schemasarrays, and the one-line SCHEMAS rows; an unescaped"there blanks the whole page while the path/count regexes still parse the prefix. (L161)main(argv: list[str] | None = None) -> int(L179) — CLI entry;--quiet; runscheck_literals+check_paths+check_counts, prints drift and returns 1, else 0.
tools/audit_sim_configs.py
Real GPU rollout audit for every YAML under scenes/. Operator-driven, one episode per config; writes outputs/audit_sim_configs.json and prints a Markdown table (just sim-audit). Two modes: a full rollout, or --check-compatibility for a cheap in-process gate with no subprocess or GPU.
REPO_ROOT: Final[Path](L39) — Repo root, derived from this file's location.SCENES_DIR: Final[Path] = REPO_ROOT / "scenes"(L40) — Root of the scanned scene tree.OUTPUT_DIR: Final[Path] = REPO_ROOT / "outputs"(L41) — Whereaudit_sim_configs.jsonis written.DEFAULT_TIMEOUT_S = 600(L42) — Default--timeout, 10 min/config — covers cold weights download.DEFAULT_DEPLOY_ALIVE_GRACE_S = 90(L43) — Default--deploy-alive-grace: how long a deploy-mode graph is left running before SIGINT.DEFAULT_DEPLOY_SHUTDOWN_GRACE_S = 30(L44) — Default--deploy-shutdown-grace: how long to wait after SIGINT before escalating to SIGKILL.RunMode = Literal["sim", "benchmark", "deploy"](L46) — Tier selector on eachConfigSpecrow; drives_run_onevs_run_one_deploydispatch.@dataclass(frozen=True) class ConfigSpec(config, rskill, uv_group, run_mode)(L50) — One row in the audit catalogue;rskillis empty for deploy rows since the reasoner picks at runtime. Only holds pairs that actually exist in the tree.CATALOGUE: tuple[ConfigSpec, ...](L78) — Explicit (YAML → rSkill → uv group → run_mode) mapping for every config currently in the tree: 13 sim + 7 benchmark + 4 deploy = 24 rows.@dataclass class AuditRow(config, rskill, status, exit_code, wall_s, peak_vram_mib, tail)(L168) — One result.status∈ {pass,pass-compat,fail-oom,fail-asset,fail-sidecar,fail-timeout,fail-other,fail-compat,skipped-opt-dep,skipped-host-setup}._classify(returncode: int, tail: str) -> str(L219) — Maps a subprocess result to a status by matching stderr against known OOM/asset/sidecar/opt-dep/host-setup patterns; a known MuJoCo/GL exit code is treated as pass when no error pattern appears.class _VramSampler(L258) — Backgroundnvidia-smi --query-gpu=memory.usedpoller, 200 ms cadence;peak_mibreported on.stop(). No-op withoutnvidia-smion$PATH._check_compat(spec: ConfigSpec) -> AuditRow(L303) —--check-compatibilitygate: load scene viaopenral_core.load_scene_strict, validate rSkill manifest (sim/benchmark) or assert the robot manifest resolves viaopenral_sim.policies.robots.resolve_robot_manifestand loads (deploy). No subprocess, no GPU. Returnspass-compat/fail-compat._build_run_cmd(spec: ConfigSpec) -> list[str](L386) — Build theuv run … openral <sim|benchmark> …argv for sim/benchmark rows. Refactored out of_run_oneso the deploy path can stay focused on lifecycle teardown._run_one_deploy(spec, *, alive_grace_s, shutdown_grace_s, timeout_s) -> AuditRow(L435) — Tier-2 deploy launch viaopenral deploy sim: runs in its own process group, waitsalive_grace_s, sends SIGINT to the group, waitsshutdown_grace_s, then escalates to SIGKILL. Passes when the startup banner appears and the exit reflects a clean or SIGINT/SIGTERM shutdown._classify_or_fallback(returncode, tail, spec, wall_s, peak_vram) -> AuditRow(L606) — Deploy-mode wrapper around_classifythat defaults tofail-otherwhen no pattern matches (sim path defaults topass)._run_one(spec: ConfigSpec, timeout_s: int) -> AuditRow(L645) — Tier-3 sim/benchmark rollout via_build_run_cmd(spec)withMUJOCO_GL=eglandOPENRAL_SIM_SEQUENTIAL_INIT=1.main(argv) -> int(L783) — CLI entry; flags--timeout/--deploy-alive-grace/--deploy-shutdown-grace/--check-compatibility/--report. Returns 0 on all-pass, 1 if any config failed, 2 on filter mismatch.
tools/validation_matrix.py
The four-scene collision-stack validation matrix as one versioned command, emitting both NOTES.md and a machine-readable verdicts.json per round. Backs just validation-matrix / -verdicts / -diff. See docs/contributing/validation-matrix.md and the ledger it feeds, docs/reference/collision-validation-evidence.md.
REPO_ROOT: Final[Path](L61) —Path(__file__).resolve().parents[1].OUTPUT_ROOT: Final[Path](L62) —REPO_ROOT/"outputs"/"validation-matrix".DEFAULT_RSKILL_ID: Final[str](L120) —"OpenRAL/rskill-xr1-panda_mobile-robocasa365-nf4".LAUNCH_FAILED_MARKER: Final[str] = "launch_failed.txt"(L1102) — Suffix of the runner's own launch-failure marker file, the first thingdetect_launch_failurechecks for.DISPATCH_READY_TIMEOUT_S: Final[float] = 180.0(L2199) — Timeout bound for the goal re-dispatch loop when the graph answers but is not assembled yet (paired withDISPATCH_RETRY_INTERVAL_S).@dataclass(frozen=True) class SceneSpec(key, config, prompt, deadline_s)— One matrix row;configis the tracked DeployScene YAML, and the round launches a resolved copy carrying the seed and CLI-less pins. (L80)MATRIX: tuple[SceneSpec, ...]— The four scenes:baguette,sink_cup,fridge,utensil. (L97)SYNC_GROUPS = ("robocasa", "sidecar-wire")— Both, always:--group robocasaalone stripspyzmqand breaks the XR-1 adapter. (L124)STACK_ARGV: tuple[str, ...]— The flag-pinnable stack: SLAM/Nav2/octomap/kernel-check on, detector + scene VLM off, headless. (L129)SCENE_RUNTIME_PIN: tuple[tuple[str, bool], ...]—enable_reasoner=False: the one pinned knob with no CLI flag, spliced into the resolved scene copy sincedeploy simdefaults it toTrue. (L170)LEGACY_SCENE_DIRS: tuple[tuple[str, tuple[str, ...]], ...]— Scene key → the directory names pre-harness rounds used, soimport-roundneeds no hand-mapping. (L209)quantization_budget_m(grid_resolution_m: float) -> float— Half the voxel's body diagonal; the largest kernel-vs-ground-truth discrepancy a correct grid can produce. (L220)collision_scale_env() -> dict[str, float]— The graded-velocity band the round runs with, read from theOPENRAL_COLLISION_SCALE_*env varsdeploy_e2e.launch.pyconsumes; recorded because an argv-based override check cannot see it. (L1774)parse_kernel_collision(lines) -> ValidationStopEvidence | None— Transcribe the firstsafety.collisionline verbatim. (L240)parse_json_log_line(lines, event) -> dict[str, Any] | None— Payload of the first<event> {...}line (sim.task_success_final,sim.estop_ground_truth_snapshot,sim.estop_initial_configuration). (L298)read_monitor(path) -> list[dict[str, Any]]— Load a monitor JSONL, skipping non-object lines. (L332)grid_resolution_from_monitor(records) -> float | None— Cell size from the firstworld_voxelsrecord; the budget is read from the run, never assumed. (L356)monitor_subscription_records(records) -> int— Record count excluding the monitor's own start/stop markers, i.e. what it actually received.0means the monitor's DDS participant missed the run — a harness fault, not evidence the run stopped early. (L379)build_witness_timeline(records, deploy_lines) -> ValidationWitnessTimeline— Producer side from the monitor, consumer side from the kernel's ownsafety.support_witness_*/safety.place_region_*lines. (L401)probe_is_collidability_filtered(snapshot) -> bool— Whether every non-empty coverage block in the snapshot excludes non-collidable side geoms, i.e. the HAL filtered both sides of each probe to solid geoms.Falsefor any snapshot recorded before that filter existed. (L503)hal_admissible_gap_m(snapshot, stop, grid_resolution_m=None) -> float | None— The HAL's own kernel-vs-probe budget for a stop, dispatched by stop class.Nonefor a snapshot predating the budget; an over-large budget silently excuses a stop rather than failing loudly, which is the direction that hides a real defect. (L571)_payload_world_gap_m(budget, grid_resolution_m) -> float | None— The payload-vs-world-voxel half ofhal_admissible_gap_m: model overhang plus the voxel half-diagonal, re-derived when the snapshot's voxel term is zero. ReturnsNone(unadjudicated) rather than a number that convicts when it can't be computed._arm_world_gap_m(budget, grid_resolution_m) -> float | None— The arm-link-vs-world-voxel half: corner slop of the worst link plus the voxel half-diagonal, re-derived when the snapshot's is zero so an omission can't understate the budget. Falls back to the published composition when a term is absent._link_link_gap_m(budget, stop) -> float | None— The link-vs-link half, extracted alongside it so the dispatcher above reads as one line per stop class.probe_is_distance_certified(snapshot) -> bool(L532) — Whether every non-empty coverage block reports zero uncertified pairs, i.e. distances were measured with the kernel's own convex-distance code rather than MuJoCo's, which can be wrong by tens of millimetres on some pairs.Falsefor any round predating this certification check.adjudicate_ground_truth(snapshot, stop, grid_resolution_m, *, monitor_records=None) -> ValidationGroundTruthAdjudication | None— Distance-probe adjudication ladder: a pair at ≤0 m isreal-contactonly when collidability-filtered; a gap beyond budget isfalse-positiveonly when the budget is trusted. Every verdict is withdrawn tounadjudicatedunless the probe is distance-certified. (L781)detect_launch_failure(run_dir, stem, deploy_lines) -> str— Why a scene is not a run at all: a launch-failure marker, aros2 launchexception, a CLI usage-error banner, no log, a Nav2 bond teardown, or a graph that never came up. Empty when the scene ran; this is whatartifacts_completechecks. (L1249)_nav2_bond_teardown(deploy_lines) -> str— A Nav2 bond-heartbeat timeout tears the whole stack down silently, leaving the graph inert until its deadline — which the harness would otherwise score as a policy failure to grasp. Discriminated from a late teardown by how early the loss occurs._lacks_stage2_hull(link) -> bool— Whether a link is known to carry no stage-2 hull. Only an explicitFalsecounts — an older snapshot without the field must read as unknown, never as "no hull". Used by_link_link_hull_gap_m.dispatch_not_ready_reason(goal_log) -> str(L2203) — Why a dispatch reports the graph as not assembled yet (e.g. a disconnected TF tree or a camera that published nothing), so the goal can be retried instead of scored as a non-completion. Never matches a real E-stop, deadline or capability mismatch.tests/unit/test_dispatch_readiness.py.DISPATCH_RETRY_INTERVAL_S: float(L2200) —12.0; how oftendispatch_not_ready_reasontriggers a re-dispatch._NAV2_BOND_LOSS_EARLY_S: float(L1142) —120.0; a bond-loss timestamp inside this window of the log's start is scored as_nav2_bond_teardown, not an ordinary non-completion._lifecycle_never_came_up(deploy_lines) -> str— A lifecycle node never completed a transition, so the graph never came up and nothing after it is a policy outcome; bucketed alongside_nav2_bond_teardownsince both represent absence rather than a real attempt.parse_goal_log(lines) -> tuple[dict[str, Any] | None, str]— The dispatcher's single JSON status line, or why it never wrote one (e.g. a traceback with nostatusfield). (L1319)classify_outcome(*, task_success_ever, stop, ground_truth, initial_configuration, grasped, artifacts_complete) -> str— Buckets one scene's outcome; ordering is load-bearing — success wins outright, and an initial-configuration E-stop outranks the ground-truth adjudication. (L1360)scene_verdict_from_artifacts(run_dir, *, scene, config_path, seed, prompt, rskill_id, stem) -> ValidationSceneVerdict— Derive one scene's verdict from recorded artifacts only. (L1414)diff_rounds(current, baseline) -> ValidationRoundDiff— Field-by-field round comparison; carries both rounds' seed as well as SHA, since a comparison counts as reproducibility only when both match — the seed decides the scene's initial configuration. (L1585)class GuardrailError(RuntimeError)— A precondition is not met; raised, never warned. (L1644)assert_worktree_clean() -> None— Refuse a dirty worktree: its recorded SHA would be a lie. (L1657)assert_sha(expected: str | None) -> str— ReturnHEAD, refusing when it is not the requested checkout. (L1670)assert_overlay_fresh(install_dir: Path) -> int— Refuse aninstall/older than any tracked.cpp/.hpp/.h/.msg/.idlundercpp/orpackages/. (L1691)resolve_launcher() -> Path— This checkout's.venv/bin/openral, by absolute path; the~/.local/binwrapper execs the parent checkout. (L1733)assert_sidecar_wire() -> None— Refuse whenpyzmqis absent. (L1757)assert_no_safety_overrides(argv) -> None— Refuse any argv token matching_SAFETY_KNOB_PATTERNS(normalised lowercase,-→_). (L1837)scene_safety_surface(document) -> dict[str, object]— The safety-relevant keys of a parsed DeployScene:safety/hal/ ACM / place-declaration wholesale,runtime.enable_octomap_kernel_checkandruntime.grasp_allowance_enabled, plus any leaf that reads as a margin, tolerance, limit, watchdog or E-stop. Stack composition is deliberately excluded. (L1893)assert_scene_safety_unmoved(tracked, resolved) -> None— The second control surface: refuse a materialised scene copy that adds, removes or changes any key ofscene_safety_surfacerelative to the tracked scene. (L1923)gpu_status() -> tuple[str | None, list[str]]— GPU name + resident compute processes; the host is shared. (L1961)pin_runtime_block(text, pins) -> str— Spliceruntime:pins into a scene YAML, changing nothing else (comments and safety commentary survive verbatim). (L1995)materialise_scene(spec, seed, run_dir) -> tuple[str, Path]— Write the round's resolved scene copy (seed +SCENE_RUNTIME_PIN), re-parse it to prove the pins landed, and check it against the tracked scene. The tracked file is never touched. (L2046)wait_for_dds_transport_ready(deploy_log, proc, *, timeout_s, poll_s=0.05) -> str— Block until the deploy log showsdds_transport_ready:(stale shared-memory clean done,ros2 launchnot yet spawned), so the monitor joins the graph being launched. Returns""on timeout or a dead deploy. (L2131)render_notes(verdicts) -> str— The round's Markdown summary: names scenes whose monitor received nothing (a harness fault) separately from those that stopped before seeing a voxel grid (a fact about the run), plus any with an uncertified probe or a lower-bound-only budget. (L2447)round_exit_code(verdicts) -> int—4when any scene bucketedharness-error, else0: a round in which a scene never launched must not exit successfully. (L2576)parse_launch_argv(lines) -> list[str]— The resolvedargv: … launch …the deploy CLI echoed: the only artifact stating the stack a run actually got; head-agnostic, so a venv-wrappedros2still parses. (L2668)stack_tokens(argv) -> list[str]— The stack-definingkey:=valuetokens of that argv, per-scene tokens dropped. (L2711)robot_facts_from_launch_argv(argv) -> dict[str, str]—repo_root/robot_id/robot_manifest_path, from the argv'srobot_yaml:=token. (L2730)parse_log_start_time(lines) -> str | None— UTC timestamp of the log's first ROS stamp; pre-harness rounds recorded no start time, their logs did. (L2759)resolve_scene_dirs(round_dir, aliases) -> dict[str, str]— Map each matrix scene onto the directory a round kept it in;--scene-aliaswins overLEGACY_SCENE_DIRS. (L2783)cmd_verdicts(round_dir, *, stem=None) -> int(L2592) —stem=Nonereads the round's recordedartifact_stem.cmd_diff(round_dir, baseline_dir, out_path) -> int(L2643) —diffsubcommand body: field-by-field round comparison viadiff_rounds;out_path=Noneprints.cmd_import(args) -> int(L2813) —import-roundsubcommand body.cmd_run(args) -> int(L2902) —runsubcommand body.main(argv=None) -> int— CLI entry;run/verdicts/diff/import-round.3on a guardrail refusal (nothing written),4when a scene bucketedharness-error. (L2982)octomap_resolution_env() -> dict[str, float]— The world-voxel resolution the round actually runs with, read fromOPENRAL_OCTOMAP_RESOLUTION_M; a finer grid is less conservative than the shipped default. Returns{}(not a value) when the override is absent, so metadata never misdescribes the run. (L1805)
tools/_validation_matrix_monitor.py
Private helper of validation_matrix.py, spawned alongside each scene's ROS graph. Records the attachment stream, kernel failure evidence, the occupied-cell set hash, the place declaration plus producer-measured region, and periodic .npz snapshots. Needs ROS 2 sourced.
class Monitor(L164) — Owns the ROS subscriptions + state for the attachment/failure/place/voxel recording described above;__init__(node, sink, snap_dir).main() -> int(L434) — CLI:sys.argv[1]=output path,[2]=snapshot dir; creates the node, runsMonitor, spins until SIGINT/SIGTERM, writesmonitor_started/monitor_stoppedmarkers.
tools/_validation_matrix_dispatch.py
Private helper of validation_matrix.py. Sends one ExecuteRskill goal at the live graph (the matrix runs with the reasoner off) and prints one JSON line — the run's goal.log. Needs ROS 2 sourced.
main(argv=None) -> int—--deadline-s/--rskill-id/--prompt/--server-timeout-s. (L24)
tools/_ceiling_probe.py
One worker of the ceiling battery: one scene, one gate arm, N rounds. Bypasses validation_matrix.py's refusal to disable the octomap check, while reusing its scene materialisation, readiness gate and dispatch tool. Answers: of the runs the kernel stops, how many would have succeeded anyway?
DEADLINE_S: float = 420.0(L56) — Deadline per scene run; the harness's own default, kept identical so a gate-off run is not given more time to succeed than a gate-on one._reap_domain(domain, sig) -> int— Teardown sweep for orphan graph nodeskillpgcan't reach, sinceros2 launchstarts the octomap pair in its own session and each orphan holds a Fast-DDS shm lock that starves the next round on that domain. Scoped byROS_DOMAIN_ID; SIGTERM first so segments are unlinked cleanly.run_one(spec, gate, seed, run_dir, rskill) -> dict[str, object](L199) — Launch one scene end to end and return its record, including host load, delivered action chunks, and whether a Nav2 bond teardown occurred, so a starved run is legible from the record alone._chunks_from_goal_log(goal_log) -> int | None— Action chunks the policy delivered inside the deadline — the single number showing whether a run got a fair trial; a starved or torn-down run delivers a small fraction of a healthy one's rate._bond_teardown(deploy_log) -> str— Delegates tovalidation_matrix._nav2_bond_teardownso the probe and the harness agree on what a voided run looks like.main(argv: list[str] | None = None) -> int(L343) — CLI entry:--scene/--gate/--rounds/--seed/--rskill/--out/--start-round; drivesrun_oneper round, appends torecords.json, prints a running success tally.
tools/ceiling_battery.sh
Drives the eight _ceiling_probe.py workers (4 scenes × 2 gate arms), interleaved by scene so the two arms run under identical host conditions. WORKERS caps concurrency; needs OPENRAL_SKIP_ORPHAN_REAP=1 so a worker's startup sweep can't kill a concurrent sibling's live graph — the domain-scoped _reap_domain in _ceiling_probe.py keeps the host clean between rounds instead.
tools/_nav2_mppi_loop_probe.py
Times the whole MPPI control loop against its 50 ms budget on a live openral deploy sim graph, dividing controller_server's CPU time by the cycles it published, in sim time since the stack runs use_sim_time. Validates which footprint polygon the costmap adopted per run. Private evidence tool, not a shipped entry point; recorded in docs/reference/robocasa-carry-survey.md.
BARE(L53) — the manifest chassis footprint polygon.GROWN(L54) — the chassis footprint grown over the payload at the live 0.860 m forward reach.CLK = os.sysconf("SC_CLK_TCK")(L55) — clock ticks per second, for converting/proc/<pid>/statfields to seconds.controller_pid() -> int(L58) —pgrepthe livenav2_controller/controller_serverPID;SystemExitif not running.cpu_seconds(pid) -> float(L71) — utime+stime from/proc/<pid>/stat, the clock-source-independent cost.class Probe(Node)(L77) — publishes the arm's polygon at 20 Hz, counts/cmd_vel_nav, and reads back/local_costmap/published_footprintfor the validity check.main(argv=None) -> int(L129) —--grown,--seconds=N; emits one JSON line carryingcpu_ms_per_cycle,cycles,footprint_len_mandarm_valid.
tools/_nav2_costmap_silhouette_probe.py
Sweeps a live graph's Nav2 costmaps for cells marked inside the robot's own silhouette or a carried payload's, which neither costmap should ever do now that Nav2 is base-only — the scan filter is the only thing preventing it. Private, like _nav2_mppi_loop_probe.py: attaches to an already-launched graph, evidence tooling rather than a shipped entry point.
LETHAL_OBSTACLE = 254(L68) —nav2_costmap_2d's LETHAL_OBSTACLE; deliberately not 253 (INSCRIBED_INFLATED_OBSTACLE) since the claim is that no cell inside the robot was marked, and 253 is what an inflation layer writes near a legitimate obstacle elsewhere.payload_mask(objects, base_from, points_xy) -> tuple[Any, int, tuple[float, float] | None](L103) — Projects every attached object onto the costmap plane; returns(union mask, objects fully placed, z span in base frame). Counts per object (not primitive) — an object counts as placed only when every one of its primitives projected.class SilhouetteProbe(Node)(L158) — Samples both costmaps and counts marked cells inside the robot silhouette.main() -> int(L351) — argparse (--robot-yaml,--scene,--seconds,--settle,--drive); spins the probe, optionally drives aNavigateToPose, emits a verdict dict with non-vacuity guards (lethal_cells_anywhere,base_travel_m,payload_samples, etc).
tools/isaac_sidecar.py
Isaac Sim scene sidecar, running Isaac Lab/Kit in its own py3.11 venv, auto-spawned by openral_sim.backends.isaac_sim. Launches Omniverse Kit headless, builds the scene named by --layout, and serves ZMQ REP + msgpack framing (ping/reset/step/render/close).
_parse_args(argv: list[str]) -> argparse.Namespace— Sidecar CLI, including--environment-usd(local path / URL /isaac:<path>) and--spawn-pose X Y Z YAW; both are rejected outside--layout manifest._serve(scene, *, host, port, sim_app, task, layout, environment, spawn, robot, objects) -> int—contactsendpoint →scene.contact_ground_truth();set_taskendpoint →scene.set_task(instruction). ZMQ REP loop;pinganswers the scene identity (task,layout,environment,spawn,robot,objects) the client checks before adopting a running sidecar, plussim_dt_per_tick_s(the scene'sIsaacSceneBase.sim_dt_per_tick_s: sim seconds onestepadvances) thatSimAttachedHAL.connectholds to the manifest control rate (issue #355).--objects-json— JSON list of scene objects (manifest layout only).--site-dir— an import dir prepended tosys.path(a binary install's wire deps). A root-owned install (ISAAC_PATH/kitnot writable) gets--portable-root ~/.cache/openral/isaac-sidecar/kit-dataso Kit's caches land in the user's home.main(argv: list[str]) -> int(L168) — Checks required dep versions (before the ~50 s Kit boot), launchesSimulationApp(headless: Kit's unused editor viewport stops updating, ~20 % of a step), then builds the manifest scene and serves the ZMQ loop; a boot exception is printed before Kit's fast shutdown (which would otherwise swallow it).
tools/_isaac_scene_base.py
Shared base for the Isaac Sim sidecar scenes (py3.11 venv only), owning the obs/step lifecycle, RGBA→HWC frame grabbing, the warmup + physics-substep loop, and eval-layer observation assembly, so a new layout only overrides a few template methods.
physics_dt_for(control_freq_hz: float) -> float(L50) — The physics dt the manifest scene builds its World at: the smallest integer multiple of the control rate at or above 60 Hz (_MIN_PHYSICS_HZ, Isaac's default and the rate the finger contacts were validated at) — 30 Hz keeps 60 Hz, 50 Hz runs at 100 Hz, 25 Hz at 75 Hz — so every rate gets a whole number of physics steps per tick instead of a boot refusal.derive_physics_substeps(physics_dt_s: float, control_freq_hz: float) -> int(L67) — Physics steps per control tick so one scenestepis one control period of the robot (1 / action_spec.control_freq_hz):round(1 / (physics_dt × control_freq)), refusing (ValueError, both rates in the message) a ratio that is not an integer within 1 % (_SUBSTEP_RATIO_TOL) instead of rounding silently — 60 Hz physics under a 30 Hz robot gives 2, under a 25 Hz robot has no faithful count (issue #355).class IsaacSceneBase(L97) — Lifecycle + obs skeleton common to the Isaac Sim sidecar scenes; class attrswarmup_steps/physics_substeps. (int | None:None= derived byresolve_time_baseat build, an int is a scene-class override that wins and is logged). Template methodsbuild/_on_reset/_after_world_reset/_after_warmup/_apply_action/_images/_state/_reward_terminatedare overridden per scene (_after_warmupruns after the warmup steps, for settling that needs live physics).IsaacSceneBase.build() -> None(L253) — Template method (raisesNotImplementedError): construct the stage (robot, props, cameras, controllers).IsaacSceneBase._after_world_reset() -> None— Hook run right afterworld.reset(), before the warmup steps, for state the reset overwrites (e.g. a robot root placed away from its import pose).IsaacSceneBase.resolve_time_base(physics_dt_s: float, control_freq_hz: float) -> int(L181) — Called bybuildonce the world exists: records the physics dt and setsphysics_substepsviaderive_physics_substeps(or the class pin), printing onetime base:line (physics Hz, control Hz, substeps, derived/override,sim_dt_per_tick_s). Returns the substep count.IsaacSceneBase._substeps() -> int— The resolved substep count;RuntimeErrorif the scene is stepped beforeresolve_time_base.- (property)
IsaacSceneBase.sim_dt_per_tick_s -> float | None(L217) — Sim seconds onestepadvances (physics_dt × substeps),Nonebeforebuild; reported in the sidecarpingso the deploy-sim HAL can refuse a tick that is not one control period. IsaacSceneBase.reset(seed: int | None = None) -> dict[str, Any](L132) — Per-episode reset: randomize, reset physics, warm up, observe.IsaacSceneBase._image_times() -> dict[str, int]— Template method:{obs key: sim time ns}each camera's frame shows; default{}._observeships a non-empty result asobs["image_time_ns"](issue #361).IsaacSceneBase._frame_time_ns(cam, name) -> int | None— The sim time the camera's current frame shows: Isaac'sCamera.get_current_frame()["rendering_time"](the delivered frame's fabric reference time as simulation time, the frameget_rgba()reads) in ns;Nonebefore the first frame, and a camera without it is reported once. Isaac's RTX pipeline delivers frames 2–4 steps after the physics they show, not at a constant lag.IsaacSceneBase.render() -> NDArray[np.uint8] | None(L248) — Last grabbed RGB frame, orNone.IsaacSceneBase.sim_time_ns() -> int | None(L227) — Elapsed sim time in ns for/clock; prefers Isaac'sSimulationContext.current_time, else integrates step count × physics dt.IsaacSceneBase.step(action: NDArray[np.float32]) -> dict[str, Any](L151) — Apply one action, advance physics by_substeps()steps (renders only the final one, so camera observations stay at the control rate), return a StepResult dict (observation/reward/terminated/truncated/info/sim_time_ns).
tools/isaac_manifest_scene.py
Robot-agnostic, URDF-driven Isaac Sim scene (the sidecar's only scene): imports the manifest robot's URDF and wires joints/sensors/control from a JSON robot spec marshaled across the venv boundary; absolute joint targets in manifest order (NaN = hold), base twist last.
drive_gain_overrides(joint_drive_gains: dict[str, list[float]] | None) -> tuple[dict[str, float], dict[str, float]](L70) — The URDF importer's per-joint(stiffness, damping)regex-pattern dicts from the spec'sjoint_drive_gains: catch-all_DRIVE_STIFFNESS/_DRIVE_DAMPINGfirst, the spec's patterns after it (later matches win)._SCAN_MAX_SELF_SKIPS = 8(L110) — Self-occlusion handling for the lidar fan (mirrorsopenral_sim.backends.robocasa._LASER_MAX_SELF_SKIPS): caps how many self-layers one beam steps through before giving up and readingrange_max_m._SCAN_SELF_SKIP_EPS_M = 1e-3(L113) — Nudge (m) added past a self-hit before re-casting.map_dof_to_manifest(values, *, dof_index, manifest_joints, grippers, base_values=None, base_joints=None, rates=False) -> NDArray[np.float32](L116) — Maps an Isaac articulation DOF vector to the full manifest joint order; a base joint readsbase_values, an arm joint itsurdf_nameDOF, a gripper its leader finger mapped linearly from URDF closed/open onto the manifest's own range (so/joint_statesstays inside the manifest limits); unresolved →0.0.rates=Truemaps velocities._rpy_quat(roll, pitch, yaw) -> NDArray[np.float64](L184) —(w, x, y, z)of the URDFrpyrotationRz·Ry·Rx; orients each scene object fromIsaacSceneObject.roll/pitch/yaw. Pure._quat_mul(a, b) -> NDArray[np.float64](L209) — Hamilton product of(w, x, y, z)quaternions; composes apose_noiseyaw onto an object's registered orientation. Pure._footprint(prim, obj) -> tuple[float, float, float, float](L400) —(cx, cy, hx, hy)of a scene object's untransformed USD bounds after its roll/pitch, in its yawed frame; the rectanglesample_object_poseskeeps apart and insidekeep_inside_xy._rect_corners(x, y, yaw, rect) -> NDArray[np.float64](L425) — World(4, 2)corners of a footprint at a planar pose. Pure._rects_overlap(a, b, margin) -> bool(L437) — Separating-axis overlap test of two convex quads,margincounted as contact. Pure.sample_object_poses(objects, footprints, rng, *, margin_m=0.002) -> list[tuple[float, float, float, str]](L449) — Per-reset(x, y, yaw, status)of each scene object:pose_noiseobjects draw truncated-normal offsets until their footprint clears every earlier object and stays insidekeep_inside_xy;statusisdeclared/sampled/declared_fallback. Deterministic per rng state; called fromIsaacManifestScene._on_reset. Pure.pose_matrix(position, quat_wxyz) -> NDArray[np.float64](L558) — 4x4 rigid transform from a position and a normalised(w, x, y, z)quaternion. Pure.manifest_to_urdf_gripper(gripper, value) -> float(L577) — A gripper command in its end effector'scommand_convention→ its URDF leader joint target, linear between the command (command_closed/command_open) and URDF closed/open ends, clamped._FINGER_FRICTION = 1.0(L98) — Coulomb friction of the robot's finger colliders (the URDF importer authors no physics material; Isaac i58/i59: a lifted prop slid out of a stalled, effort-capped jaw at PhysX's ~0.5 default).@dataclass(frozen=True) class FingerFrictionResult(L616) — Whatapply_finger_frictiondid:boundprim paths,missing_joints(named finger joints with no USD joint/body1, so that finger keeps PhysX's default — an asymmetric grip),displaceddescendant colliders whose own physics material the pad replaced, andcombine_max(FalsewhenPhysxSchemais unavailable and PhysX averages).build()prints a WARNING for each non-clean field.apply_finger_friction(stage, robot_prim, finger_joints, friction=_FINGER_FRICTION) -> FingerFrictionResult(L787) — Binds one high-friction physics material (static = dynamic =friction, no restitution,maxfriction combine whenPhysxSchemaexists) to the finger links the named gripper joints drive (thegrippers[].leader+followers[].dofURDF joint names, via each USD joint'sbody1) and to every instanced root under them — found through the joints, not by name (the OpenArm's finger colliders areee_link1/2; itsfinger_*prims are visuals), and an instance proxy cannot take a binding. BoundstrongerThanDescendants, so the pad wins over any physics material already authored on a finger collider (the logged friction is the one PhysX uses). Returns a frozenFingerFrictionResult(bound, missing_joints, displaced, combine_max):missing_jointsare requested joints that resolved to no USD joint (partial match = asymmetric grip),displacedare descendants whose own physics binding the pad replaced,combine_maxisFalsewhenPhysxSchemais unavailable (average combine).build()prints the combine mode and a WARNING line for no finger link, missing joints, average combine, or displaced materials.ValueErroron a non-positive or non-finite coefficient. Called bybuild()right after the robot is referenced.apply_color_lut(image, lut_rgb) -> NDArray[np.uint8](L1141) — Map an RGB frame through a per-channel 8-bit tone curve (IsaacCameraImagePost.color_lut_rgb, 3 × 256) withcv2.LUT; applied last in the sidecar's RGB post chain._curve_by_urdf(curve) -> tuple[list[float], list[float]](L604) — A gripper calibration curve as(manifest values, URDF values)sorted by URDF value, for mapping finger positions back to manifest units (np.interp);manifest_to_urdf_gripperuses the curve, when the spec carries one, for the opposite direction.couple_finger_targets(target, q, grippers, dof_index, margin, qd=None, stall_speed=0.2) -> NDArray[np.float32](L710) — Limits each finger's closing target tomarginpast its partner's mirrored position (leader units; followers mirrored throughmultiplier/offset); with joint velocitiesqd, a partner still closing faster thanstall_speed(rad/s) holds nothing back, so free fingers close at drive speed and only a stalled partner holds the other; opening is never limited; returns a copy. Applied per step in_apply_actionwhen the spec setsgripper_finger_coupling_rad— emulates a jaw whose fingers share one motor (PhysX's native mimic joint fought the joint limits on OpenArm's mirrored jaw).grade_scores(grades) -> dict[str, float](L274) — Grade name → score for a rubric (IsaacPlacementSuccess.grades), plusfail0.object_up_axis(roll, pitch) -> NDArray[np.float64](L241) — The object-frame axis pointing up at a declared roll/pitch (an asset stood up by a quarter roll is upright standing). Pure.placement_grade(position, quat_wxyz, up_axis, placement, upright_tol_deg, grades) -> str(L284) — The first rubric level (IsaacPlacementSuccess.grades:region=target/adjacent,requires_upright) a resting object satisfies against a spec placement'starget/adjacentboxes and its tilt, elsefail. Pure.worst_grade(grades, scores) -> str(L339) — The lowest-scoring grade underscores(grade_scores),failfor none: the episode's grade over its placements.rest_after(rest_s, moved_m, dt, rest_speed_m_s, turned_rad=0.0, rest_turn_rad_s=inf) -> float(L350) — An object's at-rest seconds after one step (None= no history restarts the timer, as does moving faster thanrest_speed_m_sor turning faster thanrest_turn_rad_s).placement_reward(grade, last_step, scores, success_grade) -> tuple[float, bool](L376) —(reward, terminated): thesuccess_grade(the rubric's first level) ends the episode with its score; on the last step any other grade scores its credit underscores; every other step scores 0.strip_urdf_mimics(urdf_text, source_dir) -> str(L875) — A URDF without<mimic>tags, relative mesh paths made absolute, for the Isaac >= 6 converter (its mimic constraint destabilises PhysX articulations).compose_planar(spawn, odom) -> tuple[float, float, float, float](L910) — World(x, y, z, yaw)of the base: the spawn pose composed with the planar odometry pose (odometry starts at the spawn). Pure.look_at_matrix(eye, target) -> NDArray[np.float64](L931) — Rotation whose columns are a camera's x (forward) / y (left) / z (up) axes aimed attarget(Isaac'sworldcamera axes); used forIsaacCameraMount.look_at. Pure.camera_resolution(meta, obs_width, obs_height) -> tuple[int, int](L948) — A planned camera's render size: its manifest intrinsics' raster (a depth camera keeps that aspect at no more thanobs_width), else the scene's observation size. Pure.camera_hfov_deg(meta) -> float | None(L977) — A planned camera's horizontal FOV: its mount'shfov_deg, else from the manifest intrinsics (2·atan(width / 2fx)), elseNone(Isaac's default lens). Pure.recolor_robot_materials(stage, robot_prim, colors) -> dict[str, list[float]](L635) — Sets the diffuse colour (UsdPreviewSurface.diffuseColor/ OmniPBRdiffuse_color_constant) of robot visual materials whose prim name matches anfnmatchpattern, only for materials bound underrobot_prim; called after the URDF import when the spec'srobot_material_colorsis set (upstream meshes carry their own colours). Needspxr.radial_fold_radius(coeffs) -> float(L999) — The largest distorted normalised radius a Brown / rational radial model reaches before it turns over (or hits a pole); tangential terms ignored. Pure.check_radial_reaches_corners(name, k, coeffs) -> None(L1025) — RaisesValueErrorwhen an RGB lens model folds inside the image (its fold radius is below the corners' normalised radius): Isaac inverts the model per output pixel and renders swirls past the fold. Called by_configure_rgb_projection. Pure.blur_rgb(image, sigma_px) -> NDArray[np.uint8](L1054) — Separable Gaussian blur of an HWC uint8 frame (sigma_px <= 0returns it unchanged); applied to every RGB frame when the spec'simage_blur_sigma_pxis set (or a camera'scamera_image_post.blur_sigma_px). Pure.relight_rgb(image, gain_rgb) -> NDArray[np.uint8](L1112) — Re-exposes an RTX op-6 (ACES + sRGB) frame by scene-linear per-channel gains through the inverse tonemap (256-entry LUT);camera_image_postauto exposure / white balance. Pure.auto_exposure_gain(image, target, wb_rgb) -> float(L1158) — Scene-linear gain (bisection, metered 1:8) that puts the frame's mean BT.601 luma attarget. Pure.points_in_frame(points, world_from_frame) -> NDArray[np.float32](L1279) — World points expressed in a frame given by its 4x4 world pose, non-finite rows (depth misses) dropped. Pure.resolve_beam_range(raycast_closest, *, robot_prim, origin_xy, angle_rad, z, range_min_m, range_max_m) -> float(L1300) — One lidar beam's range, with the robot's own body (prims underrobot_prim) skipped by rigid-body-path identity rather than assumed clear; re-casts past a self-hit up to a bounded number of times. Pure, so unit-testable without a Kit app.CONTACTS_CAVEAT: str(L1372) — What a PhysX contact list does and does not say (last physics step only; contactOffset band; no nearest-distance query; filtered colliders invisible); sent with everycontactsreply.aggregate_robot_contacts(points, robot_prim) -> tuple[list[dict[str, Any]], int](L1387) — Folds per-point PhysX contacts into one record per (robot collider, other collider):link,robot_collider,other_prim,other_body,min_separation_m,contact_points,impulse_ns,deepest_point_xyz; robot side first, deepest first; self contacts counted, world-world dropped. Pure.class IsaacManifestScene(IsaacSceneBase)(L1474) — URDF-driven, robot-agnostic Isaac scene built from the marshaled robot spec. Readsaction.control_freq_hzfrom the spec (refuses a spec without it);buildcreates the World withphysics_dt = rendering_dt = physics_dt_for(control_freq_hz)(equal, because a renderedworld.step()runsapp.update(), which advancesrendering_dt) and ends with_fix_time_base, so onestepis one control period (physics_substepsis never pinned here).IsaacManifestScene.set_task(instruction) -> dict[str, Any]— Deploy sim (placement_success_by_promptin the spec): activates that prompt's rubric (none without an entry) from a fresh grade via_activate_placement_success; asim runscene keeps its build-time rubric. Replygraded,grade_scores({}ungraded),prompts. Under deploy sim_reward_terminatednever terminates;info["placement_grade"]still reports. (L2673)IsaacManifestScene._body_speed(collider) -> float | None(L2785) — World linear speed of the robot rigid body owningcollider(deepest captured body path prefixing it;SingleRigidPrimmade on first use);Nonewhen no robot body owns it. Feedsrobot_contacts[].link_speed_mps.IsaacManifestScene._contact_points() -> list[dict[str, Any]](L2948) — Every PhysX contact point of the last physics step as plain dicts (the shapeaggregate_robot_contactsfolds); shared bycontact_ground_truthand the step info'srobot_contacts.IsaacManifestScene.contact_ground_truth() -> dict[str, Any](L2985) — The sidecarcontactsreply:aggregate_robot_contactsoverget_physx_simulation_interface().get_contact_report()(last physics step), each pair with both colliders' authoredcontact_offset_m/rest_offset_m(None= PhysX-derived),sim_time_ns,self_contact_points,nearest_robot_world_pairs: None+ reason,CONTACTS_CAVEAT._enable_contact_reports(inbuild) appliesPhysxContactReportAPI(threshold 0) to every robot rigid body.IsaacManifestScene.static_collider_boxes() -> dict[str, Any](L2803) — The sidecarstatic_collidersreply: every static collider (CollisionAPI, not under the robot, no enabled non-kinematic rigid body on itself or an ancestor) inbase_framevia_world_from_base: triangle-mesh colliders (approximationnone) askind: meshvertices + fan-triangulated triangles, others askind: boxUSD bounds (oriented_box); each withpath,type,approximation,collision_enabled.IsaacManifestScene.scene_ground_truth() -> dict[str, Any](L2893) — The sidecarscene_ground_truthreply: each declared object's USD bound posed by PhysX (get_world_pose, scale from USD) and the active rubric's placements (object,targetregion box,adjacentregion boxes), all inbase_frame. Feedstools/derive_scene_inputs.py.oriented_box(frame_from_local, local_min, local_max) -> dict(L524) — The oriented box a local axis-aligned range spans in another frame (scale folded into the half-extents):center_m,rotation(3x3 rows),half_extents_m.IsaacManifestScene._fix_time_base() -> None— Run at the end ofbuild, once the stage (environment USD included) is complete: reads the World's actual physics and rendering dts, refuses (ValueError) a rendering dt that differs from the physics dt, callsresolve_time_base, and sets the kinematic base's integration interval to the resolvedsim_dt_per_tick_s(one source for both).IsaacManifestScene._depth_frames() -> dict[str, dict[str, Any]](L2572) — Registered colour + metric depth per depth camera, from ONE render of the same Isaac camera:distance_to_image_plane(0.0= no return / pastrange_max_m), its RGB,k = [fx, fy, cx, cy]from Isaac's intrinsics matrix, and the camera's REP-103 optical pose (camera_axes="ros") inbase_frameas a 4x4 — the four streams a real RGB-D driver gives the vision attachment leg. Shipped in every step reply, so the published colour/depth pair is never more than one HAL step apart from what the segmenter and the HAL bridge each last received (the bridge'smask_depth_max_skew_sis 0.1 s).IsaacManifestScene._image_times() -> dict[str, int]—_frame_time_nsfor every camera, by obs key (a depth camera's key is its sensor name), so it stamps the RGB images,depth_framesanddepth_pointsalike._after_world_resetcalls each camera'spost_reset()(the cameras are not inworld.scene, soworld.reset()does not): without it the camera's frame-rate gate sees sim time jump back and stops refreshing the frame time for the old episode's length.buildwarns when a camera's gate rate (get_frequency(), Kit's run-loop rate) is at or below the control rate, where frame times would go stale.IsaacManifestScene._world_from_base() -> NDArray[np.float64](L2560) — World pose of the manifestbase_framefrom the articulation root's MEASURED PhysX pose ∘ root→base (not the commanded spawn ∘ odometry: a spawn PhysX does not honour, e.g. below the ground plane, left every cloud offset from the robot's own links); shared by_depth_cloudsand_depth_frames.IsaacManifestScene._root_rigid_body_prim() -> str(L2102) — The first rigid body under the robot root. A camera mounted on abase_framethat is no URDF link is parented here, not to the robot root: on Isaac >= 6 the pinned root Xform stays at the import origin while PhysX moves the links, so a root-parented camera rendered (and reported its pose) from the origin.IsaacManifestScene._relative_to_root(prim_path) -> NDArray[np.float64](L2113) — 4x4 pose of a prim in the robot root frame, as USD holds it (import pose).IsaacManifestScene.build() -> None(L1671) — Import the manifest robot's URDF (Isaac >= 6:URDFImporterbeforeWorld()+ reference with thephysxvariant; < 6: the command importer), resolve the time base from the World's physics dt (resolve_time_base), wire joints/sensors/control, place cameras per_plan_cameras; references theenvironment_usdstage (else the default ground plane), addsobjects(rigid bodies + convex-hull colliders when missing, reset with the World), and places the robot atspawn_poseby moving the base anchor joint with the root. Each slot is an absolute target (NaN keeps the commanded target); each gripper maps its end effector'scommand_conventiononto its leader and drives the mimic followers. Stepinfocarriesrobot_position(PhysX root),object_positionsandobject_orientations_wxyz, plusplacement_gradewhen the spec carriesplacement_success: each step then advances every placed object's rest timer (rest_after), grades it (placement_grade,worst_grade) and returnsplacement_reward; without the block the scene has no task reward or termination. Each reset redrawspose_noiseobjects' default poses (sample_object_poses) beforeworld.reset()and logs them. A pinned robot (fix_base) becomes a genuinely fixed-base articulation:_reference_robotmoves the articulation root from the base body to the world anchor joint and carries the importer's self-collision choice (newton:selfCollisionEnabled, off by default) over asPhysxArticulationAPI.enabledSelfCollisions, since PhysX's default (on) lets the robot's own links hold its joints off target.
tools/robocasa_carry_survey.py
Answers whether any RoboCasa task makes the base drive while holding something, by building the env and measuring the distance from the base's start pose to every manipulated object — not by reading the source. See docs/reference/robocasa-carry-survey.md.
REQUIRED_BASE_TRANSLATION_M = 1.0— Criterion 1 of the scene that closes #108 (openral_nav2_bringupREADME); below it the arm bridges the gap andNavigateToPosenever runs. (L37)DISTRACTOR_PREFIXES = ("distr", "dstr")— RoboCasa's two clutter-object spellings; both are needed, or some tasks report a distractor as their furthest object. (L44)class SurveyError(RuntimeError)— RoboCasa unavailable, or its task registry unreadable. (L47)@dataclass(frozen=True) class CarryMeasurement(task, seed, layout, style, furthest_object_m, furthest_object, nearest_object_m, nearest_object, lang)— One(task, seed)reset, measured;.requires_base_translationapplies the threshold. (L52)CarryMeasurement.requires_base_translation(L70) —@property;furthest_object_m > REQUIRED_BASE_TRANSLATION_M.robocasa_root(explicit=None) -> Path—--robocasa-root, else an importablerobocasa, else the HAL's provisioning cache. (L74)read_target50(root) -> list[str]— The 50 task names XR-1's model card pins as its reference configuration, parsed fromdataset_registry.py. (L95)measure(task, seed) -> CarryMeasurement— Build, reset, measure each object's distance frommobilebase0_base. Needs a provisioned RoboCasa. (L120)main(argv=None) -> int— CLI;--tasks(default: target50),--seeds,--robocasa-root,--json. Per-(task, seed)build failures are reported, not fatal. (L175)
tools/select_tests.py
Selective test execution — maps a git diff to the minimal pytest targets that can observe it. Backs just test-changed / the test-selective workflow. See docs/contributing/selective-testing.md.
REPO_ROOT(L39) — Repo root, derived from this file's location.class CapabilityGap(BaseModel)(L56) — A capability the CI runner provably cannot provide:summary,satisfied_by,skip_patterns(fnmatch globs matched against a skip's reason).class SelectionConfig(BaseModel)(L70) — Typed view oftools/test_selection.toml:full_run_globs,ignore_globs,isolate_globs,extra_triggers,requirement_globs,capability_gaps.class SelectionResult(BaseModel)(L81) —full_run/full_run_reason/affected_packages/targets/isolated_targets(own-process, issue #24) /requirement_targets(per opt-in lane) /reasons(per-target rationale).load_config(path) -> SelectionConfig(L105) — Load + validate the TOML config.package_dir_import_names(repo_root) -> dict[str, str](L117) —python/<dir>→ itssrc/openral_*import name.build_dependency_graph(repo_root) -> dict[str, set[str]](L136) — Import-name → directopenraldeps, derived from eachpyproject.toml(never hand-written).transitive_dependents(graph, changed) -> set[str](L160) — Closure of packages that depend on any changed package (includeschanged).map_test_imports(repo_root) -> dict[str, set[str]](L187) — Each top-leveltests/file → theopenral_*packages it imports.select(repo_root, changed_files, config) -> SelectionResult(L346) — Resolve changed paths to pytest targets (blast-radius → full run; else per-package dirs + import-intersecting tests), peelingisolate_globsmatches intoisolated_targets.changed_files_from_git(base, head, repo_root) -> list[str](L462) — Merge-basegit diff --name-only base...head.main(argv=None) -> int(L502) — CLI;--files/--base/--head,--github-outputfor CI step outputs.
tools/lane_report.py
Opt-in lane accounting — decides, records and attests what each dependency lane actually ran. Makes a vacuous green impossible (issue #163). See docs/contributing/selective-testing.md.
REPO_ROOT: Path(L43) — Repo root, derived from__file__.DEFAULT_CONFIG: Path(L53) —REPO_ROOT / "tools" / "test_selection.toml".DEFAULT_LEDGER: Path(L54) —REPO_ROOT / ".lane-ledger.jsonl".STATUS_RAN: str(L58) — Status vocabulary. Deliberately not "skipped": a lane is either coverage got, coverage declared unreachable here, or a failure.STATUS_DECLARED_NOT_RUN: str(L59) — A lane whose every test is gap-explained.STATUS_FAILED: str(L60) — Any lane with an undeclared skip, or that collected no tests at all.class LaneRecord(BaseModel)(L68) — One lane's accounted outcome:lane/status(ran/declared-not-run/failed) /passed/failed/declared_skips(gap → count) /undeclared_skips/note.declared_total(L80) — How many tests were not run because of a declared capability gap; sum ofdeclared_skips.values().read_junit(paths) -> tuple[int, int, list[str]](L111) — Aggregate junit XML reports into(passed, failed, skip_reasons); a lane may emit a batched report plus one per isolated file.build_record(lane, *, passed, failed, skip_reasons, config, exit_code=None, from_exit_code=False) -> LaneRecord(L140) — Apply the lane policy: declared capability gaps are allowed and attributed, every other skip fails, an all-gated lane isdeclared-not-runand an empty one fails.main(argv=None) -> int(L355) — CLI;lane(account one lane's reports) /attest(cross-check the ledger against the selection, write the job summary).
tools/heavy_lanes_trigger.py
Starts the required heavy-lanes check on a PR (fork PRs included) automatically once the PR is ready — no approval, no label — and keeps the heavy-lanes commit status on the PR head saying what it waits for. Run by .github/workflows/heavy-lanes-trigger.yml. See docs/contributing/development.md.
API(L75) —"https://api.github.com".LANES_WORKFLOW(L76) —"heavy-lanes.yml", the workflow it dispatches.OWN_CHECK_NAMES(L80) — Check runsheavy-lanes.ymlposts itself (lanes-select,lane,heavy-lanes) plus the trigger workflow's own job (heavy-lanes-trigger, posted on the PR head by aworkflow_runsweep); never a precondition. Kept equal to both workflows' job names bytests/unit/test_heavy_lanes_trigger.py.OWN_CHECK_PREFIXES(L81) —("lane (",): matrix legs of thelanejob.GREEN_CONCLUSIONS(L82) —success,skipped,neutral.STATUS_CONTEXT(L85) —"heavy-lanes": the commit status that carries the result onto the PR (named after the required check).RUNNING(L86) —"Running": description prefix of the status once dispatched.WAITING(L87) —"Waiting: ": description prefix while the PR is not ready (followed by the reasons).STATUS_DESCRIPTION_MAX(L88) —140, GitHub's status-description limit.FORK_BRANCH_PREFIX(L89) —"heavy-lanes/fork-": branch a fork PR's lanes run from (a copy of the base tree).DEFAULT_REQUIRED_CHECKS(L90) — Checks that must have reported green before dispatch:select-and-test,quality,Verify Signed-off-by.class GitHubAPIError(RuntimeError)(L93) — A 200 response that is unusable: GraphQLerrorspayload or nulldata(rate limit, missing scope, vanished PR).class CheckRunState(BaseModel)(L97) — One check run on the PR head:name/status/conclusion.class StatusState(BaseModel)(L105) — One commit status on the PR head:context/state/description.class LaneRunState(BaseModel)(L113) — Oneheavy-lanes.ymlrun for the PR head:status/conclusion.class PullRequestState(BaseModel)(L120) — Everything the verdict reads: draft, same-repo,behind_by, checks, commit statuses, unresolved threads, existing lane runs.class Verdict(BaseModel)(L136) —ready+ thereasonsit is not.own_status(pr) -> StatusState | None(L147) — Theheavy-lanesstatus on the PR head.lanes_started(pr) -> bool(L152) — A non-cancelled lane run, or a running / passed / failedheavy-lanesstatus, exists for this head.readiness(pr, required_checks) -> Verdict(L166) — Pure verdict: not draft, 0 behind base, every other check green and the required ones present, other statusessuccess, threads resolved, lanes not started for this head yet.class GitHub(L196) — Minimal REST + GraphQL client overurllib(the network boundary).GitHub.get(path)(L213) — GET/repos/<repo>/<path>, decoded JSON.GitHub.paginate(path, key=None) -> list(L217) — Every page of a list endpoint.GitHub.unresolved_threads(number) -> int(L230) — Unresolved review threads, via GraphQL.GitHub.fetch(pr) -> PullRequestState(L259) — Gather one PR's state.GitHub.dispatch(pr) -> None(L287) —workflow_dispatchheavy-lanes.ymlwithsha= the PR head: on the PR branch, or onfork_branch(pr)for a fork PR.GitHub.fork_branch(pr) -> str(L304) — Pointheavy-lanes/fork-<pr>at a new commit with the base branch's tree; returns the branch name.GitHub.delete_stale_fork_branches(open_prs) -> None(L339) — Deleteheavy-lanes/fork-<n>branches whose PR closed.GitHub.set_status(sha, state, description) -> None(L346) — Post theheavy-lanescommit status.main(argv=None) -> int(L395) — CLI;--repo,--pr(repeatable),--require-check,--dry-run. Posts the waiting status (only when its text changed; backfills a status from a pre-status run), re-reads the head SHA right before dispatch and defers if it moved, and prunes fork branches on a full sweep. One PR's API trouble is a::warning::, never a failed sweep.
tools/audit_tests.py
Test-suite auditor — flags dead / shadowed / duplicate / no-assertion tests; writes docs/contributing/test-audit.md. Read-only; never deletes. Backs just test-audit.
REPO_ROOT(L39) — Repo root, derived from this file's location.REPORT_PATH = REPO_ROOT / "docs" / "contributing" / "test-audit.md"(L40) — Committed report path written by--write-report.class TestFuncInfo(BaseModel)(L67) — Onetest_*function:path,qualname(class-scoped),markers,has_assertion,is_trivial,body_hash, …class DuplicateGroup(BaseModel)(L82) — Abody_hashshared by ≥2 functions and theirmembers.class AuditReport(BaseModel)(L87) — Inventory (by_tier/by_marker/by_directory) plustrivial/shadowed/no_assertion/duplicate_groups.collect(repo_root) -> list[TestFuncInfo](L206) — Scope-aware AST walk over every test root (same name in two classes is not conflated).build_report(records) -> AuditReport(L239) — Group into the inventory + finding buckets;shadowed= same(path, qualname)redefined (earlier def is dead).render_markdown(report) -> str(L291) — Render the committed report.main(argv=None) -> int(L378) — CLI;--json/--write-report.
python/observability/src/openral_observability/replay/
Query-time joiner for rosbag2 (mcap) ↔ OTel spans. Backs openral replay + openral record.
@dataclass(frozen=True) class BagMessage(topic, log_time_ns, publish_time_ns, trace_id, traceparent, schema_name, payload_summary)(bag_reader.py L84) — One mcap record surfaced to the correlator.read_bag(bag_path: str | Path) -> Iterator[BagMessage](bag_reader.py L144) — Iterate an.mcapfile or rosbag2 directory; extractstrace_idfromjsonschema-encoded payloads (a packed W3Ctraceparent, or a raw trace/span id pair for theTickschema) orros2msgCDR payloads via regex match. Norosbag2_pydep.class TraceQueryError(RuntimeError)(trace_query.py L26) — Raised on a non-JSON or unreachable dashboard response.@dataclass(frozen=True) class DashboardTraceClient(base_url="http://127.0.0.1:8000", timeout_s=5.0)(trace_query.py L31) —list_traces() -> list[dict]over/api/traces;get_spans(trace_id) -> list[dict]over/api/spans/<id>.@dataclass(frozen=True) class TimelineEntry(kind, ts_ns, trace_id, topic, span_name, attrs, duration_ms)(correlator.py L27) — One row of the joined timeline;.to_json()returns a plain dict.list_bag_trace_ids(bag_messages) -> list[dict](correlator.py L68) — Distinct trace_ids in the bag with counts, busiest first.build_timeline(bag_messages, spans, *, trace_id=None) -> list[TimelineEntry](correlator.py L95) — Pure join. Filters both inputs totrace_id, merges, sorts ascending byts_ns.RECORD_PROFILES: dict[str, dict[str, list[str]]](cli.py L52) — Slim and full topic + regex + topic-type presets (fullrecordsLaserScan/PointCloud2/Imuby type).build_record_command(*, profile, output_dir, storage="mcap", extra_topics=(), extra_regex=()) -> list[str](cli.py L102) — Composeros2 bag recordargv.@dataclass(frozen=True) class ReplayResult(trace_id, bag_trace_ids, timeline, bag_path)(cli.py L156) —.to_json()returns a plain dict.run_replay(*, bag_path, trace_id, dashboard_url) -> ReplayResult(cli.py L185) — Read a bag, fetch matching spans from the dashboard, return the joined timeline.run_record(*, profile, output_dir, storage="mcap", extra_topics=(), extra_regex=(), dry_run=False) -> tuple[list[str], CompletedProcess | None](cli.py L233) — Spawnros2 bag recordin a new process group; forwards SIGINT/SIGTERM received by the parent as SIGINT to the child group so rosbag2 flushesmetadata.yamlcleanly. Waits up to 5 s after the child exits for that file to appear.write_timeline(result: ReplayResult, out_path: Path) -> None(cli.py L306) — Persist the timeline JSON.
tools/rskill_publisher.py
Package and publish a local rSkill directory to the HF Hub.
_REPO_ROOT: Path(L59) — Repo root, derived from__file__._REQUIRED_FILES: list[str](L82) —["rskill.yaml"], the minimum a directory must contain to be a candidate rSkill.public_visibility_error(manifest, public) -> str | None(L85) — License gate (pure, no network): returns an error string when--publicis requested for a non-commercial-licensed skill, somaincan fail fast before any HF call._resolve_token(token_arg) -> str— Prefer CLI arg, fall back to env. (L130)_validate_manifest(skill_dir) -> RSkillManifest(L149)_validate_docs(skill_dir, manifest) -> DocValidationReport— Print + return the README / manifest documentation report via_rskill_doc_validator.validate_rskill_docs. Runs in both dry-run and--publishpaths; the caller decides whether to exit on errors._rewrite_manifest_name(manifest_path, old_name, new_name) -> None— Rewrite the top-levelname:value ofrskill.yamlin place (column-0 line only, so nestedname:keys are untouched; preserves quotes + trailing comment). Exits 1 if the line isn't found exactly once. Backs--fix-name._enforce_repo_name(skill_dir, manifest, *, fix_name) -> RSkillManifest— Enforces the ratified rSkill naming grammar; no kind is exempt.fix_name=Truerewrites to the expected name and reloads,fix_name=Falsehard-fails printing the suggested name._bump_revision(manifest_path, weights_uri_base, token) -> str— Resolve latest weights commit, patchrskill.yaml. (L337)_ensure_private(api, repo_id) -> None— Abort if the repo is public. (L388)_ensure_public(api, repo_id) -> None— The--publiccounterpart: abort if the (reused) repo is private, so a--publicpublish never lands in a private repo._publish(skill_dir, manifest, token, *, public=False) -> str— Create the HF repo (private unlesspublic) and upload; runs the matching visibility gate (_ensure_public/_ensure_private) aftercreate_repo.main() -> None(L529) — Entry point: validate manifest → enforce repo name → validate task space → validate docs → license-visibility gate → optional--bump-revision→--publish(private unless--public).
tools/cloud_transport_probe.py
run_pub(args) -> dict[str, Any](L74) — publisher role:--countxyz-float32PointCloud2of--pointsat--hzunder the sim bridge's depth-cloud QoS (BEST_EFFORT, KEEP_LAST 5;--reliableflips it), optionally streaming--jointjoint states for a chain node such asrobot_self_filter; reportspublish()call cost, the RMW and the Fast DDS profile.run_sub(args) -> dict[str, Any](L128) — subscriber role: counts distinct clouds by capture stamp (--depthKEEP_LAST), reports delivery ratio and publish→receive latency.main() -> None(L165) — CLI:python tools/cloud_transport_probe.py pub|sub [...], one JSON line each; run the roles as separate processes. Needs a sourced ROS 2 overlay.
Measures whether megabyte best-effort clouds arrive; the evidence behind the deploy's Fast DDS large-data profile (docs/reference/dds-large-messages.md). tests/integration/test_large_cloud_transport_live.py drives it through the real self-filter.
tools/voxel_transport_probe.py
RADIUS_M: float(L58) — a ~1 m arm's coverage radius (1.05 m;deploy_e2e.launch.py::_coverage_ballmeasures it per robot), so grid sizes are deployed-sized.TARGET_HZ: float(L59) — the publish rate the sweep drives each role at.WARMUP: int(L60) — messages discarded before timing starts, so cold-start latency does not skew the measured rate.qos() -> QoSProfile(L63) — the kernel's own/openral/world_voxelsprofile:RELIABLE,KEEP_LAST(1),VOLATILE.per_axis(res: float) -> int(L71) — cells per axis at that resolution.make_msg(res: float) -> tuple[Any, int](L76) — a full-sizeOccupancyVoxelsat that resolution.run_pub(res, count)(L85) — publisher role, emitting JSON; run as a separate process so intra-process short-circuiting cannot hide the transport.run_sub(res, count)(L110) — subscriber role, emitting JSON; likewise a separate process.run_sweep(resolutions, count) -> int(L144) — drives both roles per resolution and prints the table, reporting the RMW measured.- CLI:
uv run python tools/voxel_transport_probe.py sweep [--resolutions ...] [--count N]. Needs a sourced ROS 2 overlay.
Measures the wire cost of the dense uint8[] payload as publish→receive latency, i.e. map staleness. Result is transport- and host-specific.
tools/openarm_world_voxel_run.sh
The only sanctioned launcher for scenes/deploy/openarm_real_world_voxels.yaml and, with --autonomous, scenes/deploy/openarm_real_autonomous.yaml (reasoner + open-vocab detector + spatial memory on; also refuses without OPENRAL_REASONER_MODEL); a --scene copy under scenes/deploy/local/ must equal the selected committed scene bar grasp_declaration. Refuses unless OPENRAL_OPENARM_ALLOW_MOTION=1 and OPENRAL_OPENARM_ATTENDED=1, OPENRAL_ROBOT_UNIT naming the cell, sourced ROS 2, openral on PATH, openral deploy run resolving this checkout's robots/openarm/robot.yaml, that unit's overlay declaring head_zed's mount (openral_core.depth_extrinsic.depth_extrinsic_problems, the same gate deploy run applies, refused here before the operator confirms), an interactive terminal and the typed confirmation ESTOP IN HAND; only observability flags pass through to openral deploy run.
tools/stop_ee_speed.py
REPO_ROOT: Path(L49) — Repo root, derived from__file__.EE_BODY: str(L52) —link7, the body the payload attaches to, so its linear velocity is the carried object's.QUANTISATION_GAIN_M: float(L56) — what 25 → 15 mm recovers (the two cells' half-diagonal difference), the figure staleness cost is weighed against.class StopSpeed(NamedTuple)(L63) —round_id,stop_class,ee_speed_mps,base_speed_mps.StopSpeed.world_speed_mps(L72) — adds the base contribution worst-case-aligned.StopSpeed.is_carry(L77) — selectsattached_payloadstops.collect(round_dirs) -> list[StopSpeed](L100) — End-effector speed at each stop, from the round's recorded joint state viamj_jacBodyon the real Panda model. Raises on an arm-joint name mismatch, since a silent mismatch would read as a stationary arm.summarise(stops) -> dict[str, Any](L176) — per-class medians and maxima, and the net millimetres at the two staleness figures the wire probe measured.render(stops, summary) -> str(L195) — Render the summary as the human-readable table.main(argv=None) -> int(L226) — CLI entry.uv run python tools/stop_ee_speed.py <round dirs...> [--json]. Needs MuJoCo and the robosuite Panda assets; reads recorded artifacts only.
Settles the 25 → 15 mm trade by measuring real stop speeds rather than assuming worst case.
tools/resolution_ab.sh
The 25 mm vs 15 mm world-voxel A/B. Both arms are gate-ON; the only difference is OPENRAL_OCTOMAP_RESOLUTION_M, recorded so a round can never be mistaken for the other. The primary endpoint is the paired per-stop over-approximation, not completion rate, which is under-powered at battery scale (tools/round_power.py).
Runs one graph at a time, alternating arms round by round, since scene-interleaved concurrent lanes broke pairing and exhausted host memory. ROUNDS and SIDECAR_BOOT_S are the knobs; RUN_ROUND_CMD is a test seam. tests/unit/test_resolution_ab_pairing.py.
tools/resolution_ab_report.py
HALF_DIAGONAL_MM: dict[str, float](L38) — resolution string → cell half-diagonal in mm (0.025→ 21.65,0.015→ 12.99); the PRIMARY section's per-stop budget._stops(arm_dir) -> list[dict[str, Any]]— every stop under one arm, with its certified truth when the run recorded one, plus the run'sstarted_at/wall_swindow.main(argv=None) -> int(L99) — CLI over the A/B's output root; writesreport.jsonbeside it.
Pure and offline, so a battery run on one commit can be re-reported by another. Four sections: PRIMARY (paired per-stop over-approximation), INTEGRITY (flags an arm that silently ran at the wrong resolution), PAIRING (flags rounds that ran too far apart to pair), and SECONDARY (completion counts, explicitly under-powered). tests/unit/test_resolution_ab_report_pairing.py.
tools/stop_excess.py
PAYLOAD_PREFIX: str(L41) —"attached:", the party-name prefix identifying a payload side in a stop record.class Excess(NamedTuple)(L44) — one stop's decomposition (round_id,scene,party,is_payload,reported_depth_m,certified_gap_m,voxel_half_diagonal_m,verdict).Excess.excess_m(L57) —certified_gap − reported_depth.Excess.beyond_voxel_m(L62) — subtracts the half-diagonal.half_diagonal(resolution_m: float) -> float(L67) — half a cubic cell's body diagonal, the grid's worst-case error.collect(round_dirs: list[Path]) -> tuple[list[Excess], list[str]](L72) — Certified stops plus the reasons for every skip. Reads each round's own grid resolution; a stop without one is skipped, never defaulted, since the half-diagonal is the quantity being subtracted.summarise(stops, skipped) -> dict[str, Any](L119) — per-classn, median excess, median beyond-voxel, andhas_geometry_headroom(strict> 0: a class exactly at the voxel term has none).render(stops, summary) -> str(L141) — the per-stop table plus the per-class verdict.main(argv=None) -> int(L174) — CLI.uv run python tools/stop_excess.py <round dirs...> [--json].
Produces the decomposition table for the programme note §5 in docs/reference/collision-validation-evidence.md. Pure, offline, stdlib-only; tested in tests/unit/test_stop_excess.py.
tools/adr0101_recovery.py
PAYLOAD_PREFIX: Final[str] = "attached:"(L50) —party_aprefix identifying an attached-payload stop.CELL_PREFIX: Final[str] = "voxel_"(L51) —party_bprefix identifying a world-voxel-cell stop.CLEAR_THRESHOLD_M: float(L48) — The clearance/contact boundary,0.0; zero belongs to contact, not clearance, so a real contact is never counted as a recovery.class Stop(NamedTuple)(L54) — one payload-vs-cell stop with the certified truth behind it (round_id,scene,payload,cell,reported_depth_m,certified_gap_m,nearest_body).Stop.recovered(L66) —certified_gap_m > CLEAR_THRESHOLD_M.class Excluded(NamedTuple)(L71) — A payload-vs-cell stop that could not be adjudicated, and why; reported, never silently dropped, since shrinking the denominator would inflate the recovery rate.UNATTRIBUTED: str(L84) —"<unattributed>", the by-fixture label when the body cannot be established.fixture_at_stop(scene_dir: Path, certified_gap_m: float) -> str(L87) — The world body the payload was nearest, read from the raw ground-truth snapshot and cross-checked against the adjudicated distance; the recovery count never depends on this, only the breakdown does.collect(round_dirs: list[Path]) -> tuple[list[Stop], list[Excluded]](L138) — read each round'sverdicts.jsoninto adjudicable stops plus exclusions. Selects only world stops whoseparty_aisattached:<id>andparty_bisvoxel_<n>, and only when the probe certified its distances.summarise(stops, excluded) -> dict[str, Any](L194) — ADR-0101's Consequences table as data: counts, recovery rate, clearance stats, and the by-fixture breakdown. Returnsrecovery_rate=Noneover an empty set rather than a number.render(summary) -> str(L216) — the human-readable report; refuses to print a percentage over an empty denominator.main(argv=None) -> int(L254) — CLI.uv run python tools/adr0101_recovery.py <round dirs...> [--json].
Produces the recovery-rate figure ADR-0101 rests on. Pure, offline, stdlib-only; reads recorded artifacts, needs no GPU or simulator. Tested in tests/unit/test_adr0101_recovery.py.
tools/round_power.py
Answers how many validation-matrix runs a comparison needs, before a battery is run. Exact (every outcome enumerated, not sampled) and stdlib-only, validated against scipy.stats.fisher_exact. Feeds docs/reference/collision-validation-evidence.md.
RUNS_PER_ROUND = 4— Scene runs in one matrix round, sorequired()can report rounds as well as runs. (L38)fisher_exact_two_sided(a, n1, b, n2) -> float— Two-sided Fisher p-value fora/n1againstb/n2; the "no more probable" tail conventionscipy.stats.fisher_exactuses. (L45)power(baseline, alternative, n, *, alpha=0.05) -> float— Exact power atnper arm: enumerates every(a, b)under the two binomials and sums the probability of the pairs Fisher rejects.O(n²)Fisher evaluations, so sub-second to n=100 and a few seconds by n=300. (L83)required(baseline, alternative, *, alpha=0.05, target=0.80) -> tuple[int | None, float]— Smallest laddernper arm reachingtargetpower, or(None, best)when the ladder tops out at 800 — a comparison needing more than that is not one this programme can afford, and saying so is the useful answer. (L118)_LADDER: tuple[int, ...](L42) — The candidate per-arm sample sizesrequiredsearches,20to800.main(argv=None) -> int(L145) — CLI entry;--baseline/--alternativerates,--alpha,--target; prints the requiredn(and rounds) or that the ladder tops out.
tools/rskill_scaffolder.py
Standalone argparse wrapper around openral_cli._rskill_scaffolder.scaffold_rskill.
Mirrors openral rskill new; exists so power users can scaffold without installing the CLI distribution.
_REPO_ROOT: Path(L26) — Repo root, derived from__file__; used to addpython/<pkg>/srcontosys.pathbefore importing the CLI package._parse_args(argv) -> argparse.Namespace— argparse setup. (L35)main(argv=None) -> int— Entry point; returns a process exit code. (L78)
tools/generate_rskill_skillmd.py
Generate the standard agent-skill SKILL.md discovery view for every in-tree rSkill from its rskill.yaml.
The single canonical producer of the SKILL.md mirror: rskill.yaml is authoritative and the generated file is discovery-only, never hand-edited. --check fails on any stale or missing SKILL.md, across every skill kind including playbook.
render_skill_md(manifest_path: Path) -> str(L162) — Render theSKILL.mdtext (YAML frontmatter + capability/verb summary + license/provenance) from one manifest;_KIND_NOUNmaps eachkindto its discovery noun.main(argv=None) -> int(L261) — Entry point. No args = regenerate everyrskills/<id>/SKILL.md; positional ids regenerate a subset;--checkreports stale/missing without writing (exit 1 on drift).
tools/rldx_sidecar.py
Boot helper for the RLDX-1 inference sidecar, companion to openral_sim.policies.rldx.
Materialises a Python 3.10 venv, clones upstream RLDX-1, installs its dependencies (an override path on aarch64), patches in NF4/int8 quantization for the Qwen3-VL backbone, and execs into the inference server. Needed because upstream pins Python ~3.10 and ships a custom model class Transformers doesn't recognise.
_LABEL: str(L40) —"rldx-sidecar", the sentinel/log label for this sidecar's provisioning._REPO_URL: str(L41) — UpstreamRLWRLD/RLDX-1git URL cloned into the venv's source tree._DEFAULT_HOME: Path(L42) —~/.cache/openral/rldx-sidecar, overridable via--home._AARCH64_OVERRIDE: Path(L52) —sidecar_requirements/rldx-aarch64-override.txt, the torch/torchvision pin override_install_deps_aarch64installs under.-
_NVRTC_OVERRIDE: Path(L60) — Sharedaarch64-nvrtc-override.txt, raising nvrtc past the sm_121 cliff. -
_install_deps(*, source, uv, quantization) -> Path—uv syncin the cloned source tree, then installsbitsandbyteswhen quantizing to NF4/int8. Delegates to_install_deps_aarch64on aarch64, where the plain sync can't succeed. (L129) _install_deps_aarch64(*, source, quantization) -> Path— aarch64 replacement foruv sync: provisions the venv with pinned torch/cuda overrides plus the quantization extras, keyed so a corrected pin repairs an existing venv. (L65)_aarch64_extras(quantization) -> list[str]— the packages installed on top of upstream's own dependency set on aarch64; shared between the install pass and the sentinel spec so they cannot drift. (L113)_make_wrapper(*, work, source, args) -> Path— Generates the server-launching wrapper script: monkey-patches model loading for NF4/int8/no-op quantization, falls back tosdpaattention when flash-attn isn't importable, and hands off to the upstream server entry point. (L165)main() -> int— argparse entry point (--model,--port,--quantization,--home); stamps the sidecar identity record and execs into the sidecar venv so SIGINT reaches the server. (L322)
tools/xr1_sidecar.py + tools/_xr1_server.py
Boot helper + inference server for Xiaomi Robotics XR-1. The launcher provisions its pinned dependency stack and execs the server, which loads the pinned MiBoT checkpoint (NF4 or BF16), recreates the benchmark-specific chat template, and serves ping/reset/get_action/close over the shared ZMQ/msgpack wire.
- main() -> int (xr1_sidecar.py L122) — parse model/profile/quantization/host/port/home; --export-dir persists an NF4 checkpoint and exits, otherwise stamp sidecar identity and os.execvpe into _xr1_server.py.
- _NDARRAY_SENTINEL = "__ndarray__" (_xr1_server.py L17) — Marker key for the msgpack ndarray codec (mirrors openral_sim.sidecar.encode_ndarray's _NDARRAY_SENTINEL, re-implemented here because the sidecar venv cannot import openral_sim).
- _STATE_DIM = 60 (_xr1_server.py L18) — XR-1's internal padded state width; _pad_state pads any frame/history up to this.
- _ACTION_DIMS = {"robocasa_mg": 7, "robocasa365": 12, "vlabench_choice": 7} (_xr1_server.py L19) — Per-benchmark-profile action width the checkpoint processor decodes.
- main() -> int (_xr1_server.py L410) — ZMQ REP server loop entry point; loads the pinned checkpoint then answers ping/reset/get_action/close.
- _messages(profile, images, instruction) -> list[dict[str, Any]] — exact RoboCasa, RoboCasa365-video, or VLABench message layout from upstream revision 7c20088.
- _pad_state(state) -> NDArray[np.float32] — pad one frame or a four-frame history to XR-1's 60-D internal state.
- _local_snapshot(model) -> str — resolve a local path or hf://repo@sha ref to a local snapshot dir (snapshot_download, works offline). transformers 4.57.1's AutoProcessor drops revision from its config probes, so a repo id + revision= reads main (offline without a cached refs/main: falls back to the bare Qwen2 tokenizer).
- _require_mibot_processor(processor, model) -> Any — raise TypeError at load when AutoProcessor returned anything without decode_action (i.e. not the checkpoint's MiBotProcessor), instead of failing the first forward on missing state/action_mask.
- class _XR1Policy — Pinned AutoModel/AutoProcessor custom-code loader; NF4 uses a BF16 compute dtype, and prequantized_nf4 reloads a saved packed checkpoint without re-quantizing. export_pretrained writes sharded packed safetensors plus quantization metadata.
tools/qwen_vlm_sidecar.py + tools/_qwen_vlm_server.py
Boot helper + server for the Qwen3.5-4B scene-VLM sidecar, companion to QwenSceneVlm. Provisions an isolated venv and execs into a ZMQ REQ/REP + msgpack server answering scene questions, run out-of-process for dependency/VRAM isolation. Apache-2.0 model.
_DEFAULT_HOME: Path(L34) —~/.cache/openral/qwen-vlm-sidecar, overridable via--home/$OPENRAL_QWEN_VLM_SIDECAR_HOME._VENV_ENV: str(L35) — Env var name for the--venvoverride._HOME_ENV: str(L36) — Env var name for the--homeoverride._LOCK: Path(L53) — Hash-locked pinned deps file the venv is provisioned from._NVRTC_OVERRIDE: Path(L62) — aarch64 nvrtc override passed at install time alongside_LOCK.ensure_venv(home, *, override=None) -> Path(L67) — return the sidecar venv python, provisioning + installing pinned deps if absent (sentinel-guarded); honours$OPENRAL_QWEN_VLM_SIDECAR_VENV.main() -> int(L111) — argparse (--model,--host,--port,--max-side,--home,--venv); stripsPYTHONPATH/PYTHONHOMEandos.execvpes into_qwen_vlm_server.py._load(model_id) -> (processor, model)(_qwen_vlm_server.py L61) — dual-path NF4 load: auto-detects a pre-quantized checkpoint via its embedded config and loads 4-bit directly, else quantizes at load with serial materialization for 8 GB._query(processor, model, *, image, question, max_side, max_new_tokens) -> str(_qwen_vlm_server.py L103) — one scene-question→answer generate via the canonical Qwen-VL recipe (strips the<think>trace).main() -> int(_qwen_vlm_server.py L172) — ZMQ REP loop (ping/query/shutdown) that replies with an error object rather than dying on exception. Validated live against real hardware.
tools/locateanything_sidecar.py + tools/_locateanything_server.py
Boot helper + server for the nvidia/LocateAnything-3B open-vocabulary detector sidecar, companion to LocateAnythingDetector. Runs out-of-process over the same ZMQ pattern as rldx_sidecar because its pinned transformers version conflicts with the workspace's. No upstream repo to clone — the model is custom-code on the Hub.
_DEFAULT_HOME: Path(L33) —~/.cache/openral/locateanything-sidecar._VENV_ENV: str(L34) — Env var name for the--venvoverride._HOME_ENV: str(L35) — Env var name for the--homeoverride._LOCK: Path(L50) — Hash-locked pinned deps (transformers==4.57.1load-bearing); regenerated viauv pip compile tools/sidecar_requirements/locateanything.in._NVRTC_OVERRIDE: Path(L59) — aarch64 nvrtc override passed at install time alongside_LOCK.ensure_venv(home, *, override=None) -> Path(L64) — return the sidecar venv python, provisioning + installing pinned deps if absent (sentinel-guarded, keyed on_LOCK+_NVRTC_OVERRIDE); honours$OPENRAL_LOCATEANYTHING_SIDECAR_VENV.main() -> int(L109) — argparse (--modelrequired,--host,--port,--max-side,--home,--venv); setsOPENRAL_ALLOW_REMOTE_CODE=1(the operator opted in by launching this sidecar) and execs into_locateanything_server.py._split_model_ref(model_ref) -> tuple[str, str](_locateanything_server.py L44) — Split arepo@revisionreference into(repo, revision)._load(model_ref) -> (processor, model)(_locateanything_server.py L55) — NF4 bitsandbytes load of the pinned custom-code checkpoint._detect(processor, model, image, query, *, max_side, mode, max_new_tokens) -> str(_locateanything_server.py L99) — One detection request → the model's raw generated text;<ref>/<box>parsing stays in the main-env backend.main() -> int(_locateanything_server.py L146) — ZMQ REP loop (ping/detect/shutdown);{"ok": False, "error": ...}on exception rather than dying.
tools/da3_depth_sidecar.py + tools/_da3_depth_server.py
Boot helper + server for the Depth Anything 3 monocular metric-depth sidecar, companion to openral_perception_ros's depth-provider node. Runs in its own Python 3.12 venv behind a ZMQ REQ/REP + msgpack wire, since the model ships outside transformers; the provider republishes the reply as a depth image for nvblox. Loaded by file path so the deploy launch can autostart it under a plain interpreter.
_DEFAULT_HOME: Path(L54) — default cache dir._VENV_ENV = "OPENRAL_DA3_DEPTH_SIDECAR_VENV"(L55) —--venvoverride env var name._HOME_ENV = "OPENRAL_DA3_DEPTH_SIDECAR_HOME"(L56) —--homeoverride env var name._REQUIREMENTS = ("depth-anything-3", "pyzmq", "msgpack")(L62) — x86_64 install set._NVRTC_OVERRIDE: Path(L76) — aarch64 nvrtc override file passed at install time._AARCH64_REQUIREMENTS: tuple[str, ...](L79) — upstream's dependency list minusopen3d/pycolmap/xformers/pre-commit, plus the undeclaredaddictand the repo'storch==2.9.1aarch64 pins._AARCH64_DA3 = "depth-anything-3==0.1.1"(L106) — installed--no-depsafter_AARCH64_REQUIREMENTSon aarch64._PYCOLMAP_EAGER_IMPORT = "\nimport pycolmap\n"(L112) — the anchor statement_defer_pycolmap_importrewrites._PYCOLMAP_LAZY_IMPORT: str(L113) — the lazy__getattr__proxy it rewrites that statement into.ensure_venv(home, *, override=None) -> Path(L167) — Returns the sidecar venv python, provisioning it if absent. x86_64 installs the plain requirement set; aarch64 substitutes packages with no aarch64 wheel and applies an nvrtc override, load-bearing because the model's JIT-fused op otherwise fails on later requests._site_packages(py) -> Path(L132) — thesite-packagesof the venv owningpy;SystemExitif absent._defer_pycolmap_import(py) -> None(L140) — aarch64 only: rewrites the installed package's eagerimport pycolmapinto a lazy proxy, since that dependency has no aarch64 wheel but is only needed by a code path this sidecar never calls. A deferred import, not a stub — the real error still raises if that path is used.main() -> int(L221) — argparse (--modeldefaultdepth-anything/DA3-SMALL,--host,--portdefault 5771,--process-resdefault 504,--home,--venv); execs into_da3_depth_server.py. No JIT/fuser env knobs needed, since the nvrtc override fixes the issue at install time._load(model_id) -> (torch, model)/_infer(torch, model, image, process_res) -> (depth, K, latency_ms)— load DA3 to CUDA in eval mode; one image → metric depth(H, W)float32 + 3×3 intrinsics.main() -> int(_da3_depth_server.py L70) — ZMQ REP loop (ping/depth/shutdown) that replies with an error object rather than dying on a bad frame. Validated live on both an 8 GB Ada GPU and a GB10 aarch64 host.
tools/internvla_n1_sidecar.py + tools/_internvla_n1_server.py
Boot helper + server for InternVLA-N1/DualVLN, companion to openral_sim.policies.internvla_n1. Runs out-of-process over ZMQ because upstream's pinned transformers version conflicts with the workspace's; provisions a py3.11 venv from an inference-only pin set and serves the Qwen2.5-VL-7B S2 planner + NavDP DiT S1 policy, mapping discrete VLN-CE actions to a BODY_TWIST.
_LABEL = "internvla-n1-sidecar"(L39) — sidecar identity._REPO_URL = "https://github.com/InternRobotics/InternNav.git"(L40) — upstream clone URL._DEFAULT_HOME: Path(L41) — cache dir._PYTHON = "3.11"(L42) — venv Python version._PINNED_DEPS: list[str](L53) — Inference-only pin set mirroring upstream, minus flash-attn (sdpa instead); torch 2.9.1 on thetorch_backend()index (cu130 on aarch64) for aarch64 support, anddiffusers==0.32.2specifically since a later release changed the architecture the checkpoint was trained against._DIFFUSION_POLICY_PIN: str(L79) — Pinsdiffusion_policyto one commit installed with--no-deps, since System-1's NavDP imports onlySinusoidalPosEmbfrom it._NVRTC_OVERRIDE: Path(L88) — aarch64 nvrtc override; without it transformers 4.51's Qwen2.5-VL vision stack's.prod()dies past the sm_121 ceiling on every System-2 replan.main() -> int(L166) — argparse via the sharedbuild_parser; callsrun_sidecarwithfamily="internvla_n1",install_deps=_install_deps,make_wrapper=_make_wrapper._NDARRAY_SENTINEL = "__ndarray__"(_internvla_n1_server.py L55) — Marker key for the msgpack ndarray codec (mirrorsopenral_sim.sidecar.encode_ndarray, re-implemented here because the sidecar venv cannot importopenral_sim)._ACTION_STOP = 0(_internvla_n1_server.py L60) — Discrete VLN-CE action ids emitted by System-2 (upstreamInternVLAN1AsyncAgent.actions2idx): STOP._ACTION_FORWARD = 1(_internvla_n1_server.py L61) — forward 0.25 m._ACTION_LEFT = 2(_internvla_n1_server.py L62) — turn left 15°._ACTION_RIGHT = 3(_internvla_n1_server.py L63) — turn right 15°._ACTION_LOOK_DOWN = 5(_internvla_n1_server.py L64) — look down (no base motion)._DEFAULT_FORWARD_MPS = 0.25(_internvla_n1_server.py L69) — forward speed magnitude for_ACTION_FORWARD, held for ~1 s of wall time between S2 replans._DEFAULT_TURN_RADPS = float(np.deg2rad(15.0))(_internvla_n1_server.py L70) — turn speed magnitude for_ACTION_LEFT/_ACTION_RIGHT.discrete_action_to_twist(actions, *, forward_mps, turn_radps) -> tuple[float, float, bool](_internvla_n1_server.py L73) — Maps a VLN-CE discrete action sequence to(v_forward, w_yaw, stop); only the first action drives motion this step, STOP anywhere latchesstop=True. Pure/side-effect-free (tests/unit/test_internvla_n1_action_mapping.py).main() -> int(_internvla_n1_server.py L321) — argparse (--model,--host,--port,--device,--quantization,--resize,--num-history,--plan-step-gap,--forward-mps,--turn-radps,--work-dir); boots the ZMQ server.
tools/lingbot_vla2_sidecar.py + tools/_lingbot_vla2_server.py
Boot helper + server for LingBot-VLA (v1 and v2), companion to openral_sim.policies.lingbot_vla2. v2 (6B Qwen3-VL MoE) is the default; --variant v1 selects the 4B Qwen2.5-VL dense RoboTwin post-train, which is x86_64-only. Runs out-of-process because upstream pins a torch/kernel stack incompatible with the workspace.
_LABEL = "lingbot-sidecar"(L49) — sidecar identity._REPO_URL: str(L50) — upstreamrobbyant/lingbot-vla-v2clone URL._PINNED_SHA: str(L53) — pinned v2 commit._DEFAULT_HOME: Path(L54) — v2 cache dir._HOME_ENV: str(L55) —--homeoverride env var name._VENV_ENV: str(L56) —--venvoverride env var name (v2)._REPO_ENV: str(L57) — repo-dir override env var name (v2)._REPO_URL_V1: str(L63) — the v1 (robbyant/lingbot-vla) clone URL, driven by--variant v1._PINNED_SHA_V1: str(L64) — pinned v1 commit._DEFAULT_HOME_V1: Path(L65) — v1 cache dir._VENV_ENV_V1: str(L66) —--venvoverride env var name (v1)._REPO_ENV_V1: str(L67) — repo-dir override env var name (v1)._SERVER: Path(L69) — path to_lingbot_vla2_server.py, theos.execvpetarget for both variants._AARCH64_PTXAS: str(L74) —nvidia-cuda-nvcc==13.0.88, installed on aarch64 only so the MoE Triton kernels get aptxasthat targets both Thor (sm_110) and GB10 (sm_121); also part of the aarch64 venv spec, so a CUDA-12.9-ptxas venv is repaired._TORCH_PIN(L89) — v2's torch 2.9.1 pin, overridden from upstream's 2.8.0 so the sidecar provisions on aarch64._TORCHVISION_PIN(L90) — matching v2 torch-stack pin._TORCHAUDIO_PIN(L91) — matching v2 torch-stack pin._TORCHCODEC_PIN(L96) — matching v2 torch-stack pin (excluded on aarch64)._TRITON_PIN(L97) — matching v2 torch-stack pin._V2_OVERRIDES: tuple[str, ...](L98) — the override requirement files applied on top of upstream's v2 lock.main() -> int(L325) — argparse (--model,--host,--port,--home,--variant {v1,v2}, quantization); provisions the matching variant's venv andos.execvpes into the server._NDARRAY_SENTINEL = "__ndarray__"(_lingbot_vla2_server.py L47) — Marker key for the msgpack ndarray codec._BNB_META_SUFFIXES(_lingbot_vla2_server.py L336) — bitsandbytesParams4bitpacked-stat suffixes written alongside each.weight; mirrorsopenral_sim._quantization._BNB_META_SUFFIXESso the on-disk pack format matches every other OpenRAL nf4 rSkill.main(argv: list[str]) -> int(_lingbot_vla2_server.py L961) — Resolves the torch-version-dependent CUDA allocator env var from installed-package metadata before CUDA initializes, then serves either the v2 or v1 (--variant v1) policy.
tools/cosmos3_reasoner_sidecar.py
Boot helper for the curated NVIDIA Cosmos 3 Edge reasoner model (OPENRAL_REASONER_MODEL=cosmos3-edge), companion to Cosmos3ToolUseClient. Provisions an isolated venv plus a SHA-pinned transformers overlay, builds a flattened reasoner view for vLLM's loader, and execs into vllm serve — its OpenAI-compatible HTTP API is the wire contract the reasoner already speaks. Cosmos 3 weights are commercial-OK, so there is no license guard; forward-pass inference is currently blocked by an upstream bug (see docs/reference/cosmos3-edge-reasoner.md).
ensure_venv(home, *, override=None) -> Path(L95) — Returns the sidecar venv python, provisioning the pinned lock and the SHA-pinned transformers overlay if absent.is_diffusers_reasoner_layout(model_dir) -> bool(L150) — True when the top-levelmodel.safetensors.index.jsonmaps tensors into subfolders (the Edge layout needing a view); Nano/Super (bare top-level shards) return False.materialize_reasoner_view(model_dir, dest) -> Path(L168) — build a vLLM-loadable flat view: bare-named shard symlinks + a rewritten weight index + tokenizer/config symlinks. Idempotent.resolve_served_model(model, home, *, native_edge=False) -> tuple[str, str | None](L251) — Resolves a repo id or local dir to avllm servetarget. For the Edge diffusers layout the target depends on the serving vLLM: a native-Edge-aware vLLM serves the snapshot as-is, otherwise the flattened view is required.vllm_has_native_edge_model(py) -> bool(L216) — Asks the serving venv's own model registry whether it knows the native Edge model class, since the answer differs by platform. Fails closed to the flattened-view path on any error.build_serve_argv(*, vllm_bin, model, host, port, tool_call_parser, max_model_len, gpu_memory_utilization, enforce_eager, served_model_name=None, kv_cache_dtype="auto") -> list[str](L286) — Builds thevllm serveargv;--max-model-len,--enforce-eager,--gpu-memory-utilizationand fp8 KV cache are the knobs that make an 8 GB card fit.main() -> int(L363) — argparse entry point; sets the CUDA allocator config, resolves the served view, and execs intovllm serve.
tools/behavior_groot_sidecar.py
Python 3.10 sidecar for the official 2026 BEHAVIOR-1K GR00T N1.7 checkpoint. Imports the pinned behavior runtime, wraps Gr00tPolicy for the R1Pro modality slices, and serves ZMQ ping/reset/get_action/close. Supports whole-model NF4 quantization (default) plus dropping the unused Qwen3-VL lm_head to fit an 8 GB host.
main(argv) -> int(L366) — Parses checkpoint/task/instruction/control-mode/device/endpoint plus a quantization mode, loads the real checkpoint (CPU-first under NF4/int8), and serves the 23-D action API._drop_backbone_lm_head(model) -> None— Replace the Qwen3-VLlm_headwithIdentity; the B1K wrapper consumes onlyhidden_states[-1], so the full-vocab logits projection is dead weight and was the largest single inference allocation._quantize_nf4(model, *, device, min_params) -> None— Whole-model bitsandbytes NF4 rewrite of large linear layers, keeping small layers floating; behaviourally lossless for this checkpoint against a bf16 reference._quantize_int8(model, *, device, min_params) -> None— Same rewrite with 8-bit linear layers; higher fidelity but too large to co-reside with OmniGibson on 8 GB, so used for offline comparison only.
tools/behavior_scene_sidecar.py
Official OmniGibson evaluator environment sidecar for scene.id=behavior. Resolves the configured task instance, exposes the challenge wrapper observation, applies external 23-D actions, and returns success/metrics/sim time over ZMQ.
main(argv) -> int(L222) — Parse task/instance/mode/wrapper/max-steps/endpoint, load the real BEHAVIOR environment, and serveping/reset/step/close.
tools/_robometer_quant.py
Shared NF4 quantize + pre-quantized meta-load helpers for the Robometer reward scorer, re-implementing the repo's NF4 rule rather than importing openral_sim._quantization. Determinism is forced so a meta pre-quantized load matches a bf16-then-quantize reference bit-for-bit.
MIN_PARAMS = 4_000_000(L25) — Mirrorsopenral_sim._quantization.DEFAULT_MIN_PARAMS_TO_QUANTIZE.BNB_META_SUFFIXES: tuple[str, ...](L28) — bitsandbytesParams4bitpacked-stat suffixes written alongside each.weight.set_cublas_workspace_env() -> None(L38) — Pins the cuBLAS workspace BEFORE CUDA initialises (required for determinism).apply_determinism() -> None(L43) — Forces byte-stable numerics: disables cudnn TF32, forces math SDP (flash/mem-efficient SDP are process-state dependent, math SDP is not).quantize_nf4_in_place(root, compute_dtype) -> int(L55) — Rewrites largenn.Linear→bnb.nn.Linear4bitin place (the repo's NF4 rule); returns count replaced. Quantization happens lazily on first.to("cuda").install_linear4bit_shells(root, compute_dtype) -> int(L93) — Replaces large linear layers with emptyLinear4bitshells on a meta-device skeleton, so a prequantized load can drop in packed weights without the RSS spike of an off-meta load.install_prequantized(policy, state, device) -> set(L133) — Drops saved packed NF4 weights intoLinear4bitshells viafrom_prequantized; returns consumed checkpoint keys. Bit-identical to the in-place quantization that produced the checkpoint.assign_meta_buffers(model, state, device) -> int(L167) — Assigns any still-meta buffer by hand, sinceload_state_dictskips non-persistent buffers; raises if a meta buffer is missing from the checkpoint.is_prequantized_checkpoint(path) -> bool(L192) — True ifpathholds amodel.safetensorswith bnb NF4 packed keys.
tools/_robometer_scorer.py
In-process stateless scorer for the Robometer-4B reward monitor, companion to RobometerInProcessReward. Loaded directly by reward_monitor_node — no separate process or dedicated venv. Meta-builds lerobot's native reward-model skeleton and drops in OpenRAL's NF4 pre-quantized weights directly, with no bf16 spike and no extra download.
_NATIVE_CONFIG_REPO: str(L51) —"lerobot/Robometer-4B", the HF repo_native_configdownloadsconfig.jsonfrom to meta-build the native module skeleton.class Scorer(L104) — Meta-builds the nativeRobometerRewardModeland remaps + loads the NF4 prequant pack.__init__(weights, device="cuda", *, meta_buffers=True)(L107) —meta_buffers=Falsebuilds buffers for real from the modules' own__init__: the referencetests/sim/test_reward_nf4_buffer_equivalence.pycompares the meta load against (issue #304). Seedingoriginal_inv_freqfrominv_freqraises unless the rotary module'srope_typeis"default".score(frames_rgb, task, num_bins) -> tuple[list[float], list[float]](L211) — Computes per-frame progress/success via the module's logit-decoding path (not the scalar-onlycompute_reward).num_binsis accepted for interface parity but unused.
tools/build_qwen_vlm_nf4_checkpoint.py
Reproducible recipe for the published OpenRAL/rskill-qwen35_4b-any-general-nf4 pre-quantized NF4 checkpoint. Runs in the sidecar venv. Distinct from quantize_rskill.py, which writes an install_prequantized_linears-loaded pack for the in-process lerobot runtime; this writes a transformers-native save_pretrained checkpoint for the isolated VLM sidecar.
main() -> int(L52) — argparse (--source,--out); loads the upstream model once, quantizes to NF4, saves the weights + processor, then verifies the checkpoint reloads directly as 4-bit and answers a smoke query.
tools/fix_libero_config.py
Auto-fix for the stale ~/.libero/config.yaml pitfall.
Detects and repairs $LIBERO_CONFIG_PATH/config.yaml when its absolute paths no longer match the active libero package, since the file is written once at first import and never refreshed. Wired into the Justfile ahead of the LIBERO sim recipes; idempotent.
_expected_config(libero_pkg_dir) -> dict[str, str]— Compute the canonicalassets/bddl_files/benchmark_root/datasets/init_statespayload that LIBERO writes on first import. (L31)_parse_yaml_map(text) -> dict[str, str]— Parse the flatkey: valuemap LIBERO writes — no PyYAML dependency. (L47)_render_yaml(payload) -> str— Render the same flat layout. (L61)_locate_active_libero() -> Path—import liberoand return its package directory; raisesRuntimeErrorwith a clear message when LIBERO is absent (caller treats as no-op). (L66)main() -> int— argparse entry point; flags--dry-run,--verbose. Returns 0 when the config matches or after rewriting. (L91)
tools/refresh_methods_linenos.py
Refreshes the (LNN) line citations in the docs/methods/ inventory; --check reports drift or unresolved entries and exits 1; --coverage lists undocumented public symbols (wired into just lint).
REPO_ROOT(L40)METHODS_DIR: Path(L41) —REPO_ROOT / "docs" / "methods".refresh_file(md_path: Path, *, check: bool) -> tuple[int, list[str], dict[Path, set[str]]]— Rewrite one inventory file's markers; returns the changed-marker count, the unresolved-entry descriptions, and the symbols each source file has an entry for. (L194)coverage_report(documented: dict[Path, set[str]]) -> list[str]— Public symbols underpython/,packages/,tools/(tests,setup.py,conftest.pyexcluded) with no inventory entry, one line per file. (L365)main(argv: list[str] | None = None) -> int(L378) — CLI entry;--check/--coverageflags.
tools/build_robometer_nf4_checkpoint.py
Builds the publishable pre-quantized Robometer-4B NF4 checkpoint: loads the upstream bf16 model, quantizes in place, and saves a self-contained directory the scorer can meta-load directly as 4-bit. Uploads to OpenRAL/rskill-robometer_4b-any-general-nf4.
main() -> int— CLI entry;--out <dir>writes the quantized checkpoint directory. (L45)
tools/export_act_onnx.py
Exports a LeRobot ACT policy to a single whole-model ONNX graph (ACTPolicy.model, called as predict_action_chunk does). Normalization stays external (checkpoint's policy_preprocessor.json/policy_postprocessor.json MEAN_STD sidecars); inputs ordered by config.image_features plus the checkpoint's declared state dim. Parity checked in tests/integration/test_act_onnx.py.
export(out_path, repo_id, *, device="cpu", preprocess="host") -> str— CLI entry (--repo-id,--out). (L147)
tools/export_rtdetr_onnx.py
Exports PekingU/rtdetr_r18vd_coco_o365 to ONNX matching ObjectsDetector's contract: single image input, /255 preprocessing, two 3-D outputs (pre-sigmoid logits + cxcywh-normalised boxes). Run in an isolated uv run --isolated --no-project overlay — the project venv's torchvision would shadow it and break the RTDetrForObjectDetection import; do not uv sync the onnx-export group.
export(out_path, model_id="PekingU/rtdetr_r18vd_coco_o365") -> None— CLI entry (--out). (L30)
tools/gen_nav2_visual.py
Generates packages/openral_nav2_bringup/config/nav2_visual.yaml (the Nav2 costmap profile for the visual-SLAM backend — cuVSLAM + nvblox, static_layer off the backend-agnostic /map OccupancyGrid instead of ray-casting /scan) from the base lidar profile nav2_panda_mobile.yaml, so the two stay in sync. One-shot; re-run after editing the base config.
render(base_text: str) -> str— The derived visual-SLAM profile text for a base-profile text; pure, so the sync test can diff it against the checked-in file. (L51)main(argv=None) -> int— Writes the derived profile;--checkexits 1 when the checked-in copy is stale (run byjust lint). (L80)
tools/gen_ros_topic_graph.py
Generates docs/topics/README.md, the ROS 2 topic / service / action graph, by statically joining every publisher, subscriber, server and client in python/, packages/, tools/ and cpp/ (tests excluded) on its resolved name, plus launch-file remappings. Pre-commit rewrites the page; just lint and the quality workflow run --check.
prop REPO_ROOT, OUT_PATH, SCAN_ROOTS(L48–50) — Repo root, the generated page (docs/topics/README.md), and the scanned top-level trees (python,packages,cpp,tools).class Endpoint— One side of a connection:kind(topic/service/action),role, resolvedname(or the source expression),resolved, canonicalpkg/Type, andwhere(path (Class.method)plus a[paramx]note). (L90)extract_python(files) -> list[Endpoint]— Endpoints from Python sources; names resolve through literals, f-strings, enclosing-scope and module constants (acrossfrom x import), class andself._xattributes, parameter defaults (a parameter without one stays unresolved),declare_parameterdefaults, argparseadd_argument(default=...)andopenral_core.camera_topic(name, kind)(a non-literal name becomes{sensor}); name and type are read positionally or by rclpy's keywords (topic/msg_type,srv_name/srv_type,action_name/action_type). (L428)extract_cpp(files) -> list[Endpoint]— Endpoints from C++ sources; arguments are split with balanced brackets, bothrclcpp_action::create_server/create_clientoverloads (node, or the four node interfaces) are handled, and a name resolves from a string literal or adeclare_parameter<T>("x", "default")variable. (L471)extract_remappings(files) -> list[tuple[str, str, str]]—(from, to, launch file)for everyremappings=pair. (L537)render(endpoints, remaps) -> str— The Markdown page: concrete and per-instance ({placeholder}) topics, services and actions, unresolved endpoints, remappings. (L569)build() -> str— Scans the tree and renders the page. (L639)main(argv=None) -> int— Writes the page;--checkexits 1 when the checked-in copy is stale. (L647)
tools/quantize_lingbot_vla2.py
Pre-quantizes LingBot-VLA 2.0's Qwen3-VL backbone to an NF4 pack ahead of time (the sidecar normally does this at load) so deploys download ~7 GB instead of 25.5 GB and skip the per-boot conversion. Runs in the sidecar venv (torch 2.9 / transformers 4.57.3 / bitsandbytes) importing tools/_lingbot_vla2_server.py's own helpers so the pack matches the runtime shells byte-for-byte. Frugal streaming keeps GPU peak at a few hundred MB and host peak at ~30 GB.
main(argv) -> int— CLI entry (--ckpt,--out,--qwen). (L313)
tools/quantize_rskill.py
Quantize a lerobot policy and upload the result to the HuggingFace Hub. Policy-agnostic counterpart to the in-process fast-path in openral_sim._quantization. Loads any lerobot policy via from_pretrained, quantizes in place, saves model.safetensors + quantization_metadata.json, and uploads to a target rSkill repo — the adapter's load_prequantized_state_for_rskill detects the metadata sentinel and skips the on-line nf4 conversion on every subsequent launch. Not part of CI — a one-shot Hub-mutating tool gated on HF_TOKEN.
main() -> int(L537) — CLI entry;--repo-id/--out-repo-id/--quantization/--trust-remote-code; loads, quantizes in place, uploads.
tools/verify_test_envs.py
Verifies selected optional test environments locally: syncs the matching dependency group declared in tools/test_selection.toml, runs its selected targets, and fails if any test skips. Hardware and externally-provisioned sidecars are opt-in since this script cannot create physical devices or proprietary simulator installs.
REPO_ROOT: Path(L22) — Repo root, derived from this file's location.CONFIG: Path(L23) —tools/test_selection.toml, the lane config this script drives.PROVISIONED_GROUPS: dict[str, str](L25) — Lane name → the sidecar/fork env var (or manual-install note) that provisions it.LANE_EXTRA_GROUPS: dict[str, list[str]](L35) — Extrauv sync --groupnames to pull in alongside a lane's own group (simalso needsdataset).LANE_DEPENDENCY_GROUP: dict[str, str](L39) — Lane name → the actualuvdependency group when it differs from the lane name (robocasa-gr1syncsrobocasa).MANUAL_INSTALL_GROUPS: frozenset[str] = {"robocasa-gr1", "simpler-env"}(L43) — Lanes this script cannot provision itself; skipped with a note instead of failing.ONNX_EXPORT: Path(L44) — Expectedrtdetr-coco-r18/model.onnxexport artifact path, checked before the export-dependent lane runs.SIMPLER_ENV_SPEC: str(L45) — pip spec for thesimpler-envgit package (maniskill3 branch).ROBOCASA_GR1_REPO: str(L46) — Upstream RoboCasa-GR1 tabletop-tasks fork clone URL.ROBOCASA_GR1_DIR: Path = Path("/tmp/rg1")(L47) — Fixed checkout directory for the RoboCasa-GR1 clone.LOCATEANYTHING_VENV: Path(L48) — Expected LocateAnything sidecar venv under~/.cache/openral.QWEN_VLM_VENV: Path(L49) — Expected Qwen-VLM sidecar venv under~/.cache/openral.RLBENCH_HOME: Path(L50) — RLBench sidecar cache root.RLBENCH_VENV: Path(L51) — RLBench sidecar venv, underRLBENCH_HOME.RLBENCH_PYTHON: Path(L52) — That venv's interpreter.COPPELIASIM_ROOT: Path(L53) — Expected CoppeliaSim 4.1.0 EDU install directory.COPPELIASIM_ARCHIVE: Path(L54) — Cached CoppeliaSim download archive.COPPELIASIM_URL: str(L57) — Upstream CoppeliaSim download URL.POLICY_SRC: Path(L60) — Shared clone root for policy-adjacent source checkouts (PyRep/RLBench/3D-Diffuser-Actor).PYREP_DIR: Path(L61) — PyRep checkout dir underPOLICY_SRC.RLBENCH_DIR: Path(L62) — RLBench checkout dir underPOLICY_SRC(distinct fromRLBENCH_HOME, the sidecar's own cache).THREEDDA_DIR: Path(L63) — 3D-Diffuser-Actor checkout dir underPOLICY_SRC.PYREP_REPO: str(L64) — PyRep upstream repo URL.RLBENCH_REPO: str(L65) — RLBench upstream repo URL.THREEDDA_REPO: str(L66) — 3D-Diffuser-Actor upstream repo URL.THREEDDA_INSTRUCTIONS: Path(L67) — Expected path to the PerAct instructions pickle 3D-Diffuser-Actor needs.main(argv=None) -> int— CLI entry; drives group sync, provisioning, and_strict_pytestper lane.--junit-xml PATH(one group) writes pytest's junit report and drops the script's own no-skips rule, leaving the accounting totools/lane_report.py— how the heavy-lanes workflow runssimpler-env/robocasa-gr1. (L486)
tools/wait_for_action_and_signal_palette.py
Polls for a ROS 2 action server to appear, then publishes on /openral/skill_registry_changed so the reasoner re-seeds its rSkill palette. Needed because a wrapped-ROS rSkill can drop from the palette if its action isn't advertised yet at launch (e.g. Nav2 takes 15-30 s). Exits 0 once published, 1 on timeout.
main() -> int— CLI entry (--action,--timeout-s). (L101)
tools/galaxea_a1_ros1_sidecar.py
Galaxea A1 ROS 1 sidecar for openral_hal.galaxea_a1.GalaxeaA1HAL; owns roscore, the official serial driver, and the official joint tracker, stopping all three on every exit path. No vendor code is bundled in OpenRAL.
JOINT_NAMES = tuple(f"arm_joint{i}" for i in range(1, 7))(L28) — The six A1 arm joint names, in driver order.JOINT_LIMITS(L29) — Per-joint(lower, upper)radian limits, same order asJOINT_NAMES.PROTOCOL_VERSION = 1(L37) — Wire protocol version for the staged/host command relay.GRIPPER_STATUS_INDEX = len(JOINT_NAMES)(L38) — Index of the gripper's status code within a 7-element status tuple.MAX_STATUS_MASK = 0xFFFFFFFF(L39) — Valid uint32 range for a motor status/error code.TRACKER_NODE = "openral_a1_joint_tracker"(L40) — Name of the official joint tracker process this sidecar starts.STAGED_COMMAND_TOPIC = "/openral/arm_joint_command_staged"(L41) — Topic the HAL publishes staged joint targets on.HOST_COMMAND_TOPIC = "/arm_joint_command_host"(L42) — Topic the sidecar forwards accepted commands to on the host driver side.TRACKER_ALLOWED_MODES = (0,)(L43) — Tracker control-mode values the relay accepts as safe to arm on.class Stack(L92) — Owns and tears down the ROS 1 process group in reverse start order.Stack.start(argv)(L100) — Launch a child in its own session, tracked for teardown.Stack.stop()(L105) — SIGINT every child (reverse order), wait, escalate to SIGKILL on timeout.class Bridge(L125) — ROS 1 topic relay: buffers joint/gripper/status feedback, gates a staged command through the tracker's activation handshake, and republishes to the host driver.Bridge.configure(config)(L170) — Install the validated client contract while keeping motion locked.Bridge.ready() -> bool(L373) — Whether joint, gripper and status feedback have all arrived at least once.Bridge.command_paths_ready() -> bool(L381) — Whether staged and host command topic consumers/publishers are all connected.Bridge.relay_state() -> str(L390) — Current relay state (LOCKED/ARMING/…).Bridge.state(config)(L394) — Assemble the current feedback+relay JSON state, raisingRuntimeErroron stale feedback, a latched fault, or an out-of-limits reading.Bridge.apply(packet, config, first_joint_command)(L457) — Validate and forward one command packet (joint_targets/ gripper) to the host driver after re-checking state and motor status.main() -> int(L709) — argparse (--bind,--port,--serial,--startup-timeout-s); starts roscore + the vendor serial driver + tracker viaStack, wiresBridge, serves the sidecar's TCP/JSON protocol.
tools/joint_state_staleness_probe.py
pct(xs, p) -> float(L68) — nearest-rank percentile; NaN when empty.build_probe_hal(robot_yaml) -> RosControlHAL(L76) — builds the robot's real HAL from its manifest viabuild_hal(mode="real")(so it reads at the manifest'ssafety.joint_state_staleness_limit_son the manifest's joint-state topic); refuses a non-RosControlHALrobot (SO-100, ALOHA, Galaxea) withSystemExit.run(robot_yaml, duration_s, rate_hz, read_hz, load) -> int(L103) — publishes syntheticJointStateatrate_hzover real DDS intoRosControlTransport(production QoS + callback) on one executor, and prints callback inter-arrival gaps, stamp→callback latency, the read-side agenow - last_arrival()atread_hz(default: the manifest's control rate), and how oftenhal.read_state()raisedROSPerceptionStaleat the manifest's limit.load=Trueadds a GIL-contending thread in the same process.main(argv=None) -> int(L257) — CLI:uv run python tools/joint_state_staleness_probe.py --robot robots/<id>/robot.yaml --rate <joint_states Hz> [--duration 60] [--read-hz N] [--load]. Needs a sourced ROS 2 overlay; usesROS_DOMAIN_ID77 unless set, so it never touches a live graph.
Backs safety.joint_state_staleness_limit_s in a real manifest — the age past which read_state (and the runner's waits) refuse to answer. The number must come from a measurement on the deploy host, not a schema default. Thor 2026-09-23 (Fast-DDS): idle gap p99.9 2.6 ms / max 4.6 ms, read-side age max 32 ms; under GIL starvation latency max 43 ms, no gap above 33 ms → robots/openarm/robot.yaml declares 0.1 s (three control periods). The other real manifests are unmeasured and marked provisional (Franka / Sawyer 0.2 s, the real HALs' former constructor default).
tools/force_layer_feasibility.py
Force/contact layer (#373) feasibility tools on the MuJoCo OpenArm v2 right arm, fed only what /joint_states.effort carries (joint_actuator_effort). Analysis only — not on any control path. uv run python tools/force_layer_feasibility.py probe --force-n 10 / load-cell --xy 0.40 -0.20.
rated_nm() -> NDArray(L48) — Right-arm joint 1-7 ratings fromrobots/openarm/robot.yamleffort_limit.class RightArm(L59) — The right arm's DOFs, qpos addresses, actuators, hand body and joint limits in one model.resolve(m) -> RightArm(L70) — Resolves them by name; raises if any is missing.heavy_model(path) -> MjModel(L93) — The estimator's model: +10 % mass and inertia.hw_effort(tau, rated, rng, qd=None) -> NDArray(L101) — Current-sensed drive corruption: Coulomb (+ viscous when moving; drawn in its band at rest), white noise, 12-bit quantisation.run(force_n, *, hw, seed=0) -> NDArray(L127) — Momentum-observer episode over free sinusoidal motion with a known push at the hand's CoM over[3.0, 3.5)s;(t, |F_est|)rows.probe(force_n) -> int(L182) — Free-motion floor, 1.2x threshold and detection latency, ideal vs hw-like. Measured 2026-10-15: ideal floor 1.7 N; hw-like 8.5 N (10 N detected in 42 ms, 5 N missed).class _Cell(L204) — The cell scene (cell.xml) with IK, arm-on-table contact force, hold/average, static TCP estimate andcond(J)helpers.sweep(x, y) -> int(L300) — The simulated load-cell sweep at table site(x, y); returns 1 if no contact is found or the arm is already in contact before descending. Measured 2026-10-15: at well-conditioned sites (cond(J) 4-6) the hw-like estimate tracks the load cell within ~1-3 N from 2 N to 45 N (resting floor ~3 N); with the elbow on its limit near a singularity (cond(J) 31-112) it reads 27-40 N with no contact.main(argv=None) -> int(L341) — CLI:probe [--force-n N]orload-cell [--xy X Y].