Skip to content

feat(schemas): articulation-root schema-fragment API (additive) - #7

Draft
vidurv-nvidia wants to merge 146 commits into
vidurv/schema-frag-frameworkfrom
vidurv/schema-frag-articulation
Draft

feat(schemas): articulation-root schema-fragment API (additive)#7
vidurv-nvidia wants to merge 146 commits into
vidurv/schema-frag-frameworkfrom
vidurv/schema-frag-articulation

Conversation

@vidurv-nvidia

@vidurv-nvidia vidurv-nvidia commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Description

Additive articulation-root fragment family

  • physx: PhysxArticulationCfg (physxArticulation:*: solver iters, sleep/stabilization, enabled_self_collisions, articulation_enabled)
  • newton: NewtonArticulationCfg (newton:selfCollisionEnabled)
  • apply_articulation_root_properties(...): anchor ArticulationRootAPI presence-gated; fix_root_link is a spawner-level flag (not a fragment field).

⚠️ Review focus: fix_root_link fixed-joint logic was copied from the legacy writer; the create-new-joint branch is not unit-tested (needs Isaac Sim). New path is single-prim (not @apply_nested like legacy). Status: authored, ruff clean, sim verification pending.

Fixes # (N/A — part of the staged physics schema-fragment refactor; no tracked public issue)

Type of change

  • New feature (non-breaking change which adds functionality)

Screenshots

N/A — no user-facing visual changes.

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks (ruff + ruff-format) on the changed files
  • I have made corresponding changes to the documentation (the public API reference is auto-generated via ./isaaclab.sh -d; not separately authored)
  • My changes generate no new warnings
  • I have added tests that prove my feature works
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package
  • I have added my name to CONTRIBUTORS.md

