Skip to content

[Backport release/3.0.0] Towncrier changelog, camera hot-path 7B, and uv docs CLI (#8118, #8105, #8179) - #8210

Merged
kellyguo11 merged 3 commits into
isaac-sim:release/3.0.0from
hujc7:jichuanh/backport-8118-8105-8179-release-3.0.0
Sep 30, 2026
Merged

kellyguo11 merged 3 commits into
isaac-sim:release/3.0.0from
hujc7:jichuanh/backport-8118-8105-8179-release-3.0.0

Conversation

@hujc7

@hujc7 hujc7 commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Backports three develop PRs to release/3.0.0, in merge order:

  1. [Changelog] Compile changelog fragments with towncrier and keep uv.lock in sync #8118 — towncrier changelog tooling
  2. [Camera] Remove remaining hot-path host syncs and overhead [7B/7] #8105 — camera hot-path cleanup [7B/7]
  3. [Docs] Use uv CLI for Windows documentation builds #8179 — uv CLI for Windows docs builds

The automatic backport failed for #8118 and #8105. For #8179, this supersedes the bot's draft:

Once merged, the nightly compiles release/3.0.0 again: it skips release branches without tools/changelog/towncrier.toml.

Description

Each PR is cherry-picked with -x; every code file matches its source patch. Release-specific changes:

  1. [Changelog] Compile changelog fragments with towncrier and keep uv.lock in sync #8118 (ee99db6a820)
    • Each CHANGELOG.rst conflict resolved as the marker line above the release entries.
    • uv.lock unchanged: release's local package pins already match their pyproject.toml.
    • The bot failed here because uv.lock pushed its conflict context past the 1.5M-character inference limit.
  2. [Camera] Remove remaining hot-path host syncs and overhead [7B/7] #8105 (cd917691992)
  3. [Docs] Use uv CLI for Windows documentation builds #8179 (c1a8bfa50b5)
    • Deletes docs/make.bat; release held an older copy.
    • Splits its fragment the same way.
    • Release's docs/_redirect/index.html still hardcodes ./main/ ([CI] Prepare develop as repository and docs default #7767 is not on this branch), so isaaclab --docs_multi writes that redirect unchanged, as release's make multi-docs does.

Type of change

Validation

  1. cli.py check release/3.0.0 passes.
  2. tools/changelog tests: 18 passed.
  3. pre-commit over the range passes.
  4. cli.py compile on a scratch copy of this branch:
    • 9 packages bumped, including isaaclab 25.1.0 → 26.0.0 and isaaclab_tasks_experimental 0.0.1 → 1.0.0
    • every fragment consumed, only its outputs staged
    • uv.lock changed in version lines only
  5. Runtime coverage for [Camera] Remove remaining hot-path host syncs and overhead [7B/7] #8105 and [Docs] Use uv CLI for Windows documentation builds #8179 is left to CI.

Release backport

This PR targets the release branch; no additional backport is needed.

Checklist

hujc7 and others added 3 commits September 30, 2026 11:53
…ck in sync (isaac-sim#8118)

- Replaces the custom changelog compiler with towncrier and `uv
version`: `tools/changelog/cli.py` shrinks from 1,146 to ~320 lines and
compiles today's pending fragments to the same versions and entries.
- Keeps `uv.lock` in step with the nightly version bumps, so a clean
checkout's first `uv run` no longer rewrites it.

- **Fragments:** one `<slug>.<type>.rst` per entry type (`added`,
`changed`, `deprecated`, `removed`, `fixed`) holding only `* ` bullets;
an empty `<slug>.minor` / `<slug>.major` raises the bump; `<slug>.skip`
is unchanged. The check rejects the old `<slug>[.minor|.major].rst`
format. The nightly still splits old-format fragments merged before this
change or without re-running CI, in a marked workaround section of
`cli.py` that never overwrites an existing fragment; delete that section
once none are pending.
- **`cli.py check`** (pre-commit and the fragment-check job): each
changed package must add a valid fragment and may not change a pending
one; every `CHANGELOG.rst` keeps the `.. towncrier release notes start`
marker line; each local package must be in `uv.lock` at its
`pyproject.toml` version. The rest of the lock is not resolved, so
unrelated dependency drift never fails a PR.
- **`cli.py compile`** (nightly): runs only on a clean checkout. Per
package, `uv version --bump` + `towncrier build`, then one `uv lock` on
the uv pinned in the Docker images. If the re-lock fails or would change
anything but local packages' versions, nothing is committed that night.
`compile` stages exactly its outputs and reports any other changed file.
- **Nightly:** compiles only branches carrying
`tools/changelog/towncrier.toml`; release branches pick the change up by
backport.
- **`isaaclab_tasks_experimental`** gains a `CHANGELOG.rst`, so its
pending fragments now compile.
- **`uv.lock`** is re-locked once: 9 local package pins had fallen
behind their `pyproject.toml`.
- Supersedes isaac-sim#5867.

**Before / after**, for a PR that adds a feature and a fix with a minor
bump.

Before: one file,
`source/isaaclab/changelog.d/add-foo-sensor.minor.rst`:
```rst
Added
^^^^^

* Added :class:`~isaaclab.sensors.FooSensor` for per-link foo readings.

Fixed
^^^^^

* Fixed contact sensor reset behavior when only a subset of environments was reset.
```
After: one file per type, plus an empty tier file:
```text
* Added :class:`~isaaclab.sensors.FooSensor` for per-link foo readings.

* Fixed contact sensor reset behavior when only a subset of environments was reset.

(empty)
```
Both compile to the same `CHANGELOG.rst` entry: the check rejects the
first in new PRs, and the nightly splits any already merged into the
second.

Verified in a scratch clone of `develop`: `compile` produced the old
tool's versions for all 9 packages with pending fragments,
byte-identical `CHANGELOG.rst` entries for 7 and the same bullets in
fragment-name order (instead of merge order) for 2, consumed every
fragment, staged only its outputs, and changed only version lines in
`uv.lock`.
CI also runs a unit test with the real uv and towncrier.

- New feature (non-breaking change which adds functionality)
- Bug fix (non-breaking change which fixes an issue)
- Documentation update

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

Not applicable.

Docker and GPU tests run on demand. Push the commits you want tested,
then
comment `run-ci` on the pull request.

- [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/) on
the changed files
- [x] I have made corresponding changes to the documentation
- [ ] 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 `.skip` changelog fragment for each package whose
`CHANGELOG.rst` gained the marker; the tooling itself is outside the
source packages
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

(cherry picked from commit ee99db6)
…aac-sim#8105)

Part 7B of the camera performance series, based on the latest `develop`
(including isaac-sim#8039, isaac-sim#8042, and isaac-sim#8087). A sweep of the per-step hot path
found remaining host-device synchronizations and code that costs more
than it gives. This PR fixes the verified findings: it removes the
synchronizations, launch overhead, and dead or over-defensive code, and
fixes the verified bugs.

Profiling on `develop` motivated this. The GPU sat idle 20–27% of each
step, because the CPU blocked on synchronizations and then launched
hundreds of small kernels. On `Isaac-Velocity-Rough-AnymalD` (4096
environments), for example, the CPU was blocked 12.8 ms of a 25.4 ms
step.

- **Episode logging:** the command, termination, and curriculum
managers, `survival_success_rate`, the pose commands, and task success
rates (Cabinet, Locomotion, Lift deformable/cable, Fourbar) log 0-d
device tensors instead of reading back `.item()`/`.cpu()` on every
reset. `RewardManager` already logged tensors, and the RL wrappers
accept them. Curriculum states are logged as copies, because rsl_rl
keeps episode infos for a whole rollout. The inspection accessor
`get_active_iterable_terms()` still returns Python scalars.
- **Velocity command:** heading control is branchless (`torch.where`)
instead of `is_heading_env.nonzero()` every step. Output is identical.
- **Event ranges:** core and Lift event terms use
`sample_uniform_from_ranges()` to draw named components directly. One
private, bounded bounds cache replaces both sets of tensor-building
helpers; it is keyed by values, resolved device, and dtype. Curriculum
edits take effect on the next call, and every call draws fresh samples
in the existing order.
- **Ray caster:** `reset()` no longer uploads its range tensor or
samples drift when the drift ranges are zero (the default). In rough
locomotion this reset runs almost every step. When drift is disabled
after sampling, reset clears the selected environments’ old drift.
- **DiffIK:** the `if ee_quat.norm() != 0` guard in `apply_actions`,
which synchronized every physics substep, is now a `torch.where` with
the same all-or-nothing behavior.
- **Direct tasks:** Reorient (about 14 host-list indexes per substep),
Cabinet, and Locomotion store joint and body indices as device tensors,
precompute static joint limits and default positions, and use the
non-deprecated `actuators.target_command` API.
- **Other task terms:**
- Locomotion `walk_target_w` caches its device target (it synchronized 4
times per step).
- Reorient's `EpisodeErrorRecorder` uses `torch.where` with NaN
reductions instead of boolean masks.
- Lift reset events share the named-range sampler with the core event
terms.
- **Joint limits:** Newton, PhysX, and OvPhysX position-limit writes
reuse the clamping counter and read it back only when the resulting
message would be logged.

- **`RewardManager`:** each term writes its weighted value into a
step-reward matrix column, followed by one sum and one batched
episode-sum update. Reset is one mean and one fill. With 20 terms at
4096 environments, compute drops from 121 to 23 kernels (471 → 152 µs)
and reset from 80 to 4 kernels (504 → 49 µs).
- **`ObservationManager`:** the built-in noise functions
(`constant_noise`, `gaussian_noise`, `uniform_noise`) are out-of-place,
so the pre-noise clone and the second clone are skipped. Safe built-in
noise functions are identified during `_prepare_terms`; custom noise
functions, noise models, and modifiers still clone, including when a
caller replaces a noise function after setup. The noise sampling order
is unchanged.
- **`CircularBuffer`:** one staged shift replaces K−1 slot copies for
frames up to 2 MiB. Image-sized frames keep the slot loop, which is
faster for them.
- **Lift contacts:** one stacked norm replaces per-sensor norms.
`contacts()` runs 5 times per step in Kuka Allegro, and this removes
about 80 kernels per step.
- **ANYmal symmetry augmentation:** one cached permutation and sign
tensor per transform, bitwise-equal to the original, is 1.56 → 0.15 ms
per call at 4096 environments.
- **RTX renderer:** normals, motion vectors, `rgb_hdr`, and simple
shading no longer copy each frame into a contiguous channel slice before
reshaping.
- **Smaller changes:**
- Reorient reads its command slices directly instead of concatenating
them.
  - sb3 computes `dones` on the host side.

- **`NewtonManager.step()`** ran the solver-internals reset every
physics step. `forward()` already performs it when kinematics are dirty,
so the extra call only launched with an all-False mask.
- **`WrenchComposer.reset()`** returns early when inactive. Its buffers
are already zero, and this removes about 7 memsets per rigid object per
physics step (21 µs → 0.07 µs per call).
- **`SensorBase`:** sensors with `debug_vis=True` no longer refresh on
every physics substep. That refresh existed because debug callbacks once
read private data. The callbacks now refresh the outdated buffers
themselves. The original eager update was introduced in commit
`4565902f5` to make visualization work without a `data` read; it did not
pump rendering.
- **`VisualizationMarkers.visualize()`** returns early when no backend
is active.
- **Dead code:** removed the Newton Warp renderer's output copy loop
(every output is a zero-copy alias), the impossible PhysX ray-caster
guard, and the redundant Lift `body_state_b` index conversion (redundant
since isaac-sim#8087).

- **Newton `body_com_acc_w`:** the finite difference divided by the
physics timestep even when an update spans several physics steps (Newton
owning the decimation loop). That made the acceleration, and
`body_lin_acc_l2`, `decimation`× too large. It now uses the elapsed
time, matching `joint_acc`. The OvPhysX rigid-object implementation uses
the same elapsed-time formula. PhysX and OvPhysX articulations read
acceleration from the backend, so they do not need this
finite-difference change.
- **`reset_root_state_uniform`** built its range tensors in `__init__`
and ignored call-time `pose_range`/`velocity_range`, so curriculum
updates were silently dropped.

- **Step reset, command resample, and interval-event `nonzero`:** these
are now the only synchronizations left in
`Isaac-Velocity-Rough-AnymalD`. Each converts a mask into
variable-length environment IDs consumed across the reset, command, and
event APIs. Removing them requires a mask-based API redesign and is left
for a separate design.
- **Needs a Kit trace before changing:** the PhysX IMU/PVA per-update
COM upload, PhysX contact-sensor per-substep fetches, and the Fabric
render synchronizations. They rely on PhysX/Fabric semantics we have not
measured. A similar "pageable upload synchronizes" assumption proved
false for the Newton sensor flags.
- **Deferring the MPM sparse-grid status check:** a solver reset clears
the status, so a deferred check could lose capacity errors, and no test
covers this path.
- **RMPflow guard:** it already runs on the host, so removing the guard
gains nothing. The `joint_actions` allocation is needed for LEAPP export
tracing.
- **Lower confidence, left out:** collection mask-write kernels and
batching model-change notifications.

- Bug fix (non-breaking change which fixes an issue)
- Behavior changes with migration notes in the changelog fragments:
- Episode log values are 0-d tensors; use `float()` or `.item()` where a
Python number is needed.
- Reorient direct index attributes (`actuated_dof_indices`,
`finger_bodies`, `finger_wrench_bodies`) and `resolve_actuated_tendons`
ids are tensors.
- `EpisodeErrorRecorder` reports NaN for an empty selection after its
first update.
- Custom sensors should refresh their buffers inside
`_debug_vis_callback`.

RTX PRO 6000 Blackwell Workstation Edition (driver 595.91.07); PyTorch
2.12.0+cu130; Warp 1.17.0; Newton 1.6.0; GPU otherwise idle. `develop`
at `60bc09f17` compared with this PR on that base, with the same
`uv.lock`. The branch has since merged `develop` at `f25d3f09b` (isaac-sim#8042,
changes the Kuka camera observations and isaac-sim#8090 touches the simulation
context, so they have not been re-measured on the merged branch or after
review fixes. Static Lift success markers now resend positions to
support late backend activation; the earlier marker-index-only
optimization is not included. Runtime benchmark (`isaaclab benchmark
runtime`), Newton/MJWarp, seed 42, no visualizer. Three fresh processes
per revision, run in alternating order. Figures are the mean step time
across processes; every workload's per-process ranges are disjoint.

| Workload | `develop` | This PR | Change |
| --- | ---: | ---: | ---: |
| `Isaac-Ant`, 4096 envs | 3.369 ms | 2.629 ms | **−22.0%** (+28.1%
throughput) |
| `Isaac-Open-Drawer-Franka-Direct`, 4096 envs | 11.106 ms | 10.100 ms |
**−9.1%** (+10.0%) |
| `Isaac-Reorient-Cube-Allegro-Direct`, 4096 envs | 27.114 ms | 25.221
ms | **−7.0%** (+7.5%) |
| `Isaac-Velocity-Rough-AnymalD`, 4096 envs | 23.078 ms | 22.573 ms |
−2.2% (+2.2%) |
| `Isaac-Lift-KukaAllegro-Camera`, 256 envs,
`presets=duo_camera,rgb128`, Newton renderer | 12.396 ms | 12.202 ms |
−1.6% (+1.6%) |

Per-process step times (`develop` → PR):
- Ant: `3.367, 3.359, 3.382` → `2.639, 2.638, 2.611` ms.
- Drawer: `11.113, 11.102, 11.104` → `10.099, 10.100, 10.100` ms.
- Reorient: `27.136, 27.136, 27.070` → `25.217, 25.250, 25.197` ms.
- AnymalD: `23.081, 23.050, 23.103` → `22.551, 22.568, 22.599` ms.
- Camera: `12.389, 12.374, 12.424` → `12.373, 12.119, 12.113` ms.

Host synchronizations per `env.step()`, attributed to call sites with
PyTorch sync-debug mode over 170 steps:

| Task | `develop` | This PR | Remaining |
| --- | ---: | ---: | --- |
| `Isaac-Velocity-Rough-AnymalD` | 6.75 | 3.00 | step reset, command
resample, and interval-event `nonzero` |
| `Isaac-Lift-KukaAllegro-Camera` | 2.11 | 2.04 | step reset and command
resample `nonzero`; curriculum difficulty `.item()` (0.04 per step) |

PyTorch labels sync-debug mode a prototype that does not detect every
synchronization, and it does not see synchronizations issued by Warp, so
these counts are lower bounds.

- The shared sampling refactor passed 257 tests across the existing
math, root-state event, and Lift configuration suites. The existing
event test now checks exact seeded samples, key order, missing axes,
fresh draws, range edits, and warm-cache CUDA synchronization. Eight
standalone equivalence checks also passed across CPU/CUDA,
float32/float64, and flat/nodal batch shapes. No new tests or test files
were added.
- Before the shared-sampler refactor, 205 focused tests passed, with
each file run in its own process: curriculum, observation, reward, and
termination managers; heading commands and mutable event ranges; DiffIK;
wrench composition; ray-caster and sensor-base behavior; marker
visualization; Lift and reorientation helpers; and the existing
joint-limit tests on both PhysX and OvPhysX, on CPU and CUDA. Kit tests
used the `isaacsim` extra, and OvPhysX used `ovphysx` with separate
CPU/GPU processes.
- Regression checks fail with the old curriculum accessor, stale drift,
and static marker behavior restored. Mutations also turn the retained
tests red for custom-noise aliasing, eager debug-visualization
refreshes, partial reward reset corruption, and missing reorientation
NaN statistics.
- Applied the test-audit skill: seven standalone tests were consolidated
into existing reward, wrench, reorientation, marker, ray-caster,
sensor-update, and Lift tests. Synchronization tests run on CUDA instead
of repeating the same bookkeeping on CPU. No new test functions or files
were added in the review-fix commit.
- Retained unique heading, curriculum snapshot, mutable-range, and
ANYmal symmetry coverage: there is no equivalent existing owner test.
The symmetry test checks the new permutation tables against the previous
independent index-assignment formulation.
- `uv run isaaclab -f` passed, including changelog checks against the
actual PR base, and `git diff --check` passed.
- The full test suite and training smoke runs have not been repeated on
this revision; benchmark figures above describe the earlier measured
revision.

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

- [x] I have read and understood the contribution guidelines.
- [x] I have run the pre-commit checks with `uv run --frozen isaaclab
-f`.
- [x] I have made corresponding changes to the documentation.
- [x] I have added tests that prove the behavior and checked the
regressions against the unfixed code.
- [x] I have added a changelog fragment for every touched source
package.
- [x] My name already exists in `CONTRIBUTORS.md`.

(cherry picked from commit cd91769)
Use the existing uv-backed `isaaclab --docs` command for current
documentation on Windows and Linux. Add `isaaclab --docs_multi` for the
multi-version build, remove the obsolete Windows batch script, and
simplify `docs/README.md` to use the same commands on both platforms.

Set an explicit Isaac Sim intersphinx inventory URL. The single-slash
inventory URL returns 200; the double-slash URL reported in the issue
returns 404. Add a Windows docs build check for PRs that change docs or
the CLI.

Documentation builds reuse the repository uv environment with the `dev`
extra. Current builds clear HTML output and doctrees before running
Sphinx. Missing multi-version redirect targets report an actionable CLI
error.

Fixes isaac-sim#5273.

- Bug fix
- Documentation update

- Focused CLI tests with uv-managed Python — 9 passed. Covered current
output/cache cleanup, `--docs_multi` dispatch, redirect generation and
ref override, and missing-ref failure.
- Full local current-documentation Sphinx build passed without warnings
using the existing uv-managed environment. The corrected
deprecated-material link was verified in rendered HTML.
- Repository formatting and lint hooks passed. Changelog fragments
passed against the upstream base; the fork's local `origin/develop` is
stale.
- Windows build is covered by the PR workflow and will run on this
update.

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

(cherry picked from commit c1a8bfa)
@hujc7

hujc7 commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@github-actions github-actions Bot added documentation Improvements or additions to documentation asset New asset feature or request isaac-mimic Related to Isaac Mimic team infrastructure labels Sep 30, 2026
@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 30, 2026
@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium risk] Backport of changelog tooling migration and performance optimizations.

The PR should not merge until the multi-version documentation redirect points to the selected built ref.

Findings

  1. P1 Redirect targets the wrong version ▶
  2. P2 Marker content is silently discarded ▶
  3. P2 Orphan paragraphs pass validation ▶

Summary

The backport migrates package changelogs to Towncrier and uv, adds a cross-platform documentation CLI, and carries simulation hot-path changes across managers, sensors, backends, and tasks.

  • The new multi-version CLI does not update the checked-in redirect to its selected documentation ref.
  • The fragment gate leaves two actionable validation gaps.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  F[Package changelog fragments] --> C[cli.py check]
  C --> N[Nightly compile]
  N --> T[Towncrier release notes]
  N --> V[Package version bumps]
  V --> L[uv.lock refresh]
  D[isaaclab --docs_multi] --> B[Built versioned docs]
  B --> R[Root redirect]
Loading

Reviews (1) · Last reviewed commit: "[Docs] Use uv CLI for Windows documentat..."

Comment on lines +110 to +111
template = (docs_dir / "_redirect" / "index.html").read_text(encoding="utf-8")
(out_dir / "index.html").write_text(template.replace("__DOCS_DEFAULT_REF__", default_ref), encoding="utf-8")

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.

P1 Redirect targets the wrong version

When isaaclab --docs_multi builds the default v3.0.0-EA ref or a ref selected through DOCS_DEFAULT_REF, this replacement does nothing: the checked-in template contains ./main/index.html, not __DOCS_DEFAULT_REF__. The target check can pass while the generated redirect still sends readers to main, or to a missing page if main was not built. The existing Makefile rewrites the actual URL; the new test instead uses a template with the placeholder.

Comment thread tools/changelog/cli.py
Comment on lines +124 to +125
if MARKER_RE.match(path.name):
return []

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 Marker content is silently discarded

The gate accepts a nonempty .skip, .minor, or .major file without checking its contents. These files are meant to be empty, and Towncrier hides their contents, so a contributor who puts release-note text in one gets a passing check but loses that note during compilation. Reject nonempty markers to make the mistake visible.

Comment thread tools/changelog/cli.py
Comment on lines +114 to +118
if not re.search(r"^\s*\*", text, re.MULTILINE):
return "has no ``* `` bullet"
if re.search(r"^(?!\*|\s|$)", text, re.MULTILINE):
return "has a line that is neither a ``* `` bullet nor an indented continuation"
return None

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 Orphan paragraphs pass validation

A fragment can start with an indented paragraph and place a bullet later: the first check finds that bullet, while the second accepts the earlier indented line as a continuation. The PR gate therefore accepts content that is not a bullet list, leaving malformed RST for the nightly changelog. Only accept an indented continuation after a bullet.

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

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.

Isaac Lab Review Bot

The backport coherently integrates towncrier, hot-path optimizations, and the uv-backed documentation CLI, but it also introduces several immediate compatibility breaks without deprecation bridges. The release-specific multi-version redirect and marker-fragment validation also need correction, and the Windows workflow should follow the repository’s action-pinning convention.

  • Design and architecture: The changelog check/compiler split, cached range tensors, batched reward updates, and cached ANYmal symmetry tables are coherent. However, the hot-path design transfers ownership obligations from framework boundaries to extension implementations: noise callbacks must now preserve inputs, and sensor debug callbacks must refresh buffers themselves. Those shifts affect established extension contracts and need a compatibility transition rather than immediate enforcement.
  • API: The additive isaaclab --docs_multi, command_build_docs(multi_version=...), and sample_uniform_from_ranges APIs are consistent with surrounding interfaces. Existing API behavior changes are not additive: manager reset and logging values switch from floats to tensors, task index attributes and resolve_actuated_tendons switch from lists to tensors, headless marker visualization stops validating inputs, noise callbacks lose defensive copies, and sensor debug callbacks acquire a new refresh obligation.
  • Compatibility and deprecation: Breaking changes: docs/make.bat is removed without a forwarding wrapper; manager reset and task logging values change from Python floats to device tensors; configured noise callbacks now receive un-cloned observation storage; headless VisualizationMarkers.visualize calls no longer enforce the prior validation contract; external SensorBase debug-visualization implementations must refresh their own buffers; and public task index attributes plus resolve_actuated_tendons change from lists to tensors. Changelog and documentation migration notes are present, but none of these changes has the required functional old-contract bridge, targeted warning, removal guidance, and transition coverage.
  • Implementation: The changelog rollback/staging flow, lock-pin checks, docs build cleanup, drift caching, reward batching, and circular-buffer shift paths were traced. Two concrete issues remain: the release branch’s redirect template hardcodes ./main/, so replacing __DOCS_DEFAULT_REF__ is ineffective while the gate checks a different default target; and marker fragments matching .skip, .minor, or .major are accepted even when non-empty, allowing hidden content to be silently discarded during compilation.
  • Style consistency: The Python naming, docstrings, helper placement, and surrounding implementation patterns are generally consistent. The new Windows documentation workflow uses the floating actions/checkout@v6 tag despite adjacent workflows—and the setup-uv step in the same file—pinning actions to reviewed commit SHAs. Pin checkout consistently.
  • Test quality: The changed tests provide distinct coverage for root-state range edits, noise ownership, reward batching and partial reset, drift clearing, lazy sensor visualization, marker behavior, circular-buffer shifts, renderer channel handling, and changelog compilation. Several tests currently codify the immediate breaking contracts rather than covering deprecation transitions. The docs redirect test supplies a placeholder template and therefore misses the release branch’s hardcoded ./main/ template, while the changelog tests do not reject non-empty marker files.

Significant concerns. Posted 9 actionable findings inline.

Automated review; human maintainers own approval decisions.

Comment thread docs/make.bat
@@ -1,65 +0,0 @@
@ECHO OFF

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.

🟡 Warning · Compatibility — Windows docs entry point removed outright

Deleting docs/make.bat removes the documented make.bat current-docs and make.bat multi-docs entry points immediately; updating docs/README.md and the contribution guide is migration guidance, not a transition. Existing Windows scripts and contributor muscle memory break without notice. Keep a thin batch wrapper that forwards both targets to isaaclab --docs / --docs_multi and prints replacement and removal guidance for the deprecation window.

for metric_name, metric_value in self.metrics.items():
# compute the mean metric value
extras[metric_name] = torch.mean(metric_value[env_ids]).item()
extras[metric_name] = torch.mean(metric_value[env_ids])

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.

🟡 Warning · Compatibility — Reset metrics change from floats to tensors

CommandTerm.reset changes its annotated and actual return from dict[str, float] to device tensors, and the same swap lands in TerminationManager.reset, CurriculumManager.reset and the task extras["log"] writers. Consumers that serialize or apply float-only arithmetic to these values break with no compatibility path. Retain the scalar contract during deprecation and expose the sync-free tensor metrics under a separate key or API.

# Noise callbacks must not modify their input, but may return borrowed storage.
if isinstance(term_cfg.noise, noise.NoiseCfg):
obs = term_cfg.noise.func(obs.clone(), term_cfg.noise)
obs = term_cfg.noise.func(obs, term_cfg.noise)

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.

🟡 Warning · Compatibility — Noise callbacks lose defensive input copy

Dropping obs.clone() requires every configured NoiseCfg.func/NoiseModelCfg to leave its input untouched. An existing in-place callback (previously safe, and not forbidden by the old docstring) now writes into term-owned or asset-owned storage. The changelog marks this Breaking, but no transition exists: no warning on the old path and no opt-out. Keep the copy for the deprecation window while warning on mutation, or gate zero-copy behind explicit opt-in.

if not self.is_visible():
# If no backend consumes markers (e.g. headless) or markers are hidden, do not spend
# time normalizing or dispatching marker state.
if not self._backends or not self.is_visible():

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.

🟡 Warning · Compatibility — Headless visualize skips documented input validation

Returning before normalization when self._backends is empty means mismatched shapes and all-None calls now succeed silently in headless runs, although the docstring still documents ValueError for both. The same call then raises once a backend is active, making the failure contract depend on rendering configuration. Keep the inexpensive validation ahead of the backend early return and skip only the backend dispatch.

# Update the buffers
if force_recompute or self._is_visualizing:
# Update the buffers; debug visualization refreshes lazily from its callback.
if force_recompute:

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.

🟡 Warning · Compatibility — Debug visualization refresh moved to subclasses

update() no longer refreshes outdated buffers when debug_vis is enabled, so every sensor overriding the protected _debug_vis_callback must now call _update_outdated_buffers() itself. In-repo sensors were updated, but external sensors silently draw stale data with no warning or error. Preserve the eager refresh for the deprecation window, or refresh once before dispatching callbacks from the visualization registry.

device: str,
position_limits: tuple[float, float],
) -> tuple[list[int], torch.Tensor, torch.Tensor]:
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:

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.

🟡 Warning · Compatibility — Public index attributes change to tensors

resolve_actuated_tendons now returns a torch.Tensor instead of list[int], and the changelog documents the same switch for the public actuated_dof_indices, finger_bodies, finger_wrench_bodies, arm_joint_ids and finger_joint_ids attributes. Callers using list equality, membership, concatenation or serialization break immediately; a .tolist() note is migration guidance, not a bridge. Keep the list contracts and cache device tensors privately until a deprecation cycle completes.

runs-on: windows-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v6

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.

🔵 Suggestion · Style Consistency — Checkout action not pinned to SHA

Every other workflow pins actions to a commit SHA with a version comment (actions/checkout@de0fac2e... # v6 in changelog-check.yml), and the astral-sh/setup-uv step two lines below in this same file is pinned. Pin actions/checkout the same way instead of the floating @v6 tag so the action cannot drift outside reviewed changes.

if multi_version:
default_ref = os.getenv("DOCS_DEFAULT_REF", "v3.0.0-EA")
run_command(cmd + ["sphinx-multiversion", ".", str(out_dir), "--jobs=auto"], cwd=docs_dir)
if not (out_dir / default_ref / "index.html").is_file():

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.

🔵 Suggestion · Implementation — Multi-version redirect gate may mismatch target

The new gate aborts unless DOCS_DEFAULT_REF (default v3.0.0-EA) was built, while the redirect is produced by substituting __DOCS_DEFAULT_REF__ in _redirect/index.html. On this branch that template still hardcodes ./main/, so the substitution is a no-op: a build with main present fails the gate, and a passing build still redirects elsewhere. Add the placeholder to the release template or default the ref to the hardcoded target.

Comment thread tools/changelog/cli.py
def check_fragment(path: Path) -> list[str]:
"""Return the errors of one added fragment, named relative to the repository."""
rel = path.relative_to(REPO_ROOT)
if MARKER_RE.match(path.name):

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.

🔵 Suggestion · Implementation — Marker fragments accepted without empty-content check

check_fragment returns success for any name matching MARKER_RE without inspecting contents, but the contribution guide defines <slug>.skip, <slug>.minor and <slug>.major as empty files and the towncrier config hides them with showcontent = false. A contributor who writes bullets into a tier file passes the gate and loses the entry at compile time. Reject marker files with non-whitespace content.

@kellyguo11
kellyguo11 merged commit 9671fd0 into isaac-sim:release/3.0.0 Sep 30, 2026
56 checks passed
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 infrastructure isaac-mimic Related to Isaac Mimic team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants