Skip to content

feat(dr): generic interval term dispatch in DomainRandomizationManager - #1504

Merged
TATP-233 merged 4 commits into
mainfrom
feat/issue-1502-interval-term-descriptor
Sep 5, 2026
Merged

feat(dr): generic interval term dispatch in DomainRandomizationManager#1504
TATP-233 merged 4 commits into
mainfrom
feat/issue-1502-interval-term-descriptor

Conversation

@TATP-233

@TATP-233 TATP-233 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

UniLab half of #1502 (approved approach A: descriptor/operation registry). Consumes the unisim-core contract PR unilabsim/unisim#21.

  • DomainRandomizationManager.apply_interval_randomization_if_due is now fully generic (src/unilab/dr/manager.py:91): no interval term names, no per-field capability if branches. It validates plan.iter_ops() against capabilities.get_unsupported_interval_terms(...) and fails closed with backend type + sorted term names, then dispatches once.
  • Builtin providers migrated to descriptors: locomotion push (src/unilab/dr/dr_utils.py) and Sharpa body force (src/unilab/tasks/manipulation/sharpa_inhand/rotation.py) now emit IntervalTermOp entries with identical payloads/timing; validation uses supports_interval_term.
  • Legacy IntervalRandomizationPlan fields keep working through iter_ops() (deprecated in the provider docstring; removal in the next unisim-core major) — existing task owners and the Entity/EventManager interval path (src/unilab/base/entity.py, src/unilab/envs/mdp/events.py) are untouched and run through the compatibility adapter.
  • unilab.dr re-exports IntervalTermOp + INTERVAL_TERM_*.
  • Docs updated in en + zh_CN: DR contract (term registration, capability ownership, pickle/spawn rules, fail-closed) and provider authoring guide with migration note.
  • pyproject.toml: unisim-core>=0.1.14>=1.1.0.

Tests

  • New interval-side coverage in tests/dr/test_manager.py: custom-term extensibility without touching the manager (acceptance proof), capability-negative errors (term + backend in message), legacy-fields compat, mixed legacy+ops, empty/None plans, multi-op single dispatch, pickle protocol-4 round-trip.
  • Intended behavior change from unisim-core 1.1.0: mjwarp/genesis previously silently dropped body_torque / body_angular_velocity_delta; they now fail closed. No UniLab test relied on the silent behavior; three backend tests were updated for the new unified error messages/validation order (test_genesis_backend.py, test_isaacgym_backend.py, test_sim_backend_smoke.py).

Benchmark (interval hot path, 20k calls, min of 5 repeats, this machine)

Path Baseline (main + unisim-core 0.1.14) This PR (+ unisim-core 1.1.0)
Manager dispatch (fake backend, push+force plan) 884 ns/call 1625 ns/call
MuJoCo apply_interval_randomization (body-force plan) 1947 ns/call 2200 ns/call

The generic dispatch adds ≤0.9 µs per interval application; interval terms fire on multi-step cadence (e.g. push interval) against ~ms physics steps, so there is no measurable hot-path regression and no extra backend round-trip (still one apply_interval_randomization call per due step). An ops-only fast path in iter_ops() avoids per-call tuple re-allocation (unisim b49e8b5).

Validation

  • UV_NO_SYNC=1 make test-all: ruff format/check clean, mypy clean (148 files), pyright 0 errors, pytest not slow 1578 passed / 20 skipped / 1 xfailed, benchmark smoke 36/37 pass (1 platform-optional mlx skip).
  • One expected local failure: tests/base/test_backend_imports.py::test_unisim_dependency_is_installed_from_package_index — by design it rejects non-index unisim-core installs; local verification used an editable install of feat(dr): declarative interval term descriptors with generic backend dispatch unilabsim/unisim#21. It passes once unisim-core 1.1.0 is published and installed from PyPI.

Dependency / merge order

  1. Merge feat(dr): declarative interval term descriptors with generic backend dispatch unilabsim/unisim#21, maintainer publishes unisim-core 1.1.0 (git tag v1.1.0, trusted publishing per unisim docs/release.md).
  2. Then regenerate uv.lock here (uv lock) — deliberately not done yet since 1.1.0 is not on PyPI; remote CI on this PR will be red until then. I will push the lock update and confirm CI green after the release.

Migrate interval DR to the unisim-core 1.1.0 descriptor contract:
the manager no longer enumerates term fields or per-term capability
branches; it validates plan.iter_ops() against supported_interval_terms
and fails closed with backend type + term names. Locomotion push and
Sharpa body-force providers now emit IntervalTermOp entries; legacy
plan fields keep working through iter_ops() (deprecated, removal in
the next unisim-core major). Entity/EventManager interval paths are
unchanged via the legacy adapter.

Adds interval-side manager tests: custom-term extensibility without
manager changes, capability-negative errors, legacy compat, mixed
plans, empty plans, and pickle protocol-4 round-trip. Updates DR
contract and provider docs (en + zh_CN). Bumps unisim-core floor to
>=1.1.0.

Refs #1502
@TATP-233
TATP-233 requested a review from Mingrui-Yu as a code owner September 4, 2026 20:19
@TATP-233
TATP-233 merged commit 00eb720 into main Sep 5, 2026
8 checks passed
@TATP-233
TATP-233 deleted the feat/issue-1502-interval-term-descriptor branch September 5, 2026 09:53
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