huidongc and others added 21 commits June 24, 2026 09:18
…`` (isaac-sim#6242)

# Description

Fixed the `newton[sim]` dependency pin to use Newton commit
`79e95bf5571d70a0a46c8eaedc80644531d27368`, including the
`RenderContext` triangle-mesh construction fix from
[newton-physics/newton#3199](newton-physics/newton#3199).


## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
Bumped packages:
- isaaclab: 7.0.5 → 7.1.0
- isaaclab_newton: 1.0.4 → 1.1.0
- isaaclab_ov: 0.4.6 → 0.5.0
- isaaclab_physx: 2.0.2 → 2.1.0
- isaaclab_tasks: 8.0.4 → 8.0.5
- isaaclab_visualizers: 1.0.1 → 1.0.2
…cartpole, dexsuite_kuka, and shadow_hand with test coverage (isaac-sim#6101)

# Description

Add distance_to_camera and distance_to_image_plane camera presets to
cartpole, dexsuite_kuka, and shadow_hand with test coverage.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
…isaac-sim#6238)

# Description

Add ISAAC_LAB_ENABLE_ISAAC_RTX_PER_ENV_SCENE_PARTITION environment
variable to opt in to authoring primvars:omni:scenePartition and
omni:scenePartition on the USD stage. Previously this was always on; now
it is off by default. This is to address an OOM in one of our IsaacSim
RTX benchmark suites related to primvar inheritance of the scene
partition attributes while the root cause/fix is under investigation.

## Testing

We have a separate issue which only visualizes env_0 in kit when scene
partitioning is enabled... so I tested with:
```bash
./isaaclab.sh train --rl_library rsl_rl \
    --task Isaac-Lift-KukaAllegro-Camera \
    presets=newton_mjwarp,isaacsim_rtx_renderer,rgb64,single_camera \
    --seed 42 \
    --num_envs 4 \
    --max_iterations 1000 \
    --visualizer kit
```
... and it shows all the envs - checked all the env Xforms and camera
and they don't have the scenePartition attribute/primvars:
<img width="3813" height="2072" alt="image"
src="https://github.com/user-attachments/assets/ea22b566-db95-498b-aa5d-445c1c2b0c8b"
/>

Conversely, tested with the environment variable enabled:
```bash
ISAAC_LAB_ENABLE_ISAAC_RTX_PER_ENV_SCENE_PARTITION=1 ./isaaclab.sh train --rl_library rsl_rl \
    --task Isaac-Lift-KukaAllegro-Camera \
    presets=newton_mjwarp,isaacsim_rtx_renderer,rgb64,single_camera \
    --seed 42 \
    --num_envs 4 \
    --max_iterations 1000 \
    --visualizer kit
```

And we get the old behavior of only env_0 showing.

@fatimaanes keen to hear if this helps mitigate the benchmark OOM you
are seeing.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
# Description

## Summary (PR 1 of 2 — additive, no behavior change)

Introduces single-namespace schema **fragments** so a prim can carry
rigid-body properties from multiple USD namespaces at once (`physics:`,
`physxRigidBody:`, `mjc:`), with core naming no backend. **Purely
additive** — existing cfgs and the deprecated `RigidBodyPropertiesCfg`
class are untouched.

- **core:** `SchemaFragment`, `RigidBodyFragment`,
`UsdPhysicsRigidBodyCfg`; `apply_namespaced` (generic per-fragment
writer) and `apply_rigid_body_properties` (applies a fragment list with
`UsdPhysics.RigidBodyAPI` as the implicit anchor).
- **spawner:** `rigid_props` accepts a fragment list; legacy single cfgs
keep working via a transition bridge
(shapes/meshes/from_files/mesh_converter).
- **backends:** `PhysxRigidBodyCfg` (physx), `MujocoRigidBodyCfg`
(newton).
- new `test_schema_fragments.py` + exports.

**PR 2** (stacked) flips `RigidBodyPropertiesCfg` to a deprecation
factory and migrates all call sites: #4 (review
after this lands).

## Test Plan
- [x] `test_schema_fragments.py` — 7 passed
- [x] pre-commit clean · `./isaaclab.sh -d` docs build clean
- [ ] CI

First slice of the staged physics schema-cfg refactor (collision / mass
/ joint-drive / … follow later). Draft for review of the fragment API
shape.


## Type of change

- New feature (non-breaking change which adds functionality)

## Screenshots

N/A — no user-facing visual changes.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the pre-commit checks (`ruff` + `ruff-format`) on the
changed files
- [ ] I have made corresponding changes to the documentation (the public
API reference is auto-generated via `./isaaclab.sh -d`; not separately
authored)
- [x] My changes generate no new warnings
- [x] I have added tests that prove my feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [ ] I have added my name to `CONTRIBUTORS.md`

---------

Co-authored-by: ooctipus <zhengyuz@nvidia.com>
…ttp:// asset URLs in saved USDs (isaac-sim#6255)

# Description

Preserve URI asset paths in save_stage

Avoid resolving asset paths with explicit URI schemes as filesystem
paths
during stage save path remapping. This keeps remote assets such as
DomeLight texture URLs from being rewritten into invalid relative paths.

Fixes # ([OMPE-96696](https://jirasw.nvidia.com/browse/OMPE-96696))

## Type of change


- Bug fix (non-breaking change which fixes an issue)

## Screenshots

Please attach before and after screenshots of the change if applicable.



## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
# Description

<!--
Thank you for your interest in sending a pull request. Please make sure
to check the contribution guidelines.

Link:
https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html

💡 Please try to keep PRs small and focused. Large PRs are harder to
review and merge.
-->

Please include a summary of the change and which issue is fixed. Please
also include relevant motivation and context.
List any dependencies that are required for this change.

Fixes # (issue)

<!-- As a practice, it is recommended to open an issue to have
discussions on the proposed pull request.
This makes it easier for the community to keep track of what is being
developed or added, and if a given feature
is demanded by more than one party. -->

## Type of change

<!-- As you go through the list, delete the ones that are not
applicable. -->

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (existing functionality will not work without user
modification)
- Documentation update

## Screenshots

Please attach before and after screenshots of the change if applicable.

<!--
Example:

| Before | After |
| ------ | ----- |
| _gif/png before_ | _gif/png after_ |

To upload images to a PR -- simply drag and drop an image while in edit
mode and it should upload the image directly. You can then paste that
source into the above before/after sections.
-->

## Checklist

- [ ] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
Bumped packages:
- isaaclab: 7.1.0 → 7.2.0
- isaaclab_newton: 1.1.0 → 1.2.0
- isaaclab_ov: 0.5.0 → 0.5.1
- isaaclab_physx: 2.1.0 → 2.2.0
- isaaclab_tasks: 8.0.5 → 8.0.6
- isaaclab_visualizers: 1.0.2 → 1.0.3
…ndings (view series, part 1) (isaac-sim#6224)

> **📦 Part 1 of a 5-part series** adding an OvPhysX binding view and
migrating the assets onto it:
> 1. **This PR** — add `OvPhysxView` (the API) + tests.
> 2. Migrate the OvPhysX **Articulation** to `root_view`.
> 3. Migrate the **RigidObject**.
> 4. Migrate the **RigidObjectCollection** (uses the fused
`prim_paths`+`key_aliases` path).
> 5. Migrate the **sensors** (pose tracking; contact forces use a
separate `ContactBinding` API and may not fully adopt the view).
>
> Parts 2–5 each depend only on this PR and can be reviewed
independently.

---

# Description

Adds **`OvPhysxView`**, a string-keyed binding-management layer over the
OVPhysX tensor bindings, in `isaaclab_ovphysx`.

**Why.** OVPhysX is the odd backend out: it exposes physics attributes
as a loose `dict[TensorType, TensorBinding]` with **no view object**,
whereas Newton has `selection.ArticulationView` and PhysX has typed
tensor views. Today callers must hold the right `TensorType` enum
member, manage a destination buffer, and create bindings against a USD
glob — and the `create_tensor_binding` calls are scattered across the
asset classes behind a private `_get_binding`. `OvPhysxView` gives
OVPhysX a single, discoverable surface as pleasant as Newton's selection
API, and one owner of binding creation/caching that the asset/data
classes can delegate to. It is the narrow, independently-useful slice
carved out of the (shelved) cross-backend `get_property`/`set_property`
effort; the full rationale and decision log live in
`docs/superpowers/specs/2026-06-17-ovphysx-view-design.md`.

**What it provides**
- String-keyed access by lowercased `TensorType` name (auto-derived from
the wheel enum — no hand-maintained table); a `TensorType` member is
also accepted.
- `get_attribute(name, out=)` — fresh-allocates a **typed** array
(`wp.transformf` for poses, `wp.spatial_vectorf` for velocities, flat
`float32` otherwise; via a maintained `_ATTR_DTYPE` map), no aliasing;
**`read_into(name, dst)`** — zero-copy fill of a caller-owned, possibly
structured-dtype buffer (`wp.transformf`, …) via a `float32` reinterpret
view that is **cached per destination buffer** so the wheel's
object-identity read cache stays warm even when callers hand a
structured buffer each step; `set_attribute(name, values,
indices=/mask=)` (structured sources reinterpreted); and a raw
`binding_for(name)` accessor for adoption.
- The fused multi-prim form (`prim_paths=[...]` + `key_aliases`) so
`RigidObjectCollection` can use it.
- Discoverability (`attribute_names`, `available_attributes`,
`has_attribute`), metadata passthrough, and a nested error hierarchy
(`UnknownAttribute` / `ReadOnlyAttribute` / `AttributeUnavailable` /
`ShapeMismatch` / `DeviceMismatch`).

**Device policy:** no implicit CPU↔GPU conversion — CPU-resident
property types are read/written on CPU, and a buffer on the wrong device
raises `DeviceMismatch` rather than being staged.

**Scope / status:** this PR adds the view plus 48 mock-based unit tests
(no live sim). The asset adoption that replaces
`_get_binding`/`_binding_read`/`_binding_write` lives in the follow-up
PRs (Articulation isaac-sim#6225, RigidObject isaac-sim#6226), which dogfood the view
against a live sim on CPU and GPU and have fed fixes back here (e.g.
`try_binding_for`, the read-view cache, typed `get_attribute`).

Fixes # — N/A (internal design tracking; surviving slice of the shelved
cross-backend view effort).

## Type of change

- New feature (non-breaking change which adds functionality)

## Screenshots

N/A — no user-facing visual change.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation <!-- design
note updated separately
(docs/superpowers/specs/2026-06-17-ovphysx-view-design.md); no rendered
API-doc change in this PR yet -->
- [x] My changes generate no new warnings
- [x] I have added tests that prove my feature works
(`test/sim/test_ovphysx_view.py`, 48 tests)
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package (do **not** edit
`CHANGELOG.rst` or bump `extension.toml` — CI handles that)
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
…for normals for all renderers (isaac-sim#6261)

# Description

- Added support for the "normals" data type in the ovrtx renderer
integration
- Added render correctness test coverage for "normals" across applicable
physics/renderer combinations

## Screenshots

See new golden images

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
…sim#6246)

# Description

Introduce a new general "RTX" preset, where a user does not need to
understand the differences and caveats between Isaac Sim RTX vs. ovrtx.
As a user, they can specify presets=rtx, and we will have logic to
determine whether Isaac Sim RTX or ovrtx should be used. Users can still
explicitly specify presets=ovrtx or presets=isaacsim_rtx, and we will
produce an error if any invalid combinations are provided (e.g. ovrtx +
isaac sim).

If a user specifies presets=rtx, runs physx from isaac sim or uses the
kit visualizer, we will use isaac sim RTX.

If a user specifies presets=rtx, does not launch any isaac sim instances
(e.g. no kit visualizer and no isaac sim physx), then we can use ovrtx
(or whichever option is more performant)

Fixes OMPE-92354

<!-- As a practice, it is recommended to open an issue to have
discussions on the proposed pull request.
This makes it easier for the community to keep track of what is being
developed or added, and if a given feature
is demanded by more than one party. -->

## Type of change

- New feature (non-breaking change which adds functionality)
- Documentation update

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->

---------

Signed-off-by: Matthew Taylor <mataylor@nvidia.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
# Description

Adds the **mass** schema-fragment API. Unlike the other families, mass
has **no backend split** — it is a single core fragment.

- `MassFragment` marker + `MassCfg` (`physics:mass` / `physics:density`;
`UsdPhysics.MassAPI` anchor) in `isaaclab`.
- `apply_mass_properties` family writer (applies the `MassAPI` anchor,
then dispatches each fragment via its `func`).
- The spawner `mass_props` slot now also accepts a `MassCfg` /
`list[MassCfg]`.

This PR is purely **additive** and self-contained: it builds only on the
single-namespace schema-fragment base (`SchemaFragment` +
`apply_namespaced`) already in `develop`, existing call sites are
untouched (a transition bridge routes legacy single cfgs to the existing
`define_`/`modify_` writers), and it does **not** depend on any other
open PR.

## Type of change

- New feature (non-breaking change which adds functionality)

## Screenshots

N/A — non-visual API change.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package (do **not** edit
`CHANGELOG.rst` or bump `extension.toml` — CI handles that)
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
# Description

Adds the **collision** schema-fragment API: a prim can carry collision
properties from multiple USD namespaces (`UsdPhysics` + PhysX + Newton)
at once, and core names no backend.

- `CollisionFragment` marker + `UsdPhysicsCollisionCfg`
(`physics:collisionEnabled`; `UsdPhysics.CollisionAPI` anchor) in
`isaaclab`.
- `PhysxCollisionCfg` (`physxCollision:*` — `contact_offset`,
`rest_offset`, `torsional_patch_radius`, `min_torsional_patch_radius`)
in `isaaclab_physx`.
- `NewtonCollisionCfg` (`newton:*`) in `isaaclab_newton`.
- `apply_collision_properties` family writer (applies the anchor, then
dispatches each fragment via its `func`; core imports no backend).
- The spawner `collision_props` slot now also accepts a
`CollisionFragment` / `list[CollisionFragment]`.

This PR is purely **additive** and self-contained: it builds only on the
single-namespace schema-fragment base (`SchemaFragment` +
`apply_namespaced`) already in `develop`, existing call sites are
untouched (a transition bridge routes legacy single cfgs to the existing
`define_`/`modify_` writers), and it does **not** depend on any other
open PR.

## Type of change

- New feature (non-breaking change which adds functionality)

## Screenshots

N/A — non-visual API change.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package (do **not** edit
`CHANGELOG.rst` or bump `extension.toml` — CI handles that)
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
Bumped packages:
- isaaclab: 7.2.0 → 7.3.0
- isaaclab_newton: 1.2.0 → 1.3.0
- isaaclab_ov: 0.5.1 → 0.5.2
- isaaclab_ovphysx: 3.2.0 → 4.0.0
- isaaclab_physx: 2.2.0 → 2.3.0
- isaaclab_tasks: 8.0.6 → 8.0.7
# Description

Adds so101 stack env for teleop + imitation learning

Fixes # (issue)

## Type of change

- New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

---------

Co-authored-by: Rafael Wiltz <rwiltz@nvidia.com>
apply_articulation_root_properties applied UsdPhysics.ArticulationRootAPI
unconditionally on the input prim. USD assets author the root on a child
prim (the root link / fixed joint), so this stamped a SECOND root on the
top prim and wrote the fragment properties + fix_root_link logic to the
wrong prim -- a duplicate root that also violates the single-root asset
requirement.

Descend the subtree to the existing root and tune it in place (matching
the legacy @apply_nested modify_articulation_root_properties writer); only
define a fresh root on the input prim when the subtree has none (primitive
or programmatic spawns). Fragments and the fix_root_link reparent logic
now target the resolved root. Also guard an invalid input prim path.

Add a regression test covering the child-root case (verified to fail
before the fix).
Replace the hand-rolled subtree BFS with the existing
get_first_matching_child_prim query helper (predicate =
HasAPI(ArticulationRootAPI)). Same find-or-define behavior; the helper
also validates the path, so the bespoke helper and the separate IsValid
guard are dropped. Pass traverse_instance_prims=False to keep parity with
the legacy @apply_nested writer, which does not author through instances.
The function docstring already explains the find-or-define rationale, so
collapse the inline comments to terse intent. The fix_root_link block is
left untouched -- it is reproduced verbatim from the legacy writer.
The create-new-joint branch of apply_articulation_root_properties was
sim-unexercised (only the toggle-existing-joint case was tested). Add two
tests: (1) fix_root_link=True with no existing joint creates a fixed joint
and reparents the articulation root from the rigid-body root link to its
parent; (2) fix_root_link=True on a non-rigid-body root raises
NotImplementedError.
@vidurv-nvidia
vidurv-nvidia force-pushed the vidurv/schema-frag-articulation branch from 35e87e6 to 6892d5d Compare June 26, 2026 07:42
@github-actions github-actions Bot added documentation Improvements or additions to documentation asset infrastructure labels Jun 26, 2026
AntoineRichard and others added 4 commits June 26, 2026 09:50
…saac-sim#6225)

> ### 🔗 Stacked on top of isaac-sim#6224 (Part 1 — `OvPhysxView`)
> This PR depends on **isaac-sim#6224** and is stacked on top of it. It targets
> `develop`, but because isaac-sim#6224 has not merged yet, the diff below
includes the
> Part 1 `OvPhysxView` commits **as well as** the Part 2 migration.
**Please
> review isaac-sim#6224 first.** Once isaac-sim#6224 merges, this branch will be rebased
onto
> `develop` and the diff will shrink to the articulation migration only.

# Description

Part 2 of the OVPhysX view-migration series. It migrates the OVPhysX
**`Articulation`** onto the new `OvPhysxView` binding manager introduced
in
**isaac-sim#6224 (Part 1)**.

The goal of the series is to *dogfood* `OvPhysxView` on the real asset
classes
to surface weaknesses before the rigid-object/collection/sensor
migrations, and
to consolidate the scattered `create_tensor_binding` / `binding.read` /
`binding.write` calls behind one managed surface.

### What changed

* `Articulation._initialize_impl` now builds a single
`OvPhysxView(physx, pattern, device)` and populates it via
`try_binding_for`
(best-effort: tensor types that do not apply to these prims are skipped,
the
asset still raises if *no* binding could be created). All binding
creation,
  caching, and the CPU/GPU device policy now live in the view.
* `ArticulationData` is constructed from the view; its counts come from
the
view metadata, and both `_get_binding` helpers (asset + data container)
  delegate to `OvPhysxView.try_binding_for`.
* **Every write now goes through `root_view.set_attribute(...)`**
instead of
calling `binding.write` on a binding obtained from the view — the ~70
property
/ state / target / wrench / tendon writes, including the per-step
actuation
path. This brings the view's read-only, device, dtype, and contiguity
guards
  to the asset write path, which previously bypassed them.
* **Every read now goes through `root_view.read_into(...)`.**
`ArticulationData`
drops its bespoke `_get_read_view` reinterpret cache; the view now
caches the
`float32` reinterpret per destination buffer (keeping the wheel's read
cache
  warm) and derives the structured layout from the binding shape, so the
  transform / spatial-vector / scalar read helpers collapse to one
  implementation. CPU-only reads keep their pinned-host staging.
* `Articulation.root_view` now returns the `OvPhysxView` instead of a
raw
`dict[TensorType, TensorBinding]` (**breaking** — see migration note
below).
* The articulation tests route through the new API
  (`root_view.get_attribute(...)`, `root_view.try_binding_for(...)`).

### Breaking change / migration

`Articulation.root_view` returns an `OvPhysxView`, not a dict:

* `root_view[tensor_type]` → `root_view.try_binding_for(tensor_type)`
* `tensor_type in root_view` (availability) →
`root_view.try_binding_for(tensor_type) is not None`
* full-tensor read → `root_view.get_attribute(tensor_type)`

### Findings surfaced (the point of the exercise)

* **CPU-only property writes work through `set_attribute`.**
mass/COM/inertia/DOF
limits/stiffness/… are CPU-resident even on a GPU sim, and
`set_attribute`
refuses to stage CPU↔GPU. This is fine because the asset *already*
pre-stages
those to pinned CPU buffers, so the source is on the binding's native
(CPU)
device and the no-stage policy is satisfied with no change. (An initial
assumption that the device policy would block these turned out to be
wrong —
  verified by the green `cuda:0` run.)
* `read_into` allocates a fresh `float32` reinterpret view per call,
which would
defeat the wheel binding's internal read cache that the data container
caches
by `(tensor_type, ptr)`; hot-path reads were kept on the cached-view
path.
* Per-step writes re-resolve the binding through `set_attribute` (a dict
lookup
+ cheap guards) rather than the previously cached binding handle; the
cost is
negligible because the pre-built `float32` write-view passes through the
reinterpret unchanged. A "bound writer" handle on the view would remove
even
  that lookup — a possible Part 1 follow-up.
* The view rejects 0-count bindings (stricter than the old loop, which
could
  store a phantom binding) — a correctness improvement.

## Type of change

- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] This change requires a documentation update

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have added tests that prove my fix is effective or that my
feature works (articulation tests route through the new API)
- [x] I have updated the changelog
(`source/isaaclab_ovphysx/changelog.d/`)
- [ ] I have updated the documentation accordingly
- [x] I have added my changes to the right `changelog.d` fragment(s)

### Testing

Run kitless; cpu and cuda must be separate invocations (process-global
device lock):

```
101 passed, 4 xfailed   # -k cpu
101 passed, 4 xfailed   # -k cuda
```
## Summary
- cache PhysX body-frame COM offsets as model properties instead of
re-reading them every sim timestamp
- invalidate all PhysX COM-offset-dependent cached buffers after
set_coms_index writes
- apply the same model-property cache policy and dependent invalidation
to OVPhysX articulation COM offsets
- add PhysX and OVPhysX regression tests for timestamp reuse, setter
cache updates, joint writes, partial writes, and dependent invalidation
- add changelog fragments for the touched packages

This intentionally keeps the scope to the cached-property fix; it does
not include PR isaac-sim#6260's local-only composition fast path.

## Profiling
- G1 PhysX, 4096 env quick profile before the dependent-invalidation
follow-up: compose_to_body_frame dropped from ~7.25 ms to ~0.24 ms
- after the cache fix, normal step time was 69.20 ms vs 68.76 ms with
compose skipped in the same quick profile
- full-run wall timings were noisy on the laptop/GPU, likely thermal
throttling, but no longer showed the pre-fix COM-read cliff

## Test Plan
- python3 tools/changelog/cli.py check develop
- pre-commit run --from-ref origin/develop --to-ref HEAD
- git diff --check origin/develop...HEAD
- ./isaaclab.sh -p -m py_compile
source/isaaclab_physx/isaaclab_physx/assets/articulation/articulation_data.py
source/isaaclab_physx/isaaclab_physx/assets/articulation/articulation.py
source/isaaclab_ovphysx/isaaclab_ovphysx/assets/articulation/articulation_data.py
source/isaaclab_ovphysx/isaaclab_ovphysx/assets/articulation/articulation.py
source/isaaclab/test/assets/test_articulation_iface.py
source/isaaclab_ovphysx/test/assets/test_articulation.py
- ./isaaclab.sh -p -m pytest
source/isaaclab/test/assets/test_articulation_iface.py -k
'physx_set_coms_index_invalidates_body_com_pose_b_dependents or
physx_body_com_pose_b_is_cached_across_sim_timestamps or
physx_set_coms_index_updates_body_com_pose_b_cache or
physx_joint_position_write_preserves_body_com_pose_b_cache or
physx_partial_set_coms_index_initializes_cold_body_com_pose_b_cache' -q
- ./isaaclab.sh -p -m pytest
source/isaaclab_ovphysx/test/assets/test_articulation.py -k
'body_com_pose_b_cache_and_set_coms_invalidation' -q
…m#6247)

# Description

All other tests are treated as a part of the full suite and do not get
run on push only the following:


[rendering-correctness](https://github.com/isaac-sim/IsaacLab/actions/runs/27923944023/job/82630331274#logs)
(~20m)

[rendering-correctness-kitless](https://github.com/isaac-sim/IsaacLab/actions/runs/27923944023/job/82630331226#logs)
(~20m)


<!-- As a practice, it is recommended to open an issue to have
discussions on the proposed pull request.
This makes it easier for the community to keep track of what is being
developed or added, and if a given feature
is demanded by more than one party. -->

## Type of change

- New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
# Description

Adds the **tendons** schema-fragment API.

- `FixedTendonFragment` / `SpatialTendonFragment` markers +
`PhysxFixedTendonCfg` / `PhysxSpatialTendonCfg` in `isaaclab_physx`.
These are data carriers that override `func` to the existing
multi-instance `modify_fixed_tendon_properties` /
`modify_spatial_tendon_properties` writers (tune-not-apply), since
tendon attributes live under multi-instance `PhysxTendonAxisRootAPI:*`
schemas that the generic `apply_namespaced` writer cannot handle.
- The spawner `fixed_tendons_props` / `spatial_tendons_props` slots now
also accept fragment lists.

This PR is purely **additive** and self-contained: it builds only on the
single-namespace schema-fragment base (`SchemaFragment` +
`apply_namespaced`) already in `develop`, existing call sites are
untouched (a transition bridge routes legacy single cfgs to the existing
`define_`/`modify_` writers), and it does **not** depend on any other
open PR.

## Type of change

- New feature (non-breaking change which adds functionality)

## Screenshots

N/A — non-visual API change.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package (do **not** edit
`CHANGELOG.rst` or bump `extension.toml` — CI handles that)
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
AntoineRichard and others added 28 commits July 8, 2026 16:53
# Description

Clears per-world solver-internal buffers on env reset via Newton's
solver-reset API — closing the NaN-recovery gap discussed in
[newton-physics/newton#1266](newton-physics/newton#1266).

Without this, a world that produces a NaN in one solve warm-starts the
next iteration from that NaN (MJWarp leaves `mj_checkPos` /
`mj_checkVel` / `mj_checkAcc` as TODOs, so nothing in the solver cleans
it up). IsaacLab's standard reset rewrites `joint_q` / `joint_qd` /
`body_q` but never touches MJWarp-internal `qacc_warmstart`, applied
forces, or activations — the world is permanently dead.

## What changed

* New `NewtonManager._reset_solver_internals(world_mask)` hook, invoked
at **both** boundaries that consume the accumulated reset masks,
immediately before the masks are zeroed: the top of `step()` and
`forward()`. The `forward()` call site matters because data reads may
trigger `forward()` between an env reset and the next `step()`, which
would otherwise consume the mask before the solver internals were ever
cleared.
* The **base implementation is solver-agnostic**: it forwards to
`SolverBase.reset(state, world_mask=..., flags=0)` — the upstream API
from
[newton-physics/newton#2657](newton-physics/newton#2657),
available at the Newton commit `develop` already pins. `flags=0` clears
only solver-owned buffers and preserves the joint state IsaacLab
authored during the reset. `SolverBase.reset` is a documented no-op, so
solvers that do not implement it (VBD, XPBD, Featherstone, MPM today)
are unaffected — and any solver that adds a `reset()` upstream is
covered automatically with no IsaacLab change.
* `NewtonMJWarpManager` specializes the hook only to gate the CPU-MuJoCo
path (`use_mujoco_cpu=True`): its reset branch owns a single global
`MjData` and is not mask-aware, and the hook fires on every boundary
with a usually-all-`False` mask. For MJWarp,
`SolverMuJoCo.reset(flags=0)` zeroes `qacc_warmstart`, `qfrc_applied`,
`xfrc_applied`, `ctrl`, `act` per masked world.
* `NewtonKaminoManager` opts out with a documented no-op override — its
FK delegate already performs the masked `SolverKamino.reset` with an
explicit `ResetConfig` at the same boundaries, so the generic call would
be a redundant second reset.

## Type of change

* Bug fix (non-breaking change which fixes an issue)

## Screenshots

N/A — physics behavior fix, no UI.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

## Test plan

* New regression test
`source/isaaclab_newton/test/physics/test_newton_solver_reset.py` (2
envs, CUDA): poisons `qacc_warmstart`, authors a joint write for one
env, and verifies both public boundaries (`sim.forward()` and
`sim.step()`) clear the flagged world's history while preserving the
other world's history and the authored joint state. Verified to fail
with the reset disabled.
*
`source/isaaclab_newton/test/physics/test_newton_manager_abstraction.py`
passes (74 tests).
* Canonical training probes run to completion with no tracebacks:
* `./isaaclab.sh train --rl_library rsl_rl --task Isaac-Cartpole-Direct
--num_envs 16 presets=newton_mjwarp --max_iterations 5`
* `./isaaclab.sh train --rl_library rsl_rl --task Isaac-Cartpole-Direct
--num_envs 16 presets=newton_kamino --max_iterations 5`
isaac-sim#6363)

## Problem

```bash
--kit_args "--ext-folder=/path/to/ext"       # exit 2: "argument --kit_args: expected one argument"
--kit_args=--ext-folder=/path/to/ext         # worked
--kit_args "--ext-folder=/a --ext-folder=/b" # worked
```

argparse rejects a value token that looks like an option (`-`-prefixed,
no space) — and Kit args always start with `--`. Affects every entry
point.

## Fix

Two normalization points, sharing one fusing helper that rewrites
`["--kit_args", "--ext-folder=/path/to/ext"]` into
`["--kit_args=--ext-folder=/path/to/ext"]`:

1. `AppLauncher.add_app_launcher_args` fuses the pair in `sys.argv`
before any parsing. Covers every script that parses `sys.argv`: demos,
tutorials, tools, benchmarks, and the per-library play scripts.
2. `dispatch_library_entrypoint` applies the same fusing to the explicit
argv list it forwards to the per-library train/play scripts. Those
scripts parse that list (not `sys.argv`), so the `sys.argv`
normalization alone never reached the unified `train` command or the
multi-GPU ranks (each child rank runs through the dispatcher).

Already-working forms are unchanged: a guard test asserts the
equals-attached, quoted multi-token, and plain-flag forms are forwarded
byte-identical.

Tests: 17 in
`source/isaaclab/test/cli/test_train_multigpu_command_building.py`. 12
fail with the `AppLauncher` fusing reverted; the dispatcher regression
test fails with the dispatcher fusing reverted. Verified end-to-end:
cartpole training via `train --rl_library rsl_rl ... --kit_args
"--ext-folder=..."` (previously exit 2) now trains to completion, and
the same command without `--kit_args` behaves identically to before.

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package (do **not** edit
`CHANGELOG.rst` or bump `extension.toml` — CI handles that)
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
…onfig (isaac-sim#6429)

## Summary

Cherry-pick of isaac-sim#6428 onto `develop`.

- Removes the duplicated `L_thumb_distal_joint` entry in
`fourier_hand_left_dexpilot.yml`'s `target_joint_names` list (reported
in isaac-sim#6325)
- The right-hand equivalent (`fourier_hand_right_dexpilot.yml`) is
unaffected

## Test plan

- [ ] Verify `fourier_hand_left_dexpilot.yml` has exactly one
`L_thumb_distal_joint` entry
- [ ] Confirm OpenXR Fourier left-hand retargeting initializes without
duplicate joint warnings

Fixes isaac-sim#6325
…6431)

# Description

`test_rendering_shadow_hand.py` builds and tears down a full RTX env
once per parametrized AOV (data type). It had no entry in
`PER_TEST_TIMEOUTS`, so it fell back to `DEFAULT_TIMEOUT` (1000s). That
budget never scaled as data types were added to
`_DEFAULT_SENSOR_DATA_TYPES` (the list grew from 7 → 13), so the file
eventually exceeded 1000s and timed out on CI (retry-masked).

This gives the file an explicit **1500s** budget (~45s per AOV) and adds
a reminder comment to bump it when renderer cases are added.

Fixes nvbug 6299039.

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Screenshots

N/A

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Description

Continues isaac-sim#6305 (includes @pbarejko's `Remove quality settings` commit)
and supersedes the now-closed isaac-sim#6278. Branched on top of the post-isaac-sim#6279
changes.

Removes the three RTX rendering-mode presets (`performance`, `balanced`,
`quality`) and the machinery that loaded them. With the RTX Minimal
renderer now serving the high-performance path, the presets added little
value. The former `quality` settings are retained as high-fidelity
defaults baked into the camera rendering Kit experiences, applied
automatically when RGB camera rendering is enabled.

Updated 18 rgb/rgba golden images (isaacsim_rtx renderer, both
physx/newton) from the CI-rendered output, since baking the
high-fidelity RTX defaults into kit changes the composited color:
confirmed the shift is color-only, so no geometry/segmentation goldens
were touched.

## Breaking change
- Removed the `--rendering_mode` launcher argument and
`IsaacRtxRendererGlobalSettingsCfg.rendering_mode`, plus the
`apps/rendering_modes/` presets.
- Baked high-fidelity RTX defaults into
`apps/isaaclab.python.rendering.kit` and the headless variant.

## Type of change

- Breaking change (existing functionality will not work without user
modification)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

---------

Co-authored-by: Piotr Barejko <pbarejko@nvidia.com>
…undle deletion, pin-pink) (isaac-sim#6329)

# Description

Fixes the Docker-only error flood in nvbugs 6343978 (follow-up to
isaac-sim#6288): streaming starts, but
the log carries 438 `[Error]` lines and 14 Isaac Sim extensions fail to
load. uv installs are
unaffected. Two independent causes, both Isaac Lab's install mutating
packages that Isaac Sim's
extensions rely on.

## Summary

- **`packaging` deleted from a shared prebundle.** The vestigial
`packaging<24` bound in
`isaaclab_rl` forced a downgrade; pip (which sees prebundle paths
through `python.sh`'s
environment) uninstalled `packaging-26.0` from the
`omni.isaac.core_archive` prebundle.
`omni.services.pip_archive` shares that package as per-file symlinks, so
the deletion dangled
the farm and cascaded into 13 extension startup failures. Fixed by
relaxing the bound (no
consumer requires it; now in the root `pyproject.toml` after the isaac-sim#6009
centralization), plus a
**fail-loud invariant**: the install aborts if pip leaves a prebundled
package with a dangling
  `__init__.py`.
- **`pin-pink==3.1.0` too old for Isaac Sim 6.x.**
`isaacsim.robot_motion.pink` needs
`pink.exceptions.NoSolutionFound` (pink ≥ 3.3.0). Isaac Sim bundles pink
4.2.0, but the
install replaces it with the kit-site-packages copy, pinned to 3.1.0
since pink 3.4+ broke
the `pink_ik` task API (isaac-sim#5846). Bumped to **3.3.0**, which satisfies
both consumers
(`DampingTask.set_target_from_configuration` verified present on both
wheels). The pin lives
once in the root `pyproject.toml`; the install CLI now derives its
force-install stack from
  those entries instead of a hardcoded copy.
- **Impact**: an image rebuilt with this PR runs the exact reported
command with
**0 errors / 0 tracebacks / 0 extension failures** (broken image and the
customer's attached
  log: 438 / 34 / 14).

## 1. Design notes

1. **Invariant scoping (empirical).** Every docker build routinely
replaces prebundled dists
(numpy, the cmeel/pinocchio stack, scipy, …) and leaves ~42 dangling
links to files Python
never imports at startup (test modules, `WHEEL`/license files, cmake
hooks) — none of them
`__init__.py`. The harmful class (this bug) dangles package
`__init__.py` files, making the
package unimportable for every extension that loads it. The install
therefore fails only on
   a new dangling `__init__.py` and warns on other new dangling links.
2. **Considered and rejected: hiding prebundles from pip.** Routing pip
to the concrete kit
interpreter also prevents deletions, but changes dependency resolution
build-wide: deps
previously satisfied by prebundled copies get freshly resolved into kit
site-packages, and
the `isaacteleop` step then downgraded numpy to 2.3.5 and pin to 3.9.0 —
CI measured the
`rsl_rl` export flow at ~4.4× baseline (600s timeouts vs 168s).
Prebundle-visible
   resolution is kept as-is, with the invariant as the guard.

## 2. Validation

- **End-to-end on a fresh image built from this PR** (Isaac Sim base
digest `99e4e4cfae17…`):
`isaac-sim.streaming.sh --allow-root` reaches streaming at ~34 s, stays
alive to timeout,
with 0 Kit errors, 0 tracebacks, 0 extension-startup failures. Baked
state: `packaging` 26.0
resolves from the prebundle, pink 3.3.0 imports from kit site-packages,
0 dangling
  `__init__.py` anywhere in the prebundles.
- **Customer log cross-check**: the attached
`isaaclab_streaming_20260702.log` has the
identical 438-error class set as the local broken reproduction — both
roots, no third issue.
- **Invariant**: catches the packaging cascade in-container
(RuntimeError naming the broken
`omni.services.pip_archive` links) and passes the routine-residue case.
- **Tests**: install CLI suites 148 passed / 1 skipped (invariant +
derived-stack tests);
`test_pink_ik_components.py` with pink 3.3.0 — 21 passed. CI fully
green; the export flow
  runs at its 168 s baseline.

Fixes nvbugs 6343978.
Move the resolution and application of the Python logging level out of
the Kit-based AppLauncher into a backend-agnostic module so kitless
backends can honor it too.

Previously AppLauncher owned _resolve_python_logging_level and
_apply_python_logging_level, so the --verbose / --info CLI arguments
only took effect for Kit-based runs. Kitless backends (Newton, OvPhysX)
launched via launch_simulation never constructed AppLauncher and
silently ignored them.

Extract those two helpers into isaaclab.app.logging_utils and apply the
resolved level in the kitless branch of launch_simulation. The
Kit-specific info-stream handler workaround stays in AppLauncher.

# Description

<!--
Thank you for your interest in sending a pull request. Please make sure
to check the contribution guidelines.

Link:
https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html

💡 Please try to keep PRs small and focused. Large PRs are harder to
review and merge.
-->

Please include a summary of the change and which issue is fixed. Please
also include relevant motivation and context.
List any dependencies that are required for this change.

Fixes # (issue)

<!-- As a practice, it is recommended to open an issue to have
discussions on the proposed pull request.
This makes it easier for the community to keep track of what is being
developed or added, and if a given feature
is demanded by more than one party. -->

## Type of change

<!-- As you go through the list, delete the ones that are not
applicable. -->

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (existing functionality will not work without user
modification)
- Documentation update

## Screenshots

Please attach before and after screenshots of the change if applicable.

<!--
Example:

| Before | After |
| ------ | ----- |
| _gif/png before_ | _gif/png after_ |

To upload images to a PR -- simply drag and drop an image while in edit
mode and it should upload the image directly. You can then paste that
source into the above before/after sections.
-->

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
Bumped packages:
- isaaclab: 10.0.0 → 10.1.0
- isaaclab_newton: 1.6.1 → 1.6.2
- isaaclab_ov: 0.6.0 → 0.7.0
- isaaclab_ovphysx: 6.2.0 → 6.3.0
- isaaclab_physx: 2.7.1 → 2.8.0
# Description

Retargeted this documentation-only cleanup to `develop`. The former
Quickstart typo is no longer applicable because that page was rewritten
on `develop`.

- Fixes duplicate-word and wording typos in the asset-import, IMU,
task-workflow, and OSC-controller documentation.
- Fixes the `add_sensors_on_robot` figure path so the existing image
renders.
- Adds Lin He to `CONTRIBUTORS.md`.

## Type of change

- Documentation update

## Validation

- `./isaaclab.sh -f`
- `git diff --check`

---------

Co-authored-by: Antoine Richard <antoiner@nvidia.com>
# Description

### Summary

- Added a repo-owned agent skills framework with developer and user
skill categories, authoring guidance, validation rules, and path-scoped
CI.
- Seeded developer skills for PR workflow, changelog fragments, and
coding style.
- Seeded user skills for Isaac Gym migration, Isaac Lab 2.x to 3.x
migration, domain randomization events, environment building, RL
training, sensors/actuators, backend selection, and setup
troubleshooting.

### Details

- Added `skills/` as the canonical home for Isaac Lab agent skills.
- Added `tools/skills/cli.py` to validate skill frontmatter, required
sections, links, portable paths, user evaluations, and scenario quality.
- Added `docs/source/overview/developer-guide/agent_skills.rst` and
linked it from the developer guide.
- Added `.github/workflows/skills-check.yml` so skill validation runs
only when skills, validator code, or the skills workflow change.
- Updated `AGENTS.md` with high-level skill ownership, structure, and
validation guidance.

### Validation

- Ran `python tools/skills/cli.py check`
  - Result: `Validated 11 skills.`
- Ran `python -m py_compile tools/skills/cli.py
tools/skills/test/test_validate.py`
- Checked edited files for linter issues.

Includes skills from isaac-sim#4927

## Type of change

- Documentation update

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->

---------

Co-authored-by: Ruben D'Sa <rdsa@nvidia.com>
…refactor, Part 3/5) (isaac-sim#6199)

# Description

**Part 3 of 5** of the benchmark refactor series — the unified training
dispatcher + RL adapters.

> **Stacked on Parts 1–2 (isaac-sim#6197, isaac-sim#6198).** The diff *against develop*
below also includes Parts 1–2 until they merge. For the **incremental
Part 3 changes only**, view:
>
AntoineRichard/IsaacLab@antoiner/benchmark-runtime-startup...antoiner/benchmark-training

Series: Part 1/5 core (isaac-sim#6197) → Part 2/5 runtime + startup (isaac-sim#6198) →
**Part 3/5 training (this PR)** → Part 4/5 play (isaac-sim#6201) → Part 5/5
cleanup.

This PR is **purely additive** — it adds `training.py` and the
per-backend adapters alongside the existing `benchmark_rsl_rl.py` /
`benchmark_rlgames.py` / `run_training_benchmarks.sh`, which keep
working unchanged. Removal of the legacy scripts and `utils.py` is
deferred to **Part 5/5**.

Adds:
- `scripts/benchmarks/training.py` — dispatcher selecting the RL library
with `--rl_library {rsl_rl, rl_games, skrl, sb3}` (mirrors
`scripts/reinforcement_learning/train.py`).
- Per-backend adapters (`rsl_rl/bench_rsl_rl.py`,
`rl_games/bench_rl_games.py`, `skrl/bench_skrl.py`, `sb3/bench_sb3.py`)
that run real training under `BenchmarkMonitor` and emit a
`TrainingBundle` via the shared core.
- Smoke tests for all four backends.

Also repoints the shared `early_stop.py` at the core
`SuccessRateTracker`. This is a behavior-preserving change: the public
wrappers/observers/CLI helpers are unchanged, and the legacy
`benchmark_rsl_rl.py` / `benchmark_rlgames.py` (which import only those
preserved symbols) keep working against it.

Docs: updates the RL-training sections of the benchmarking / performance
/ warp-environments / visualization pages. (The 3.0 migration-guide
"Benchmark Scripts" section, which documents the legacy-script removal,
lands with Part 5/5.)

Validated on `develop` (Newton/MJWarp): all four training smokes pass
(rsl_rl / skrl / sb3 at 16 envs, rl_games at 512).

Fixes # (n/a)

## Type of change

- New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
…6158)

# Description

The Factory and FORGE environments share the `CtrlCfg` fields
`pos_action_bounds` / `rot_action_bounds` and `pos_action_threshold` /
`rot_action_threshold`, but apply them in *opposite roles*, because the
two families use different action spaces:

| | Factory (`factory_env.py`) | FORGE (`forge_env.py`) |
|---|---|---|
| Action meaning | displacement relative to current EE pose | absolute
target relative to fixed asset |
| `pos_action_threshold` | **scales** the normalized action to a
per-step displacement | **clips** the per-step motion of the target
w.r.t. the current EE pose |
| `pos_action_bounds` | **clips** the target relative to the fixed asset
(workspace bound) | **scales** the normalized action onto the
operational volume around the fixed asset |

Read side by side, this looks like the two variables were accidentally
swapped in `ForgeEnv` (see isaac-sim#5424). The FORGE implementation is, however,
faithful to the FORGE paper:

- The paper defines the action as a relative pose applied to the fixed
part's pose to obtain an absolute target, which "is clipped by an action
scale, λ, to ensure that the target is not too far from the EE's current
pose" (Sec. III-B, Eq. 6), and states "we allow targets to be up to 5cm
away in all directions" (the operational volume, i.e. `pos_action_bounds
= 0.05`).
- λ is listed in the paper's dynamics randomization table (Appendix A)
as "Action Scale: λ ∈ [1.6, 2.5] cm". With the implementation's noise
scheme (`x * m` or `x / m` with `m = 1 + U(0,1) · noise_level`),
`pos_action_threshold = 0.02` and `pos_threshold_noise_level = 0.25`
give exactly `0.02 × [1/1.25, 1.25] = [1.6, 2.5] cm`. The same check
works for the controller gains: `565 × [1/1.41, 1.41] ≈ [400, 800]`,
matching the paper's "Controller Gains [400, 800]".
- Since FORGE actions are positions (not displacements), the per-step
motion limit can only be realized as a clip on the delta to the current
EE pose — a multiplicative scale on the action cannot play that role in
this action space.

Because this keeps being read as a bug, this PR documents both semantics
where a reader would look for them: a class docstring on `CtrlCfg`
(Factory semantics), a class docstring on `ForgeCtrlCfg` (FORGE
semantics, the λ correspondence and the randomization ranges), and an
expanded `ForgeEnv._apply_action` docstring with the paper reference.

Documentation-only change; no behavior is modified.

Related to isaac-sim#5424 (a detailed analysis is posted on the issue).

## Type of change

- Documentation update

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

---------

Signed-off-by: Advait Jayant <advait@vannalabs.ai>
Co-authored-by: Advait Jayant <advait@vannalabs.ai>
Co-authored-by: Antoine Richard <antoiner@nvidia.com>
…iculations (isaac-sim#6407)

# Description

The init-time actuator gain snapshot (`scatter_gain_kernel`, shipped
with the actuators integration isaac-sim#5455) decodes environment/local joint
slots from **global model DOF indices** using the articulation's joint
count as the per-environment stride. Newton's global DOF space also
contains free-root DOFs, so for a **floating-base articulation with more
than one environment** the per-env stride is larger than the joint count
(ANYmal: 18 vs 12), later environments' joints decode to the wrong or a
nonexistent environment slot, and the kernel **writes past the snapshot
buffer**.

Observed failure modes, all from the same OOB write:
- **CUDA, release:** silent — `randomize_actuator_gains` baselines
(`actuator.stiffness`/`damping` defaults) are corrupted (env-1 rows
partially zero / misplaced) with no error.
- **CPU, warp ≥ 1.15.0.dev20260626** (the minimum required by the
current newton pin): glibc `corrupted size vs. prev_size` →
deterministic SIGABRT at articulation init. Older warp allocator layouts
absorbed the write silently.
- **warp debug mode:** device-side bounds asserts on both devices,
naming this kernel.

**Why no existing test caught it:** the equivalence suites build
multi-env floating-base ANYmal with Newton actuators — they *execute*
the buggy scatter — but only compare joint trajectories; the corrupted
snapshot never feeds the sim step. The gain-randomization test reads
`controller.kp/kd` directly rather than the snapshot. Verified
side-by-side: the DR test passes while the new regression test fails on
the identical unfixed build.

**Fix:** thread the true per-environment DOF stride
(`adapter.num_joints`, which by construction equals the model's per-env
DOF count on both backends) into the kernel and decode `env = global_dof
// env_stride`. The PhysX call site passes a stride identical to its
joint count and is behaviorally unchanged (covered by its existing
tests). `patch_actuator_param_kernel` shares the decode pattern but its
only live caller guarantees stride == joint count; documented that
invariant in its docstring. All other kernels in the module audited
clean.

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the `pre-commit` checks with `./isaaclab.sh --format`
- [x] I have added tests that prove my fix is effective
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [x] My name exists in `CONTRIBUTORS.md`

## Test Plan

- [x] New
`TestNewtonActuatorGainSnapshotEnvStride::test_snapshot_matches_config_for_all_envs`
(floating-base ANYmal, 2 envs, explicit PD gains) — FAILS without the
fix (`Mismatched elements: 6 / 24`, env-1 rows zeroed), PASSES with it
- [x] `./isaaclab.sh -p -m pytest
source/isaaclab_newton/test/assets/test_newton_actuators_newton.py` → 72
passed
- [x] PhysX cross-check (`TestRandomizeActuatorGainsViaEventsPhysx`,
`TestIdealPDEquivalence`) → 6 passed (signature threading is a no-op on
PhysX)
- [x] `./isaaclab.sh -f` → all hooks pass
# Description

<!--
Thank you for your interest in sending a pull request. Please make sure
to check the contribution guidelines.

Link:
https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html

💡 Please try to keep PRs small and focused. Large PRs are harder to
review and merge.
-->

Headless RGB video recording forced a Kit app.update() on every env
step, even when no frame was being captured.

Fix is to exclude offscreen rendering from is_rendering so it only is
True during continuous rendering (GUI, RTX sensors, visualizers, XR).

Add unit test

<!-- As a practice, it is recommended to open an issue to have
discussions on the proposed pull request.
This makes it easier for the community to keep track of what is being
developed or added, and if a given feature
is demanded by more than one party. -->

Fixes: isaac-sim#6316 
## Type of change

<!-- As you go through the list, delete the ones that are not
applicable. -->

- Bug fix (non-breaking change which fixes an issue)

## Screenshots

Please attach before and after screenshots of the change if applicable.

<!--
Example:

| Before | After |
| ------ | ----- |
| _gif/png before_ | _gif/png after_ |

To upload images to a PR -- simply drag and drop an image while in edit
mode and it should upload the image directly. You can then paste that
source into the above before/after sections.
-->

## Checklist

- [ ] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
… frames (isaac-sim#6423)

# Description

**Summary**
Camera-heavy Newton scenes exhibited a severe environment-initialization
time spike that scaled quadratically with num_envs. On an RTX PRO 6000
(Blackwell), the Isaac-Lift-KukaAllegro-Camera benchmark at 8192 envs
spent ~29 minutes in "Simulation Start" alone.

The root cause is an O(num_envs²) regex loop in
NewtonSiteFrameView._initialize_from_specs: for a frame that resolves to
a per-environment body path (e.g. a body-mounted camera), the view
issued one resolve_matching_names call per environment, and each call
regex-scans the entire Newton body_label list (which itself grows with
num_envs).

This PR fast-paths literal body paths through an exact dict lookup built
once, keeping the common per-environment case linear while preserving
the regex fallback for genuine patterns (e.g. the cloned .* pattern).

**How the slow path is reached**
The spike only appears when a frame/sensor is anchored to a physics body
that is replicated per environment. The duo_camera preset for
Isaac-Lift-KukaAllegro-Camera includes exactly such a camera, mounted on
the robot hand:

- /World/envs/env_.*/Camera — anchored at the env root (a static frame)

- /World/envs/env_.*/Robot/ee_link/palm_link/Camera — anchored to the
palm_link rigid body

Call chain during env creation:

gym.make(...)
└─ sim.reset() # Timer: "simulation_start"
   └─ NewtonManager.start_simulation()
      └─ dispatch_event(PhysicsEvent.PHYSICS_READY)
└─ Camera._initialize_impl() # one per camera sensor
└─ FrameView(cfg.prim_path) # == NewtonSiteFrameView
               └─ _initialize_from_specs(model)
                  └─ for each of num_envs specs:
resolve_matching_names(<per-env body path>, body_labels) # scans ALL
labels

The env-root camera resolves to body_patterns is None and takes the
cheap branch (~174 ms at 2048 envs).

The body-mounted camera expands to one concrete body path per
environment. Each is regex-matched against all body labels:

At 2048 envs: resolve_matching_names called 2048 times, each scanning
65,536 body labels → 70,136 ms.

Because both the number of calls and the label-list length grow with
num_envs, cost is O(num_envs²).

# Fixes 

In _initialize_from_specs:

- Build label_to_index = {label: idx for idx, label in
enumerate(body_labels)} once (O(num_bodies)).

- For each body pattern, if it contains no regex metacharacters, resolve
it with an O(1) dict lookup; otherwise fall back to
resolve_matching_names.

This is behavior-preserving: literal paths previously matched exactly
one label via regex full-match, which the dict lookup reproduces;
patterns with metacharacters (.*[]()+?|\^$) still use the regex scan.

using benchmark_non_rl, Isaac-Lift-KukaAllegro-Camera, preset
cube,duo_camera,newton,newton_renderer,rgb64 (matching the benchmark
runs that identified the issue) the fix produced the following results:

Simulation Start Time: before 1729 seconds, after 19 seconds
Task Creation and Start Time: before 1763 seconds, after 59 seconds

note the cost is CPU-bound (python regex) so it is not GPU specific

## Type of change

- Bug fix (non-breaking change which fixes an issue)


## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
Bumped packages:
- isaaclab: 10.1.0 → 10.2.0
- isaaclab_newton: 1.6.2 → 1.7.0
- isaaclab_physx: 2.8.0 → 2.8.1
…art 4/5) (isaac-sim#6201)

# Description

**Part 4 of 5** of the benchmark refactor series — a checkpoint-driven
**play** (inference) benchmark, the inference counterpart to the
training benchmark.

> **Stacked on Part 3 (isaac-sim#6199).** The diff *against develop* below also
includes Parts 1–3 until they merge. For the **incremental Part 4
changes only**, view:
>
AntoineRichard/IsaacLab@antoiner/benchmark-training...antoiner/benchmark-play

Series: Part 1/5 core (isaac-sim#6197) → Part 2/5 runtime + startup (isaac-sim#6198) →
Part 3/5 training (isaac-sim#6199) → **Part 4/5 play (this PR)** → Part 5/5
cleanup.

Purely additive (a new script + new schema type). Loads a trained
checkpoint, runs the policy-driven rollout, and emits a new typed
**`PlayBundle`** capturing inference/step performance plus the played
policy's reward / episode-length / success.

Adds:
- **`PlayBundle`** schema type (mirrors `RuntimeBundle` with
`run.framework` set, plus typed `success_rate` / `reward` / `ep_length`
(`MeanStd`) / `checkpoint_path` / `video_path`; no learning curve).
Additive — Odin gains a `play.json` shape; existing bundles unchanged.
- Core helpers: `build_play_bundle`, `run_play_loop` (policy-driven
rollout, aggregates per-episode return/length/success; handles 4- and
5-tuple step signatures + numpy returns), and `resolve_play_checkpoint`
(chain: `--checkpoint <path or Nucleus URI>` → else the published
Nucleus checkpoint *with a warning* → else a clear error).
- `scripts/benchmarks/play.py` dispatcher over `--rl_library {rsl_rl,
rl_games, skrl, sb3}` + per-backend `bench_play_<backend>.py` adapters
(each mirrors its `reinforcement_learning/<backend>/play.py`
checkpoint-load + inference policy; develop launch API).
- Four gated **generate-then-play** smokes (train a tiny checkpoint,
then play it).
- Docs: `benchmarks.rst` play section + arg table. (The 3.0
migration-guide "Benchmark Scripts" section, including the `play.py`
entry, lands with Part 5/5 alongside the legacy-script removal.)

Validated on `develop` (Newton/MJWarp): all four backends
generate-then-play and emit a valid `PlayBundle` (rsl_rl ≈7.5k inference
FPS, rl_games ≈209k @512 envs, skrl ≈5.4k, sb3 ≈4.6k; reward/ep_length
populated). Note: `reward`/`ep_length`/`success_rate` aggregate only
*completed* episodes, so `--num_frames` must exceed the task's episode
length (documented).

Fixes # (n/a)

## Type of change

- New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
# Description

Reports came in that our stack is slow with PhysX, and profiling the
contact sensor update confirmed that the eager `wp.launch` calls
dominate its per-step CPU cost: a single eager launch of
`update_net_forces_kernel` costs ~110 us of CPU submit time, while
replaying the same kernel from a CUDA graph costs ~7 us. The PhysX
tensor reads themselves are comparatively cheap (~34 us).

This PR captures the warp kernels of the PhysX `ContactSensor` buffer
update into CUDA graphs on first use and replays them on subsequent
updates:

- **PhysX tensor reads stay eager.** They cannot be captured —
`GpuRigidContactView` enqueues its work on the legacy CUDA stream, and
capture fails with `operation would make the legacy stream depend on a
capturing blocking stream`. Fortunately the tensor API caches its output
buffers and refreshes them in place on every call, so the getters run
eagerly before each graph replay and the graphed kernels read the
refreshed data.
- **Per-stage graphs.** `get_contact_data` and `get_friction_data` share
their count/start-index buffers on the view, so each stage's kernel must
run before the next stage's PhysX read. Each stage (net forces, pose,
contact points, friction forces) is therefore captured as its own graph,
preserving the exact ordering of the eager path.
- **Only graphs when not already being graphed.** If an outer CUDA graph
capture is active (`device.is_capturing`), the kernels run "eagerly" and
are recorded into that outer graph instead of replaying a nested one.
- **Safe fallbacks.** Eager execution on CPU devices; a one-time warning
and permanent eager fallback if capture fails; graphs bake input
pointers and are dropped/re-captured if a pointer changes; all graphs
are dropped when the physics views are invalidated.

A new benchmark script compares the two paths:

```bash
./isaaclab.sh -p scripts/benchmarks/benchmark_contact_sensor.py --num_envs 4096 --headless
./isaaclab.sh -p scripts/benchmarks/benchmark_contact_sensor.py --num_envs 4096 --disable_graph --headless
```

Results on an RTX 5000 Ada laptop GPU (default sensor config: net forces
+ air time, 500 timed steps, mean synchronized update time):

| num_envs | eager | graphed |
|---|---|---|
| 32 | 0.463 ms | 0.407 ms |
| 4096 | 0.490 ms | 0.391 ms |

The saving matches one graphed kernel (the default config launches a
single kernel per update); configs with `track_pose` /
`track_contact_points` / `track_friction_forces` graph up to four. The
remaining overhead is the base-class `update_timestamp_kernel` /
`update_outdated_envs_kernel` launches in `SensorBase`, which are shared
across backends and left for a follow-up.

## Type of change

- New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
…ns (isaac-sim#6157)

# Description

When type annotations are provided on only some attributes of a
`configclass`, the resulting field order does not follow the declaration
order: all annotated attributes jump ahead of the non-annotated ones.
This breaks the documented guarantee that attribute order is preserved,
which matters in particular for `InteractiveSceneCfg`, where the
attribute order determines the scene entity creation order.

```python
@configclass
class SceneCfg(InteractiveSceneCfg):
    plane = AssetBaseCfg(...)
    robot = ArticulationCfg(...)
    peg: ArticulationCfg = ArticulationCfg(...)
    hole: ArticulationCfg = ArticulationCfg(...)
    camera = TiledCameraCfg(...)
    light = AssetBaseCfg(...)

# before this fix:
# ['peg', 'hole', 'plane', 'robot', 'camera', 'light']
# with this fix:
# ['plane', 'robot', 'peg', 'hole', 'camera', 'light']
```

**Root cause**: `_add_annotation_types` bulk-adds each base class's
`__annotations__` into the type-hints dictionary *before* iterating over
the class members (`hints.update(ann)` prior to the `base.__dict__`
walk), so annotated fields are always inserted first.

**Fix**: build the hints dictionary in a single pass over
`base.__dict__` (which preserves declaration order), picking up the
explicit annotation when one exists and deducing the type from the
default value otherwise. A trailing `hints.update(ann)` keeps the
previous behavior for corner cases (annotation-only declarations,
re-annotated inherited members, members skipped by
`_skippable_class_member`) — for keys already present it only refreshes
the type and keeps the position.

The semantics are otherwise unchanged: cross-base ordering (parent
fields first, overrides keep the parent position), `MISSING` handling,
`ClassVar` handling, and nested-class handling all behave as before.

**Verification**

- New regression test `test_configclass_mixed_type_annotations_ordering`
(mirrors the issue repro, plus an inheritance case). It fails before the
fix and passes after.
- Full `test_configclass.py` suite passes (44 tests).
- The complete `source/isaaclab/test/utils/` suite was run on CPU before
and after the change with byte-identical results (the only failing tests
are CUDA-/Nucleus-dependent and fail identically on both sides).
- An AST scan over `source/` found 81 configclasses whose field order
changes with this fix (i.e., classes currently affected by the silent
reordering), of which ~15 are `InteractiveSceneCfg` subclasses. For
these, entity creation order now matches the declaration order, which is
what the documentation promises (e.g., terrain/ground declared first now
actually spawns first). Managers and scene entities are referenced by
name, so no name-based lookups are affected.

Fixes isaac-sim#1949
Related to isaac-sim#1743 (the same hoisting also affected `None`-typed members
before it was special-cased)

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

Signed-off-by: Advait Jayant <advait@vannalabs.ai>
Co-authored-by: Advait Jayant <advait@vannalabs.ai>
## Summary

- Adds an `arm-ci` job to the existing `Docker + Tests` workflow for
NVIDIA DGX Spark self-hosted runners. It builds and tests on the same
ARM runner because ECR is not wired for arm64.
- Adds marker-driven ARM test selection through `CI_MARKER`, plus a
shared kitless Cartpole state/camera smoke used by ARM and installation
CI.
- Extracts Docker dependency-hash and registry-login setup into shared
composite actions used by the local Docker and ECR build paths.
- Makes Docker dependency-cache keys platform-specific and bounds stale
ARM cache tags on the long-lived Spark runner.

## 1. ARM/Spark CI

1.1 The `arm-ci` job shares the existing `changes` and `config` gating.
It builds `Dockerfile.base` for `linux/arm64`, runs the
`arm_ci`-selected tests, and then runs the shared Cartpole smoke.

1.2 OVRTX and OVPhysX are installed explicitly for the rendering probes.
Missing ARM runtime dependencies fail instead of being hidden by
architecture-specific skips.

1.3 The job uses the same workflow and shared actions as the amd64 jobs.
ARM enables 14-day stale dependency-cache eviction because its runner
has persistent local Docker storage and no ECR handoff.

1.4 The `arm_ci` marker run passes `test-k-expr: not ovphysx`, the same
per-file `-k` expression the x86 `rendering-correctness-kitless` job
applies on public pip-index runs. The ovphysx-backed rendering params
require OVPhysX >= 0.5.1, which has no aarch64 wheel.

## 2. Shared CI utilities

2.1 `_lib/compute-deps-hash` computes one dependency-cache identity from
install inputs, the resolved base-image digest, and target platform.
Both `docker-build` and `ecr-build-push-pull` consume it.

2.2 `_lib/setup-docker-config` centralizes the credential-helper
workaround and optional NGC login. It is idempotent when the ECR action
delegates to `docker-build`.

2.3 `run-tests` forwards both upstream's per-file `test-k-expr` and this
PR's `ci-marker` inputs into the test container.

## 3. Shared Cartpole smoke

3.1 `source/isaaclab/test/install_ci/misc/cartpole_training_smoke.py` is
the common prepared-environment probe for state Cartpole training,
camera observation/reward validity, and camera Cartpole training.

3.2 CLI and wheel installation tests execute the same probe inside their
newly installed environments; ARM executes it inside its prepared image.

3.3 The base image installs `git-lfs` so RSL-RL can snapshot repository
state from a mounted LFS checkout.

## 4. Cross-platform support

4.1 `AppLauncher` derives `EXP_PATH` from the installed `isaacsim`
package when the variable is missing, while leaving existing configured
environments unchanged.

4.2 `tools/conftest.py` supports `CI_MARKER` as a file-selection and
pytest marker filter parallel to `ISAACSIM_CI_SHORT`, exact node-ID
selection, and per-file `-k` filtering.

## Known problems

- The three rendering modules apply `arm_ci` at module scope, so ARM
collects all 32 cases per module. The ovphysx-backed cases are now
deselected via `test-k-expr: not ovphysx` (section 1.4), leaving 15
Newton cases running per module. Without the filter, the extra
ovphysx-ovrtx cases in `test_rendering_cartpole_kitless.py` pushed a
single process past the OVRTX per-process SyncScopeId limit (~15
renderer creations), crashing HydraEngine initialization on the 16th
env; this also reproduces on x86, so the failure is not ARM-specific.
Narrowing ARM to the two intended representative tests is still pending.
- Current `develop` pins OVPhysX `0.5.2+head.f62c22207c`, while this job
installs the publicly available ARM `0.4.13` wheel. With the `not
ovphysx` filter the ARM rendering selection is Newton-only, matching the
x86 public pip-index fallback; revisit if an aarch64 OVPhysX >= 0.5.1
wheel or wheelhouse becomes available.

## 5. Series

Part 2 of `[CI] Cross-platform —`. Depends on isaac-sim#5695 (Part 1). The
Windows workflow is isaac-sim#5700 (Part 3).

## Test plan

- [x] Merge current `develop`
(`5f2db9902baa724427b7aa654835aa559fce64e8`).
- [x] Run `./isaaclab.sh -f` before commit and before push.
- [x] Collect the refreshed ARM rendering selection locally: 96 items
(32 per rendering module), confirming the current over-selection.
- [x] Deselect ovphysx rendering params in the ARM job (`test-k-expr:
not ovphysx`), mirroring the x86 kitless public pip-index fallback.
- [ ] Narrow ARM rendering coverage to the two intended representative
tests.
- [ ] Run the two selected tests and shared Cartpole smoke on
Spark/aarch64.
- [ ] Confirm the refreshed `Docker + Tests` workflow is green.
- [ ] Trigger `daily-compatibility` before merge.
…-sim#6206)

# Description

**Part 5 of 5** of the benchmark refactor series — removes the legacy
benchmark scripts now superseded by the unified suite added in Parts
1–4.

> **Stacked on Part 4 (isaac-sim#6201).** The diff *against develop* below also
includes Parts 1–4 until they merge. For the **incremental Part 5
changes only**, view:
>
AntoineRichard/IsaacLab@antoiner/benchmark-play...antoiner/benchmark-cleanup

Series: Part 1/5 core (isaac-sim#6197) → Part 2/5 runtime + startup (isaac-sim#6198) →
Part 3/5 training (isaac-sim#6199) → Part 4/5 play (isaac-sim#6201) → **Part 5/5 cleanup
(this PR)**.

Parts 1–4 add the unified `runtime.py` / `startup.py` / `training.py` /
`play.py` suite **alongside** the legacy scripts, so nothing breaks
while they merge. This final PR removes the legacy scripts once
downstream consumers (OmniPerf ingestion, job runners) have migrated —
**kept as a draft; merge it last, on the consumers' signal.**

Removes:
- `benchmark_non_rl.py` → `runtime.py`
- `benchmark_startup.py` → `startup.py`
- `benchmark_rsl_rl.py` → `training.py --rl_library rsl_rl`
- `benchmark_rlgames.py` → `training.py --rl_library rl_games`
- `run_non_rl_benchmarks.sh`, `run_physx_benchmarks.sh`,
`run_training_benchmarks.sh` — express their behavior with script args +
`presets=`; run the PhysX micro-benchmarks under
`source/isaaclab_physx/benchmark/` directly.
- `scripts/benchmarks/utils.py` (obsolete helper) and the orphaned
`test/test_training_metrics.py`.

Also repoints `benchmark_hydra_resolve.py` at `_common` for
`get_backend_type`, and adds the "Benchmark Scripts" section to the 3.0
migration guide documenting the full old → new command mapping
(including `play.py`).

**Backward-compatibility note (outputs):** the unified scripts emit the
same OmniPerf / JSON / Osmo / Summary KPI files as the legacy scripts —
every pre-existing KPI row is byte-identical in name, value, and unit.
The only difference is four **additive** peak rows contributed by the
shared recorders in Part 1 (`GPU [i] Memory Used peak`, `System Memory
RSS/VMS/USS peak`). Nothing is renamed, removed, or recomputed. Direct
callers of the removed scripts must switch to the unified entry points
per the migration guide.

Fixes # (n/a)

## Type of change

- Breaking change (removes the legacy benchmark entry-point scripts; a
documented migration path to the unified scripts is provided)
- This change requires a documentation update

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation (3.0
migration guide "Benchmark Scripts")
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works (covered by Parts 1–4; this PR only removes superseded
scripts)
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
# Description

Corrects stale terminology in `TerminationManager.reset()` while
preserving the original documentation fix:

- Replaces the stale references to reward terms with termination terms.
- Clarifies that the logged per-term metric is a mean activation across
environments, rather than an episodic sum or count.

## Type of change

- Documentation update

## Validation

- `./isaaclab.sh -f`
- `git diff --check`

---------

Co-authored-by: Antoine Richard <antoiner@nvidia.com>
# Description

Fixes broken source links on the Available Environments docs page.

Corrects the Hydra preset-system doc reference.
Adds a reusable :isaaclab-source: Sphinx role that links to GitHub
source files using the current versioned-doc branch/tag.
Updates environment source links to use that role instead of hardcoded
main/develop URLs.

## Type of change

- Documentation update


## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
…-articulation

# Conflicts:
#	source/isaaclab/isaaclab/physics/physics_manager.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.