Skip to content

feat(config_io): template-overlay export + UI sidecar#3

Merged
HugoFara merged 2 commits into
talmolab:mainfrom
HugoFara:feat-template-overlay-export
Apr 22, 2026
Merged

feat(config_io): template-overlay export + UI sidecar#3
HugoFara merged 2 commits into
talmolab:mainfrom
HugoFara:feat-template-overlay-export

Conversation

@HugoFara

Copy link
Copy Markdown
Collaborator

Summary

Closes the two remaining blockers that prevent the UI's export from being a drop-in stac-mjx config.

  1. Template overlay. load_stac_yaml now returns _rawTemplate — the full parsed YAML. dump_stac_yaml uses it to overlay UI edits onto the original, preserving its shape (flat vs wrapped) and every field the UI doesn't manage (N_ITERS, ROOT_OPTIMIZATION_KEYPOINT, TRUNK_OPTIMIZATION_KEYPOINTS, SITES_TO_REGULARIZE, ...). Without a template, dump falls back to the wrapped UI-internal format.

  2. Skeleton editor sidecar. skeleton_editor: no longer leaks into the main export — it moves to a separate download (*.ui.yaml) via a new /api/export-ui-sidecar endpoint that returns 204 when there's nothing to save.

Store gains a persisted rawTemplate field; Toolbar export triggers both downloads in parallel and only emits the sidecar when non-default.

Why this matters

Before this change, exporting the UI state produced a YAML that stac-mjx rejected with either ConfigKeyError: Key 'skeleton_editor' not in 'Config' or ConfigKeyError: Key 'model' not in 'ModelConfig', plus a dozen missing required fields. Now: load configs/model/rodent.yaml, reassign a keypoint in the UI, re-export, drop it back into stac-mjx/configs/model/compose_config() loads it cleanly with the UI edits applied and every other field preserved.

Test plan

  • pytest tests/test_config_io.py — 10/10 pass
    • new: _rawTemplate round-trip, flat-template overlay, wrapped-template overlay, skeleton_editor stripped from main export, no-template falls back to wrapped, sidecar None when default, sidecar emits non-default
  • pytest tests/test_app.py/api/health still passes
  • tsc --noEmit clean
  • Integration: TestClient hits /api/export-ui-sidecar (204 empty, 200 populated) and /api/export-config (template preserved, overlay applied)
  • E2E: load stac-mjx/configs/model/rodent.yaml, edit mappings, export, feed to stac_mjx.config.compose_config — loads successfully, N_ITERS=6, ROOT_OPTIMIZATION_KEYPOINT=SpineL, user edits applied

Out of scope

  • MJCF_PATH portability (still uses whatever xmlPath the server returned from /api/load-xml)
  • Pre-export validation (unmapped keypoints, unknown bodies, duplicates)
  • Starting from scratch without a template and producing a valid stac-mjx config

Fixes the two remaining blockers that prevent the UI's export from being
a drop-in stac-mjx config.

1. Template overlay. load_stac_yaml now returns `_rawTemplate` — the full
   parsed YAML. dump_stac_yaml uses it to overlay UI edits onto the
   original, preserving its shape (flat vs wrapped) and every field the
   UI does not manage (N_ITERS, ROOT_OPTIMIZATION_KEYPOINT,
   TRUNK_OPTIMIZATION_KEYPOINTS, SITES_TO_REGULARIZE, ...). Without a
   template, dump falls back to the wrapped UI-internal format.

2. Skeleton editor sidecar. `skeleton_editor:` no longer leaks into the
   main export — it moves to a separate download (`*.ui.yaml`) via a new
   /api/export-ui-sidecar endpoint that returns 204 when empty.

Store gains a persisted `rawTemplate` field; Toolbar export now triggers
both downloads in parallel and only emits the sidecar when non-default.

Confirmed end-to-end: loading stac-mjx/configs/model/rodent.yaml,
reassigning Snout, and re-exporting produces a file that compose_config()
accepts and loads with all non-UI fields preserved.
When exporting after loading a config but before loading mocap data,
the UI sends empty kpNames (and similar empty fields) that overwrote
the template's populated KP_NAMES list. Now empty UI values are
skipped if the template has a populated value at that key.

Repro: load data/stac_rodent_acm.yaml, export without loading .mat —
before: KP_NAMES: []
after:  KP_NAMES preserved from template (21 entries)
@HugoFara

Copy link
Copy Markdown
Collaborator Author

Double-checked with another model, merging.

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