Skip to content

Decouple backend-specific cloning from InteractiveScene#5770

Open
ooctipus wants to merge 4 commits into
isaac-sim:developfrom
ooctipus:feature/clone_plan_new_representation
Open

Decouple backend-specific cloning from InteractiveScene#5770
ooctipus wants to merge 4 commits into
isaac-sim:developfrom
ooctipus:feature/clone_plan_new_representation

Conversation

@ooctipus
Copy link
Copy Markdown
Collaborator

Summary

This PR removes backend-specific cloning logic from InteractiveScene and
replaces the previous implicit replicate_session_defaults /
replicate_session machinery with three orthogonal, explicit primitives that
compose identically whether you drive cloning through InteractiveScene or
by hand in a DirectRLEnv or standalone script.

The result is that InteractiveScene no longer knows anything about USD vs.
PhysX vs. Newton — it just enters a ReplicateSession and lets each asset's
constructor register the backend(s) it needs. This is foundational for two
follow-on capabilities the project has wanted for a while: flexible backend
cloning
and skip-cloning workflows.

What changed

New core primitives in isaaclab.cloner

  • REPLICATION_QUEUE — module-level list that asset constructors append
    (cfg, BackendCtxCls) pairs to via tiny per-backend helpers
    (queue_usd_replication, queue_physx_replication,
    queue_newton_replication). Backends are no longer special-cased inside
    InteractiveScene; each one self-registers.
  • ClonePlan — self-contained dataclass describing the world layout
    (sources, destinations, clone_mask, env_ids, positions,
    cfg_rows). Stage-agnostic by design; the USD stage is now passed
    explicitly to consumers so the same plan can be replayed, inspected, or
    serialized.
  • replicate(plan, *, stage) — free function that drains
    REPLICATION_QUEUE against a plan, groups queued cfgs by backend context
    class, runs each context in ascending replicate_priority order (physics
    before USD), publishes the plan to SimulationContext, and clears the
    queue. The queue is snapshotted and cleared up front so a backend failure
    cannot leak stale entries into the next call.
  • ReplicateSession is now a thin context manager that calls
    make_clone_plan in __enter__ and replicate in __exit__. The
    state-bag version with plan / stage / cfg_rows /
    replicate_on_exit fields is gone.
  • ClonePlan.from_env_0 — classmethod that builds the single-source
    homogeneous plan most direct envs need by auto-populating cfg_rows
    from REPLICATION_QUEUE filtered by env-root prefix.
  • CloneCfg.clone_regex (default "/World/envs/env_.*") — single
    source of truth for the env-namespace convention. InteractiveScene
    reads it directly when expanding {ENV_REGEX_NS} cfg macros.

Two equivalent invocation paths

# InteractiveScene path (what the scene runs under the hood)
with cloner.ReplicateSession(cfgs, num_clones=N, env_spacing=2.0,
                             device=device, stage=stage):
    for cfg in cfgs:
        cfg.class_type(cfg)

# Direct env / script path
plan = cloner.ClonePlan.from_env_0(src, dest, num_envs, device, positions)
cloner.replicate(plan, stage=scene.stage)

Both end in the same cloner.replicate(plan, stage=...) call. The only
difference is how the plan was built and how asset construction was
interleaved.

What got removed from InteractiveScene

  • clone_environments(...) deprecated shim. The scene now replicates
    inside __init__ via ReplicateSession.
  • env_ns / env_regex_ns properties (used only internally).
  • _build_clone_plan_from_cfg and _default_env_origins internals.
    Cfg-driven plan construction now lives in make_clone_plan; per-env
    positions are read from the published ClonePlan.
  • InteractiveScene.env_origins now reads from the plan published to
    SimulationContext, making the plan the single source of truth for
    env placement.

Why this matters (the actual point of the PR)

This refactor is foundational for two capabilities the current scene
coupling blocks:

  • Flexible backend cloning. Backends now plug in by shipping a
    <Backend>ReplicateContext class + a one-line queue helper. Swapping
    PhysX ↔ Newton no longer requires InteractiveScene to change; cfgs
    and user code stay untouched, and a third-party backend can register
    itself without modifying core.
  • Skip-cloning workflows. Because plan construction, asset
    registration, and drain are three independent primitives, callers
    that want to author env-0 prims by hand and skip the cloner — or
    drive replication out-of-band from a visualizer, replay tool, or
    test fixture — can do so without fighting InteractiveScene.

Migration notes

  • with cloner.ReplicateSession(): (no-arg) →
    cloner.replicate(cloner.ClonePlan.from_env_0(...), stage=...).
  • InteractiveScene.clone_environments(...) → removed; the scene
    replicates inside __init__.
  • make_clone_plan(sources, destinations, ...)
    make_clone_plan(cfgs, num_clones, env_spacing, device, ...).
  • Pass stage=... explicitly to replicate() and ReplicateSession().
  • Read CloneCfg.clone_regex if you previously used
    InteractiveScene.env_ns / env_regex_ns.

About 17 direct envs were migrated to the new pattern in this PR.

Test plan

  • ./isaaclab.sh -p -m pytest source/isaaclab/test/sim/test_cloner.py
  • ./isaaclab.sh -p -m pytest source/isaaclab/test/scene/test_interactive_scene.py
  • ./isaaclab.sh -p -m pytest source/isaaclab_physx/test/sim/test_cloner.py
  • Migrated direct envs (cartpole, anymal_c, franka_cabinet,
    factory, humanoid_amp, inhand_manipulation, locomotion,
    quadcopter, shadow_hand_*, automate/*, cart_double_pendulum,
    cartpole_warp, inhand_manipulation_warp, locomotion_warp)
    spawn and step on PhysX
  • Same envs spawn and step on Newton
  • ./isaaclab.sh -f passes
  • Docs build (cd docs && make html)

@ooctipus ooctipus changed the base branch from main to develop May 25, 2026 11:10
@github-actions github-actions Bot added documentation Improvements or additions to documentation enhancement New feature or request isaac-sim Related to Isaac Sim team isaac-mimic Related to Isaac Mimic team infrastructure labels May 25, 2026
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Isaac Lab Review Bot — Multi-Perspective Analysis

PR: Decouple backend-specific cloning from InteractiveScene
SHA: b12c47cc5d03d7896dad6b9600b57abf5f2b2da1


Architecture Assessment (Isaac Lab Expert)

This is an excellent structural improvement. The PR replaces InteractiveScene's hard-coded backend dispatching (if physx... elif newton... elif ovphysx...) with a self-registering queue pattern where each backend ships a <Backend>ReplicateContext + a queue_<backend>_replication() helper. The three orthogonal primitives (REPLICATION_QUEUE, ClonePlan, replicate()) compose well regardless of whether you're in InteractiveScene, a DirectRLEnv, or a standalone script.

Design wins:

  • Clean separation of concerns — InteractiveScene now only cares about what to clone, not how
  • Backend extensibility without core modification (Open/Closed principle)
  • Both invocation paths (ReplicateSession context manager vs. manual ClonePlan.from_env_0 + replicate) converge on the same drain function — no hidden divergence
  • The replicate_priority ordering (physics=0, USD=100) ensures correct execution order

Findings

1. ✅ Performance Regression Risk: disabled_fabric_change_notifies Removed — ADDRESSED

The new UsdReplicateContext.replicate() method wraps copy work in disabled_fabric_change_notifies(self.stage) — performance optimization is preserved in the new architecture.

2. 🟡 Module-Level REPLICATION_QUEUE — Implicit Global State

REPLICATION_QUEUE is a module-level mutable list that asset constructors append to and replicate() drains. While the PR handles the "exception during session" case by clearing the queue in ReplicateSession.__exit__, there are still scenarios where the queue could accumulate stale entries:

  • If replicate() is called without a ReplicateSession and a backend raises mid-drain, the queue is already cleared up front (good), but the partial work from earlier backends cannot be rolled back.
  • If user code calls queue_<backend>_replication(cfg) outside of any session/replicate cycle (e.g., in a test or standalone script that forgets to call replicate()), entries accumulate silently until the next replicate() call — possibly in a completely unrelated context.

Suggestion: Consider adding a warnings.warn() or debug log in replicate() when queued contains entries whose cfg is not in plan.cfg_rows (currently silently skipped). This would help developers catch mismatched queue/plan scenarios.

3. ✅ ClonePlan.from_env_0 Couples to Live Queue State — ADDRESSED

The docstring now documents the ordering constraint: "Must be called after all asset constructors have run, so their replication entries are already in the queue."

4. 🟢 _collect_asset_cfgs + _add_entities_from_cfg — Clear Flow

The scene now resolves {ENV_REGEX_NS} macros in _collect_asset_cfgs() before planning, and _add_entities_from_cfg() uses the already-resolved paths. The redundant double-format concern from earlier is no longer applicable.

5. 🟡 SimulationContext.instance() Crash in replicate()

In replicate(), the final line calls SimulationContext.instance().set_clone_plan(plan). If SimulationContext hasn't been initialized yet (e.g., in a unit test that manually creates a stage), .instance() returns None and this line raises AttributeError: 'NoneType' object has no attribute 'set_clone_plan'.

The ClonePlan.from_env_0 + replicate pattern in direct envs assumes a SimulationContext exists, but the function has no guard.

Suggestion: Add a defensive check: sim = SimulationContext.instance(); if sim is not None: sim.set_clone_plan(plan) — or document that replicate() requires an active SimulationContext.

6. 🟢 Strong Test Coverage for New Primitives

The test additions are solid:

  • test_usd_replicate_context_queue_and_replicate — validates the new UsdReplicateContext
  • test_queue_usd_replication_only_appends — confirms queue-only semantics
  • test_make_clone_plan_homogeneous_returns_env_root_plan — validates the fast-path
  • test_make_clone_plan_heterogeneous_mutates_spawn_paths — validates multi-variant behavior
  • test_replicate_dedupes_shared_rows_across_cfgs — validates dedup logic
  • _drain_replication_queue fixture prevents test cross-contamination

Gap: No integration test verifies the full ReplicateSession context-manager flow (enter → construct assets → exit → verify plan published). The unit tests cover individual primitives but not the composed lifecycle that InteractiveScene relies on. Consider adding a test that exercises ReplicateSession end-to-end with a mock backend.


Summary

Category Rating
Architecture ✅ Excellent — clean decoupling, extensible backends
Error Handling ⚠️ Minor gaps (SimulationContext guard, silent queue skipping)
Performance ✅ Fabric notice suspension restored
Test Coverage ✅ Good unit tests; integration test for composed lifecycle would strengthen
Migration Safety ✅ Good — direct-env tasks migrated consistently

Verdict: Strong architectural improvement ready for merge. The findings above are advisory — the design is sound and the implementation is clean.


Change History

Update (28b9473): Reviewed incremental changes from 322ec99a28b94730. This update rebases onto develop absorbing several merged PRs:

Upstream changes absorbed:

  • #5928: isaaclab_visualizers changelog infrastructure — added config/extension.toml and docs/CHANGELOG.rst
  • CI auto version bump: isaaclab 6.2.0 → 6.2.1, newton 0.14.0 → 0.14.1, ovphysx 3.0.0 → 3.0.1, physx 1.1.1 → 1.1.2, tasks 2.0.0 → 2.0.1, visualizers 0.1.0 → 0.1.1
  • #5917 (TacSL update): PhysX config type migrations, deprecated wrench application calls, compliant-contact USD spawning fix
  • #5926 (Newton SDF collision): NewtonSDFCollisionPropertiesCfg for SDF/hydroelastic collision attributes
  • #5930 (Cartpole refactor): Task consolidation, permute argument for mdp.image() observation

PR-specific changes (replication-session-redesign):

  • ✅ Changelog fragments added for the cloner refactor (replication-session-redesign.minor.rst)
  • ✅ Skip fragments added for backend packages (newton, ovphysx, physx, tasks) indicating no user-facing changes in those packages from this PR
  • ✅ Final squash commit titled "single commit" consolidates all PR work

Previous findings status:

  • 🟡 Finding #2 (silent queue skipping) — unchanged, advisory
  • 🟡 Finding #5 (SimulationContext guard in replicate()) — unchanged, advisory

New observations:

  • ✅ The cartpole-image-permute feature adds a permute argument to mdp.image() for channel-first layout — clean addition, orthogonal to replication refactor
  • NewtonSDFCollisionPropertiesCfg shim exports added to isaaclab.sim and isaaclab.sim.schemas — correctly wired through lazy exports
  • ✅ TacSL demo uses PhysxRigidBodyMaterialCfg instead of deprecated aliases — aligns with the PhysX config consolidation

No new issues introduced. The PR remains ready for merge with the same advisory findings.


Previous updates:

  • 322ec99: Rebase absorbing lazy pxr imports, resample_interval_on_reset, ProxyArray, task module renames, version bumps
  • d3a2eab: Sensor USD replication queueing, OvPhysx envIdInBoundsBitCount authoring
  • b12c47c: Squashed force-push with complete implementation

Update (463a05a): Reviewed incremental changes from 28b94730463a05ae.

Changes in Newton replication (replicate.py):

  • _build_newton_builder_from_mapping return type extended to 4-tuple, adding world_xforms list of absolute per-world transforms
  • _cl_inject_sites now returns world_sites (bodyless sites needing per-world placement)
  • ✅ New per-world bodyless site loop correctly uses wp.transform_multiply(world_xform, xform) to place sites in each env's global frame
  • ✅ Clear separation between env_xform (delta-based, for add_builder) and world_xform (absolute, for sites and frame placement)
  • NewtonManager._world_xforms stored on commit — consumed by FrameView for camera/non-physics frame placement

Assessment: Clean, well-documented extension. The dual-transform pattern (env_xform vs world_xform) is correctly reasoned about in comments. No new issues introduced.

Previous findings status:

  • 🟡 Finding #2 (silent queue skipping) — unchanged, advisory
  • 🟡 Finding #5 (SimulationContext guard) — unchanged, advisory

Update (6f34c5a): Reviewed incremental changes from 463a05ae6f34c5ac.

This is a large consolidation commit that completes the replication session redesign. Key changes:

Core API changes:

  • InteractiveScene.clone_environments() removed — replaced by explicit cloner.replicate(plan, stage=...) in all direct envs
  • InteractiveScene.env_ns / env_regex_ns properties removed — cloner_cfg.clone_regex is now the canonical source
  • _build_clone_plan_from_cfg() replaced by simpler _collect_asset_cfgs() — returns resolved cfg list without planning logic
  • env_origins property now reads from clone_plan.positions instead of internal _default_env_pose
  • make_clone_plan() API changed: takes cfgs list + num_clones/env_spacing instead of raw source/destination lists

Sensor replication queueing:

  • Camera.__init__ and BaseRayCaster.__init__ now call queue_usd_replication(self._source_cfg)
  • SensorBase stores original cfg as _source_cfg before copy for replication registration
  • ✅ Sensor _initialize_impl handles Newton solver-side cloning (where USD only has env_0 prototype)

Backend replication contexts:

  • ✅ Newton: newton_replicate.pyreplicate.py, NewtonReplicateContext fully replaces newton_visualizer_prebuild
  • ✅ OvPhysX: ovphysx_replicate.pyreplicate.py, OvPhysxReplicateContext wraps the pending-clone registration
  • ✅ PhysX: physx_replicate.pyreplicate.py, PhysxReplicateContext encapsulates the replicator interface
  • ✅ All three backends now append (cfg, ContextClass) to REPLICATION_QUEUE from asset constructors

Lazy import guards (isaaclab_experimental):

  • envs/__init__.py, managers/__init__.py, and MDP action/term packages now use lazy_export() + .pyi stubs
  • ✅ Runtime types (Articulation, InteractiveScene, ContactSensor) moved behind TYPE_CHECKING
  • actions_cfg.py uses string class_type references ("{DIR}.joint_actions:JointPositionAction") for deferred resolution

Task migrations:

  • ✅ All 15+ direct envs consistently migrated to cloner.grid_transforms() + ClonePlan.from_env_0() + cloner.replicate()
  • ✅ Direct task templates updated for new API
  • ✅ Cartpole/Ant/Humanoid experimental tasks split env cfg into separate _cfg.py files to avoid eager backend imports

Test coverage:

  • ✅ Comprehensive new tests for UsdReplicateContext, queue_usd_replication, make_clone_plan (cfg-driven), ClonePlan.from_env_0, replicate (drain/dedup/priority/failure/skip)
  • ReplicateSession cleanup-on-failure test added
  • resolve_clone_plan_source tests for nested/ambiguous/partial coverage
  • ✅ Old clone_environments-based tests properly replaced with new _collect_asset_cfgs and replicate-based tests

Minor cleanups:

  • Module-level imports in scene_data_provider.py, schemas_actuators.py, terrains/utils.py (removed deferred imports)
  • clone_in_fabric docstring updated to mark as deprecated
  • Test sensor files pass env_ids/positions/cfg_rows to ClonePlan constructors

Previous findings status:

  • 🟡 Finding #2 (silent queue skipping) — unchanged, advisory
  • 🟡 Finding #5 (SimulationContext guard in replicate()) — unchanged, advisory

New observation:

  • 🟡 The generate_synthetic_gaussian_asset.py test script manually constructs a ClonePlan.from_env_0() + cloner.replicate() after the scene's ReplicateSession has already exited, because the camera is constructed late. This "Path B" pattern works but introduces a coupling to the scene's internal env layout. The inline comment documents this clearly, so it's acceptable.

Verdict: This commit delivers the complete migration away from InteractiveScene.clone_environments(). The architecture is clean, the lazy-import strategy prevents forbidden-import regressions, and the test coverage is thorough. Ready for merge.

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label May 25, 2026
@ooctipus ooctipus force-pushed the feature/clone_plan_new_representation branch from fb61d98 to 090cdcc Compare May 26, 2026 21:59
@isaaclab-review-bot
Copy link
Copy Markdown

Update (090cdcc):

Summary of Incremental Changes

This update contains significant refactoring across multiple files:

1. ClonePlan Extended (clone_plan.py):

  • Added env_ids, positions, and cfg_rows fields
  • New from_env_0() class method for building single-source plans with auto-populated cfg_rows

2. CloneCfg Simplified (cloner_cfg.py):

  • Removed clone_usd, clone_physics, physics_clone_fn, clone_in_fabric — these are now handled by the queued backend contexts
  • Retained only clone_strategy, device, and clone_regex

3. make_clone_plan Rewritten (cloner_utils.py):

  • Now accepts cfgs: Iterable[Any] instead of pre-flattened sources/destinations
  • Auto-expands MultiAssetSpawnerCfg/MultiUsdFileCfg into per-variant rows
  • Mutates each cfg's spawn_path/spawn_paths directly
  • Returns a self-contained ClonePlan with cfg_rows populated

4. New ReplicateSession Context Manager (replicate_session.py):

  • Folds make_clone_plan + replicate into a with block
  • Asset constructors inside the block register to REPLICATION_QUEUE
  • __exit__ drains and dispatches all queued backends

5. New UsdReplicateContext (usd.py):

  • Queue-based USD replication with replicate_priority = 100
  • queue_usd_replication(cfg) helper for asset constructors

6. InteractiveScene Simplified (interactive_scene.py):

  • Removed clone_environments() method
  • Removed env_ns, env_regex_ns properties
  • Now uses ReplicateSession in __init__
  • env_origins now pulls from the published ClonePlan.positions

7. Backend Modules Updated:

  • isaaclab_physx: Added PhysxReplicateContext, queue_physx_replication()
  • isaaclab_newton: Added NewtonReplicateContext, queue_newton_physics_replication()
  • isaaclab_ovphysx: Added OvPhysxReplicateContext, queue_ovphysx_replication()
  • Each asset constructor now calls queue_usd_replication(cfg) + queue_<backend>_replication(cfg)

8. Direct Envs Updated (isaaclab_tasks):

  • All _setup_scene() methods now use:
    plan = cloner.ClonePlan.from_env_0(src, dest, num_envs, device, positions)
    cloner.replicate(plan, stage=scene.stage)

9. Test Coverage Expanded:

  • New tests for UsdReplicateContext, PhysxReplicateContext
  • Tests for make_clone_plan homogeneous/heterogeneous paths
  • Tests for ClonePlan.from_env_0 cfg_rows population
  • Tests for replicate() dispatch ordering, deduplication, and failure handling
  • Tests for ReplicateSession cleanup on exception

Assessment

No new issues introduced. The changes are consistent with the original PR design:

  1. Queue-then-drain pattern fully implemented across all backends
  2. Backend isolation achieved — each <Backend>ReplicateContext owns its dispatch logic
  3. Backward compatibility maintained via legacy free-function wrappers (physx_replicate, newton_physics_replicate, etc.)
  4. Test coverage is comprehensive for the new primitives

The removal of clone_environments() and the shift to ReplicateSession is a clean simplification. Direct envs using ClonePlan.from_env_0() + replicate() have a straightforward migration path.

hundreds, sometimes tens of thousands per GPU — and authoring each of those envs
by hand would be hopelessly slow. Cloning is Isaac Lab's answer: you author a
small representative scene under ``/World/envs/env_n`` and the cloner expands it
across the rest of the env population for you, optionally with per-env variation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding the wording "heterogenous" when discussing per-env cloning variations (and maybe some details on how that work?)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont know, I think I want to try avoid using the world heterogenous/homogeneous. Newton doesn't use it at all

The plan is stage-agnostic by design — the same instance can be replayed against a
different stage, inspected by tooling, or serialized.

When every env is a copy of env_0:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the terminology "homogenous" here and other places where possible.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the same reason as mentioned above, but happy to be convinced otherwise

``clone_mask[i, j]`` is ``True`` when environment ``j`` should receive source row ``i``.
The same plan can be passed to USD replication, physics replication, and scene-data
providers.
When envs differ — say a cartpole in every env plus a 2-variant obstacle (box into
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads a little bit confusing. Maybe re-write to something like:
"We can build heterogenous envs through ..., as an example we can build clone a cartpole environment that has two variants, half the environments use a box obstacle, the other half use sphere"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good suggestion Ill try to incorporate that.

in the same ``cloner.replicate(plan, stage=...)`` call, so the choice between
them is purely about ergonomics:

* The first wraps both phases in a context manager and is what
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems duplicated since below is the breakdown for all three, we can just remove these bullet points and maybe list the 3 replication methods, and then jump into below.

of env_0. Reach for it in :class:`~isaaclab.envs.DirectRLEnv` and standalone
scripts that hand-build the env-0 prototype prim by prim.

``ReplicateSession``
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use 1. 2. 3. for each of the methods, so that users can follow easily


* :doc:`multi_asset_spawning` -- configuring multi-asset and multi-USD spawners.
* :doc:`optimize_stage_creation` -- Fabric cloning and stage-in-memory optimizations.
Newton isolates envs through its world system and does not need this pass.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newton envs are inherently isolated, they don't truly live in the same world, since state is batched.

device: Torch device for the mask and env id buffers.
positions: Optional per-env world positions [m], shape ``[num_clones, 3]``.
"""
from .replicate_session import REPLICATION_QUEUE # noqa: PLC0415
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not import at top?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some ai sloppyness...

positions=plan.positions,
)

for ctx in sorted(backend_ctxs.values(), key=lambda c: getattr(c, "replicate_priority", 0)):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For env cloning, why is the sorting important?

Copy link
Copy Markdown
Collaborator Author

@ooctipus ooctipus May 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the case there is usd_cloning, its usually cloned at last to avoid other engine reads the entire scene.

)
self.cloner_cfg = cloner.CloneCfg(device=self.device)
env_root = self.cloner_cfg.clone_regex.rsplit("/", 1)[0]
self.env_prim_paths = [f"{env_root}/env_{i}" for i in range(self.cfg.num_envs)]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still needed? Does not seem used anymore since clone plan uses the {} pattern

spawn_ground_plane(prim_path="/World/ground", cfg=GroundPlaneCfg())
# clone and replicate
self.scene.clone_environments(copy_from_source=False)
src, dest = "/World/envs/env_0", "/World/envs/env_{}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we create a helper called cloner.homogenous_cloning_from_env_0(...) that makes these 4 lines into 1 line? Or even just cloner.homogenous_cloning

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still want to make string explicit enough that user sees key information from the, I have implemented cloner.homogenous_cloning_from_env_0(...), but ditched this option because it feels a bit too magical.

@ooctipus ooctipus force-pushed the feature/clone_plan_new_representation branch 5 times, most recently from 322ec99 to 28b9473 Compare June 3, 2026 10:08
@ooctipus ooctipus force-pushed the feature/clone_plan_new_representation branch from 463a05a to 78f998b Compare June 3, 2026 10:27
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Isaac Lab Review Bot — Update Review

SHA: 6f34c5acdbca989859a276e9339f51f23fe463b3
Previous SHA: 463a05aeb77f01c37831b4847d89d46eec596a88


Changes Since Last Review

Upstream changes absorbed:

  • #5916: Warp-first experimental envs lazy export + cfg implementation split — splits env config classes (*EnvCfg) into separate *_cfg.py modules to avoid eager imports of backend-dependent types (Articulation, InteractiveScene, ContactSensor, action terms) at config-load time. The runtime env classes import the cfg at use time. This fixes the crash where loading a warp task's env config before SimulationApp was launched would fail on forbidden imports.
  • #5929: Fix clone-plan source resolution for nested destination templates — resolve_clone_plan_source() now correctly handles paths under nested templates (e.g., /World/envs/env_.*/Robot/ee_link/Camera) by selecting the most specific (longest-matching) template.

PR-specific changes:

  • 78f998ba — fix replicate logic: Fixed NewtonReplicateContext.replicate() to propagate world_xforms to NewtonManager._world_xforms. The _build_newton_builder_from_mapping() function now correctly returns a 4-tuple including world_xforms, and the caller stores this on NewtonManager when commit_to_manager=True. This ensures FrameView can place non-physics frames (cameras) in the correct per-env locations.
  • 6f34c5ac — lint: Import sorting in test file (cosmetic).

Assessment

The Newton replication fix (78f998ba) is critical — without it, cameras/frames under Newton-managed articulations would be placed incorrectly. The previous 463a05ae commit introduced world_xforms computation but failed to propagate it to NewtonManager._world_xforms. This commit completes that work:

# Before (463a05ae): world_xforms computed but lost
builder, stage_info, site_index_map = _build_newton_builder_from_mapping(...)

# After (78f998ba): world_xforms stored on manager
builder, stage_info, site_index_map, world_xforms = _build_newton_builder_from_mapping(...)
if self.commit_to_manager:
    NewtonManager._world_xforms = world_xforms

The fix is clean and follows the established pattern.


Previous Findings Status

Finding Status
#1 Performance (fabric notices) ✅ Addressed
#2 Silent queue skipping 🟡 Advisory — unchanged
#3 from_env_0 ordering ✅ Addressed
#4 _collect_asset_cfgs flow 🟢 Clear
#5 SimulationContext guard 🟡 Advisory — unchanged
#6 Test coverage 🟢 Good

No new issues introduced. The PR remains ready for merge with the same advisory findings from the initial review.


Verdict: ✅ Ready for merge


📝 Update — 3579870e (2026-06-03)

New commit: Makes ClonePlan fields (env_ids, positions, cfg_rows) optional with sensible defaults (None, None, field(default_factory=dict)).

Rationale: Allows lightweight ClonePlan construction for callers that only need iter_clone_plan_matches or resolve_clone_plan_source without providing the full set of replication fields. The docstring correctly documents that env_ids is still required for replicate().

Assessment: ✅ Clean change. Uses field(default_factory=dict) correctly for the mutable cfg_rows default. No new issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request infrastructure isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team isaac-sim Related to Isaac Sim team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants