Skip to content

[CI] Cross-platform — Part 3: Windows workflow - #5700

Open
hujc7 wants to merge 24 commits into
isaac-sim:mainfrom
hujc7:jichuanh/windows-spark-ci-perception
Open

hujc7 wants to merge 24 commits into
isaac-sim:mainfrom
hujc7:jichuanh/windows-spark-ci-perception

Conversation

@hujc7

@hujc7 hujc7 commented May 20, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Windows gets the same CI shape as ARM: the locked uv environment runs the windows_ci marker tests through the shared orchestrator (tools/conftest.py), then the shared Cartpole smoke, then camera Cartpole trained on every physics and renderer pairing. Windows has no Docker, so the job syncs the environment on the runner and keeps it there between jobs, and restores the Linux jobs' Warp and shader caches.
  • The installation suite (install_ci) gets a Windows job beside x86 and ARM, run natively.
  • The checks the workflow used to run as inline scripts are now test files.

Description

Part 3 of the cross-platform CI series (Part 1 #5695 and Part 2 #5698 are merged). Runs on the [self-hosted, gpu-windows] runners.

1. Jobs

# Job Mirrors Runs
1.1 Windows CI / windows-ci ARM CI / Build & Test uv sync --frozen --extra test --extra isaacsim --extra ov into an environment kept in the runner's tool cache; restores the Warp kernel, Kit shader and OVRTX shader caches; CI_MARKER=windows_ci pytest tools; install_ci/misc/cartpole_training_smoke.py on Newton, as on ARM; install_ci/misc/cartpole_backend_combinations_smoke.py: Isaac-Cartpole-Camera-Direct on each of the 10 pairings of {Newton MJWarp, Newton Kamino, Isaac Sim PhysX, OvPhysX} x {Newton, OVRTX, Isaac RTX} renderer that can share a process
1.2 Installation Tests / Installation Tests (Windows) Installation Tests (x86) / (ARM) tools/run_install_ci.py native on a wheel built with Git's bash: fresh uv sync --locked (base, isaacsim) with Cartpole training on Newton and Isaac Sim PhysX, wheel installs, lock resolution

2. windows_ci tests

# File Checks
2.1 isaaclab/test/utils/test_{configclass,dict,episode_data,hdf5_dataset_file_handler}.py Existing unit tests, now marked

3. Orchestrator on Windows

tools/conftest.py keeps its Linux behavior and gains three Windows paths:

  • Output: Windows cannot select() on pipes, so each pipe is peeked (PeekNamedPipe) before a read.
  • Kill: Windows has no process groups, so a hung test's tree is killed with taskkill /T.
  • Report names: the drive colon is dropped; Windows would read it as an alternate data stream.

4. Design notes

  • uv: astral-sh/setup-uv v10.2.0 with uv 0.12.9, the uv the Docker images pin. v6, which the Linux workflows and the install-CI actions use, crashes on exit on these runners once uv is in the tool cache (Node/libuv assertion error on Windows self-hosted GitHub Actions runner astral-sh/setup-uv#686).
  • Environment: checkout cleans the workspace, so the environment lives in the runner's tool cache. A reused runner re-syncs only what uv.lock changed and keeps the packages' compiled bytecode; a failed sync rebuilds it once.
  • Caches: the Linux test jobs' Warp kernel cache and OVRTX shader caches (Kit's and the kit-less renderer's), each in a Windows collection: pull requests restore the newest snapshot, pushes to protected branches save what changed. The shared actions run bash, which resolves to WSL on these runners, so .github/scripts/windows_ci_caches.ps1 rebuilds the same keys (with the installed Isaac Sim and ovrtx versions) and reports. The caches sit on the runner beside the environment, so a reused runner keeps what earlier pull requests compiled; a save clears them first and publishes only the restored snapshot plus what that push compiled. Pull requests also run in the kept environment and uv cache, so a save reinstalls the environment from a uv cache of its own. uv, the Python it installs and the runner's own files still carry over from pull-request jobs; only runners kept apart from pull requests avoid that. Warp reports its directory with the \\?\ prefix on Windows, which tools/verify_warp_cache.py rejects, so the script checks the path itself.
  • Isaac Sim version: the Windows installation tests install isaacsim 6.2.0.0 from pypi.nvidia.com, as the lock gives users.

5. Test plan

  • pre-commit, the changelog check, and the orchestrator's unit tests (tools/test_crash_journal.py, tools/test_file_scheduler.py) pass.
  • On Linux, CI_MARKER=windows_ci pytest tools selects the four marked files and passes them (62 tests).
  • On a Windows 11 VM (L40), the Newton Cartpole smoke cases pass against an environment outside the checkout: 209 s with a cold Warp kernel cache, 69 s warm.
  • Camera Cartpole on every pairing, before the caches were wired: 10/10 trained; 19.5 min on a fresh runner (5.5 min sync, first Newton, OVRTX and Isaac RTX runs 132 / 235 / 180 s), 4.3 min on a reused one (17-29 s per pairing).
  • windows-ci green with the combinations and caches (run 40006339958): 5.0 min on a reused runner (sync 0 s, combinations 220 s); 17.3 min on a runner with nothing installed or cached, before main has saved a Windows cache (sync 245 s, combinations 680 s, of which the first OVRTX and Isaac RTX pairings compile shaders for 223 and 189 s). The Kit, OVRTX and Warp caches fill to 141, 119 and 75 MB.
  • Still green after the push runs began rebuilding the environment (run 40043168812, 23a67be): 19.7 min on another runner with nothing installed or cached (sync 327 s, combinations 646 s); the rebuild itself runs only on pushes.
  • Installation Tests (Windows) under 10 min on a reused runner, the budget windows-ci meets at 5.0 min. While iterating, TEMP commits mask jobs with no signal for this change; they are reverted before review.
  • Installation Tests (Windows) green, 8/8 in 10.1 min (run 38380247601). The first run failed test_workspace_trains[isaacsim]: pytest's default base temp on the runner put Kit's DLLs past the 260-character path limit, so the job now passes --basetemp under RUNNER_TEMP.

Type of change

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

Release backport

  • Backport this pull request to the active release branch after it merges into develop

Screenshots

Not applicable.

Checklist

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

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with uv run isaaclab --format
  • Documentation changes are not required because the documented install path is unchanged
  • My changes generate no new warnings
  • I have validated the changed behavior with focused coverage and applied the test-audit criteria to any test changes
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump package versions — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added isaac-lab Related to Isaac Lab team infrastructure labels May 20, 2026

@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.

Review Summary

This PR adds experimental Windows CI jobs for perception smoke testing, building on the uv-based installation path. The approach is well-structured, with incremental jobs that progressively test more functionality.

✅ Strengths

  1. Incremental approach: The workflow builds from simple torch/scipy tests → IsaacLab core install → full perception smoke
  2. Cross-platform fix in AssetConverterBase: Moving from hardcoded /tmp/IsaacLab to tempfile.gettempdir() is the correct POSIX/Windows-agnostic solution
  3. Proper marker recognition in AppLauncher: The windows_ci and arm_ci markers are now correctly filtered from sys.argv
  4. Good use of continue-on-error: true: Appropriate for experimental jobs that should not gate merges

Architecture

  • ✅ Clean separation of reusable GitHub Actions (windows-instance-state, windows-sim-paths) from the main workflow
  • ✅ Consolidated single-job design prevents runner teardown between steps — smart approach for autoscaling runners
  • ✅ OS-level watchdogs via Start-Process + WaitForExit instead of relying on GIL-vulnerable Python thread watchdogs
  • ✅ Develop-aligned Isaac Sim builds from internal Artifactory index (authenticated)
  • ✅ Perception and training smoke tests enabled (WDDM mode confirmed)

⚠️ Optional Suggestions (Non-blocking)

  1. run_docker_tests: 'false' in build.yaml: The comment says "TEMP: disable heavy Linux Docker + Tests" — should be reverted before merge if not intentional.
  2. Hardcoded Git Bash Path: C:\Program Files\Git\bin\bash.exe assumes standard installation. Consider fallback or documentation.

Update (ad92f43): Reviewed incremental diff from bae6977...ad92f43 (rebase on develop + Windows CI refinements):

Windows CI Changes:

  • ✅ Perception test fully re-enabled: Both the standalone test-perception step and the perception subcase in training smoke now run. Perception added to $blocking in aggregate.
  • ✅ Develop-aligned Isaac Sim install: Setup step now resolves and installs the develop-branch-aligned Isaac Sim build from the internal Artifactory index (authenticated via ISAACSIM_ARTIFACTORY_READONLY_* secrets). This replaces the previous public pip install and ensures CI tests against the same Sim as the Linux/ARM develop container.
  • ✅ Wheel install adjusted: The [all] extra (which pins isaacsim==5.1.0) is no longer used during wheel validation, preventing a downgrade of the develop Sim build.
  • ✅ Training smoke expanded: Step renamed to "state + perception" with increased timeout (25 min); -k "not perception" filter removed.

Non-CI changes (develop rebase): The diff includes a large number of unrelated develop-branch changes (cloner refactoring, observation pipeline improvements, new tutorials, bugfixes, etc.) that are not part of this PR's Windows CI scope. No new issues found.

Approval stands.

@hujc7 hujc7 changed the title [CI] Cartpole-camera perception smoke on Windows (experimental) [CI] Add Windows CI workflow May 20, 2026
@hujc7 hujc7 changed the title [CI] Add Windows CI workflow [CI] Cross-platform CI 3/3: Windows workflow May 20, 2026
@hujc7 hujc7 changed the title [CI] Cross-platform CI 3/3: Windows workflow [CI] Cross-platform: Windows workflow May 20, 2026
@hujc7 hujc7 changed the title [CI] Cross-platform: Windows workflow [CI] Cross-platform — Part 3: Windows workflow May 20, 2026
@hujc7
hujc7 force-pushed the jichuanh/windows-spark-ci-perception branch 3 times, most recently from d25f9bb to 6811028 Compare May 20, 2026 23:52
hujc7 added a commit to hujc7/IsaacLab that referenced this pull request May 23, 2026
Duplicate test_cartpole_training_smoke.py from PR isaac-sim#5698's branch so PR
isaac-sim#5700 doesn't chain on it. Cross-platform tweaks vs ARM's copy:
  - pytestmark = [arm_ci, windows_ci]   # dual marker
  - _LAUNCHER picks isaaclab.bat on Windows, isaaclab.sh elsewhere

Add training-smoke-windows job that pytests this file in the same
install + Sim-paths context as perception-windows. continue-on-error
true and timeout-minutes 30 mirror the other Windows jobs.

State case (Isaac-Cartpole-Direct-v0 / rsl_rl) should pass on TCC —
no RTX, no Vulkan touch. Perception case
(Isaac-Cartpole-RGB-Camera-Direct-v0 / rl_games) needs Vulkan and
will fail on this runner until WDDM is enabled.

Whichever of isaac-sim#5698 / isaac-sim#5700 merges first wins the test file; the other
PR will drop the duplicate on rebase.
@hujc7 hujc7 closed this May 27, 2026
@hujc7
hujc7 deleted the jichuanh/windows-spark-ci-perception branch May 27, 2026 22:09
@hujc7
hujc7 restored the jichuanh/windows-spark-ci-perception branch May 27, 2026 22:11
@hujc7 hujc7 reopened this May 27, 2026
hujc7 added a commit to hujc7/IsaacLab that referenced this pull request Jun 1, 2026
PR 5695 lays foundation only. The two tagged tests (test_scipy.py,
test_torch.py) had pytestmark applied here but no in-PR consumer —
the arm-ci and windows-ci workflows that select on these markers
ship in isaac-sim#5698 and isaac-sim#5700 respectively.

Each downstream PR should land the marker annotations on the tests
it actually wants in its canary, alongside the workflow that runs
them. This keeps 5695 self-contained as scaffolding and prevents
unused annotations from accumulating here.

@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.

Updated Review: Windows CI Pipeline (Part 3)

This is a comprehensive and well-structured PR that adds Windows CI support to IsaacLab. The implementation shows strong attention to platform-specific challenges and includes robust error handling. Below is my detailed analysis:


✅ Strengths

1. Solid Architecture

  • Clean separation of reusable GitHub Actions (windows-instance-state, windows-sim-paths) from the main workflow
  • Marker-driven test discovery (windows_ci) allows adding tests without YAML edits
  • Consolidated single-job design prevents runner teardown between steps — smart approach for autoscaling runners

2. Robust Process Management

  • OS-level watchdogs via Start-Process + WaitForExit instead of relying on GIL-vulnerable Python thread watchdogs
  • Per-job timeouts with --timeout-method=thread (correctly avoiding Unix-only SIGALRM)
  • Hard timeouts with explicit kill on hung Kit/Vulkan processes

3. Cross-Platform Improvements

  • AssetConverterBase now uses tempfile.gettempdir() instead of hardcoded /tmp — correct fix
  • wheel_builder/build.sh PYTHON override handles Windows git-bash (which only has python, not python3)
  • HDF5 fixture uses ignore_cleanup_errors=True to handle Windows file-lock races — good catch

4. Comprehensive Environment Setup

  • EULA acceptance variables properly configured
  • DLL search paths correctly prepended for Vulkan ICD discovery
  • Instance state reporting helps diagnose runner issues (GPU presence, disk space, cache sizes)

⚠️ Suggestions & Minor Issues

1. Temporary Docker/Tests Disable in build.yaml

run_docker_tests: 'false'  # TEMP: disable heavy Linux Docker + Tests

The comment says "revert before final review" — this should be reverted before merge. Consider adding a # TODO: tag that linters/CI can catch.

2. Hardcoded Git Bash Path

$gitBash = "C:\Program Files\Git\bin\bash.exe"
if (-not (Test-Path $gitBash)) { throw "Git Bash not found at $gitBash" }

This assumes a standard Git for Windows installation. Consider:

  • Falling back to where.exe bash or checking common alternate paths (C:\Program Files (x86)\Git\bin\bash.exe)
  • Or documenting this as a runner requirement

3. Perception Test Gating
The perception test depends on WDDM mode for Vulkan. If runners could be in TCC mode, consider:

  • Auto-detecting driver mode via nvidia-smi output
  • Adding a conditional skip rather than a CI failure

4. pytestmark Placement in test_configclass.py

from isaaclab.utils.configclass import _field_module_dir, configclass

pytestmark = pytest.mark.windows_ci
from isaaclab.utils.dict import class_to_dict, ...

The pytestmark is sandwiched between imports — while functional, it's unconventional. Consider grouping it with other module-level declarations after all imports.

5. Magic Numbers
Several timeout values are hardcoded (300000ms, 180000ms, 600s, etc.). Consider:

  • Documenting why these specific values were chosen
  • Using named constants or environment variables for runner-specific tuning

📝 Questions

  1. Checkpoint Cleanup: The cartpole training smoke tests run two iterations and create checkpoints. Are these cleaned up, or will they accumulate on runners?

  2. Change Detection Logic: The changes job patterns don't include .github/actions/windows-* — is this intentional? Changes to these actions wouldn't trigger the workflow for validation.

  3. Python 3.12 Assumption: The user site-packages path assumes Python 3.12:

    "user site-pkgs" = "$env:APPDATA\Python\Python312\site-packages"

    Should this be dynamic based on the installed Python version?


🔧 Final Notes

Overall, this is high-quality CI infrastructure work. The attention to Windows-specific quirks (DLL search order, file locking, PowerShell encoding, process watchdogs) demonstrates deep platform expertise.

Before merge:

  1. Revert the run_docker_tests: 'false' workaround in build.yaml
  2. Consider addressing the Git Bash path hardcoding

Other items are suggestions for future improvement rather than blockers.


Update (ad92f43): Reviewed the new commits since bae6977.

Changes Observed

  1. Perception/Rendering Steps Re-enabled ✅

    • Commit 27def394 re-enables the perception and rendering test steps in the Windows CI workflow
    • The cartpole-camera perception smoke test now exercises the full RTX/Vulkan path
  2. Develop-Aligned Isaac Sim Installation ✅

    • The workflow now installs a develop-aligned Isaac Sim build from the internal Artifactory index (instead of the public pip release)
    • Uses authenticated index URLs with ISAACSIM_ARTIFACTORY_READONLY_USERNAME/PASSWORD secrets
    • The tools/resolve_isaacsim_develop.py resolver verifies the build is on the develop branch
    • Good approach to ensure Windows CI tests the same Sim as Linux/ARM develop
  3. Authentication with Read-Only Secrets ✅

    • Proper credential handling with URL-encoding for special characters
    • GitHub masks secrets and uv redacts credentials when echoing index URLs

Outstanding Items

  1. build.yaml Still Has run_docker_tests: 'false' ⚠️

    • The temporary disable is still in place with the comment "revert before final review"
    • This needs to be reverted before merge
  2. Hardcoded Git Bash Path (unchanged from previous review)

    • Still assumes standard Git for Windows installation at C:\Program Files\Git\bin\bash.exe

Summary

The new commits address the perception/rendering testing and add proper develop-aligned Isaac Sim installation with authentication. The Windows CI workflow is now more comprehensive and aligned with the develop branch testing strategy.

Remaining before merge:

  • Revert run_docker_tests: 'false' in build.yaml

Update (5c04d23): Reviewed incremental changes since ad92f43.

Changes in This Push

  1. Artifactory URL Migration ✅
    • All internal Artifactory URLs updated from urm.nvidia.com to artifactory.nvidia.com
    • PyPI index paths updated from sw-isaacsim-pypi/simple → sw-isaacsim-pypi-local/simple and ct-omniverse-pypi/simple → ct-omniverse-pypi-local/simple
    • This affects both the uv pip install index URLs and the resolve_isaacsim_develop.py --index-url argument
    • Standard infrastructure migration from the legacy URM hostname to the canonical Artifactory hostname with corrected local repository paths

Assessment

This is a straightforward infrastructure-only change — no logic modifications, no new features. The URL pattern change (-local/simple suffix) suggests these now point to the correct local Artifactory repositories rather than virtual aggregators.

No new concerns introduced. Previously noted items still apply:

  • build.yaml still has run_docker_tests: 'false' that needs reverting before merge
  • Hardcoded Git Bash path remains unchanged

Update (5941931): Reviewed incremental changes since 5c04d23.

Changes in This Push

  1. Fork PR Secret Handling — Graceful Degradation ✅

    • Previously the workflow would hard-fail (throw) when ISAACSIM_ARTIFACTORY_READONLY_* secrets were not set
    • Now emits a GitHub Actions ::warning:: annotation and proceeds unauthenticated
    • This allows fork PRs (which don't receive repository secrets) to still exercise URL/DNS reachability
    • Auth-dependent failures will surface later in in-repo runs where secrets are present
    • Good approach — matches standard CI best practice for fork-safe workflows
  2. Artifactory URL Path Correction ✅

    • Removed /api/pypi/ prefix and /simple suffix from all Artifactory index URLs
    • Before: https://...artifactory.nvidia.com/artifactory/api/pypi/sw-isaacsim-pypi-local/simple
    • After: https://...artifactory.nvidia.com/artifactory/sw-isaacsim-pypi-local/
    • Same change applied to ct-omniverse-pypi-local and the resolve_isaacsim_develop.py --index-url argument
    • This likely aligns with the actual repository layout on the new artifactory.nvidia.com host (non-virtual repos don't use the /api/pypi/.../simple PEP 503 endpoint)

Assessment

Both changes are operational improvements with no logic risk:

  • The fork PR fix unblocks external contributors from running the workflow
  • The URL path fix ensures correct repository resolution on the migrated Artifactory instance

No new concerns introduced. Previously noted items still apply:

  • build.yaml still has run_docker_tests: 'false' that needs reverting before merge
  • Hardcoded Git Bash path remains unchanged

Update (77685d1): Reviewed incremental changes since 5941931.

Changes in This Push

  1. Network Reachability Diagnostic Step ✅
    • Added a new "Probe index reachability (diagnostic)" step in the Windows CI workflow
    • Uses if: always() and continue-on-error: true — purely diagnostic, won't block the build
    • Probes three hosts: artifactory.nvidia.com, urm.nvidia.com, pypi.nvidia.com
    • Tests both DNS resolution ([System.Net.Dns]::GetHostAddresses) and TCP 443 connectivity (Test-NetConnection)
    • Logs runner metadata: COMPUTERNAME, RUNNER_NAME, proxy environment variables, DNS server addresses
    • This decouples network/DNS diagnostics from pip failures — useful for debugging transient CI infra issues

Assessment

This is a non-blocking diagnostic addition. It helps isolate whether Windows CI failures stem from network reachability issues vs. package availability, especially given the recent Artifactory URL migrations. The step runs unconditionally (always()) so it will capture state even on prior step failures.

No new concerns introduced. Previously noted items still apply:

  • build.yaml still has run_docker_tests: 'false' that needs reverting before merge
  • Hardcoded Git Bash path remains unchanged

@hujc7

hujc7 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #6086 — re-opened from a branch in this repo (not a fork) so the Windows CI job receives the ISAACSIM_ARTIFACTORY_READONLY_* org secrets (fork PRs don't get workflow secrets). Closing this one.

@hujc7 hujc7 closed this Jun 9, 2026
@hujc7 hujc7 reopened this Jun 9, 2026
@hujc7

hujc7 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Reopened — #6086 (same-repo variant) is closed. Confirmed the fork rule was not the blocker: even on an in-repo PR the ISAACSIM_ARTIFACTORY_READONLY_* secrets resolve empty, so they aren't scoped to isaac-sim/IsaacLab. Fix is on the secret placement (scope to this repo like NGC_API_KEY) or bake the read-only creds into the Windows self-hosted runner; no change needed in this PR's wiring. This branch also now has develop merged in (no longer conflicting).

hujc7 added a commit that referenced this pull request Jun 20, 2026
…base) (#5695)

## Summary

Base PR for cross-platform CI on Windows and NVIDIA DGX Spark
(ARM/aarch64 Linux). No user-facing API change.

- Registers `windows_ci` and `arm_ci` pytest markers in pyproject.toml.
- AppLauncher argv strip recognizes the new markers so `pytest -m
windows_ci` (etc.) does not leak into Isaac Sim's argparse.
- AssetConverterBase USD scratch dir: hardcoded `/tmp/IsaacLab` →
`tempfile.gettempdir()` for cross-platform compatibility.

This base PR ships only the marker registration and the shared
scaffolding. Tagging specific suites with these markers, and the CI
workflows that consume them, ship in the follow-up parts below — that
keeps the marker/scaffolding change reviewable on its own and lets the
consumer PRs rebase cleanly once it lands.

## Prior art and credits

This work is a derivative of and builds directly on two prior PRs by
other contributors:

- #3900 by Kelly Guo (kellyguo11), against `main`, 2025-10-31 — "test
windows CI". Designed and introduced the cross-platform marker scheme
(`windows`, `windows_ci`, `arm`, `arm_ci`), tagged ~50 existing tests
across the codebase, added the AppLauncher argv-strip pattern so the new
pytest `-m` filters do not leak into Isaac Sim's argument parser, and
pioneered the Windows CI job wiring. The marker design and AppLauncher
behavior in this PR are taken directly from #3900.
- #3845 by Alexander Poddubny (nv-apoddubny), against `main`, 2025-10-27
— "Adds basic CI verification on Windows". Built the original Windows
self-hosted runner infrastructure: `isaaclab.bat` entry script, the
initial `.github/workflows/build.yml` Windows job, and the
self-hosted-runner labeling conventions this PR's downstream Part 2/Part
3 workflows still rely on.

Both PRs target `main` and have not been merged. This PR rebases that
work onto `develop` (where the active development happens — `main` is
behind by hundreds of commits), narrows the base PR to just the marker
scheme plus shared scaffolding (so the marker/runner plumbing can be
validated end-to-end before tests are tagged and re-expanded), and adds
an `arm_ci` marker variant + ARM/Spark runner support that #3900/#3845
did not include.

Credit for the architecture goes to the authors above; this PR is the
rebase + minimization step.

## Series

PRs prefixed with `[CI] Cross-platform —` all contribute to bringing
Isaac Lab CI up on Windows and NVIDIA DGX Spark runners. This PR is the
base everything else builds on. Current siblings:

- Part 1 (this PR, base) — Markers and shared scaffolding
- Part 2 — #5698 — ARM/Spark workflow (`.github/workflows/arm-ci.yaml`)
- Part 3 — #5700 — Windows workflow
(`.github/workflows/windows-ci.yaml`)

Siblings depend on this PR's marker scheme; the same scaffolding lines
are carried in their branches and dedupe on rebase after this lands.
Additional follow-up parts can be added later without renumbering
existing ones.

## Test plan

- [x] `pytest --markers` lists `windows_ci` and `arm_ci` (registered, no
`PytestUnknownMarkWarning`).
- [x] AppLauncher argv strip drops `-m windows_ci` / `-m arm_ci` before
Isaac Sim's argparse runs.
- [x] `./isaaclab.sh -f` (pre-commit) passes.
- [x] Merged latest `develop`: the markers list is the union with the
newly added `device_split` marker, and `--capture=no` argv stripping
from develop is preserved.
hujc7 added a commit that referenced this pull request Jul 10, 2026
## 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 #5695 (Part 1). The
Windows workflow is #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.
matthewtrepte pushed a commit to matthewtrepte/IsaacLab that referenced this pull request Aug 4, 2026
…base) (isaac-sim#5695)

## Summary

Base PR for cross-platform CI on Windows and NVIDIA DGX Spark
(ARM/aarch64 Linux). No user-facing API change.

- Registers `windows_ci` and `arm_ci` pytest markers in pyproject.toml.
- AppLauncher argv strip recognizes the new markers so `pytest -m
windows_ci` (etc.) does not leak into Isaac Sim's argparse.
- AssetConverterBase USD scratch dir: hardcoded `/tmp/IsaacLab` →
`tempfile.gettempdir()` for cross-platform compatibility.

This base PR ships only the marker registration and the shared
scaffolding. Tagging specific suites with these markers, and the CI
workflows that consume them, ship in the follow-up parts below — that
keeps the marker/scaffolding change reviewable on its own and lets the
consumer PRs rebase cleanly once it lands.

## Prior art and credits

This work is a derivative of and builds directly on two prior PRs by
other contributors:

- isaac-sim#3900 by Kelly Guo (kellyguo11), against `main`, 2025-10-31 — "test
windows CI". Designed and introduced the cross-platform marker scheme
(`windows`, `windows_ci`, `arm`, `arm_ci`), tagged ~50 existing tests
across the codebase, added the AppLauncher argv-strip pattern so the new
pytest `-m` filters do not leak into Isaac Sim's argument parser, and
pioneered the Windows CI job wiring. The marker design and AppLauncher
behavior in this PR are taken directly from isaac-sim#3900.
- isaac-sim#3845 by Alexander Poddubny (nv-apoddubny), against `main`, 2025-10-27
— "Adds basic CI verification on Windows". Built the original Windows
self-hosted runner infrastructure: `isaaclab.bat` entry script, the
initial `.github/workflows/build.yml` Windows job, and the
self-hosted-runner labeling conventions this PR's downstream Part 2/Part
3 workflows still rely on.

Both PRs target `main` and have not been merged. This PR rebases that
work onto `develop` (where the active development happens — `main` is
behind by hundreds of commits), narrows the base PR to just the marker
scheme plus shared scaffolding (so the marker/runner plumbing can be
validated end-to-end before tests are tagged and re-expanded), and adds
an `arm_ci` marker variant + ARM/Spark runner support that isaac-sim#3900/isaac-sim#3845
did not include.

Credit for the architecture goes to the authors above; this PR is the
rebase + minimization step.

## Series

PRs prefixed with `[CI] Cross-platform —` all contribute to bringing
Isaac Lab CI up on Windows and NVIDIA DGX Spark runners. This PR is the
base everything else builds on. Current siblings:

- Part 1 (this PR, base) — Markers and shared scaffolding
- Part 2 — isaac-sim#5698 — ARM/Spark workflow (`.github/workflows/arm-ci.yaml`)
- Part 3 — isaac-sim#5700 — Windows workflow
(`.github/workflows/windows-ci.yaml`)

Siblings depend on this PR's marker scheme; the same scaffolding lines
are carried in their branches and dedupe on rebase after this lands.
Additional follow-up parts can be added later without renumbering
existing ones.

## Test plan

- [x] `pytest --markers` lists `windows_ci` and `arm_ci` (registered, no
`PytestUnknownMarkWarning`).
- [x] AppLauncher argv strip drops `-m windows_ci` / `-m arm_ci` before
Isaac Sim's argparse runs.
- [x] `./isaaclab.sh -f` (pre-commit) passes.
- [x] Merged latest `develop`: the markers list is the union with the
newly added `device_split` marker, and `--capture=no` argv stripping
from develop is preserved.
matthewtrepte pushed a commit to matthewtrepte/IsaacLab that referenced this pull request Aug 4, 2026
## 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.
hujc7 added a commit to hujc7/IsaacLab that referenced this pull request Oct 9, 2026
# Conflicts:
#	source/isaaclab/test/install_ci/misc/cartpole_training_smoke.py
hujc7 added 2 commits October 21, 2026 20:04
The Cartpole smoke now renders the camera through the Newton renderer and Kit's RTX renderer, each in a fresh interpreter, and the ovrtx coexistence test reuses that check instead of keeping its own copy.
…ark-ci-perception

# Conflicts:
#	.github/workflows/install-ci.yml
@greptile-apps

greptile-apps Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes affect Windows CI and installation checks on GPU runners.

The PR appears safe to merge, with a non-blocking gap in tests for Windows output capture and timeout cleanup.

Findings

  1. P2 Windows timeout paths lack tests ▶

Summary

Adds native Windows installation tests and a Windows CI workflow using the shared test runner.

  • Windows CI now runs marked tests and Cartpole smoke checks on GPU runners.
  • Windows now builds and tests an Isaac Lab wheel on a native runner.
  • Windows CI checks ovrtx rendering with USD and MaterialX loaded in either order.
  • Windows CI checks Cartpole camera output through Kit's RTX renderer.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Relevant changes] --> B[Windows CI]
  A --> C[Windows installation tests]
  B --> D[Sync locked environment]
  D --> E[Run windows_ci tests]
  E --> F[Run Cartpole smoke tests]
  C --> G[Build wheel with Git Bash]
  G --> H[Run native installation suite]
  F --> I[Upload reports]
  H --> I
Loading

Reviews (1) · Last reviewed commit: "Keep the Windows installation venvs unde..." · Reviewed by Greptile

Comment thread tools/conftest.py
Comment on lines +177 to +185
def _readable(fds, timeout):
"""Return the pipes in ``fds`` that a read would not block on, waiting up to ``timeout`` seconds for one."""
if os.name != "nt":
return select.select(fds, [], [], timeout)[0]
# Windows cannot select() on pipes, so poll each one instead.
deadline = time.monotonic() + timeout
while not (ready := [fd for fd in fds if _pipe_readable(fd)]) and time.monotonic() < deadline:
time.sleep(0.01)
return ready

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 Windows timeout paths lack tests

The new Windows pipe and process-kill paths have no focused tests. The existing test that runs a hung child is POSIX-only, so it cannot catch Windows failures in output capture or timeout cleanup. This is a non-blocking coverage gap: ordinary passing tests do not exercise cleanup after a timeout.

Add Windows tests for short output followed by silence, pipe closure, and killing a hung child with descendants, including the taskkill fallback.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@hujc7

hujc7 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@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 Oct 22, 2026

@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

Needs attention: Design and architecture (1), Style consistency (1). Other reviewed categories look good.

  • PR description: Remove the unsupported claim that prior inline scripts became test files; the diff adds one coexistence test and modifies an existing smoke, while cited CI timings include run IDs.
  • Design and architecture: Windows skips post-exit process-tree cleanup, allowing orphaned Kit processes to accumulate; launch tests in a Windows job object that terminates descendants on close.
  • Scope and over-engineering: No over-engineering issues.
  • API: API changes look good.
  • Compatibility and deprecation: No breaking changes identified.
  • Implementation: Implementation looks good.
  • Style consistency: The new workflow uses .yaml while adjacent workflows use .yml; rename it to windows-ci.yml and update its detect-changes pattern.
  • Test quality: Test quality looks good.

Minor fixes needed. Posted 2 inline findings.

Automated review; human maintainers own approval decisions.

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

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 · Style Consistency — Workflow uses .yaml, not .yml

Adjacent workflows use .yml (install-ci.yml, and arm-ci.yml named in this file's header). Rename to windows-ci.yml and update the detect-changes pattern on line 65.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Keeping .yaml. The workflows directory uses both extensions (10 .yaml, 13 .yml), and build.yaml, which runs the x86 test jobs, is .yaml.

Comment thread tools/conftest.py
pass
# Kill any orphaned child processes (Kit, Isaac Sim) left by the test. On Windows the
# tree is unreachable once its root has exited.
if pgid is not 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.

🟡 Warning · Design Architecture — Windows never reaps orphaned simulator children

On Windows pgid is None, so the post-exit cleanup that kills orphaned Kit processes on Linux is skipped entirely; self-hosted runners accumulate them. Launch the child in a job object that terminates on close.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not adding a job object here. A test that times out is killed with taskkill /T while its root is still alive, so its tree goes with it. Children that outlive a root that exited normally are reaped by the runner at job end: the Windows job logs show its "Cleaning up orphan processes" step, and in this PR's runs it has found nothing to terminate.

hujc7 added 17 commits October 22, 2026 15:54
usd-exchange 3.0.1 fixed the DLL name clash the test guarded against (nvbug 6817794). The
Cartpole smoke returns to the Newton probes it runs on main, so ARM CI runs what it runs there.
ARM CI's smoke runs Newton only, so Windows syncs the base environment with the test extra and
no longer installs Isaac Sim or ovrtx, or keeps their shader caches.
Checkout cleans the workspace, so the environment moves to the runner's tool cache. A reused
runner then re-syncs only what uv.lock changed and keeps the packages' compiled bytecode.
Skips ARM CI, the x86 and ARM installation tests, multi-GPU pytest, the license checks and the
docs build. Must be reverted before final review.
Prints the runner, its boot time and the size of uv's cache, the kept environment and Warp's
kernel cache before the sync and after the tests. Must be reverted before final review.
Adds a job that trains camera Cartpole for each physics and renderer pair in an environment kept
on the runner, and masks the other Windows jobs meanwhile. Must be reverted before final review.
Pull requests restore the newest snapshot of a Windows Warp cache
collection and pushes to protected branches save what they compiled, the
policy of the Linux test jobs. The key comes from the same collection_id.py;
the shared actions run bash, which resolves to WSL on these runners.
Simulates a fresh instance (attempts 1-2 of windows-ci; the seed and fresh
legs of the Cartpole combinations), lets this PR save the caches, and
restores Warp, Kit and ovrtx shader caches in the combinations job. Must be
reverted before final review.
Reverts 31bd022 (measurement harness), 234820c (Cartpole
combinations job) and 61e8745 (runner cache-state print).
The runner empties RUNNER_TEMP at the start of every job and pull requests
only restore, so a reused runner recompiled every kernel on each pull
request. The cache now lives in the tool cache beside the environment; a
save clears it first, so it never publishes kernels a pull request built.
It carries no signal for the Windows CI Warp cache change. Must be reverted
before final review.
Warp reports its kernel cache directory with the \\?\ prefix on Windows, so
tools/verify_warp_cache.py's os.path.commonpath raises. Its version check
always passes on an environment synced from uv.lock, so Windows CI checks
the path itself instead of changing the tool the Linux jobs share.
Windows CI installs the isaacsim and ov extras and trains camera Cartpole on
each of the ten physics and renderer pairings that can share a process. The
Kit and OVRTX driver shader caches join the Warp kernel cache under the Linux
policy, so a fresh runner skips the shader compiles once main has saved them.
The cache steps live in one script, since the shared actions run bash.

This branch has not been deployed

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

Labels

infrastructure isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant