Skip to content

[Task Clean-up][Benchmark] Dexterous Part 8/9: Add success-rate support to the benchmark utilities - #6415

Open
hujc7 wants to merge 70 commits into
isaac-sim:developfrom
hujc7:jichuanh/task-cleanup-dex-part05
Open

[Task Clean-up][Benchmark] Dexterous Part 8/9: Add success-rate support to the benchmark utilities#6415
hujc7 wants to merge 70 commits into
isaac-sim:developfrom
hujc7:jichuanh/task-cleanup-dex-part05

Conversation

@hujc7

@hujc7 hujc7 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Review Map

PR Status Depends on Exact changes
#6411 Part 1/9: Newton cloner/cubric/visualizer fixes merged
#6412 Part 2/9: OVPhysX articulation + manager runtime merged
#6413 Part 3/9: Reorient Direct, torch changes
#6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct #6413 changes
#6418 Part 5/9: Reorient manager counterparts #6413 changes
#6421 Part 6/9: Handover + camera manager counterparts #6413, #6414, #6418 changes
#6410 Part 7/9: Environment overview docs #6421 changes
📌 #6415 Part 8/9: Benchmark success-rate utilities (this PR) #6421 changes
#6582 Part 9/9: Warp variants → experimental (draft; merges last) #6413 changes
#6324 [DO-NOT-MERGE] Lumped validation reference ALL

Summary

  • Reports the success-rate metric through the environment training benchmark utilities and excludes inference-only camera benchmark registrations from training-benchmark discovery (with unit tests for the discovery helpers).
  • Regenerates the environment overview table and covers the install-order constants with a unit test.

Stacking

Validation

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jul 8, 2026
@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends the training benchmark utilities to record Metrics/success_rate alongside reward and episode length, using a new sustained-window threshold type (consecutive_samples) that requires N consecutive samples to meet a criterion. It also replaces the narrow endswith(\"Play-v0\") task filter with _is_training_task, which correctly excludes all Play and Benchmark variants.

  • env_benchmark_test_utils.py: adds _is_training_task, _parse_threshold_spec, _extract_sustained_feature, and wires success_rate into _extract_log_val; evaluate_job now populates the KPI payload even for missing/non-finite metrics instead of silently continuing.
  • test_env_benchmark_test_utils.py: new unit-test file with 9 parametrised scenarios covering the filter, scalar-threshold backward-compatibility, sustained-pass/fail paths, and unsupported-workflow fallback.
  • test_environments_training.py: single-line swap to the new _is_training_task helper.

Confidence Score: 4/5

Safe to merge; the changes are additive and record-only for tasks that do not emit success_rate, with no impact on existing reward/episode_length benchmarks

The global non-finite check in _extract_sustained_feature could cause a valid training run to fail its benchmark if any NaN appears in the early success_rate history before the metric stabilises, and the undocumented aggregation switch for reward+consecutive_samples could mislead future config authors. Neither affects existing tasks today but they are latent correctness traps in new code paths.

env_benchmark_test_utils.py — specifically _extract_sustained_feature (global NaN check) and the _extract_log_val reward branch when consecutive_samples is set

Important Files Changed

Filename Overview
source/isaaclab_tasks/test/benchmarking/env_benchmark_test_utils.py Core utility extended to add success_rate metric support and sustained-window evaluation via _extract_sustained_feature and _parse_threshold_spec; two subtle design decisions worth attention
source/isaaclab_tasks/test/benchmarking/test_env_benchmark_test_utils.py New unit-test file covering success_rate evaluation paths, filter logic, and scalar-threshold backward compatibility; missing one edge-case scenario (early NaN warm-up with later valid window)
source/isaaclab_tasks/test/benchmarking/test_environments_training.py Single-line change replaces the narrow Play-v0 suffix guard with the new _is_training_task helper for broader Benchmark/Play exclusion; change is correct and safe
source/isaaclab_tasks/changelog.d/task-cleanup-dex-part05.rst New changelog fragment noting the training benchmark discovery fix; content is accurate

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[evaluate_job] --> B[_retrieve_logs]
    B -->|no logs| C[fail: training did not finish]
    B -->|logs found| D[iterate thresholds]
    D --> E[_parse_threshold_spec]
    E -->|plain number| F[consecutive_samples = None]
    E -->|dict| G[consecutive_samples = N]
    F --> H{threshold_name}
    G --> H
    H -->|duration| I[val = duration arg]
    H -->|reward or episode_length or success_rate| J[_extract_log_val]
    J -->|reward, no consecutive| K[_extract_reward avg top-k]
    J -->|other, no consecutive| L[_extract_feature max or min]
    J -->|any metric, with consecutive| M[_extract_sustained_feature]
    M -->|len less than N| N[return None]
    M -->|any non-finite globally| O[return NaN]
    M -->|all finite| P[best window extremum]
    K --> Q{val None or non-finite?}
    L --> Q
    P --> Q
    N --> Q
    O --> Q
    I --> Q
    Q -->|yes| R[payload = None, success = False]
    Q -->|no| S{exceeds threshold?}
    S -->|yes| T[success = False with msg]
    S -->|no| U[payload = val, success unchanged]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[evaluate_job] --> B[_retrieve_logs]
    B -->|no logs| C[fail: training did not finish]
    B -->|logs found| D[iterate thresholds]
    D --> E[_parse_threshold_spec]
    E -->|plain number| F[consecutive_samples = None]
    E -->|dict| G[consecutive_samples = N]
    F --> H{threshold_name}
    G --> H
    H -->|duration| I[val = duration arg]
    H -->|reward or episode_length or success_rate| J[_extract_log_val]
    J -->|reward, no consecutive| K[_extract_reward avg top-k]
    J -->|other, no consecutive| L[_extract_feature max or min]
    J -->|any metric, with consecutive| M[_extract_sustained_feature]
    M -->|len less than N| N[return None]
    M -->|any non-finite globally| O[return NaN]
    M -->|all finite| P[best window extremum]
    K --> Q{val None or non-finite?}
    L --> Q
    P --> Q
    N --> Q
    O --> Q
    I --> Q
    Q -->|yes| R[payload = None, success = False]
    Q -->|no| S{exceeds threshold?}
    S -->|yes| T[success = False with msg]
    S -->|no| U[payload = val, success unchanged]
Loading

Reviews (1): Last reviewed commit: "Add success-rate support to the benchmar..." | Re-trigger Greptile

Comment on lines +319 to +325
def _extract_sustained_feature(log_data, feature, uses_lower_threshold, consecutive_samples):
"""Extract the best threshold-facing value sustained over a sample window."""
values = np.asarray(log_data[feature], dtype=float)[:, 1]
if len(values) < consecutive_samples:
return None
if not np.all(np.isfinite(values)):
return math.nan

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.

P2 Global NaN check rejects series with any early non-finite value

np.all(np.isfinite(values)) is applied to the full historical series before any windowing, so a single NaN anywhere — including in early warm-up steps before the metric stabilises — causes the function to return math.nan and fail the threshold even when a valid consecutive_samples-length window exists entirely within the finite portion of the data. For success_rate in particular, early episodes may not record any successes and could produce NaN values before converging; those early samples would silently disqualify an otherwise passing run. Restricting the finiteness check to each candidate window (or filtering non-finite entries before slicing) would make the "best sustained window" semantics consistent with the function's name.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Confirmed on the current head: [NaN] + [0.3] * 20 returns NaN even though the suffix contains a valid contiguous 20-sample window. Please evaluate finiteness per candidate window without filtering across gaps, and add this exact regression case.

Comment on lines 266 to +296
@@ -230,7 +271,7 @@ def _extract_log_val(name, log_data, uses_lower_threshold, workflow):
"skrl": "Reward / Total reward (mean)",
}
tag = reward_tags.get(workflow)
if tag:
if tag and consecutive_samples is None:
return _extract_reward(log_data, tag)

elif name == "episode_length":
@@ -241,8 +282,20 @@ def _extract_log_val(name, log_data, uses_lower_threshold, workflow):
"skrl": "Episode / Total timesteps (mean)",
}
tag = episode_tags.get(workflow)
if tag:
return _extract_feature(log_data, tag, uses_lower_threshold)
elif name == "success_rate":
success_rate_tags = {
"rl_games": "Episode/Metrics/success_rate",
"rsl_rl": "Metrics/success_rate",
"skrl": "Metrics/success_rate",
}
tag = success_rate_tags.get(workflow)

if tag:
if consecutive_samples is not None:
return _extract_sustained_feature(log_data, tag, uses_lower_threshold, consecutive_samples)
return _extract_feature(log_data, tag, uses_lower_threshold)

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.

P2 reward bypasses _extract_reward when consecutive_samples is set

When name == "reward" and consecutive_samples is not None, the early return _extract_reward(...) branch is skipped (lines 274–275) and the code falls through to the generic if tag: block, where _extract_sustained_feature is called instead. _extract_reward uses an "average of the top-k" aggregation that is quite different from the sliding-window min/max in _extract_sustained_feature. Any future YAML config that specifies a structured threshold for the reward metric would silently receive a semantically different aggregation than the scalar-threshold path. There are no tests covering this combined path, and the behaviour change is not documented.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Confirmed on the current head: values 1 through 10 produce 6.5 with the scalar reward path and 8.0 with consecutive_samples=3. Because structured specs are accepted generically, this is a silent aggregation-contract switch. Restrict structured specs to success_rate, or define and test an explicit reducer for every supported metric.

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should store the success rate / metrics / expectations somewhere else.

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should discuss how to go about this. It's not clear if we should do any training tests on our regular CI. If we make such changes to this API they should not belong in that PR series. I would rather discuss this first.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is also hiding major changes under an incorrect PR scope

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Confirmed at the current head. The exact b50ac890...f21a2124 contribution includes a camera physics-default change, rendering coverage, install-order coverage, manager/direct parity coverage, and a manager changelog fragment in this benchmark PR. Please move each item to its owning stack layer so the benchmark behavior can be reviewed and reverted independently.

Comment on lines +17 to +24
def _is_training_task(task_id: str) -> bool:
"""Return whether a registered task is intended for training benchmarks."""
stem, separator, version = task_id.rpartition("-v")
if separator and version.isdigit():
task_id = stem
return not {"Play", "Benchmark"}.intersection(task_id.split("-"))


Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is a major change.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Agreed: this expands discovery from one Play-v0 suffix to every task containing a Play or Benchmark token, across versions. The unit test covers synthetic IDs only and does not prove that every excluded registered task is inference-only. Please split this into the separately discussed discovery-contract change and validate it against the actual registered task set.

hujc7 added 6 commits July 16, 2026 17:44
Add a behavioral Metrics/success_rate signal (goal-reach streaks per
episode) and threshold-independent episode orientation-error diagnostics
to the Direct reorientation environments, with the shared helpers in
isaaclab_tasks.core.utils and torch math tests. The task logic is
torch-first per the mainline convention; success gates task health while
reward stays diagnostic. Also fix hand resets that could initialize
joints below their lower position limits.
Add the RSL-RL runner configuration for the Shadow handover Direct task
and success-rate metrics on the torch-first path, fix handover
construction on Newton (renamed distal joints), and land the camera
Direct renderer presets with configuration validation. RSL-RL
observations now read from the public environment-owned obs_buf on all
Direct env bases (reset stores the buffer like step), replacing the
adapter-side private hook.
Add manager-based training environments for the Allegro and Shadow cube
reorientation tasks (state and OpenAI FF/LSTM variants). The manager
cfgs share the Direct tasks' scalar parameters through per-family task
constants, and the shared MDP terms reuse the Direct success evaluation
so both variants report the same boolean success metric.
Add manager-based training environments for the Shadow handover and
Shadow camera reorientation tasks, completing manager coverage of the
dexterous families. Direct-vs-manager scalar parity across all families
is enforced by a new value-parity test.
Report the success-rate metric through the environment training
benchmark utilities, exclude inference-only camera benchmark
registrations from training-benchmark discovery, regenerate the
environment overview table, and cover the install-order constants with
a unit test.
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part05 branch from 381c55b to df070af Compare July 17, 2026 01:00
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 17, 2026
hujc7 added 9 commits July 22, 2026 09:24
The rename round updated the camera gym-registration entry-point
strings to shadow_hand_direct_camera_env* at this layer, but the
camera modules here still carry their pre-rename names, so every
registry-driven cfg load failed at import (isaaclab_tasks suites,
forbidden-imports test, registered-tasks rendering). Point the
registrations back at the modules that exist at this layer.
The lower layer's registration revert merged forward and un-renamed
the camera entry points here, where the camera modules do carry the
renamed filenames. Pin the registration block back to the final
state.
…eanup-dex-part11

# Conflicts:
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/__init__.py
hujc7 added a commit that referenced this pull request Jul 22, 2026
…isualizer teardown (#6411)

## Review Map

- **Exact changes**: a stacked PR's page shows the cumulative diff of
its dependency chain; the link pins the commit range that is the PR's
own contribution.
- Links pin specific SHAs and can go stale after a branch update — the
table on #6324 is refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| #6410 [Docs] Environment overview regen |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6410?label=)
| — | — |
| 📌 #6411 Part 1/8: Newton cloner/cubric/visualizer fixes (this PR) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6411?label=)
| — | — |
| #6412 Part 2/8: OVPhysX articulation + manager runtime |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6412?label=)
| — | — |
| #6413 Part 3/8: Reorient Direct, torch |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6413?label=)
| — | — |
| #6414 Part 4/8: MARL-to-single-agent fix + handover/camera Direct |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6414?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6414/changes/6e8a63e4e028b2d43676ea30c446b9dc9068c7b5..5cb00e7cb5cc813b202521272e043007cd255194)
|
| #6418 Part 5/8: Reorient manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6418?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/79f87501ac4c81de93a71dab00dc443da62113aa..e7c9a9a3fae3a7972b0c5165ae683abffb7d0e0f)
|
| #6421 Part 6/8: Handover + camera manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6421?label=)
| #6413, #6414, #6418 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/01c9f4d8c5c35a5688b2a5bb90209e16b8f81b99..835a5815ec49b11aada1d20a76c177054505e6e7)
|
| #6415 Part 7/8: Benchmark success-rate utilities + docs |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6415?label=)
| #6413, #6414, #6418, #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/e1abb6b1790ccc57af42551eebccf743633f1f13..d6348539aa8032d9668c20a8fea462c5d88d3af9)
|
| #6582 Part 8/8: Warp variants → experimental (draft; merges last) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6582?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/21dbb1769c4e30c8e9e5b0f563c2dae24c230349..83e1587cadd9712a60615ed2a3cb2d177c2ac24d)
|
| #6324 [DO-NOT-MERGE] Lumped validation reference |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6324?label=)
| ALL | — |

## Summary

- Fixes Newton cloner label rows, the cubric IAdapter version audit
(exact-match fallback to the CPU hierarchy path), and visualizer
teardown.
- Retains an in-tree `ignore_paths` workaround for custom-frequency USD
traversal; it becomes redundant once the Newton pin advance
(#6584) merges — this PR then
only needs a rebase.

## Stacking

- Independent; based on `develop`.

## Review history

- Approved. The Newton pin + MuJoCo overrides were split out to
#6584 via revert commits
(2026-07-17) so this PR's CI runs against develop's pins.
hujc7 added 10 commits July 23, 2026 13:26
Applies the P3-owned share of the lump review-response commits:

- Default the dexterous tasks to newton_mjwarp (from 3f9ce324).
- Drop solver defaults matching the backend + inline the scene preset
  via preset() instead of a wrapper class (from 29e189bf).
- Simplify the Direct reorientation reward computation (from bfb73735).
- Source the actuated-joint and fingertip body-name lists from the
  robot assets instead of the config module (from 34676102).

Deferred to their owning layers: the core/utils relocation (S17) lands
at the manager layer where reorient/mdp/events.py is introduced, and the
handover default/preset changes land with the handover part.
P4-owned share of the lump review-response commits:

- Default the handover task to newton_mjwarp and add the ovphysx object
  preset alias (from 3f9ce324, 29e189bf).
- Source the handover joint/body name lists from the robot assets
  (from 34676102).

S17 (core/utils relocation) defers to the manager layer where
reorient/mdp/events.py is introduced.
Rebuilt from the reviewed lump so the manager counterparts land with
the review rounds folded in: inline section values per file (drift
guarded by the value-parity test incl. sim), identity from the common
modules, the OpenAI variant in its own module, and no sim mixins.

Lump review commits folded: 2c22af0, 792e400, 42675b6,
1f05f85, c6140f9, 173e9dc, 2727616, 1732493,
3659a33, ee272c9, cdaadac.
P5-owned share of the lump review-response commits:

- Relocate the shared reset/rotation helpers into reorient/mdp/events.py
  and EpisodeErrorRecorder into reorient/mdp/rewards.py, removing the
  core/utils.py module (S17, from 428297c2).
- Default the reorient manager cfgs to newton_mjwarp and source the
  hand name lists from the robot assets (from 3f9ce324, 34676102).
- Repoint the Direct env to the relocated helpers.
Rebuilds P6 on the updated P4+P5, folding the P6-owned share:

- Repoint handover to the relocated reorient.mdp helpers after the
  core/utils.py removal (S17 handover side, from 428297c2).
- Inherits N2/preset/reward/names fixes via the rebuilt P4 and P5.
…6415-fold

# Conflicts:
#	source/isaaclab_tasks/isaaclab_tasks/core/handover/handover_manager_env_cfg.py
#	source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/events.py
#	source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/rewards.py
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/allegro_hand/allegro_hand_manager_env_cfg.py
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_camera_manager_env_cfg.py
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_manager_env_cfg.py
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_openai_manager_env_cfg.py
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/events.py
#	source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/rewards.py
@github-actions github-actions Bot added the asset New asset feature or request label Jul 23, 2026
hujc7 added 2 commits July 23, 2026 14:43
Repoints the shadow-hand env.rst source links to the renamed _direct_
modules and lists ovphysx on the OpenAI-FF illustrated row (C1), completing
the dexterous environment docs in the series.
The environment overview updates for the dexterous series belong in the
dedicated docs PR (isaac-sim#6410), not the benchmark part. Reverts env.rst to the
base version here.
@hujc7 hujc7 changed the title [Task Clean-up][Benchmark] Dexterous Part 7/8: Add success-rate support to the benchmark utilities [Task Clean-up][Benchmark] Dexterous Part 7/9: Add success-rate support to the benchmark utilities Jul 23, 2026
@hujc7 hujc7 changed the title [Task Clean-up][Benchmark] Dexterous Part 7/9: Add success-rate support to the benchmark utilities [Task Clean-up][Benchmark] Dexterous Part 8/9: Add success-rate support to the benchmark utilities Jul 23, 2026
The vision env renders through the Isaac RTX tiled camera, whose render
products require the Fabric cloning path. The Newton backend disables
Fabric cloning, so under Newton the rgb annotator has no render products
at num_envs > 1 and the default RGB/depth/semantic render fails with
"Annotator rgb is not attached to any render products".

The shared PhysicsCfg/RobotCfg/ObjectCfg now default to Newton, so the
camera env inherited a Newton default it cannot render with. Override the
camera env's backend PresetCfgs to default to PhysX in __post_init__;
Newton stays selectable via physics=newton_mjwarp for the depth-only
Newton-warp-renderer benchmark path.
hujc7 added a commit that referenced this pull request Jul 24, 2026
…eorientation Direct tasks (#6413)

## Review Map

- **Exact changes**: a stacked PR's page shows the cumulative diff of
its dependency chain; the link pins the commit range that is the PR's
own contribution.
- Links pin specific SHAs and can go stale after a branch update — the
table on #6324 is refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| #6411 Part 1/9: Newton cloner/cubric/visualizer fixes |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6411?label=)
| — | merged |
| #6412 Part 2/9: OVPhysX articulation + manager runtime |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6412?label=)
| — | merged |
| 📌 #6413 Part 3/9: Reorient Direct, torch (this PR) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6413?label=)
| — |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6413/changes/f4895f0f9ee..d29afc75e71)
|
| #6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6414?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6414/changes/d29afc75e71..b10a84948f8)
|
| #6418 Part 5/9: Reorient manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6418?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/d29afc75e71..707d37f8f99)
|
| #6421 Part 6/9: Handover + camera manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6421?label=)
| #6413, #6414, #6418 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/707d37f8f99..b50ac8906fc)
|
| #6410 Part 7/9: Environment overview docs |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6410?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6410/changes/b50ac8906fc..af259c0778d)
|
| #6415 Part 8/9: Benchmark success-rate utilities |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6415?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/b50ac8906fc..c7f2f019d8b)
|
| #6582 Part 9/9: Warp variants → experimental (draft; merges last) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6582?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/d29afc75e71..167c28578b3)
|
| #6324 [DO-NOT-MERGE] Lumped validation reference |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6324?label=)
| ALL | — |

## Summary

- Adds a behavioral `Metrics/success_rate` signal (goal-reach streaks
per episode) and threshold-independent episode orientation-error
diagnostics to the Direct reorientation environments; success gates task
health, reward stays diagnostic.
- Task logic is **torch-first** per the mainline convention (plain torch
buffers; `.torch` accessors only at the core-lib boundary). This
supersedes the earlier warp-first revision of this PR; the warp
implementation moved to `isaaclab_tasks_experimental`
(#6582).
- Lands shared helpers in `isaaclab_tasks.core.utils`
(`EpisodeErrorRecorder`, `sample_joint_positions_within_limits`) with
torch math tests; fixes hand resets below lower joint limits.

## Stacking

- First stack PR; based on `develop`.

## Validation

- Kit-free torch math + utils tests green; Direct state training on
Newton: success rate 0.85–1.00, reward ≈3600–3900 at 2000 iterations,
frame-verified policy video. Full integrated evidence: #6324.

## Review history

- The earlier warp-era review rounds on this PR are superseded by the
torch restack (2026-07-16); the warp implementation and its
review-polished kernels live on in
#6582.

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Reviewed the exact stacked contribution from b50ac890 through f21a2124 (10 files). The inline comments identify correctness, scope, comment-quality, duplication, and repository-hygiene issues that should be addressed before merge. Local verification: 76 focused tests passed and ./isaaclab.sh -f passed; the GPU/Kit rendering test was not run. The PR is currently conflicting with its base.

physx = _ShadowHandCameraManagerSceneCfg(clone_in_fabric=True)
newton_mjwarp = _ShadowHandCameraManagerSceneCfg(clone_in_fabric=False)
ovphysx = physx
default = newton_mjwarp

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Important — the manager camera default remains incompatible with RTX. The final fix changes only ShadowHandCameraEnvCfg, while this scene still resolves to newton_mjwarp (clone_in_fabric=False) and its camera resolves to IsaacRtxRendererCfg. The newly added rendering test uses four environments, so it exercises the exact no-render-products combination described in f21a2124; retrying it as flaky cannot fix a deterministic incompatibility. Make the manager training and play camera defaults PhysX too, or select a compatible renderer, and add a config-level assertion for the resolved pair.

workflow,
consecutive_samples=consecutive_samples,
)
if val is None or not isinstance(val, Real) or not math.isfinite(float(val)):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Important — this changes every existing benchmark's failure semantics. Previously, a missing or non-finite reward/episode-length metric was omitted; now any configured metric fails the job. That is broader than success-rate support and can turn existing workflow runs red when a tag is absent or renamed. Please either scope the new failure behavior to success_rate, or split it into a separately discussed change with coverage for every supported workflow and an explicit changelog entry.

Isaac-Reorient-Cube-Shadow-Camera:
max_iterations: 3000
lower_thresholds:
# interim reward gate: catches pipeline breakage well below the truncated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] These calibration notes are transient review history rather than durable functional documentation: evidence-calibrated, interim, tighten ... once, and provisional describe past runs and future intentions. Move that evidence to the PR or a benchmark artifact. Keep only stable metric semantics next to the configuration; the detailed rationale for why a numeric threshold was chosen should not live here.

state_space = 187 + 27 # asymmetric states + vision CNN embedding

def __post_init__(self):
# The vision env renders through the Isaac RTX tiled camera, whose render

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] The constraint is useful, but this seven-line diagnostic/history comment is too long for the implementation. Keep the stable functional rule only, for example: Default to PhysX because RTX tiled cameras require Fabric cloning; Newton remains available for depth-only benchmarks. Put the failure text and investigation details in the regression test or PR.

@@ -0,0 +1,159 @@
# Copyright (c) 2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] New files must use the repository's current header exactly: Copyright (c) 2022-2026, .... Please replace the single-year 2026 header.

@@ -0,0 +1,8 @@
Added

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This is a second fragment for isaaclab_tasks and describes manager work owned by an earlier stack layer. The repository requires one fragment per touched package. Move this fragment to the owning PR and keep one isaaclab_tasks fragment here. Also add a source/isaaclab/changelog.d/*.skip fragment for the test-only install change, remove the internal with unit tests wording from the user-facing entry, and document the camera default change if it remains in this PR.

def test_reorient_direct_manager_scalars_match(family):
"""Direct cfg scalars equal the manager term params they mirror."""
direct_cfg, manager_cfg = _pairs()[family]
for i, (direct_value, manager_value) in enumerate(_reorient_cases(direct_cfg, manager_cfg)):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This constructs all four config pairs for every parameterized family, and failures report only an opaque case N. Make the cases lazy and named, such as (field_name, direct_value, manager_value), instantiate only the selected pair, and report the field name. That removes repeated construction/lookups and makes CI failures directly actionable.

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Follow-up comment-quality pass: each remaining transient calibration comment and each redundant Verify ... test docstring now has its own inline remediation. The manager interim-threshold block and camera-default comment were already anchored in the previous review.

Isaac-Reorient-Cube-Shadow-Camera-Direct:
max_iterations: 3000
lower_thresholds:
# evidence-calibrated: full-budget Newton run crosses 1000 at iter ~2300

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This records run-specific calibration evidence (iter ~2300, iter ~1000, and a measured tail rate) rather than a stable functional contract. Remove it from the configuration and keep the evidence in the PR or benchmark results. The threshold fields are self-describing.

Isaac-Shadow-Handover:
max_iterations: 3000
lower_thresholds:
# evidence-calibrated: the manager variant plateaus near 785 on PhysX

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This comment explains why 500 was chosen using one observed PhysX plateau. That calibration history will become stale and is not needed to understand the configuration. Remove it and retain the supporting run evidence outside the source file.

# (the Direct rows keep the shared 1000 gate)
reward: 500
episode_length: 150
# provisional gate matching the validation campaign's controller

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] Provisional and matching the validation campaign are process/history notes, not functional documentation. Either define the stable semantics of this gate or remove the comment and track its provisional status in the PR or follow-up issue.

],
)
def test_training_task_filter_excludes_play_and_benchmark(task_id: str, expected: bool):
"""Verify inference-only variants never enter the training benchmark matrix."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This docstring only restates the descriptive test name. Remove it; the test name and parameter cases already express the behavior.

ids=["missing", "nan"],
)
def test_evaluate_job_fails_when_configured_reward_is_unavailable(monkeypatch, log_data):
"""Verify missing or invalid configured metrics cannot produce a successful KPI payload."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This Verify ... docstring repeats the test name without adding a contract or non-obvious constraint. Remove it and keep the test self-documenting through its name and parameter IDs.



def test_evaluate_job_fails_when_success_rate_is_missing(monkeypatch):
"""Verify a missing configured success-rate metric fails."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This docstring restates the test name exactly. Remove it.



def test_evaluate_job_treats_success_rate_as_missing_for_unsupported_workflow(monkeypatch):
"""Verify an unmapped workflow fails the KPI instead of raising an exception."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This docstring repeats the already explicit unsupported-workflow test name and assertion. Remove it.



def test_evaluate_job_fails_when_success_rate_is_nonfinite(monkeypatch):
"""Verify a non-finite configured success-rate metric fails."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This docstring adds no information beyond the non-finite success-rate test name and input. Remove it.



def test_evaluate_job_resets_sustained_success_streak(monkeypatch):
"""Verify a below-threshold sample resets the consecutive-success streak."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This docstring repeats the sustained-streak reset behavior already stated by the test name. Remove it.



def test_scalar_threshold_behavior_is_preserved(monkeypatch):
"""Verify numeric thresholds retain the existing reward aggregation behavior."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] This docstring is redundant with test_scalar_threshold_behavior_is_preserved and the assertions below it. Remove it.

hujc7 added a commit that referenced this pull request Jul 29, 2026
… and enable handover Direct RSL-RL (#6414)

## Review Map

- **Exact changes**: a stacked PR's page shows the cumulative diff of
its dependency chain; the link pins the commit range that is the PR's
own contribution. This PR (#6414) is now rebased directly onto
`develop`, so its own **Files changed** tab is its contribution.
- Links pin specific SHAs and can go stale after a branch update — the
table on #6324 is refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| #6411 Part 1/9: Newton cloner/cubric/visualizer fixes |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6411?label=)
| — | merged |
| #6412 Part 2/9: OVPhysX articulation + manager runtime |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6412?label=)
| — | merged |
| #6413 Part 3/9: Reorient Direct, torch |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6413?label=)
| — | merged |
| 📌 #6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct
(this PR) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6414?label=)
| — (on develop) | Files changed tab |
| #6418 Part 5/9: Reorient manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6418?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/d29afc75e71..707d37f8f99)
|
| #6421 Part 6/9: Handover + camera manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6421?label=)
| #6414, #6418 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/707d37f8f99..b50ac8906fc)
|
| #6410 Part 7/9: Environment overview docs |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6410?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6410/changes/b50ac8906fc..af259c0778d)
|
| #6415 Part 8/9: Benchmark success-rate utilities |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6415?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/b50ac8906fc..c7f2f019d8b)
|
| #6582 Part 9/9: Warp variants → experimental (draft; merges last) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6582?label=)
| — |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/d29afc75e71..167c28578b3)
|
| #6324 [DO-NOT-MERGE] Lumped validation reference |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6324?label=)
| ALL | — |

## Summary

Converts the two-hand Shadow Hand **handover** task from multi-agent
(MARL) to **single-agent** (enabling RSL-RL training), fixes the
underlying MARL→single-agent observation bridge, and consolidates the
shared Shadow Hand definitions into the asset.

- **MARL → single-agent bridge (general, broader than this task).**
Single-agent RL libraries train `DirectMARLEnv` tasks via
`multi_agent_to_single_agent`; the bridge dropped the latest
observations from the public buffer. Fixed generally — RSL-RL
observations read from the env-owned `obs_buf`, stored by `reset` like
`step` on all env bases (`DirectRLEnv`, `DirectMARLEnv`, the
experimental warp base). Every MARL task + single-agent runner benefits;
handover is the first consumer.
- **Handover Direct → single-agent + RSL-RL.** Single-agent conversion,
RSL-RL runner config, shared identity in `handover_common`, success-rate
reward metrics, and a fix for its Newton construction failure (see
below).
- **Shadow Hand Newton robot → the asset.** Moved the Newton (MJWarp)
robot cfg into `isaaclab_assets` as `SHADOW_HAND_NEWTON_CFG` (beside
`SHADOW_HAND_CFG`); reorient and handover consume it as **siblings**
(neither imports the other). Reorient uses the default gains; handover
overrides only the finger stiffness/damping to `20/2` for its catch.
- **Shadow camera cleanup.** Renamed the camera Direct modules to
`shadow_hand_direct_camera_env[_cfg]`; moved cube-keypoint math to the
shared, unit-tested `reorient/mdp/observations.py` (replacing the
per-env `compute_keypoints` shim); and added OVPhysX physics presets to
the handover and camera Direct environments. The camera env config is
otherwise unchanged from develop.

### Behavior changes

**Reorient-on-Newton is unchanged.** The Newton hand definition moves
**verbatim** into `SHADOW_HAND_NEWTON_CFG` — same joint expressions,
effort limits, gains, friction and armature — so its config diff vs
`develop` is purely the move, and the Direct env config has no diff at
all.

Handover changes in three ways:

- Its **default physics backend moves from PhysX to Newton** (MJWarp),
matching the reorientation tasks. Pass `physics=physx` for the previous
backend.
- Its `distal_passive` actuator group is **removed**. It targeted
`robot0_(FF|MF|RF|LF)J0` — joints that **do not exist** on the Newton
asset (its fingers are numbered `J1`–`J4`/`J5`), so constructing the
environment raised `No joints found for actuator group`. The `fingers`
group already drives those joints, and the comment justifying the group
(USD-baked `stiffness=286/damping=57`) does not apply to this asset,
which authors no drive stiffness at all.
- Two orientation fixes: the goal orientation was initialized to a
180-degree rotation instead of identity, and the Newton root rotation
replaced the asset's baked rotation instead of composing with it,
leaving both palms rotated 90 degrees.

Two pre-existing discrepancies were found while verifying against the
asset and are left for a follow-up, since each is a behavior change
needing its own validation: the config sets `armature=2e-3` where the
asset authors `0.0002`, and the per-finger `J1`/`J2` pair is coupled by
a fixed tendon that the MJWarp solver currently skips — the actuator
gains are what hold that pair together today, which is why the `J4`
knuckle-abduction joints cannot simply be added to the driven set.

## Notes

- Rebased onto **latest develop**; clean 3-commit history: `Add
single-agent flattening for MARL Direct environments` / `Convert Shadow
Hand handover to single-agent Direct with RSL-RL` / `Clean up Shadow
reorient/camera tasks and consolidate the Newton hand`.

## Validation

- Kit-free suite green: handover, keypoint math, the MARL adapter, and
new checks pinning the RSL-RL wrapper observation contract (verified to
fail against the previous implementation).
- Camera Direct reaches training takeoff under `rsl_rl` (frame-verified
videos); its env config now matches develop's established vision env.
- **Reorient-on-Newton vs `develop`** (`rsl_rl`, 2048 envs, 1500
iterations, 4 runs per config): this branch spans 524–664 reward,
`develop` spans 654–822 — overlapping distributions whose per-config
spreads (140–168) exceed the gap between them. The move is additionally
verified at the config level: the Newton robot configuration is
character-for-character identical to `develop`'s.
- **Handover-on-Newton** trains end-to-end on this branch (reward 1314),
which the `develop` config cannot do at all — it fails during
construction. Full evidence: #6324.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asset New asset feature or request documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants