Skip to content

fix(install): resolve canonical ROCm streams (EAI-8268) - #308

Open
michaelroy-amd wants to merge 21 commits into
mainfrom
eai-8268-canonical-rocm-streams
Open

fix(install): resolve canonical ROCm streams (EAI-8268)#308
michaelroy-amd wants to merge 21 commits into
mainfrom
eai-8268-canonical-rocm-streams

Conversation

@michaelroy-amd

Copy link
Copy Markdown
Member

Summary

  • resolve release and nightly SDK wheels exclusively from their canonical aggregate TheRock streams
  • validate aggregate and tarball layouts, reject incomplete streams, and prevent release tarballs from selecting prerelease artifacts
  • report canonical source, selected ROCm version, build date, and layout generation in dry-run output
  • add focused future-major, channel-isolation, layout-validation, and Cucumber coverage

Verification

  • cargo test --workspace --all-targets (2234 passed, 8 ignored)
  • cargo clippy --workspace --all-targets -- -D warnings
  • python3 scripts/smoke_local.py --skip-build
  • runtime-resolve-canonical-nightly Cucumber scenario
  • live release/nightly wheel and tarball dry-runs

Tracking

  • EAI-8268

  • If this PR fixes a bug, searched tests/e2e-cucumber/expectations.toml for the fixed ticket ID and removed/narrowed any now-stale xfail rows. No matching xfail row exists.

@fredespi fredespi 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 reviewed this against the current head (69ee614) and checked the new canonical streams directly rather than trusting the constants: both aggregate indexes serve the expected rocm/, torch/, torchvision/ and torchaudio/ package pages, and a resolver run against each one from a clean environment produces a complete, mutually consistent stack — release and nightly, Linux and Windows, without any family segment and without needing an amd-torch-device-* package. Device coverage on the aggregate stream matches what the old family indexes offered. So the central move is sound, and deleting the dead whl/<family> fallback is a real improvement.

Five things I would fix before merge. None of them break resolution; three are user-visible and two are test hygiene.

The one that matters most: the wheel index is now family-independent, but the surrounding code still treats the family as the thing that selects wheels. On a resolution failure the CLI still tells the user to re-run with an explicit --family, which can no longer change the outcome, and the managed runtime is still keyed by family, so two family values now produce two identical multi-gigabyte installs. Details inline.

Also worth noting for the record: the new scenario is untagged, so it puts a live dependency on the nightly index into the blocking merge gate for the whole repository.

A few things I suspected and then ruled out, so they do not need your time: the metadata signature policy is inert by default (the pinned key is empty), so the new root fetch does not require a new .sig sidecar for anyone who has not opted in; the aggregate stream is not missing older families; and the multi-arch payload is not larger than the family-specific one it replaces.

Comment thread apps/rocm/src/therock.rs
)
.with_context(|| {
format!(
"failed to resolve TheRock {} wheel runtime from canonical source {}\n\n{}",

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.

The wheel index is now family-independent, but the failure guidance still tells the user their family is the problem.

resolve_pip_runtime_from_index is now called with source.wheel_index and no /<family> segment, so family_resolution no longer influences which wheels are found — it is only carried into the result for display. When resolution fails, this context still appends family_resolution_hint(...), which for an auto-detected family says:

Re-run with an explicit package family: `rocm install sdk --family <FAMILY>`.
Recognized families: ...

On the wheel path that advice can no longer change anything: every --family value now yields the identical index URL and the identical resolution, so a user who follows it gets the same error a second time.

Two related spots while you are here:

  • the dry-run still prints family: / family_source: immediately under canonical_source: (line 904), which reads as though the family scoped the selection;
  • runtime_key(channel, "wheel", &resolution.family, ...) (line 877) still keys the managed venv by family, so --family A and --family B on one host now build two separate multi-gigabyte environments with identical content.

Suggestion: for format == "wheel", drop the family half of the hint and keep the --channel / --format half, which is still actionable — then decide deliberately whether the family should stay in the wheel runtime key.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 05edff0. Wheel failures now use aggregate-specific guidance without --family; dry-run labels the value as target_family; and managed wheel keys are now channel-wheel-multi-arch-version, preventing duplicate aggregate environments across family values.

Comment thread apps/rocm/src/therock.rs
let _ = writeln!(output, " channel: {}", channel.as_str());
let _ = writeln!(output, " canonical_source: {source_url}");
let _ = writeln!(output, " selected_rocm_version: {version}");
let _ = writeln!(output, " build_date: {build_date}");

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.

build_date: <not published by canonical source> will print on every release-channel install.

runtime_version_build_date only returns a date when the version string embeds eight date digits. Nightly versions do (10.1.0a20260822); stable release versions never do (7.14.0). So every --channel release preview reports <not published by canonical source>, which reads as a provenance gap at the source when nothing is actually missing — a stable version simply does not carry a build date.

It also contradicts the convention already set in this file: runtime_version_display("7.14.0") returns plain 7.14.0 and just omits the (build ...) suffix when there is no embedded date (see runtime_version_display_mentions_embedded_build_date).

Suggestion: omit the build_date line when there is no embedded date, or use neutral wording such as not encoded in this version.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 05edff0. Stable versions now report build_date: not encoded in stable version; dated nightly versions continue to report the parsed date.

Comment thread apps/rocm/src/therock.rs
const THEROCK_RELEASE_PIP_INDEX_BASE: &str = "https://repo.amd.com/rocm/whl";
const THEROCK_RELEASE_PIP_MULTI_ARCH_INDEX_BASE: &str = "https://repo.amd.com/rocm/whl-multi-arch";
const THEROCK_NIGHTLY_PIP_INDEX_BASE: &str = "https://rocm.nightlies.amd.com/whl-multi-arch";
const THEROCK_RELEASE_PIP_INDEX_BASE: &str = "https://repo.amd.com/rocm/whl-multi-arch";

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.

Not about this line specifically — anchored here because MANIFEST.md is not part of the diff.

MANIFEST.md lines 649-650 still document the endpoints this PR removes:

Release channel wheels are served from `https://repo.amd.com/rocm/whl/<gpu-family>/`.
Nightly channel wheels are served from `https://rocm.nightlies.amd.com/v2/<gpu-family>/`.

Both are now wrong in host and in shape — the family segment is gone. That section is the repository's statement of what the CLI downloads at runtime, so it is worth keeping exact. The tarball paragraph directly below it is still correct and needs no change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 05edff0. MANIFEST.md now documents the canonical release and nightly whl-multi-arch endpoints without family segments.

Then the adoption is refused
And the error explains which install types can be adopted

@id:runtime-resolve-canonical-nightly

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 scenario carries no capability tag, so it runs in the blocking mock E2E tests job — and it needs live network access to pass. install sdk --dry-run still performs the full resolution: the new root layout fetch plus four simple-index fetches.

Every other scenario on that lane is served locally or by the in-process mock server. This one makes an external service's availability and layout a merge gate for the whole repository, so an outage or a layout change lands as a red required check on unrelated PRs rather than on the change that needs to know.

It does pass today — I confirmed the full nightly stack resolves for cp312 on Linux and Windows from the aggregate index. The concern is the standing coupling, not the current result.

Options: tag it for a lane where a live-stream dependency is expected, or split it so the blocking lane asserts the rendered provenance against a locally served index and only the tagged lane touches the real stream.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 05edff0. The live canonical-stream scenario is now tagged @nightly, so it no longer adds an external network dependency to the blocking mock lane.

And the error explains which install types can be adopted

@id:runtime-resolve-canonical-nightly
Scenario: 4 - Previewing a nightly SDK install reports canonical provenance

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.

Duplicate scenario number: Scenario: 4 - Reinstalling the SDK leaves the installed engine's requirements satisfied is already number 4 in this file (line 30). The numbers are used for name filtering (cargo xtask e2e -- -n ...) and in the report grid, so this one probably wants to be 5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 05edff0. The canonical provenance scenario is now numbered 5.

@fredespi fredespi 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 re-reviewed the two follow-up commits against the full current PR. The five issues from my previous review are addressed: wheel guidance and runtime identity now match the aggregate stream, stable provenance wording is neutral, the manifest is current, and the live scenario is isolated to the nightly lane. The merge from main introduced one small numbering regression that still needs correction before merge; details inline.

And the error explains which install types can be adopted

@id:runtime-resolve-canonical-nightly @nightly
Scenario: 5 - Previewing a nightly SDK install reports canonical provenance

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 again a duplicate Scenario: 5. Commit 05edff0c correctly changed this scenario from 4 to 5, but the subsequent merge brought in The update check reports the active runtime's freshness as scenario 5 at line 45. Scenario numbers are used in name filters and report output, so please renumber this new canonical-provenance scenario to 6.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 0eefc89. The canonical-provenance scenario is now numbered 6. The same commit also activates the refreshed canonical shared runtime in isolated GPU scenarios, addressing the multi-runtime CI failure exposed by the new aggregate key.

@fredespi

Copy link
Copy Markdown
Collaborator

Re-review complete at 0eefc897. The duplicate scenario number is corrected: canonical provenance is now scenario 6. I also reviewed the added shared-runtime activation path and found no blocking issue in this follow-up. The PR looks safe to approve after final CI and runtime validation; this comment is not a formal approval.

@fredespi fredespi 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 reviewed only the new pre-warm commit against the previously cleared head. Scenario numbering remains correct, and the shared-runtime activation path is unchanged. One control-flow issue prevents this commit from repairing the persisted runtime state it targets; details inline.

Comment thread xtask/src/e2e_prewarm.rs
}
}

ensure_default_engine(&rocm, prewarm_dir)?;

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 call is unreachable when the runtime is reused: Decision::Reuse returns at line 231. That is the important repair case here. The previous run already updated the persistent shared tree to release-wheel-multi-arch-7-14-0 without vLLM; on the next run rocm update reports that runtime as up_to_date, decide returns Reuse, and pre-warm exits before installing the engine, so the same serve scenarios still fail. Please arrange for the default-engine check/install to run for a reused current runtime too (while keeping the intended degraded-index behavior), and cover the reuse path.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 9f63cfb. The decision match now joins at one shared ensure_default_engine call, so Reuse cannot return before engine validation. Repair is a distinct decision path and both reuse and repair routing are covered.

@fredespi

Copy link
Copy Markdown
Collaborator

Re-review complete at 74418ccf. The prior reuse-path issue is fixed: Decision::Reuse now runs ensure_default_engine before returning, so an existing current shared runtime is repaired too. Scenario numbering remains unique through scenario 6, and the shared-runtime activation refactor preserves the behavior cleared earlier. Focused xtask engine-inventory and e2e-cucumber canonical-runtime-key tests pass. This head looks safe to approve after final self-hosted CI and runtime validation; this comment is not a formal approval.

@fredespi fredespi 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 reviewed only the new aggregate-device-payload commit against the head cleared in the last round. The reuse-path engine repair, unique scenario numbering, and shared-runtime activation remain intact. One cache-identity issue means this commit does not repair the persistent runtime that exposed the missing device payload; details inline. This is now an accumulating design problem rather than another isolated test slip: the persistent runtime cache is version-keyed, while successive fixes change the required package composition without changing that identity.

Separately, device-all installs every device wheel available for the current OS, and individual published device wheels can be hundreds of megabytes to over 1.5 GB. If the generic or target-specific device extra can satisfy the detected family, it would avoid a very large managed environment; please confirm that all payloads are truly required.

Comment thread apps/rocm/src/therock.rs Outdated
vec![
format!("rocm[libraries,devel]=={}", package_versions.rocm),
format!(
"rocm[libraries,devel,device-all]=={}",

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.

Adding device-all changes the required runtime contents, but it does not change the runtime identity or freshness decision. The persistent MI300X tree already contains release-wheel-multi-arch-7-14-0 without device payloads. Its manifest still says version 7.14.0, and runtime_update_plan compares only that version with the index, so the next pre-warm reports up_to_date, takes Decision::Reuse, and only ensures vLLM; it never reruns this SDK install. The same cached environment therefore remains without the payload needed to fix the observed Failed to infer device type failures. Please add a repair/migration for same-version runtimes, or include the package/layout composition in runtime identity and freshness, with coverage for an existing old-composition cache.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 9f63cfb. device-all is removed. Aggregate installs require one target-specific device extra (including gfx943 -> device-gfx942); absent or mismatched exact detection now fails clearly instead of installing every published payload.

@fredespi fredespi 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 re-reviewed the cache design at the full current head, not only the latest patch. The reuse-path engine repair, scenario numbering, and shared-runtime activation remain intact. However, the round-6 cache-identity issue is not resolved: this commit narrows the payload chosen for a new install, but it still does not invalidate or repair an existing same-version runtime. Details inline.

Comment thread apps/rocm/src/therock.rs Outdated
version_selector,
)?;
let device_target = aggregate_device_target(&resolution.family);
let rocm_extras = device_target.as_deref().map_or_else(

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 improves fresh installs by selecting device-gfx942 instead of every device payload, but it still changes only the install arguments. wheel_runtime_key remains channel + version, InstalledRuntimeManifest records no package/layout composition, and runtime_update_plan still compares only manifest.version with latest_version. Therefore the persistent release-wheel-multi-arch-7-14-0 that lacks any device payload still reports up_to_date; pre-warm takes Reuse, only ensures the engine, and never executes this target-specific SDK install. No migration or invalidation path was added. Please either include the required composition in runtime identity/freshness, or explicitly detect and repair same-version runtimes, with a regression test starting from the old 7.14.0 cache shape.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 9f63cfb. Managed wheel manifests now record source-layout generation plus exact pinned package specs. Freshness reports repair_available when either composition or its composition-keyed runtime identity is stale. Applying that repair creates and activates a side-by-side runtime selected by its exact target key. Regression coverage starts from the old 7.14.0 manifest shape with no composition.

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

The round-6/7 cache-identity issue is STILL OPEN at this head. I traced the complete existing-cache path again. The new launch environment handling does not migrate, invalidate, repair, or re-key a same-version runtime. The previously cleared engine-prewarm repair, unique scenario numbering, and shared-runtime activation remain intact.

Comment thread engines/vllm/src/lib.rs

fn apply_therock_env(command: &mut ProcessCommand, runtime: &VllmRuntime) -> Result<()> {
command.env("VLLM_TARGET_DEVICE", "rocm");
if let Some(target_family) = therock_device_target(runtime) {

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 launch-time workaround that only runs when sdk_library_paths already contains an _rocm_sdk_device_* directory. The stale persistent 7.14.0 runtime lacks that device package, so therock_device_target returns None and this adds nothing. More importantly, the actual cache path is unchanged: runtime_update_plan compares only the version, reports up_to_date, e2e-prewarm takes Decision::Reuse, runs only ensure_default_engine, and returns. No SDK reinstall, migration, invalidation, or re-key occurs, so this commit cannot repair the old cache. Please make composition participate in runtime identity/freshness, or explicitly detect and repair the same-version runtime before reuse.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed at the cache boundary in 9f63cfb. The launch variable remains necessary after a target package exists, but it is no longer treated as the migration: an old same-version manifest now becomes repair_available and installs a composition-keyed replacement before reuse.

Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
michaelroy-amd and others added 2 commits August 27, 2026 08:07
Signed-off-by: Michael Roy <michael.roy@amd.com>
Two installers write torch into the same managed runtime. `install sdk`
writes TheRock's build; an engine install then writes the build from its
own index, pinned to an exact version. Letting either side win outright is
wrong, and both failures have been seen on real hardware:

- With the engine's build, the runtime can hold a torch that loads against
  the installed SDK and then enumerates no devices. vLLM resolves no
  platform and serving dies with "Failed to infer device type", long after
  the install reported success.
- With the SDK's build, the runtime can hold a torch *release* the engine
  does not accept, which breaks the engine a different way.

The release and the build answer different questions, so take them from
different places: the release from the engine, which was built against it,
and the build from the SDK, which owns the libraries the runtime loads.
The SDK's torch is read before the engine install, since that install is
what overwrites it, and its build identifier is carried onto the release
the engine pins. Where the SDK publishes no such build, the engine's own
is kept rather than failing a multi-gigabyte install; where the install
fails for any other reason the error is reported as it happened, since
calling a network or permission failure a missing wheel sends the reader
hunting for something that exists.

This applies to every path that installs an engine into a managed runtime,
not just the auto-install after `install sdk`. A standalone
`rocm engines install <engine> --reinstall` is what someone reaches for
when a runtime already looks wrong, so it above all must not be the thing
that breaks it; it now re-settles torch and leaves the runtime usable.
Environments rocm-cli does not own are left alone, and anyone wanting a
different torch can still install it into the environment directly.

Reporting is adjusted so the result is legible. A new device check asks
the runtime whether torch can actually open a GPU, because a satisfied
dependency check does not mean a usable environment -- the broken state
reports `is_available() == True` with a device count of zero, which is why
it stayed invisible until first serve. The check composes the runtime's
recorded library paths, not `rocm_sdk.initialize_process()`: measured on a
runtime that serves correctly, the former reports 8 devices and the latter
0, so a probe built on it would condemn healthy runtimes.

The dependency check learns to tell a deliberate divergence from a real
violation, since after alignment the engine's exact pin is unsatisfied by
design and the reinstall remedy no longer applies.

An install that leaves a runtime unable to open a device now fails
instead of exiting 0, but only on that conjunction: an alignment that could
not run may still leave a working environment, and a device count of zero
is the right answer wherever no GPU is present. `install sdk` needs the
distinction, because it deliberately downgrades engine auto-install
failures to a warning so a failed engine install does not discard a good
multi-gigabyte SDK -- which is still right, and still what happens for
every other engine failure. It was catching this one too, so the single
case where the install really did produce something broken kept reporting
success, which is the reported symptom exactly. The error says the SDK
itself installed fine and what to do next, so a transient index failure
does not read as a ruined install.

The nightly scenario covering a second SDK install moves with it. It
asserted the wording of the dependency check, which a settled runtime no
longer produces; it now asserts that the runtime can still open a GPU,
which is the outcome it was always trying to protect, while still failing
on any genuine unmet requirement.

Verified end to end on MI300X: an unmodified `install sdk` realigns torch,
reports the runtime usable with 8 devices, and serves a real completion;
a subsequent `engines install --reinstall` re-settles it rather than
breaking it.

Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
@michaelroy-amd
michaelroy-amd force-pushed the eai-8268-canonical-rocm-streams branch from 62db3c9 to 46a5967 Compare August 27, 2026 15:13
Signed-off-by: Michael Roy <michael.roy@amd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants