Skip to content

Add mac-sim sensor boundaries #81

Add mac-sim sensor boundaries

Add mac-sim sensor boundaries #81

Workflow file for this run

# Copyright (c) 2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
name: MLX macOS smoke
on:
push:
branches:
- main
- "codex/**"
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
mlx-import-safety:
name: MLX import safety
runs-on: macos-14
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install uv
run: python -m pip install --upgrade uv
- name: Create import-safety virtual environment
run: uv venv --python 3.11 .venv-import
- name: Install MLX import-safety dependencies
run: |
uv pip install --python .venv-import/bin/python \
-e source/isaaclab[macos-mlx,dev] \
-e source/isaaclab_rl[dev] \
-e source/isaaclab_tasks
- name: Prove MLX path does not require Isaac Sim
run: |
mkdir -p logs/benchmarks/mlx/import-safety
PYTHONPATH=.:source/isaaclab:source/isaaclab_rl:source/isaaclab_tasks .venv-import/bin/python - <<'PY'
import importlib.util
import json
from pathlib import Path
forbidden = {}
for module_name in ("isaacsim", "omni", "carb", "pxr"):
forbidden[module_name] = importlib.util.find_spec(module_name) is None
if not all(forbidden.values()):
raise SystemExit(f"Unexpected upstream modules available: {forbidden}")
payload = {
"forbidden_modules_absent": forbidden,
"python": "3.11",
}
Path("logs/benchmarks/mlx/import-safety/specs.json").write_text(
json.dumps(payload, indent=2, sort_keys=True) + "\n",
encoding="utf-8",
)
print(payload)
PY
- name: Run import-safety regression tests
run: |
PYTHONPATH=.:source/isaaclab:source/isaaclab_rl:source/isaaclab_tasks .venv-import/bin/pytest \
source/isaaclab_rl/test/test_import_safety.py \
source/isaaclab_rl/test/test_mlx_wrapper.py \
source/isaaclab/test/backends/test_runtime.py -q
- name: Upload import-safety artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: mlx-import-safety-${{ github.run_id }}
path: logs/benchmarks/mlx/import-safety
if-no-files-found: warn
mlx-cartpole:
name: MLX cartpole backend smoke
runs-on: macos-14
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install uv
run: python -m pip install --upgrade uv
- name: Create virtual environment
run: uv venv --python 3.11 .venv
- name: Install MLX smoke dependencies
run: |
uv pip install --python .venv/bin/python \
-e source/isaaclab[macos-mlx,dev] \
-e source/isaaclab_rl[dev] \
-e source/isaaclab_tasks
- name: Prepare benchmark artifact directory
run: mkdir -p logs/benchmarks/mlx/install-matrix
- name: Run fresh-env install matrix
run: |
uv venv --python 3.11 .venv-core
uv pip install --python .venv-core/bin/python -e source/isaaclab[macos-mlx,dev]
.venv-core/bin/python - <<'PY'
import json
from pathlib import Path
from isaaclab.backends import resolve_runtime_selection, set_runtime_selection
set_runtime_selection(resolve_runtime_selection(compute_backend="mlx", sim_backend="mac-sim", device="cpu"))
from isaaclab.envs import ViewerCfg
payload = {"combo": "core", "viewer_cfg_type": ViewerCfg.__name__}
Path("logs/benchmarks/mlx/install-matrix/core.json").write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
print(payload)
PY
uv venv --python 3.11 .venv-core-tasks
uv pip install --python .venv-core-tasks/bin/python -e source/isaaclab[macos-mlx,dev] -e source/isaaclab_tasks
PYTHONPATH=.:source/isaaclab:source/isaaclab_tasks .venv-core-tasks/bin/python - <<'PY'
import json
from pathlib import Path
from isaaclab.backends import resolve_runtime_selection, set_runtime_selection
set_runtime_selection(resolve_runtime_selection(compute_backend="mlx", sim_backend="mac-sim", device="cpu"))
import isaaclab_tasks
from isaaclab_tasks.utils.parse_cfg import parse_env_cfg
cfg = parse_env_cfg("Isaac-Cartpole-Direct-v0", device="cpu", num_envs=8)
payload = {"combo": "core+tasks", "task_cfg_type": type(cfg).__name__, "task_cfg_num_envs": cfg.num_envs}
Path("logs/benchmarks/mlx/install-matrix/core_tasks.json").write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
print(payload)
PY
uv venv --python 3.11 .venv-core-rl
uv pip install --python .venv-core-rl/bin/python -e source/isaaclab[macos-mlx,dev] -e source/isaaclab_rl[dev]
PYTHONPATH=.:source/isaaclab:source/isaaclab_rl .venv-core-rl/bin/python - <<'PY'
import json
from pathlib import Path
from isaaclab.backends import resolve_runtime_selection, set_runtime_selection
set_runtime_selection(resolve_runtime_selection(compute_backend="mlx", sim_backend="mac-sim", device="cpu"))
import isaaclab_rl.sb3
import isaaclab_rl.skrl
payload = {"combo": "core+rl", "modules": ["isaaclab_rl.sb3", "isaaclab_rl.skrl"]}
Path("logs/benchmarks/mlx/install-matrix/core_rl.json").write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
print(payload)
PY
- name: Run public install smoke
run: |
PYTHONPATH=.:source/isaaclab:source/isaaclab_rl .venv/bin/python - <<'PY'
import json
from pathlib import Path
from isaaclab.backends import resolve_runtime_selection, set_runtime_selection
set_runtime_selection(resolve_runtime_selection(compute_backend="mlx", sim_backend="mac-sim", device="cpu"))
import isaaclab
import isaaclab.backends.mac_sim
import isaaclab.controllers
import isaaclab.envs
import isaaclab.envs.mdp.actions.actions_cfg
import isaaclab.envs.mdp.actions.rmpflow_actions_cfg
import isaaclab.sim
import isaaclab.sim.converters
import isaaclab.sim.schemas
import isaaclab.sim.spawners.from_files
import isaaclab.utils.io
import isaaclab.utils.noise
import isaaclab.utils.types
import isaaclab_tasks
import isaaclab_rl.sb3
import isaaclab_rl.skrl
from isaaclab.backends.mac_sim import MacCartpoleEnv
from isaaclab.envs import ViewerCfg
from isaaclab_tasks.utils.parse_cfg import parse_env_cfg
env = MacCartpoleEnv()
observations, _ = env.reset()
task_cfg = parse_env_cfg("Isaac-Cartpole-Direct-v0", device="cpu", num_envs=64)
payload = {
"modules": [
"isaaclab",
"isaaclab.backends.mac_sim",
"isaaclab.controllers",
"isaaclab.envs",
"isaaclab.envs.mdp.actions.actions_cfg",
"isaaclab.envs.mdp.actions.rmpflow_actions_cfg",
"isaaclab.sim",
"isaaclab.sim.converters",
"isaaclab.sim.schemas",
"isaaclab.sim.spawners.from_files",
"isaaclab.utils.io",
"isaaclab.utils.noise",
"isaaclab.utils.types",
"isaaclab_tasks",
"isaaclab_rl.sb3",
"isaaclab_rl.skrl",
],
"policy_shape": list(observations["policy"].shape),
"task_cfg_type": type(task_cfg).__name__,
"task_cfg_num_envs": task_cfg.num_envs,
"viewer_cfg_type": ViewerCfg.__name__,
"package": isaaclab.__name__,
}
out_path = Path("logs/benchmarks/mlx/install_import_smoke.json")
out_path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print(payload["policy_shape"])
PY
- name: Run release-surface MLX install smoke
run: |
release_root="$(mktemp -d)"
uv venv --python 3.11 "$release_root/.venv-release"
uv pip install --python "$release_root/.venv-release/bin/python" \
-e source/isaaclab[macos-mlx] \
-e source/isaaclab_tasks \
-e source/isaaclab_rl
RELEASE_ROOT="$release_root" GITHUB_WORKSPACE="$GITHUB_WORKSPACE" "$release_root/.venv-release/bin/python" - <<'PY'
import json
import os
from pathlib import Path
from isaaclab.backends import resolve_runtime_selection, set_runtime_selection
from isaaclab_tasks.utils.parse_cfg import parse_env_cfg
from isaaclab_rl.mlx import evaluate_mlx_task, list_trainable_mlx_tasks
set_runtime_selection(resolve_runtime_selection(compute_backend="mlx", sim_backend="mac-sim", device="cpu"))
rough_cfg = parse_env_cfg("Isaac-Velocity-Rough-H1-v0", device="cpu", num_envs=4)
stack_cfg = parse_env_cfg("Isaac-Stack-Cube-RedGreenBlue-Franka-IK-Rel-v0", device="cpu", num_envs=4)
bin_stack_cfg = parse_env_cfg("Isaac-Stack-Cube-Bin-Franka-IK-Rel-Mimic-v0", device="cpu", num_envs=4)
stack_instance_cfg = parse_env_cfg("Isaac-Stack-Cube-Instance-Randomize-Franka-v0", device="cpu", num_envs=4)
teddy_cfg = parse_env_cfg("Isaac-Lift-Teddy-Bear-Franka-IK-Abs-v0", device="cpu", num_envs=4)
ur10e_cfg = parse_env_cfg("Isaac-Deploy-Reach-UR10e-v0", device="cpu", num_envs=4)
gear_2f140_cfg = parse_env_cfg("Isaac-Deploy-GearAssembly-UR10e-2F140-v0", device="cpu", num_envs=4)
gear_2f85_cfg = parse_env_cfg("Isaac-Deploy-GearAssembly-UR10e-2F85-v0", device="cpu", num_envs=4)
gear_2f140_ros_cfg = parse_env_cfg("Isaac-Deploy-GearAssembly-UR10e-2F140-ROS-Inference-v0", device="cpu", num_envs=4)
gear_2f85_ros_cfg = parse_env_cfg("Isaac-Deploy-GearAssembly-UR10e-2F85-ROS-Inference-v0", device="cpu", num_envs=4)
ur10_long_stack_cfg = parse_env_cfg("Isaac-Stack-Cube-UR10-Long-Suction-IK-Rel-v0", device="cpu", num_envs=4)
ur10_short_stack_cfg = parse_env_cfg("Isaac-Stack-Cube-UR10-Short-Suction-IK-Rel-v0", device="cpu", num_envs=4)
payload = evaluate_mlx_task(
"h1-rough",
num_envs=4,
episodes=1,
episode_length_s=0.25,
max_steps=128,
random_actions=False,
seed=11,
)
artifact = {
"rough_cfg_type": type(rough_cfg).__name__,
"stack_cfg_type": type(stack_cfg).__name__,
"bin_stack_cfg_type": type(bin_stack_cfg).__name__,
"stack_instance_cfg_type": type(stack_instance_cfg).__name__,
"teddy_cfg_type": type(teddy_cfg).__name__,
"ur10e_cfg_type": type(ur10e_cfg).__name__,
"gear_2f140_cfg_type": type(gear_2f140_cfg).__name__,
"gear_2f85_cfg_type": type(gear_2f85_cfg).__name__,
"gear_2f140_ros_cfg_type": type(gear_2f140_ros_cfg).__name__,
"gear_2f85_ros_cfg_type": type(gear_2f85_ros_cfg).__name__,
"ur10_long_stack_cfg_type": type(ur10_long_stack_cfg).__name__,
"ur10_short_stack_cfg_type": type(ur10_short_stack_cfg).__name__,
"trainable_tasks": list(list_trainable_mlx_tasks()),
"eval_task": payload["task"],
"episodes_completed": payload["episodes_completed"],
"release_root": os.environ["RELEASE_ROOT"],
}
out_path = Path(os.environ["GITHUB_WORKSPACE"]) / "logs" / "benchmarks" / "mlx" / "release_install_smoke.json"
out_path.parent.mkdir(parents=True, exist_ok=True)
out_path.write_text(json.dumps(artifact, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print(artifact)
PY
"$release_root/.venv-release/bin/isaaclab-mlx-runtime-diagnostics" logs/runtime/release-runtime-diagnostics.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task h1-rough \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx-evaluate" \
--task h1-rough \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-eval-split.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task franka-teddy-bear-lift \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-teddy-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task franka-stack-instance-randomize \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-stack-instance-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task Isaac-Stack-Cube-Bin-Franka-IK-Rel-Mimic-v0 \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-bin-stack-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task Isaac-Deploy-GearAssembly-UR10e-2F140-Play-v0 \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-gear-2f140-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task Isaac-Deploy-GearAssembly-UR10e-2F85-Play-v0 \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-gear-2f85-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task Isaac-Deploy-GearAssembly-UR10e-2F140-ROS-Inference-v0 \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-gear-2f140-ros-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task Isaac-Deploy-GearAssembly-UR10e-2F85-ROS-Inference-v0 \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-gear-2f85-ros-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx" evaluate \
--task ur10-long-suction-stack \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-ur10-long-stack-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx-evaluate" \
--task ur10-short-suction-stack \
--num-envs 4 --episodes 1 --episode-length-s 0.25 --max-steps 128 --no-random-actions \
--json-out logs/runtime/release-ur10-short-stack-eval.json
"$release_root/.venv-release/bin/isaaclab-mlx-train" \
--task ur10e-gear-assembly-2f140 \
--num-envs 4 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.25 \
--checkpoint logs/runtime/release-gear-2f140-policy.npz \
--json-out logs/runtime/release-gear-2f140-train.json
"$release_root/.venv-release/bin/isaaclab-mlx-train" \
--task ur10-long-suction-stack \
--num-envs 4 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.25 \
--checkpoint logs/runtime/release-ur10-long-stack-policy.npz \
--json-out logs/runtime/release-ur10-long-stack-train.json
"$release_root/.venv-release/bin/isaaclab-mlx" train \
--task cartpole \
--num-envs 4 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.25 \
--checkpoint logs/runtime/release-cartpole-policy.npz \
--json-out logs/runtime/release-train.json
"$release_root/.venv-release/bin/isaaclab-mlx-train" \
--task cartpole \
--num-envs 4 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.25 \
--checkpoint logs/runtime/release-cartpole-policy-split.npz \
--json-out logs/runtime/release-train-split.json
- name: Run MLX backend smoke tests
run: |
PYTHONPATH=.:source/isaaclab:source/isaaclab_rl .venv/bin/pytest \
scripts/tools/test/test_bootstrap_isaac_sources.py \
scripts/tools/test/test_bootstrap_uv_mlx.py \
source/isaaclab/test/backends/test_runtime.py \
source/isaaclab/test/backends/test_task_registry.py \
source/isaaclab/test/backends/test_kernel_inventory.py \
source/isaaclab/test/backends/test_kernel_compat.py \
source/isaaclab/test/backends/test_mac_hotpath.py \
source/isaaclab/test/backends/test_mac_camera_capture.py \
source/isaaclab/test/backends/test_mac_sensor_raycast.py \
source/isaaclab/test/backends/test_mac_stereo_depth.py \
source/isaaclab/test/backends/test_mac_runtime_diagnostics.py \
source/isaaclab/test/backends/test_mlx_task_cli.py \
source/isaaclab/test/backends/test_planner_compat.py \
source/isaaclab/test/backends/test_ros2_bridge.py \
source/isaaclab/test/backends/test_mac_semantic_drift.py \
source/isaaclab_rl/test/test_import_safety.py \
source/isaaclab_rl/test/test_mlx_cli.py \
source/isaaclab_rl/test/test_mlx_wrapper.py \
source/isaaclab/test/backends/test_portability_utils.py \
source/isaaclab/test/backends/test_mac_benchmark_suite.py \
source/isaaclab/test/backends/test_mac_state_primitives.py \
source/isaaclab/test/backends/test_mac_phase_b_support.py \
source/isaaclab/test/backends/test_mac_cartpole.py \
source/isaaclab/test/backends/test_mac_cartpole_showcase.py \
source/isaaclab/test/backends/test_mac_cart_double_pendulum.py \
source/isaaclab/test/backends/test_mac_quadcopter.py \
source/isaaclab/test/backends/test_mac_cartpole_camera.py \
source/isaaclab/test/backends/test_mac_anymal_c.py \
source/isaaclab/test/backends/test_mac_anymal_c_rough.py \
source/isaaclab/test/backends/test_mac_franka_reach.py \
source/isaaclab/test/backends/test_mac_ur10e_deploy_reach.py \
source/isaaclab/test/backends/test_mac_ur10_stack.py \
source/isaaclab/test/backends/test_mac_franka_lift.py \
source/isaaclab/test/backends/test_mac_franka_teddy_bear_lift.py \
source/isaaclab/test/backends/test_mac_franka_stack_instance_randomize.py \
source/isaaclab/test/backends/test_mac_franka_stack.py \
source/isaaclab/test/backends/test_mac_franka_stack_rgb.py \
source/isaaclab/test/backends/test_mac_franka_bin_stack.py \
source/isaaclab/test/backends/test_mac_franka_cabinet.py \
source/isaaclab/test/backends/test_mac_franka_open_drawer.py \
source/isaaclab/test/backends/test_mac_h1.py -q
- name: Run MLX cart-double-pendulum smoke script
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task cart-double-pendulum \
--num-envs 8 --episodes 1 --max-steps 256 --random-actions
- name: Run MLX quadcopter smoke script
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task quadcopter \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --thrust-action 0.2 --no-random-actions
- name: Run MLX ANYmal-C flat smoke script
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task anymal-c-flat \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --no-random-actions
- name: Run MLX ANYmal-C rough smoke script
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task anymal-c-rough \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --no-random-actions
- name: Run MLX ANYmal-C flat training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task anymal-c-flat \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/anymal_c_flat_policy.npz --eval-interval 1
- name: Run MLX ANYmal-C rough training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task anymal-c-rough \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/anymal_c_rough_policy.npz --eval-interval 1
- name: Run MLX cartpole RGB camera smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task cartpole-rgb-camera \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --no-random-actions
- name: Run MLX cartpole depth camera smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task cartpole-depth-camera \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --no-random-actions
- name: Run MLX H1 flat smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task h1-flat \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --no-random-actions
- name: Run MLX H1 rough smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task h1-rough \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 256 --no-random-actions
- name: Run MLX Franka reach smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-reach \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka reach training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-reach \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_reach_policy.npz --eval-interval 1
- name: Run MLX UR10e deploy-reach smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task ur10e-deploy-reach \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX UR10e deploy-reach training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task ur10e-deploy-reach \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/ur10e_deploy_reach_policy.npz --eval-interval 1
- name: Run MLX UR10e gear-assembly 2F140 smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task ur10e-gear-assembly-2f140 \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX UR10e gear-assembly 2F140 training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task ur10e-gear-assembly-2f140 \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/ur10e_gear_assembly_2f140_policy.npz --eval-interval 1
- name: Run MLX UR10e gear-assembly 2F85 smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task ur10e-gear-assembly-2f85 \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX UR10e gear-assembly 2F85 training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task ur10e-gear-assembly-2f85 \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/ur10e_gear_assembly_2f85_policy.npz --eval-interval 1
- name: Run MLX Franka lift smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-lift \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka lift training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-lift \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_lift_policy.npz --eval-interval 1
- name: Run MLX Franka teddy-bear lift smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-teddy-bear-lift \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka teddy-bear lift training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-teddy-bear-lift \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_teddy_bear_lift_policy.npz --eval-interval 1
- name: Run MLX Franka stack instance-randomize smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-stack-instance-randomize \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka stack instance-randomize training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-stack-instance-randomize \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_stack_instance_randomize_policy.npz --eval-interval 1
- name: Run MLX Franka stack smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-stack \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka stack training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-stack \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_stack_policy.npz --eval-interval 1
- name: Run MLX Franka stack RGB smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-stack-rgb \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka stack RGB training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-stack-rgb \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_stack_rgb_policy.npz --eval-interval 1
- name: Run MLX Franka bin-stack smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-bin-stack \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka bin-stack training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-bin-stack \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_bin_stack_policy.npz --eval-interval 1
- name: Run MLX Franka cabinet smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/evaluate_task.py \
--task franka-cabinet \
--num-envs 8 --episodes 1 --episode-length-s 0.5 --max-steps 512 --no-random-actions
- name: Run MLX Franka cabinet training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task franka-cabinet \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/franka_cabinet_policy.npz --eval-interval 1
- name: Run MLX H1 flat training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task h1-flat \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/h1_flat_policy.npz --eval-interval 1
- name: Run MLX H1 rough training smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/reinforcement_learning/mlx/train_task.py \
--task h1-rough \
--num-envs 8 --updates 1 --rollout-steps 8 --epochs-per-update 1 --episode-length-s 0.5 \
--checkpoint logs/mlx/h1_rough_policy.npz --eval-interval 1
- name: Run public MLX wrapper smoke
run: |
PYTHONPATH=.:source/isaaclab:source/isaaclab_rl .venv/bin/python - <<'PY'
from isaaclab_rl.mlx import evaluate_mlx_task, list_mlx_tasks, list_trainable_mlx_tasks, train_mlx_task
assert "h1-flat" in list_mlx_tasks()
assert "h1-rough" in list_mlx_tasks()
assert "anymal-c-rough" in list_trainable_mlx_tasks()
assert "h1-rough" in list_trainable_mlx_tasks()
assert "cartpole-rgb-camera" in list_mlx_tasks()
assert "cartpole-depth-camera" in list_mlx_tasks()
assert "franka-reach" in list_mlx_tasks()
assert "ur10e-deploy-reach" in list_mlx_tasks()
assert "ur10e-deploy-reach" in list_trainable_mlx_tasks()
assert "ur10e-gear-assembly-2f140" in list_mlx_tasks()
assert "ur10e-gear-assembly-2f85" in list_mlx_tasks()
assert "ur10e-gear-assembly-2f140" in list_trainable_mlx_tasks()
assert "ur10e-gear-assembly-2f85" in list_trainable_mlx_tasks()
assert "franka-lift" in list_mlx_tasks()
assert "franka-teddy-bear-lift" in list_mlx_tasks()
assert "franka-stack-instance-randomize" in list_mlx_tasks()
assert "franka-stack" in list_mlx_tasks()
assert "franka-stack-rgb" in list_mlx_tasks()
assert "franka-bin-stack" in list_mlx_tasks()
assert "franka-cabinet" in list_mlx_tasks()
assert "franka-open-drawer" in list_mlx_tasks()
train_payload = train_mlx_task(
"ur10e-gear-assembly-2f140",
num_envs=8,
updates=1,
rollout_steps=8,
epochs_per_update=1,
hidden_dim=32,
checkpoint="logs/mlx/ur10e_gear_assembly_2f140_wrapper_policy.npz",
eval_interval=1,
episode_length_s=0.5,
seed=31,
)
payload = evaluate_mlx_task(
"Isaac-Deploy-GearAssembly-UR10e-2F140-Play-v0",
checkpoint=train_payload["checkpoint_path"],
episodes=1,
episode_length_s=0.5,
seed=31,
)
assert payload["episodes_completed"] == 1
print(payload["task"], payload["episodes_completed"])
PY
- name: Run synthetic MLX stereo depth smoke
run: |
mkdir -p logs/hardware
PYTHONPATH=.:source/isaaclab .venv/bin/python - <<'PY'
from pathlib import Path
import numpy as np
root = Path("logs/hardware")
width = 8
height = 4
left_luma = np.tile(np.array([20, 40, 60, 80], dtype=np.uint8), (height, 1))
right_luma = np.zeros_like(left_luma)
right_luma[:, :-1] = left_luma[:, 1:]
left = np.zeros((height, width // 2, 2), dtype=np.uint8)
right = np.zeros((height, width // 2, 2), dtype=np.uint8)
left[:, :, 0] = left_luma
right[:, :, 0] = right_luma
left[:, :, 1] = 128
right[:, :, 1] = 128
frame = np.concatenate([left, right], axis=1)
raw_path = root / "synthetic_stereo.raw"
raw_path.write_bytes(frame.tobytes())
Path(f"{raw_path}.txt").write_text(
"width=8\nheight=4\nchannels=2\npixel_format=yuyv422\ntimestamp=1\nframe_id=1\n",
encoding="utf-8",
)
print(raw_path)
PY
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/tools/mac_stereo_depth_smoke.py \
logs/hardware/synthetic_stereo.raw \
logs/hardware/synthetic_depth \
--max-disparity 4 \
--window-size 1 \
--fx 700.0 \
--baseline-mm 120.0 \
--summary-out logs/hardware/synthetic_depth/summary.json
test -f logs/hardware/synthetic_depth/left_rgb.png
test -f logs/hardware/synthetic_depth/right_rgb.png
test -f logs/hardware/synthetic_depth/disparity.png
test -f logs/hardware/synthetic_depth/summary.json
- name: Run mac planner compatibility smoke
run: |
mkdir -p logs/planner
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/tools/mac_planner_smoke.py \
logs/planner/mac-planner-smoke.json
test -f logs/planner/mac-planner-smoke.json
- name: Run ROS 2 bridge smoke
run: |
mkdir -p logs/hardware
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/tools/ros2_bridge_smoke.py \
logs/hardware/ros2-bridge-smoke.jsonl \
--summary-out logs/hardware/ros2-bridge-smoke-summary.json
test -f logs/hardware/ros2-bridge-smoke.jsonl
test -f logs/hardware/ros2-bridge-smoke-summary.json
- name: Run runtime diagnostics smoke
run: |
mkdir -p logs/runtime
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/tools/mac_runtime_diagnostics.py \
logs/runtime/mac-runtime-diagnostics.json
test -f logs/runtime/mac-runtime-diagnostics.json
- name: Run uv bootstrap dry-run smoke
run: |
uv run scripts/bootstrap_uv_mlx.py --dry-run --venv .venv-bootstrap-smoke
- name: Run MLX benchmark smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/benchmarks/mlx/benchmark_mac_tasks.py \
--task-group current-mac-native \
--num-envs 64 \
--steps 128 \
--json-out logs/benchmarks/mlx/smoke.json
- name: Run MLX sensor benchmark smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/benchmarks/mlx/benchmark_mac_tasks.py \
--task-group sensor-mac-native \
--num-envs 32 \
--steps 64 \
--json-out logs/benchmarks/mlx/sensor-smoke.json
- name: Run MLX full-suite dashboard smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/benchmarks/mlx/benchmark_mac_tasks.py \
--task-group full \
--num-envs 8 \
--steps 8 \
--train-updates 1 \
--rollout-steps 4 \
--epochs-per-update 1 \
--json-out logs/benchmarks/mlx/full-smoke.json
- name: Verify semantic baseline against full-suite smoke
run: |
PYTHONPATH=.:source/isaaclab .venv/bin/python \
scripts/benchmarks/mlx/check_semantic_drift.py \
--results logs/benchmarks/mlx/full-smoke.json \
--baseline scripts/benchmarks/mlx/baselines/semantic-baseline.json \
--snapshot-out logs/benchmarks/mlx/full-smoke-semantic-snapshot.json \
--report-out logs/benchmarks/mlx/full-smoke-semantic-report.json
- name: Verify benchmark artifact payload
run: |
test -f logs/benchmarks/mlx/smoke.json
test -f logs/benchmarks/mlx/smoke-dashboard.json
test -f logs/benchmarks/mlx/smoke-trend.json
test -f logs/benchmarks/mlx/release_install_smoke.json
test -f logs/benchmarks/mlx/sensor-smoke.json
test -f logs/benchmarks/mlx/sensor-smoke-dashboard.json
test -f logs/benchmarks/mlx/sensor-smoke-trend.json
test -f logs/benchmarks/mlx/full-smoke.json
test -f logs/benchmarks/mlx/full-smoke-dashboard.json
test -f logs/benchmarks/mlx/full-smoke-trend.json
test -f logs/benchmarks/mlx/full-smoke-semantic-snapshot.json
test -f logs/benchmarks/mlx/full-smoke-semantic-report.json
PYTHONPATH=.:source/isaaclab .venv/bin/python - <<'PY'
import json
from pathlib import Path
payload = json.loads(Path("logs/benchmarks/mlx/smoke.json").read_text(encoding="utf-8"))
assert payload["task_group"] == "current-mac-native"
assert payload["cpu_fallback_detected"] is False
assert len(payload["benchmarks"]) >= 5
print(payload["tasks"])
dashboard = json.loads(Path("logs/benchmarks/mlx/smoke-dashboard.json").read_text(encoding="utf-8"))
assert dashboard["summary"]["rollout_task_count"] == 24
assert dashboard["summary"]["training_task_count"] == 0
trend = json.loads(Path("logs/benchmarks/mlx/smoke-trend.json").read_text(encoding="utf-8"))
assert trend["summary"]["task_count"] == 24
planner_payload = json.loads(Path("logs/planner/mac-planner-smoke.json").read_text(encoding="utf-8"))
assert planner_payload["planner"]["implementation"] == "joint-space-linear-interpolation"
assert planner_payload["plan"]["waypoint_count"] == 6
ros_payload = json.loads(Path("logs/hardware/ros2-bridge-smoke-summary.json").read_text(encoding="utf-8"))
assert ros_payload["message_count"] == 6
assert ros_payload["pub_command"][:3] == ["ros2", "topic", "pub"]
assert ros_payload["planner_roundtrip_ok"] is True
assert ros_payload["trajectory_roundtrip_ok"] is True
assert ros_payload["planner_batch_size"] == 2
assert ros_payload["trajectory_batch_size"] == 2
stereo_payload = json.loads(Path("logs/hardware/synthetic_depth/summary.json").read_text(encoding="utf-8"))
assert stereo_payload["validated_capture"] is True
assert stereo_payload["disparity_shape"] == [4, 4]
assert stereo_payload["depth_mm_mean"] is not None
assert Path(stereo_payload["left_rgb_path"]).is_file()
runtime_payload = json.loads(Path("logs/runtime/mac-runtime-diagnostics.json").read_text(encoding="utf-8"))
assert runtime_payload["runtime"]["supported_tasks"]["public_task_count"] == 28
assert runtime_payload["sim"]["supported_tasks"]["current_mac_native_count"] == 26
sensor_payload = json.loads(Path("logs/benchmarks/mlx/sensor-smoke.json").read_text(encoding="utf-8"))
assert sensor_payload["task_group"] == "sensor-mac-native"
assert sensor_payload["cpu_fallback_detected"] is False
assert len(sensor_payload["benchmarks"]) == 4
benchmark_by_task = {benchmark["task"]: benchmark for benchmark in sensor_payload["benchmarks"]}
for task in ("cartpole-rgb-camera", "cartpole-depth-camera"):
benchmark = benchmark_by_task[task]
assert benchmark["diagnostics"]["sensor"]["implementation"] == "analytic-cartpole-camera"
assert benchmark["runtime"]["capabilities"]["sensor"]["cameras"] is False
assert benchmark["runtime"]["capabilities"]["sensor"]["analytic_camera_tasks"] is True
assert benchmark["image_shape"][:2] == [100, 100]
assert benchmark["output_signature"]["final_frame_energy"] > 0.0
for task in ("anymal-c-flat-height-scan", "h1-flat-height-scan"):
benchmark = benchmark_by_task[task]
assert benchmark["sensor_scan_dim"] == 9
assert benchmark["runtime"]["capabilities"]["sensor"]["raycast"] is True
assert benchmark["diagnostics"]["sensor"]["implementation"] == "analytic-terrain-raycast"
assert benchmark["output_signature"]["height_scan_hit_ratio"] == 1.0
print(sensor_payload["tasks"])
release_payload = json.loads(Path("logs/benchmarks/mlx/release_install_smoke.json").read_text(encoding="utf-8"))
assert release_payload["rough_cfg_type"] == "MacH1RoughEnvCfg"
assert release_payload["stack_cfg_type"] == "MacFrankaStackRgbEnvCfg"
assert release_payload["bin_stack_cfg_type"] == "MacFrankaBinStackEnvCfg"
assert release_payload["stack_instance_cfg_type"] == "MacFrankaStackInstanceRandomizeEnvCfg"
assert release_payload["teddy_cfg_type"] == "MacFrankaTeddyBearLiftEnvCfg"
assert release_payload["ur10e_cfg_type"] == "MacUR10eDeployReachEnvCfg"
assert release_payload["gear_2f140_cfg_type"] == "MacUR10eGearAssembly2F140EnvCfg"
assert release_payload["gear_2f85_cfg_type"] == "MacUR10eGearAssembly2F85EnvCfg"
assert release_payload["gear_2f140_ros_cfg_type"] == "MacUR10eGearAssembly2F140RosInferenceEnvCfg"
assert release_payload["gear_2f85_ros_cfg_type"] == "MacUR10eGearAssembly2F85RosInferenceEnvCfg"
assert release_payload["ur10_long_stack_cfg_type"] == "MacUR10LongSuctionStackEnvCfg"
assert release_payload["ur10_short_stack_cfg_type"] == "MacUR10ShortSuctionStackEnvCfg"
assert "anymal-c-rough" in release_payload["trainable_tasks"]
assert "h1-rough" in release_payload["trainable_tasks"]
assert "ur10e-deploy-reach" in release_payload["trainable_tasks"]
assert "ur10e-gear-assembly-2f140" in release_payload["trainable_tasks"]
assert "ur10e-gear-assembly-2f85" in release_payload["trainable_tasks"]
assert "ur10-long-suction-stack" in release_payload["trainable_tasks"]
assert "ur10-short-suction-stack" in release_payload["trainable_tasks"]
assert "franka-teddy-bear-lift" in release_payload["trainable_tasks"]
assert "franka-stack-instance-randomize" in release_payload["trainable_tasks"]
assert "franka-bin-stack" in release_payload["trainable_tasks"]
assert release_payload["eval_task"] == "h1-rough"
assert release_payload["episodes_completed"] == 1
release_runtime_payload = json.loads(Path("logs/runtime/release-runtime-diagnostics.json").read_text(encoding="utf-8"))
assert release_runtime_payload["runtime"]["supported_tasks"]["public_task_count"] == 28
assert release_runtime_payload["sim"]["supported_tasks"]["current_mac_native_count"] == 26
release_eval_payload = json.loads(Path("logs/runtime/release-eval.json").read_text(encoding="utf-8"))
assert release_eval_payload["task"] == "h1-rough"
assert release_eval_payload["episodes_completed"] == 1
assert release_eval_payload["task_spec"]["task"] == "h1-rough"
assert release_eval_payload["task_spec"]["semantic_contract"] == "aligned"
release_eval_split_payload = json.loads(Path("logs/runtime/release-eval-split.json").read_text(encoding="utf-8"))
assert release_eval_split_payload["task"] == "h1-rough"
assert release_eval_split_payload["episodes_completed"] == 1
assert release_eval_split_payload["task_spec"]["task"] == "h1-rough"
assert release_eval_split_payload["task_spec"]["semantic_contract"] == "aligned"
release_teddy_eval_payload = json.loads(Path("logs/runtime/release-teddy-eval.json").read_text(encoding="utf-8"))
assert release_teddy_eval_payload["task"] == "franka-teddy-bear-lift"
assert release_teddy_eval_payload["episodes_completed"] == 1
release_bin_stack_eval_payload = json.loads(Path("logs/runtime/release-bin-stack-eval.json").read_text(encoding="utf-8"))
assert release_bin_stack_eval_payload["task"] == "franka-bin-stack"
assert release_bin_stack_eval_payload["episodes_completed"] == 1
assert release_bin_stack_eval_payload["task_spec"]["task"] == "franka-bin-stack"
assert release_bin_stack_eval_payload["task_spec"]["semantic_contract"] == "reduced-no-mimic"
assert release_bin_stack_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_gear_2f140_eval_payload = json.loads(Path("logs/runtime/release-gear-2f140-eval.json").read_text(encoding="utf-8"))
assert release_gear_2f140_eval_payload["task"] == "ur10e-gear-assembly-2f140"
assert release_gear_2f140_eval_payload["episodes_completed"] == 1
assert release_gear_2f140_eval_payload["task_spec"]["semantic_contract"] == "reduced-analytic-assembly"
assert release_gear_2f140_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_gear_2f85_eval_payload = json.loads(Path("logs/runtime/release-gear-2f85-eval.json").read_text(encoding="utf-8"))
assert release_gear_2f85_eval_payload["task"] == "ur10e-gear-assembly-2f85"
assert release_gear_2f85_eval_payload["episodes_completed"] == 1
assert release_gear_2f85_eval_payload["task_spec"]["semantic_contract"] == "reduced-analytic-assembly"
assert release_gear_2f85_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_gear_2f140_ros_eval_payload = json.loads(
Path("logs/runtime/release-gear-2f140-ros-eval.json").read_text(encoding="utf-8")
)
assert release_gear_2f140_ros_eval_payload["task"] == "ur10e-gear-assembly-2f140"
assert release_gear_2f140_ros_eval_payload["episodes_completed"] == 1
assert release_gear_2f140_ros_eval_payload["task_spec"]["semantic_contract"] == "reduced-no-ros-inference"
assert release_gear_2f140_ros_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_gear_2f85_ros_eval_payload = json.loads(
Path("logs/runtime/release-gear-2f85-ros-eval.json").read_text(encoding="utf-8")
)
assert release_gear_2f85_ros_eval_payload["task"] == "ur10e-gear-assembly-2f85"
assert release_gear_2f85_ros_eval_payload["episodes_completed"] == 1
assert release_gear_2f85_ros_eval_payload["task_spec"]["semantic_contract"] == "reduced-no-ros-inference"
assert release_gear_2f85_ros_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_ur10_long_stack_eval_payload = json.loads(
Path("logs/runtime/release-ur10-long-stack-eval.json").read_text(encoding="utf-8")
)
assert release_ur10_long_stack_eval_payload["task"] == "ur10-long-suction-stack"
assert release_ur10_long_stack_eval_payload["episodes_completed"] == 1
assert release_ur10_long_stack_eval_payload["task_spec"]["semantic_contract"] == "reduced-analytic-suction-stack"
assert release_ur10_long_stack_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_ur10_short_stack_eval_payload = json.loads(
Path("logs/runtime/release-ur10-short-stack-eval.json").read_text(encoding="utf-8")
)
assert release_ur10_short_stack_eval_payload["task"] == "ur10-short-suction-stack"
assert release_ur10_short_stack_eval_payload["episodes_completed"] == 1
assert release_ur10_short_stack_eval_payload["task_spec"]["semantic_contract"] == "reduced-analytic-suction-stack"
assert release_ur10_short_stack_eval_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
release_gear_2f140_train_payload = json.loads(Path("logs/runtime/release-gear-2f140-train.json").read_text(encoding="utf-8"))
assert release_gear_2f140_train_payload["task"] == "ur10e-gear-assembly-2f140"
assert release_gear_2f140_train_payload["task_spec"]["semantic_contract"] == "reduced-analytic-assembly"
assert Path(release_gear_2f140_train_payload["checkpoint_path"]).exists()
release_ur10_long_stack_train_payload = json.loads(
Path("logs/runtime/release-ur10-long-stack-train.json").read_text(encoding="utf-8")
)
assert release_ur10_long_stack_train_payload["task"] == "ur10-long-suction-stack"
assert release_ur10_long_stack_train_payload["task_spec"]["semantic_contract"] == "reduced-analytic-suction-stack"
assert release_ur10_long_stack_train_payload["task_spec"]["upstream_alias_semantics_preserved"] is False
assert Path(release_ur10_long_stack_train_payload["checkpoint_path"]).exists()
release_stack_instance_eval_payload = json.loads(
Path("logs/runtime/release-stack-instance-eval.json").read_text(encoding="utf-8")
)
assert release_stack_instance_eval_payload["task"] == "franka-stack-instance-randomize"
assert release_stack_instance_eval_payload["episodes_completed"] == 1
release_train_payload = json.loads(Path("logs/runtime/release-train.json").read_text(encoding="utf-8"))
assert release_train_payload["task"] == "cartpole"
assert release_train_payload["task_spec"]["task"] == "cartpole"
assert release_train_payload["task_spec"]["semantic_contract"] == "aligned"
assert Path(release_train_payload["checkpoint_path"]).exists()
release_train_split_payload = json.loads(Path("logs/runtime/release-train-split.json").read_text(encoding="utf-8"))
assert release_train_split_payload["task"] == "cartpole"
assert release_train_split_payload["task_spec"]["task"] == "cartpole"
assert release_train_split_payload["task_spec"]["semantic_contract"] == "aligned"
assert Path(release_train_split_payload["checkpoint_path"]).exists()
full_payload = json.loads(Path("logs/benchmarks/mlx/full-smoke.json").read_text(encoding="utf-8"))
assert full_payload["task_group"] == "full"
full_dashboard = json.loads(Path("logs/benchmarks/mlx/full-smoke-dashboard.json").read_text(encoding="utf-8"))
assert full_dashboard["summary"]["rollout_task_count"] == 30
assert full_dashboard["summary"]["training_task_count"] == 1
full_trend = json.loads(Path("logs/benchmarks/mlx/full-smoke-trend.json").read_text(encoding="utf-8"))
assert full_trend["summary"]["task_count"] == 31
assert any(entry["kind"] == "training" for entry in full_trend["tasks"])
semantic_report = json.loads(Path("logs/benchmarks/mlx/full-smoke-semantic-report.json").read_text(encoding="utf-8"))
assert semantic_report["passed"] is True
assert semantic_report["baseline_task_count"] == 30
assert semantic_report["current_task_count"] == 30
PY
- name: Upload MLX smoke artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: mlx-macos-smoke-${{ github.run_id }}
path: logs/benchmarks/mlx
if-no-files-found: warn
retention-days: 14