Skip to content

feat(damiao): support native macOS CAN transport - #3465

Open
TomCC7 wants to merge 1 commit into
cc/feat/dual-yamfrom
cc/feat/openyam-macos-support
Open

feat(damiao): support native macOS CAN transport#3465
TomCC7 wants to merge 1 commit into
cc/feat/dual-yamfrom
cc/feat/openyam-macos-support

Conversation

@TomCC7

@TomCC7 TomCC7 commented Aug 14, 2026

Copy link
Copy Markdown
Member

Contribution path

Problem

Damiao-based arms could only construct Linux SocketCAN transports. The macOS workaround lived above the shared hardware layer, so it did not apply coherently to every Damiao topology.

Solution

  • Upgrade can-motor-control to 0.0.6 on Linux and macOS.
  • Select SocketCanBus on Linux and the package's native Rust GsUsbBus on macOS in DamiaoWholeBodyAdapter.
  • Treat runtime bus overrides as SocketCAN interface names on Linux and USB serial numbers on macOS.
  • Route OpenYAM, Dual OpenYAM, and OpenArm through the shared bus factory.
  • Preserve stable default bus ordering and reject undeclared or duplicate logical buses.
  • Document macOS setup and device selection.

Co-authored with @aromeoes, whose original macOS hardware work established the transport requirements.

How to Test

uv run pytest dimos/hardware/whole_body/damiao/test_adapter.py dimos/hardware/whole_body/openyam_damiao/test_adapter.py dimos/hardware/whole_body/dual_openyam_damiao/test_adapter.py dimos/hardware/whole_body/openarm_damiao/test_adapter.py dimos/robot/manipulators/openyam/test_openyam.py dimos/robot/manipulators/dual_openyam/test_config.py dimos/robot/manipulators/openarm/test_openarm_teleop.py -q

Result: 91 passed, 3 deselected.

Ruff and Mypy pass on the changed modules. The repository-wide fast suite reaches 4,110 passes but is currently blocked by three failures already present in the #3463 stack: the removed prepare_urdf_for_drake import and two case-sensitive ControlCoordinator test expectations.

AI assistance

Codex was used to inspect the existing implementation, design the shared transport seam, implement the change, resolve the rebase, and run tests. The resulting diff and test output were reviewed during the session.

Checklist

  • I have read and approved the CLA.

@TomCC7 TomCC7 changed the title cc/feat/openyam macos support feat(damiao): support native macOS CAN transport Aug 14, 2026
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

❌ 16 Tests Failed:

Tests completed Failed Passed Skipped
3922 16 3906 175
View the top 3 failed test(s) by shortest run time
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[keyboard-teleop-openarm]
Stack Traces | 0.002s run time
blueprint_name = 'keyboard-teleop-openarm'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
        blueprint = _get_blueprint_or_skip(blueprint_name)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'keyboard-teleop-openarm' passes unknown module kwargs:
E             - dimos.teleop.keyboard.keyboard_teleop_module.KeyboardTeleopModule: unknown kwargs ['task_name']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/openarm_description.tar.gz after 3 att...on.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] BlueprintAtom object at 0xff86a8695700>
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/openarm_description.tar.gz after 3 att...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff86a86956d0>
blueprint_name = 'keyboard-teleop-openarm'
listing    = "  - dimos.teleop.keyboard.keyboard_teleop_module.KeyboardTeleopModule: unknown kwargs ['task_name']"
unknown_kwargs = []
violations = ["dimos.teleop.keyboard.keyboard_teleop_module.KeyboardTeleopModule: unknown kwargs ['task_name']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[teleop-quest-dual-openyam]
Stack Traces | 0.002s run time
blueprint_name = 'teleop-quest-dual-openyam'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
        blueprint = _get_blueprint_or_skip(blueprint_name)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'teleop-quest-dual-openyam' passes unknown module kwargs:
E             - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] BlueprintAtom object at 0xff86a86dc230>
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff86a86d78c0>
blueprint_name = 'teleop-quest-dual-openyam'
listing    = "  - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"
unknown_kwargs = []
violations = ["dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.imitation.collection.test_blueprint::test_recorder_reads_aggregate_joint_state[blueprint0]
Stack Traces | 0.002s run time
blueprint = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/xarm_description.tar.gz after 3 attemp...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff20f233fef0>

    @pytest.mark.parametrize("blueprint", [learning_collect_quest_xarm7, learning_collect_quest_piper])
    def test_recorder_reads_aggregate_joint_state(blueprint: Blueprint) -> None:
        streams = _joint_streams(blueprint)
    
        # Plain name pairing on both ends, no remap in between. The coordinator
        # atom carries its explicit instance_name (the RPC lookup contract).
        assert streams[("collectionrecorder", AGGREGATE)] == AGGREGATE
        assert streams[("ControlCoordinator", AGGREGATE)] == AGGREGATE
>       assert not [port for _instance, port in streams if port.endswith("_joints")]
E       AssertionError: assert not ['arm_joints']

blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/xarm_description.tar.gz after 3 attemp...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff20f233fef0>
streams    = {('ControlCoordinator', 'arm_joints'): 'arm_joints', ('ControlCoordinator', 'coordinator_joint_state'): 'coordinator_j..., 'joint_command'): 'joint_command', ('collectionrecorder', 'coordinator_joint_state'): 'coordinator_joint_state', ...}

.../imitation/collection/test_blueprint.py:47: AssertionError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[teleop-quest-openarm]
Stack Traces | 0.003s run time
blueprint_name = 'teleop-quest-openarm'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
        blueprint = _get_blueprint_or_skip(blueprint_name)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'teleop-quest-openarm' passes unknown module kwargs:
E             - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = BlueprintAtom(kwargs={'kinematics': PinkKinematicsConfig(backend='pink', solver='proxqp', dt=0.01, max_iterations=200,...ntrol_coordinator', spec=<class 'dimos.control.coordinator.ControlCoordinator'>, optional=False),), instance_name=None)
blueprint  = Blueprint(blueprints=(BlueprintAtom(kwargs={'task_names': {'left': 'teleop_openarm', 'right': 'teleop_openarm'}}, modu...mteleopmodule', 'right_controller_output'): 'right_cartesian_command'}), requirement_checks=(), configurator_checks=())
blueprint_name = 'teleop-quest-openarm'
listing    = "  - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"
unknown_kwargs = []
violations = ["dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[teleop-quest-openyam]
Stack Traces | 0.004s run time
blueprint_name = 'teleop-quest-openyam'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
        blueprint = _get_blueprint_or_skip(blueprint_name)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'teleop-quest-openyam' passes unknown module kwargs:
E             - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/yam_description.tar.gz after 3 attempt...on.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] BlueprintAtom object at 0xff86a85b0f20>
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/yam_description.tar.gz after 3 attempt...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff86a85b0410>
blueprint_name = 'teleop-quest-openyam'
listing    = "  - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"
unknown_kwargs = []
violations = ["dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.imitation.collection.test_blueprint::test_recorder_reads_aggregate_joint_state[blueprint1]
Stack Traces | 0.004s run time
blueprint = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/piper_description.tar.gz after 3 attem...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff20f238edb0>

    @pytest.mark.parametrize("blueprint", [learning_collect_quest_xarm7, learning_collect_quest_piper])
    def test_recorder_reads_aggregate_joint_state(blueprint: Blueprint) -> None:
        streams = _joint_streams(blueprint)
    
        # Plain name pairing on both ends, no remap in between. The coordinator
        # atom carries its explicit instance_name (the RPC lookup contract).
        assert streams[("collectionrecorder", AGGREGATE)] == AGGREGATE
        assert streams[("ControlCoordinator", AGGREGATE)] == AGGREGATE
>       assert not [port for _instance, port in streams if port.endswith("_joints")]
E       AssertionError: assert not ['arm_joints']

blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/piper_description.tar.gz after 3 attem...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff20f238edb0>
streams    = {('ControlCoordinator', 'arm_joints'): 'arm_joints', ('ControlCoordinator', 'coordinator_joint_state'): 'coordinator_j..., 'joint_command'): 'joint_command', ('collectionrecorder', 'coordinator_joint_state'): 'coordinator_joint_state', ...}

.../imitation/collection/test_blueprint.py:47: AssertionError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[keyboard-teleop-openarm-planner]
Stack Traces | 0.005s run time
blueprint_name = 'keyboard-teleop-openarm-planner'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
        blueprint = _get_blueprint_or_skip(blueprint_name)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'keyboard-teleop-openarm-planner' passes unknown module kwargs:
E             - dimos.teleop.keyboard.keyboard_teleop_module.KeyboardTeleopModule: unknown kwargs ['task_name']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/openarm_description.tar.gz after 3 att...on.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] BlueprintAtom object at 0xff86a8695d00>
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/openarm_description.tar.gz after 3 att...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff86a86945c0>
blueprint_name = 'keyboard-teleop-openarm-planner'
listing    = "  - dimos.teleop.keyboard.keyboard_teleop_module.KeyboardTeleopModule: unknown kwargs ['task_name']"
unknown_kwargs = []
violations = ["dimos.teleop.keyboard.keyboard_teleop_module.KeyboardTeleopModule: unknown kwargs ['task_name']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[unitree-g1-teleop]
Stack Traces | 0.006s run time
blueprint_name = 'unitree-g1-teleop'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
        blueprint = _get_blueprint_or_skip(blueprint_name)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'unitree-g1-teleop' passes unknown module kwargs:
E             - dimos.teleop.quest.quest_extensions.MobileVideoArmTeleopModule: unknown kwargs ['task_names']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = BlueprintAtom(kwargs={'db_path': '.../dimos/recordings/session_g1_20260814_215942.db', ... type=<class 'dimos.msgs.geometry_msgs.PoseStamped.PoseStamped'>, direction='in')), module_refs=(), instance_name=None)
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/groot.tar.gz after 3 attempts: Command.../groot.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff86a81a7aa0>
blueprint_name = 'unitree-g1-teleop'
listing    = "  - dimos.teleop.quest.quest_extensions.MobileVideoArmTeleopModule: unknown kwargs ['task_names']"
unknown_kwargs = []
violations = ["dimos.teleop.quest.quest_extensions.MobileVideoArmTeleopModule: unknown kwargs ['task_names']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.robot.manipulators.dual_openyam.test_model::test_model_contains_no_workbench_camera_or_environment_geometry
Stack Traces | 3.12s run time
def test_model_contains_no_workbench_camera_or_environment_geometry() -> None:
>       root = _tree()


.../manipulators/dual_openyam/test_model.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../manipulators/dual_openyam/test_model.py:29: in _tree
    return ET.parse(DUAL_OPENYAM_MODEL_PATH).getroot()
....../usr/lib/python3.12....../xml/etree/ElementTree.py:1204: in parse
    tree.parse(source, parser)
        parser     = None
        source     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
        tree       = <xml.etree.ElementTree.ElementTree object at 0xffd71d7d42f0>
....../usr/lib/python3.12....../xml/etree/ElementTree.py:557: in parse
    if not hasattr(source, "read"):
        close_source = False
        parser     = None
        self       = <xml.etree.ElementTree.ElementTree object at 0xffd71d7d42f0>
        source     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:366: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = 'read'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError
dimos.hardware.whole_body.dual_openyam_damiao.test_adapter::test_adapter_connects_complete_dual_yam_topology
Stack Traces | 3.12s run time
adapter = <dimos.hardware.whole_body.dual_openyam_damiao.adapter.DualOpenYamDamiaoAdapter object at 0xffd71c37d760>

    def test_adapter_connects_complete_dual_yam_topology(
        adapter: DualOpenYamDamiaoAdapter,
    ) -> None:
>       assert adapter.connect()
E       assert False
E        +  where False = connect()
E        +    where connect = <dimos.hardware.whole_body.dual_openyam_damiao.adapter.DualOpenYamDamiaoAdapter object at 0xffd71c37d760>.connect

adapter    = <dimos.hardware.whole_body.dual_openyam_damiao.adapter.DualOpenYamDamiaoAdapter object at 0xffd71c37d760>

.../whole_body/dual_openyam_damiao/test_adapter.py:44: AssertionError
dimos.robot.manipulators.dual_openyam.test_integration::test_authoritative_arm_only_model_prepares_for_viser
Stack Traces | 3.12s run time
def test_authoritative_arm_only_model_prepares_for_viser() -> None:
        config = dual_openyam_model_config()
        prepared = Path(
>           prepare_urdf(
                config.model_path,
                package_paths=config.package_paths,
                convert_meshes=config.auto_convert_meshes,
            )
        )

config     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff2085ba69e0>

.../manipulators/dual_openyam/test_integration.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../planning/utils/mesh_utils.py:75: in prepare_urdf
    urdf_path = Path(urdf_path)
        convert_meshes = True
        package_paths = {'dual_openyam_abc_box': <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_..._box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9ce50>}
        urdf_path  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9f850>
        xacro_args = None
....../usr/lib/python3.12/pathlib.py:1164: in __init__
    super().__init__(*args)
        __class__  = <class 'pathlib.Path'>
        args       = (<[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after ...box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9f850>,)
        kwargs     = {}
        self       = <[AttributeError("'PosixPath' object has no attribute '_raw_paths'") raised in repr()] PosixPath object at 0xff2084def5a0>
....../usr/lib/python3.12/pathlib.py:362: in __init__
    if arg._flavour is ntpath and self._flavour is posixpath:
        arg        = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9f850>
        args       = (<[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after ...box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9f850>,)
        ntpath     = <module 'ntpath' (frozen)>
        paths      = []
        self       = <[AttributeError("'PosixPath' object has no attribute '_raw_paths'") raised in repr()] PosixPath object at 0xff2084def5a0>
dimos/utils/data.py:366: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = '_flavour'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9f850>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff20f4e9f850>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError
dimos.robot.manipulators.dual_openyam.test_model::test_both_arm_chains_are_symmetric_and_use_two_rad_s_limits
Stack Traces | 3.12s run time
def test_both_arm_chains_are_symmetric_and_use_two_rad_s_limits() -> None:
>       root = _tree()


.../manipulators/dual_openyam/test_model.py:78: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../manipulators/dual_openyam/test_model.py:29: in _tree
    return ET.parse(DUAL_OPENYAM_MODEL_PATH).getroot()
....../usr/lib/python3.12....../xml/etree/ElementTree.py:1204: in parse
    tree.parse(source, parser)
        parser     = None
        source     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
        tree       = <xml.etree.ElementTree.ElementTree object at 0xffd71c456810>
....../usr/lib/python3.12....../xml/etree/ElementTree.py:557: in parse
    if not hasattr(source, "read"):
        close_source = False
        parser     = None
        self       = <xml.etree.ElementTree.ElementTree object at 0xffd71c456810>
        source     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:366: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = 'read'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError
dimos.robot.manipulators.dual_openyam.test_model::test_model_package_is_versioned_and_self_contained
Stack Traces | 3.13s run time
def test_model_package_is_versioned_and_self_contained() -> None:
        assert DUAL_OPENYAM_ARTIFACT == "dual_openyam_abc_box_v2"
>       assert Path(DUAL_OPENYAM_PACKAGE).name == DUAL_OPENYAM_ARTIFACT


.../manipulators/dual_openyam/test_model.py:46: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
....../usr/lib/python3.12/pathlib.py:1164: in __init__
    super().__init__(*args)
        __class__  = <class 'pathlib.Path'>
        args       = (<[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after ...box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369ae50>,)
        kwargs     = {}
        self       = <[AttributeError("'PosixPath' object has no attribute '_raw_paths'") raised in repr()] PosixPath object at 0xffd71c2db300>
....../usr/lib/python3.12/pathlib.py:362: in __init__
    if arg._flavour is ntpath and self._flavour is posixpath:
        arg        = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369ae50>
        args       = (<[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after ...box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369ae50>,)
        ntpath     = <module 'ntpath' (frozen)>
        paths      = []
        self       = <[AttributeError("'PosixPath' object has no attribute '_raw_paths'") raised in repr()] PosixPath object at 0xffd71c2db300>
dimos/utils/data.py:366: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = '_flavour'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369ae50>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369ae50>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2')
        name       = 'dual_openyam_abc_box_v2'
        nested_path = None
        path_parts = ('dual_openyam_abc_box_v2',)
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError
dimos.robot.manipulators.dual_openyam.test_model::test_model_has_one_geometry_free_root_and_only_preserves_arm_spacing
Stack Traces | 3.14s run time
def test_model_has_one_geometry_free_root_and_only_preserves_arm_spacing() -> None:
>       root = _tree()


.../manipulators/dual_openyam/test_model.py:59: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../manipulators/dual_openyam/test_model.py:29: in _tree
    return ET.parse(DUAL_OPENYAM_MODEL_PATH).getroot()
....../usr/lib/python3.12....../xml/etree/ElementTree.py:1204: in parse
    tree.parse(source, parser)
        parser     = None
        source     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
        tree       = <xml.etree.ElementTree.ElementTree object at 0xffd71c2b4740>
....../usr/lib/python3.12....../xml/etree/ElementTree.py:557: in parse
    if not hasattr(source, "read"):
        close_source = False
        parser     = None
        self       = <xml.etree.ElementTree.ElementTree object at 0xffd71c2b4740>
        source     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:366: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = 'read'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError
dimos.robot.manipulators.dual_openyam.test_model::test_model_exposes_twelve_arm_joints_and_fixed_finger_geometry
Stack Traces | 3.15s run time
def test_model_exposes_twelve_arm_joints_and_fixed_finger_geometry() -> None:
>       model = pinocchio.buildModelFromUrdf(str(DUAL_OPENYAM_MODEL_PATH))


.../manipulators/dual_openyam/test_model.py:94: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/utils/data.py:371: in __str__
    return str(self._ensure_downloaded())
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffd79369aed0>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError
dimos.robot.manipulators.dual_openyam.test_blueprints::test_quest_blueprint_selects_physical_hardware_from_both_can_ports
Stack Traces | 3.28s run time
value = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>

    def _copy_opaque(value: Any) -> Any:
        try:
>           return copy.deepcopy(value)

value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>

.../coordination/blueprint_config/values.py:148: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
............................../usr/lib/python3.12/copy.py:162: in deepcopy
    y = _reconstruct(x, memo, *rv)
        _nil       = []
        cls        = <class 'dimos.control.coordinator.TaskConfig'>
        copier     = None
        d          = 280953816445296
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        reductor   = <built-in method __reduce_ex__ of TaskConfig object at 0xff86a86d7170>
        rv         = (<function __newobj__ at 0xff8795e505e0>, (<class 'dimos.control.coordinator.TaskConfig'>,), {'auto_start': False, 'jo...lter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}, None, None)
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>
        y          = []
............................../usr/lib/python3.12/copy.py:259: in _reconstruct
    state = deepcopy(state, memo)
        args       = <generator object _reconstruct.<locals>.<genexpr> at 0xff869b4473d0>
        deep       = True
        deepcopy   = <function deepcopy at 0xff87957ea020>
        dictiter   = None
        func       = <function __newobj__ at 0xff8795e505e0>
        listiter   = None
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        state      = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'lef...nt_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>
        y          = <[AttributeError("'TaskConfig' object has no attribute 'name'") raised in repr()] TaskConfig object at 0xff869b858110>
............................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff87955e8ae0>
        d          = 280953372908032
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        x          = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'lef...nt_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}
        y          = []
............................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff87957ea020>
        key        = 'params'
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        value      = {'bindings': [{'gripper_closed_position': 0.0, 'gripper_joint': 'left_arm/gripper', 'gripper_open_position': 1.0, 'han..., 'joint_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}
        x          = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'lef...nt_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}
        y          = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...], 'name': 'teleop_dual_openyam', 'priority': 10, ...}
............................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff87955e8ae0>
        d          = 280953603963584
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        x          = {'bindings': [{'gripper_closed_position': 0.0, 'gripper_joint': 'left_arm/gripper', 'gripper_open_position': 1.0, 'han..., 'joint_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}
        y          = []
............................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff87957ea020>
        key        = 'robot_model'
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff86a8162f30>
        x          = {'bindings': [{'gripper_closed_position': 0.0, 'gripper_joint': 'left_arm/gripper', 'gripper_open_position': 1.0, 'han..., 'joint_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}
        y          = {}
............................../usr/lib/python3.12/copy.py:143: in deepcopy
    y = copier(memo)
        _nil       = []
        cls        = <class 'dimos.manipulation.planning.spec.config.RobotModelConfig'>
        copier     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...bc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] method object at 0xff86980caa00>
        d          = 280953810726704
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff86a8162f30>
        y          = []
.venv/lib/python3.12.../site-packages/pydantic/main.py:978: in __deepcopy__
    _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo))
        cls        = <class 'dimos.manipulation.planning.spec.config.RobotModelConfig'>
        m          = RobotModelConfig()
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff86a8162f30>
............................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff87955e8ae0>
        d          = 280953604351936
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        x          = {'auto_convert_meshes': True, 'base_link': 'dual_openyam_base', 'base_pose': Pose(position=Vector([          0           0           0]), orientation=Quaternion(0.000000, 0.000000, 0.000000, 1.000000)), 'collision_exclusion_pairs': [], ...}
        y          = []
............................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff87957ea020>
        key        = 'model_path'
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff871007ea50>
        x          = {'auto_convert_meshes': True, 'base_link': 'dual_openyam_base', 'base_pose': Pose(position=Vector([          0           0           0]), orientation=Quaternion(0.000000, 0.000000, 0.000000, 1.000000)), 'collision_exclusion_pairs': [], ...}
        y          = {'default_rpc_timeout': 120.0, 'frame_id': None, 'frame_id_prefix': None, 'g': GlobalConfig(robot_ip=None, robot_ips=N...'127.0.0.1', dimsim_scene='apartment', dimsim_port=8090, dimsim_headless=True, local_relay=False, relay_url=None), ...}
............................../usr/lib/python3.12/copy.py:141: in deepcopy
    copier = getattr(x, "__deepcopy__", None)
        _nil       = []
        cls        = <class 'dimos.utils.data.LfsPath'>
        copier     = None
        d          = 280955554622032
        memo       = {280953372908032: {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left..._native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, 280953603963584: {}, ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff871007ea50>
        y          = []
dimos/utils/data.py:366: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = '__deepcopy__'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff871007ea50>
dimos/utils/data.py:349: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff871007ea50>
dimos/utils/data.py:306: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:250: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'd40b93b6-acf8-4933-8e85-f7300f88ea43.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:218: RuntimeError

The above exception was the direct cause of the following exception:

    def test_quest_blueprint_selects_physical_hardware_from_both_can_ports() -> None:
>       parsed = BlueprintConfigParser(teleop_quest_dual_openyam).parse(
            [
                "--left-can-port",
                "follower_l",
                "--right-can-port",
                "follower_r",
                "--manipulationmodule.visualization.host=0.0.0.0",
            ],
            environ={},
        )


.../manipulators/dual_openyam/test_blueprints.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../coordination/blueprint_config/parser.py:169: in parse
    key: plain(value)
        cli_tokens = ['--left-can-port', 'follower_l', '--right-can-port', 'follower_r', '--manipulationmodule.visualization.host=0.0.0.0']
        config_path = None
        environ    = {}
        global_overrides = None
        overrides  = None
        schema     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3..._v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] ParserSchema object at 0xff8698a71700>
        self       = <dimos.core.coordination.blueprint_config.parser.BlueprintConfigParser object at 0xff869b85b8c0>
.../coordination/blueprint_config/values.py:50: in plain
    return [plain(item) for item in value]
        value      = [<[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after ...oint5', 'right_arm/joint6'], priority=20, auto_start=False, params={'start_position_tolerance': 0.05}, stream_bind={})]
.../coordination/blueprint_config/values.py:55: in plain
    return _copy_opaque(value)
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

value = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>

    def _copy_opaque(value: Any) -> Any:
        try:
            return copy.deepcopy(value)
        except Exception as error:
>           raise BlueprintConfigError(
                f"Configuration value of type {type(value).__name__} cannot be copied safely: {error}"
            ) from error
E           dimos.core.coordination.blueprint_config.errors.BlueprintConfigError: Configuration value of type TaskConfig cannot be copied safely: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff86a86d7170>

.../coordination/blueprint_config/values.py:150: BlueprintConfigError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@TomCC7
TomCC7 marked this pull request as ready for review August 14, 2026 20:31
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from 97ee374 to f88d119 Compare August 14, 2026 21:37
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from e71acfc to 0a813a5 Compare August 14, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant