Problem Statement
A FreeFlightUnsteadyProblem built with mujoco_assets cannot be saved: save() raises, because the MuJoCo engine is rebuilt on load from the stored XML string alone, whose asset references would be unresolvable. This blocks saving any free flight simulation whose body geometry comes from a mesh file, such as an STL supplied through mujoco_assets.
Separately, the guard behind that refusal has a gap. A model whose extra_xml fragments reference a mesh by absolute on-disk path compiles without mujoco_assets, because MuJoCo falls back to the filesystem, and such a simulation saves without complaint today. The resulting file is a trap: it loads only while the referenced file still exists at that machine-specific path, and the failure surfaces as a MuJoCo file-open error long after the expensive run is gone. This is exactly the failure mode the guard exists to prevent, so these saves should be caught the same way.
Location(s): pterasoftware/_serialization.py, pterasoftware/_mujoco_model.py, pterasoftware/problems.py
Proposed Solution
- Serialize the assets faithfully. Add a bytes case to
_serialize_value and _deserialize_value that encodes contents as base64, the same pattern _ndarray_to_dict already uses for array buffers. Serialize the _mujoco_assets dict instead of skipping it, and remove the save-time refusal. On load, _rebuild_engine passes the restored dict to mujoco.MjModel.from_xml_string as the assets parameter, mirroring the existing branch in MuJoCoModel.__init__. Saved files stay fully self-contained, and load never touches the filesystem.
- Complete the save guard. At save time, raise if the model XML contains file references that are not covered by the assets dict, so a save can never produce a file that only loads while some on-disk file survives at a hard-coded path.
- Strengthen the existing
mujoco_assets validation in FreeFlightUnsteadyProblem to require each virtual filename to be a bare basename with a nonempty extension, rejecting path separators and absolute-path shapes. MuJoCo selects its asset decoder from the extension, so the extension is load-bearing, and the basename requirement keeps machine-specific paths out of saved files.
- Bump
_FORMAT_VERSION and update the docstrings in problems.py, _mujoco_model.py, and _serialization.py that document the current refusal.
Additional Context
Verified empirically against the pinned MuJoCo version: absolute paths in the XML compile from disk with no assets dict, relative paths fail for string-built models, and extension-less virtual filenames fail even with an explicit content_type attribute. The commit that added the refusal (368e2a8) anticipated this work, noting that "A faithful asset round trip can be added later if a real need appears."
Problem Statement
A
FreeFlightUnsteadyProblembuilt withmujoco_assetscannot be saved:save()raises, because the MuJoCo engine is rebuilt on load from the stored XML string alone, whose asset references would be unresolvable. This blocks saving any free flight simulation whose body geometry comes from a mesh file, such as an STL supplied throughmujoco_assets.Separately, the guard behind that refusal has a gap. A model whose
extra_xmlfragments reference a mesh by absolute on-disk path compiles withoutmujoco_assets, because MuJoCo falls back to the filesystem, and such a simulation saves without complaint today. The resulting file is a trap: it loads only while the referenced file still exists at that machine-specific path, and the failure surfaces as a MuJoCo file-open error long after the expensive run is gone. This is exactly the failure mode the guard exists to prevent, so these saves should be caught the same way.Location(s):
pterasoftware/_serialization.py,pterasoftware/_mujoco_model.py,pterasoftware/problems.pyProposed Solution
_serialize_valueand_deserialize_valuethat encodes contents as base64, the same pattern_ndarray_to_dictalready uses for array buffers. Serialize the_mujoco_assetsdict instead of skipping it, and remove the save-time refusal. On load,_rebuild_enginepasses the restored dict tomujoco.MjModel.from_xml_stringas theassetsparameter, mirroring the existing branch inMuJoCoModel.__init__. Saved files stay fully self-contained, and load never touches the filesystem.mujoco_assetsvalidation inFreeFlightUnsteadyProblemto require each virtual filename to be a bare basename with a nonempty extension, rejecting path separators and absolute-path shapes. MuJoCo selects its asset decoder from the extension, so the extension is load-bearing, and the basename requirement keeps machine-specific paths out of saved files._FORMAT_VERSIONand update the docstrings inproblems.py,_mujoco_model.py, and_serialization.pythat document the current refusal.Additional Context
Verified empirically against the pinned MuJoCo version: absolute paths in the XML compile from disk with no assets dict, relative paths fail for string-built models, and extension-less virtual filenames fail even with an explicit
content_typeattribute. The commit that added the refusal (368e2a8) anticipated this work, noting that "A faithful asset round trip can be added later if a real need appears."