Skip to content

fix(serve): validate --device via clap possible values (exit 2) - #304

Merged
r0x0r merged 3 commits into
mainfrom
fix/serve-device-clap-possible-values
Aug 27, 2026
Merged

fix(serve): validate --device via clap possible values (exit 2)#304
r0x0r merged 3 commits into
mainfrom
fix/serve-device-clap-possible-values

Conversation

@r0x0r

@r0x0r r0x0r commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

rocm serve --device bogus previously rejected the invalid value via application
logic (exit code 1, message "unsupported device policy") instead of clap's
possible values validation (exit code 2). Every other enum-style argument in
the CLI — --engine, config set-*, engines install, etc. — uses clap
possible values, which produces exit code 2 and lists the valid choices.

This models --device as a clap ValueEnum (DevicePolicyArg) so invalid input
is rejected consistently and the valid choices are listed in the error.

Changes

  • Add DevicePolicyArg and change serve --device from Option<String> to
    Option<DevicePolicyArg>. Only gpu_required and gpu_preferred are
    advertised; cpu_only is #[value(hide = true)] — still accepted so the
    intentional exit-1 rejection keeps working, but hidden from --help, shell
    completion, and the invalid-value list.
  • The historical aliases (auto/gpugpu_required, cpucpu_only) stay
    accepted for backward compatibility but are hidden from the advertised list.
  • The intentional cpu_only/cpu app-level rejection (exit 1 with rocm serve requires ROCm GPU execution; CPU mode is not a fallback path in rocm-cli) is
    preserved — only the generic "unsupported device policy" exit-1 path is
    replaced by clap's exit-2 usage error.
  • Reworded the gpu_preferred help so it no longer implies a CPU-fallback path:
    it now reads "Accepted for compatibility; behaves identically to gpu_required
    (rocm serve has no CPU fallback path)" (AGENTS.md §6).
  • Dropped cpu_only from the README rocm serve synopsis and removed the stale
    README line that described --gpu being ignored with --device cpu_only, so no
    documented surface advertises a value that --help deliberately hides.
  • Reworked the device possible-values sync test to read clap's structural possible
    values instead of a hand-written doc string, mirroring the existing --engine
    test.

Behavior

Before:

$ rocm serve qwen --device bogus
Error: unsupported device policy: bogus      # exit 1

After:

$ rocm serve qwen --device bogus
error: invalid value 'bogus' for '--device <DEVICE>'
  [possible values: gpu_required, gpu_preferred]   # exit 2

--device cpu_only (and the cpu alias) still exit 1 with the GPU-required
message; they are simply no longer advertised as choices.

Tests

  • serve_rejects_unknown_device_policy_as_usage_error — asserts invalid
    --device is a clap InvalidValue usage error (fails before the fix, passes
    after).
  • serve_accepts_device_policy_values_and_aliases — asserts every value and
    legacy alias still parses to the expected variant.
  • serve_device_help_lists_match_device_policy_names — reworked to verify clap's
    structural possible values (including hidden entries, via get_possible_values)
    stay in sync with the full DevicePolicy set.
  • device_policy_arg_maps_through_parse_device_policy — pins the DevicePolicyArg
    DevicePolicy mapping so a mis-wired variant is caught.

cargo test -p rocm --bin rocm, cargo clippy -p rocm --all-targets -- -D warnings, and cargo fmt all pass. No new e2e scenario is added: the change is a
CLI usage-validation/exit-code correction with no new runtime engine behavior, and
it is fully covered by the argument-parsing unit tests above.

Model `rocm serve --device` as a clap `ValueEnum` (`DevicePolicyArg`) so an
invalid value is rejected by clap's usage validation (exit code 2) with the
valid choices listed, instead of parsing as a free-form string and failing
later in application logic with a generic "unsupported device policy" error
(exit code 1).

This makes `--device` consistent with every other enum-style argument in the
CLI (`--engine`, config set-*, engines install, etc.), all of which use clap
possible values. The historical aliases (`auto`/`gpu` for gpu_required, `cpu`
for cpu_only) stay accepted for backward compatibility but are hidden from the
advertised list, and the intentional cpu_only app-level rejection (exit 1 with
a GPU-required message) is preserved.

Adds regression tests asserting invalid `--device` is a clap InvalidValue usage
error and that every value and alias still parses, and reworks the device
possible-values sync test to read clap's structural possible values rather than
a hand-written doc string.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
@r0x0r
r0x0r requested a review from a team as a code owner August 24, 2026 09:13
@r0x0r
r0x0r requested a review from volen-silo August 24, 2026 09:14
@volen-silo

Copy link
Copy Markdown
Collaborator

Review — changes requested

Reviewed main...HEAD (1 commit, apps/rocm/src/main.rs, +80/-45). The core idea is right and the implementation is clean: DevicePolicyArg is a genuine improvement over the free-form Option<String>, the alias set is preserved faithfully (verified EnumValueParser matching is case-sensitive by default, same as the old exact-string match — no input that used to work is now rejected), and hidden aliases really are excluded from the advertised list. One blocking item, plus a few notes.

Blocking

1. The new per-variant doc comments are rendered as user-facing help text, and one of them is wrong.

Because --device is now a ValueEnum, clap promotes the variant doc comments into --help and shell completions. Confirmed against the built binary:

      --device <DEVICE>
          Device policy

          Possible values:
          - gpu_required:  Require a ROCm GPU; fail if none is usable (the default)
          - gpu_preferred: Prefer a ROCm GPU when one is available
          - cpu_only:      Run on CPU only (not a supported fallback path in rocm serve)

parse_device_policy (main.rs:16763-16771) maps gpu_required, gpu_preferred, auto and gpu all to DevicePolicy::GpuRequired. gpu_preferred does not "prefer" anything — it hard-requires a GPU and fails if none is usable, identically to gpu_required. Both engine normalizers do the same (engines/vllm/src/lib.rs:1154, engines/lemonade/src/lib.rs:3756); no layer implements prefer-with-CPU-fallback.

This text is new in this PR — before the change the doc comment was just /// Device policy [possible values: gpu_required, gpu_preferred, cpu_only]. with no descriptions. So the PR introduces user-facing documentation that contradicts the code, and specifically advertises what reads as a CPU-fallback path, which AGENTS.md §6 explicitly guards against ("preserve strict GPU-required behavior; do not introduce silent CPU fallback").

Suggested fix (one line): reword to state actual behavior, e.g.

/// Accepted for compatibility; behaves identically to `gpu_required`
/// (rocm serve has no CPU fallback path).
GpuPreferred,

Please re-read all three variant docs as user-facing help text, not internal comments — that is what they now are.

Non-blocking

2. cpu_only is advertised as a valid choice in the error message that corrects a typo. It is unconditionally rejected (main.rs:16766). The old error path had no possible-values list, so this is the one dimension where the change makes the advertised contract slightly less honest than before: a user who types --device bogus is now told [possible values: gpu_required, gpu_preferred, cpu_only], steering them at a value that can never succeed. #[value(hide = true)] on CpuOnly would keep it accepted (preserving the deliberate exit-1 message) while dropping it from help, completions and the suggestion list. Consistent with the alias-hiding already used on this enum, and it does not break serve_device_help_lists_match_device_policy_names (get_possible_values() still returns hidden entries). Your call — the parenthetical caveat in the description is a partial mitigation.

3. as_policy_str() is untested and is the one place a swap ships silently. It has exactly two references: its definition (main.rs:1004) and the single call site (main.rs:4878). Neither new test exercises it — they stop at DevicePolicyArg, never crossing into DevicePolicy. A mis-typed arm mapping CpuOnly to "gpu_required" would turn the intentional CPU rejection into a silent GPU-required serve and every test in the suite would still pass. Cheapest fix: extend serve_accepts_device_policy_values_and_aliases to feed the parsed variant through parse_device_policy and assert the resulting DevicePolicy (including that cpu_only still errors).

It is also the third hand-written copy of the same three strings, alongside device_policy_name() (main.rs:17110) and parse_device_policy's match arms. The new sync test guards the possible-values list against DevicePolicy, but nothing guards this mapping.

4. The scope is right, but the half-migration is undisclosed. engines/vllm/src/lib.rs:1164 and engines/lemonade/src/lib.rs:3853 carry the identical pre-fix pattern — free-form String --device-policy, manual match, bail! on a bad value, exit 1, no possible-values, no completions. These are not internal-only: docs/vllm.md:34 documents rocm-engine-vllm resolve-model ... --device-policy gpu_required as a directly-runnable command, so a typo there still hits exactly the bug this PR fixes for rocm serve. Migrating them is legitimately separable work per AGENTS.md §11 — just worth a line in the description or a tracked follow-up so this does not read as done everywhere.

5. While you're here: README.md's --gpu paragraph states "--gpu is ignored with --device cpu_only (the model runs on CPU)", which is false for the same reason as item 2. Pre-existing and outside the diff, but this PR is precisely about the honesty of the --device value list, so it is a natural companion fix.

6. e2e scenario justification. AGENTS.md §3 names exit codes as user-observable and says a unit test does not discharge the scenario requirement. I checked the actual norm rather than the letter: PR #303 is directly on point (a pure CLI exit-code correction, 3 → 0, justified in near-identical language, merged with no scenario), and tests/e2e-cucumber/expectations.toml has no row tracking this behavior, so the PR #296 xfail-flip route does not apply either. I am satisfied the omission is consistent with repo practice — but citing #303 in the description would preempt the next reviewer reading §3 literally. No existing scenario regresses or silently passes on a stale assumption (the serve-no-gpu-fails-fast family tests the app-level GPU refusal path with valid --device, untouched here).

Tradeoff worth noting

Routing DevicePolicyArg back through a string into parse_device_policy rather than a direct From impl looks like a smell but is defensible: parse_device_policy is the single choke point enforcing the cpu_only rejection across three callers (the CLI, the disk-persisted managed-service restart at main.rs:13940, and the hidden __engine-serve-http subcommand at main.rs:16689). A direct conversion would create a path that bypasses that guardrail. Worth confirming this was deliberate — if so, a one-line comment on as_policy_str saying so would lock the reasoning in.

Positive

  • --device gains structural shell completion for the first time (it had none as a bare String). Worth a line in the description; it is a real user-facing win beyond the exit-code fix.
  • Consolidating serve_arg_help + possible_values_listed_in_help into a single serve_possible_values(arg_id) shared by both sync tests is a genuine simplification, and dropping the rendered-help string parsing costs no coverage now that there is no hand-written list left to drift.
  • serve_rejects_unknown_device_policy_as_usage_error genuinely fails on main (where --device had no value parser, so parse_serve returned Ok and .expect_err would panic) — a real regression test, per AGENTS.md §3.

Verification performed

cargo clippy -p rocm --bin rocm --all-targets -- -D warnings clean; cargo fmt --all -- --check clean; cargo test -p rocm --bin rocm device 6/6 and serve_engine 5/5 pass. Rendered rocm serve --help from the built binary to confirm item 1. Checked clap 4.6 source for EnumValueParser case sensitivity, PossibleValue::alias hiding, and Error::exit_code() returning 2 for InvalidValue — the exit-2 claim holds for both --device and --engine. Swept the repo for other --device/--device-policy consumers, scripts, feature files, expectations rows, completion snapshots and docs.

@r0x0r

r0x0r commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the catch — pushed in 8b1b470.

  • Misleading gpu_preferred help (blocking): the per-variant ValueEnum doc comments render in serve --help, completions, and the invalid-value suggestion list, so "Prefer a ROCm GPU when one is available" was actively wrong — parse_device_policy maps gpu_preferred straight to GpuRequired and there is no CPU fallback. It now reads: "Accepted for compatibility; behaves identically to gpu_required (rocm serve has no CPU fallback path)."
  • cpu_only advertised as a choice: taken your suggestion and added #[value(hide = true)], so it no longer appears in --help, completions, or the invalid-value hint ([possible values: gpu_required, gpu_preferred]). It still parses so the deliberate exit-1 rejection message is preserved, and serve_device_help_lists_match_device_policy_names still passes (get_possible_values() returns hidden entries).
  • as_policy_str was untested: added device_policy_arg_maps_through_parse_device_policy, which feeds each parsed variant back through parse_device_policy and asserts the resulting DevicePolicygpu_required/gpu_preferredGpuRequired, cpu_only → rejected — so a mis-typed arm can't silently swap the policy while other tests stay green.

Verified locally: the 7 device/serve unit tests pass and serve --help / --device bogus render as described.

@volen-silo

Copy link
Copy Markdown
Collaborator

Follow-up review — resolved

Re-verified against the current head 8b1b470 (was 4bd5a84 at the time of the first review). All three items are genuinely fixed — checked against the rebuilt binary, not the claim.

Blocking

1. Misleading gpu_preferred help text — resolved. Rendered from the rebuilt binary:

      --device <DEVICE>
          Device policy

          Possible values:
          - gpu_required:  Require a ROCm GPU; fail if none is usable (the default)
          - gpu_preferred: Accepted for compatibility; behaves identically to `gpu_required` (rocm serve has no CPU fallback path)

No CPU-fallback claim survives in any of the variant docs. The AGENTS.md §6 concern is discharged.

Non-blocking, previously raised

2. cpu_only advertised — resolved, on all three surfaces:

  • rocm serve qwen --device bogus[possible values: gpu_required, gpu_preferred], exit 2
  • rocm completions bashcompgen -W "gpu_required gpu_preferred"
  • a near-miss (--device cpu_onl) no longer suggests it either

And the deliberate rejection is intact: --device cpu_only and the cpu alias both still exit 1 with rocm serve requires ROCm GPU execution; CPU mode is not a fallback path in rocm-cli.

3. as_policy_str untested — resolved. device_policy_arg_maps_through_parse_device_policy passes and genuinely bites: the CpuOnly => "gpu_required" swap I described flips the is_err() assertion. The as_policy_str doc comment now also records the choke-point reasoning, which closes the tradeoff item as well.

4, 5, 6 — not addressed, and that is fine. The engine-crate half-migration disclosure, the README --gpu/cpu_only line, and citing #303 for the e2e omission. All were non-blocking; none block merge.

Small ripples from this commit

None blocking, but hide = true left three consistency loose ends:

  • The PR description is now stale. Its "After" block still shows [possible values: gpu_required, gpu_preferred, cpu_only], which is not what the binary prints any more, and it does not mention the hidden cpu_only, the reworded help, or the fourth test. It is the artifact maintainers read — worth a refresh before merge.
  • README.md:298 still lists [--device gpu_required|gpu_preferred|cpu_only] in the serve synopsis, so the README now advertises a value that --help deliberately hides. Same family as item 5; those two README lines are now the last place cpu_only is presented as a real choice for rocm serve.
  • crates/rocm-dash-tui/src/ui/serve_wizard.rs:45-50 hardcodes DEVICES = ["(engine default)", "gpu_required", "gpu_preferred", "cpu_only"]. It is not clap-derived, so it did not pick up the hide: a user can still select cpu_only in the TUI wizard and get a launch that always fails. Pre-existing and out of scope, just noting it is now the remaining surface offering the dead choice.

Minor: the comment at apps/rocm/src/main.rs:18110-18114 says the possible values "are advertised in --help and shell completion" and that "the sync tests below keep the advertised lists honest". For --device that is no longer quite true — cpu_only is deliberately unadvertised, and serve_device_help_lists_match_device_policy_names compares against the full DevicePolicy set including hidden entries. The test is still the right test; the sentence describing it drifted.

Gates

Run at 8b1b470, exit codes checked:

  • cargo fmt --all -- --check — 0
  • cargo clippy --workspace --all-targets -- -D warnings — 0
  • cargo test --workspace --all-targets — 0, zero failures workspace-wide, including the four device/serve argument tests

CI is green apart from docs/readthedocs..., which is also failing on unrelated open PRs and is not caused by this change.

Verdict

LGTM. The blocking finding is resolved and nothing outstanding blocks merge. Refreshing the PR description is the only thing I would still do before landing.

r0x0r added 2 commits August 27, 2026 12:24
The per-variant ValueEnum doc comments render in `serve --help`, shell
completions, and the invalid-value suggestion list. `gpu_preferred`
previously read "Prefer a ROCm GPU when one is available", which is
misleading: parse_device_policy maps gpu_preferred to GpuRequired and
rocm serve has no CPU fallback path. Reword it to state it behaves
identically to gpu_required.

cpu_only is always rejected (rocm serve requires GPU execution), so hide
it from the advertised choices with #[value(hide = true)] while keeping it
parseable so the deliberate rejection message is preserved.

Add device_policy_arg_maps_through_parse_device_policy to guard the
DevicePolicyArg::as_policy_str -> parse_device_policy mapping (gpu_required
and gpu_preferred resolve to GpuRequired; cpu_only is rejected), closing
the previously untested conversion path.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Hiding `cpu_only` from `--device` help/completion left three surfaces still
presenting it as a real choice. Align them with what the CLI now advertises:

- README serve synopsis dropped `cpu_only` from the --device value list.
- Removed the '--gpu is ignored with --device cpu_only (the model runs on CPU)'
  sentence: cpu_only is rejected (exit 1), never runs on CPU, so the line
  advertised a fallback path that does not exist (AGENTS.md §6).
- Corrected the drifted test comment to note cpu_only is #[value(hide = true)]
  and that serve_device_help_lists_match_device_policy_names compares against
  the full DevicePolicy set (hidden entries included).

Doc/comment only; no behavior change.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
@r0x0r
r0x0r force-pushed the fix/serve-device-clap-possible-values branch from 8b1b470 to c4e9ac6 Compare August 27, 2026 12:25
@r0x0r

r0x0r commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough re-verification. The description refresh is done, and the three hide = true ripples are addressed:

  • PR description: the "After" block now shows [possible values: gpu_required, gpu_preferred], and the body documents the hidden cpu_only (#[value(hide = true)], still accepted for the exit-1 rejection), the reworded gpu_preferred help, and the fourth test (device_policy_arg_maps_through_parse_device_policy).
  • README: the same push drops cpu_only from the rocm serve synopsis (README.md:298) and removes the stale line describing --gpu being ignored with --device cpu_only, so no documented surface advertises a value that --help hides. That also closes the earlier non-blocking README item.
  • main.rs:18110 comment: updated to note --device's cpu_only is deliberately unadvertised and that serve_device_help_lists_match_device_policy_names compares against the full DevicePolicy set (hidden entries via get_possible_values), so the sentence no longer overstates what is in --help/completion.

serve_wizard.rs:45-50's hardcoded DEVICES list is left as-is — as you noted, it's pre-existing and out of scope for this change.

Note on history: the branch's fix commit was signed-off but not cryptographically signed, which was failing the commit-signatures gate and blocking the push hook. I re-signed the range and force-pushed with lease; git range-diff confirms content is byte-identical (signatures only). verify-commits, clippy, fmt and test pass at the new head.

@r0x0r
r0x0r added this pull request to the merge queue Aug 27, 2026
Merged via the queue into main with commit 8d9355c Aug 27, 2026
23 of 25 checks passed
@r0x0r
r0x0r deleted the fix/serve-device-clap-possible-values branch August 27, 2026 13:37
pmoutsias-amd pushed a commit that referenced this pull request Aug 27, 2026
* fix(serve): validate --device via clap possible values (exit 2)

Model `rocm serve --device` as a clap `ValueEnum` (`DevicePolicyArg`) so an
invalid value is rejected by clap's usage validation (exit code 2) with the
valid choices listed, instead of parsing as a free-form string and failing
later in application logic with a generic "unsupported device policy" error
(exit code 1).

This makes `--device` consistent with every other enum-style argument in the
CLI (`--engine`, config set-*, engines install, etc.), all of which use clap
possible values. The historical aliases (`auto`/`gpu` for gpu_required, `cpu`
for cpu_only) stay accepted for backward compatibility but are hidden from the
advertised list, and the intentional cpu_only app-level rejection (exit 1 with
a GPU-required message) is preserved.

Adds regression tests asserting invalid `--device` is a clap InvalidValue usage
error and that every value and alias still parses, and reworks the device
possible-values sync test to read clap's structural possible values rather than
a hand-written doc string.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* fix(serve): correct --device help text and hide cpu_only choice

The per-variant ValueEnum doc comments render in `serve --help`, shell
completions, and the invalid-value suggestion list. `gpu_preferred`
previously read "Prefer a ROCm GPU when one is available", which is
misleading: parse_device_policy maps gpu_preferred to GpuRequired and
rocm serve has no CPU fallback path. Reword it to state it behaves
identically to gpu_required.

cpu_only is always rejected (rocm serve requires GPU execution), so hide
it from the advertised choices with #[value(hide = true)] while keeping it
parseable so the deliberate rejection message is preserved.

Add device_policy_arg_maps_through_parse_device_policy to guard the
DevicePolicyArg::as_policy_str -> parse_device_policy mapping (gpu_required
and gpu_preferred resolve to GpuRequired; cpu_only is rejected), closing
the previously untested conversion path.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* docs(serve): stop advertising hidden cpu_only device value

Hiding `cpu_only` from `--device` help/completion left three surfaces still
presenting it as a real choice. Align them with what the CLI now advertises:

- README serve synopsis dropped `cpu_only` from the --device value list.
- Removed the '--gpu is ignored with --device cpu_only (the model runs on CPU)'
  sentence: cpu_only is rejected (exit 1), never runs on CPU, so the line
  advertised a fallback path that does not exist (AGENTS.md §6).
- Corrected the drifted test comment to note cpu_only is #[value(hide = true)]
  and that serve_device_help_lists_match_device_policy_names compares against
  the full DevicePolicy set (hidden entries included).

Doc/comment only; no behavior change.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

---------

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>
mikeroySoft pushed a commit to mikeroySoft/rocm-cli that referenced this pull request Sep 1, 2026
* Add Sphinx documentation site

Adds a Sphinx documentation site under docs/rocm-docs/, single-sourced
from README.md and CONTRIBUTING.md via MyST {include} directives so
the docs and repo content stay in sync automatically. Covers
installation, getting started, command reference, demos, and
contributing/license, and is set up to publish with the rocm-docs-core
theme. Updates some links in README.md and CONTRIBUTING.md to be
absolute so they render correctly when reused via {include}.

Signed-off-by: pmoutsia_amdeng <peter.moutsias@amd.com>

* Single-source the platform-support table in the install page

Anchor the table in README.md and pull it into
docs/rocm-docs/install/installation.md via {include} instead of
duplicating it by hand.

Signed-off-by: pmoutsia_amdeng <peter.moutsias@amd.com>

* fix(docs): address review feedback on Sphinx docs site

- Add the MIT license header to the 7 new files hawkeye flagged as
  missing it.
- Fix the WSL2 platform-support-table link to docs/wsl.md: it's now an
  absolute GitHub URL so it resolves when the table is pulled into
  install/installation.md via MyST include, matching the pattern
  already used for the other README anchors.
- Pin rocm-docs-core to the exact version that resolved locally
  (1.40.0) instead of an open->= range.

Signed-off-by: pmoutsia_amdeng <peter.moutsias@amd.com>

* fix(docs): add ReadTheDocs config and a CI job to build docs with -W

- Add .readthedocs.yaml so RTD builds against docs/rocm-docs/conf.py
  with the same pinned rocm-docs-core toolchain CI uses.
- Add a docs-build CI job that runs sphinx-build -W (warnings as
  errors) against the same source RTD points at, gated on the new
  `docs` path-filter category so it only runs when doc sources,
  README.md/CONTRIBUTING.md (single-sourced via MyST includes), or
  the build config change.
- Suppress the myst.header warning from :start-after:/:end-before:
  README includes stripping the anchor heading, which is cosmetic:
  docutils re-normalizes the resulting heading depth in the rendered
  output.
- Scope external_projects to [] instead of the implicit "all" default,
  which was fetching intersphinx inventories for every project in
  rocm_docs' bundled catalog (~90 projects) - several of which 404 or
  have moved upstream. No page here uses a cross-project intersphinx
  role, so this is lossless and makes -W builds deterministic instead
  of flaky against infrastructure this repo doesn't control.
- Filter the "current project not found in projects" warning: rocm-cli
  isn't registered in rocm-docs-core's shared projects catalog yet, so
  external_projects_current_project can never resolve until that's
  added upstream. rocm_docs.projects handles the unresolved project as
  None everywhere it's used, so this is informational, not a defect.

Signed-off-by: pmoutsia_amdeng <peter.moutsias@amd.com>

* docs: use docs-relative cross-page links consistently

README.md's own #model-serving and #interactive-interfaces anchors were
rewritten to absolute GitHub URLs so they'd still work once pulled into
the docs site, but that breaks in-page anchor scrolling when the README
is viewed on GitHub. Revert both to relative anchors and instead apply
the cut-and-reauthor pattern already used for the CONTRIBUTING.md link
in installation.md: narrow the surrounding {include} in getting-started.md
and commands.md around each sentence and hand-author a docs-relative
replacement (commands.md#model-serving, getting-started.md#interactive-interfaces).

Signed-off-by: pmoutsia_amdeng <peter.moutsias@amd.com>

* docs: use descriptive nav title for Demos section

Avoids the sidebar rendering as duplicated Demos > Demos for the
single-entry section by overriding the nav link text to match the
homepage tile's wording.

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs: fix sentence fragments in intro blurb

Joins the "single prebuilt binary" fragments into one complete
sentence in both README.md and the standalone index.rst homepage
copy, and adds a lead-in sentence before the bare `rocm` code fence
in the Getting Started "First run" section.

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs: style guide pass on README and CONTRIBUTING

Sentence-case headings, expand DCO acronym, replace banned/informal
wording (may, e.g.), normalize slash usage, lowercase version
placeholder.

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix(lemonade): retry interrupted backend setup (ROCm#249)

* fix(lemonade): retry interrupted backend setup

Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>

* ci(e2e): build prebuilt lanes with the test-hooks feature

The suite's deterministic failure seams are compiled out without
`rocm/e2e-test-hooks`. `cargo xtask e2e` passes the feature only when it
builds the binaries itself, so every lane that pre-builds and exports
ROCM_CLI_BINARY silently tested a binary without those seams. The
scripted-Lemonade-failure scenario then never reached its premise and
failed as a regression on the one lane that selects it.

Pass the feature on all prebuilt e2e lanes, and add a workflow-contract
test so a lane cannot drift back. Release and packaging builds keep the
feature off — a shipped binary must not carry a failure-injection seam.

Also name the cause in the retry assertion, which otherwise reports a
baffling missing announcement rather than the real misconfiguration.

Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>

---------

Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* ci(dependabot): track pre-commit hook versions (ROCm#235)

The hook pins in .pre-commit-config.yaml were bumped by hand and drifted
between releases. Dependabot's pre-commit ecosystem resolves each rev
against the hook repository's tags, and skips the builtin and local
blocks, which have no upstream release to track.

Weekly and grouped, with the same 7-day cooldown as the other two
ecosystems: a hook is executable code that runs on every contributor's
machine at commit time and in the prek CI job, so a compromised release
would run before anyone reads the bump.

Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix: raise the supported Linux minimum to Ubuntu 24.04 (ROCm#261)

* fix: raise the supported Linux minimum to Ubuntu 24.04

Every published Lemonade embeddable, v10.2.0 through v11.5.2, is linked
against GLIBC_2.38 and GLIBCXX_3.4.32. Ubuntu 22.04 ships glibc 2.35, so
the Lemonade engine cannot start there at all, yet README.md advertised
Linux x86_64 as "full support ... both inference engines" and docs/wsl.md
named 22.04 as a supported WSL base.

Document a single minimum of Ubuntu 24.04 for Linux and WSL2, keeping the
glibc number as the reason so the requirement stays meaningful on other
distributions, and drop 22.04 from the WSL preflight's supported set so the
automated check matches the prerequisite it enforces.

Fixes ROCm#258

Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>

* fix(wsl): accept Ubuntu releases after 24.04

Signed-off-by: Michael Roy <michael.roy@amd.com>

---------

Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Co-authored-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* ci(e2e): repair a pre-warm tree that records a folder elsewhere (ROCm#316)

A scenario reaches the shared pre-warm tree through a symlink at its own
`data/runtimes`. An `install sdk` run that way writes the link's path — a
per-scenario temp dir — into the manifest that lands in the SHARED
registry, and into the venv's console-script shebangs. The temp dir goes
away with the scenario and the shared runtime is left naming a folder
that no longer exists, so later, unrelated runs fail.

Drop such a runtime before deciding whether the tree is fresh, so the
pre-warm reinstalls instead of serving a dead one. `rocm update` cannot
see this: it compares versions against the index, not the runtime
against the disk.

Removing the folder is the repair, not a precaution. A poisoned venv
keeps a working `bin/python` — a symlink to the base interpreter, still
present — so the install reuses it and audits already-satisfied packages
rather than reinstalling them, leaving every shebang pointing at the
folder that went away. Measured on uv 0.9.30: reinstalling over a
poisoned venv reports success and repairs nothing.

The signal is an install root outside the tree, deliberately not
`status=unusable`. Unusable has many causes — a missing rocm_sdk probe
block alone reports it — and this deletes what it selects, so a healthy
multi-GiB runtime must not hang on a validation detail. Read-only
runtimes are exempt: `runtimes adopt` records an external folder on
purpose.

Refs: ROCm#315

Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix(install): record the folder the files land in, not the link (ROCm#317)

* fix(install): record the folder the files land in, not the link

`install sdk` built the install root by joining onto the data dir and
recorded whatever that produced. Reaching `data/runtimes` through a
symlink is enough to make that name a route rather than a place: correct
while the link exists, and wrong the moment it goes.

The path outlives the command. It goes into the registry manifest, the
sidecar beside the runtime, and — through uv — the `#!` line of every
console script in the environment. So a runtime installed that way keeps
reporting itself installed at a folder that is not there, while the files
sit untouched next door and every entry point fails to start.

Resolve the root before anything is written to it. Only the root:
`python_executable` is derived from it and must keep the venv's own
`bin/python`, which is itself a symlink to the base interpreter, so
resolving that would record the system Python instead. The adopt path
already draws the line in the same place, canonicalizing the install root
next to `absolute_existing_file_path_preserving_symlink` for the
interpreter; this gives the install path the same treatment, `--prefix`
included.

The E2E harness creates exactly this shape when a scenario opts into the
shared pre-warmed runtime, so the shared tree on a runner was what got
poisoned — but nothing about the fault is test-only. Any data dir reached
through a link has it.

Refs: ROCm#315
Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>

* fix(vllm): name the missing interpreter behind a failed launch

Two messages described a stale runtime as an absence.

A spawn that fails on a console script whose `#!` interpreter is gone
reports ENOENT against the script, so the error named a file that is
plainly there. Say which interpreter is missing when that is what
happened, and stay quiet when the ordinary reading is right — a genuinely
absent file, a binary, or a live interpreter.

Resolution drops a registered runtime whose recorded interpreter is not
there. That is correct — a runtime that cannot run is not a candidate —
but it left the failure describing an empty registry while `rocm runtimes
list` prints the entry. Name the manifests that were passed over and the
interpreters they record.

Both are additive: the note only ever decorates an error already being
returned, and a registry it cannot read yields no note rather than
replacing the original failure.

First tests for this area, which had none.

Refs: ROCm#315
Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>

* test(install): compare resolved paths, not verbatim ones, on Windows

The Windows lane failed on the prefix rather than the behaviour.
`canonicalize` hands back `\\?\C:\…` there, so a test that built its
expectation that way compared a verbatim path against the plain one the
resolver deliberately returns, and three assertions turned on the
difference.

Build the expectations with the resolver instead, which strips the prefix
for the same reason the product does: a stored path is later compared
against ordinary ones, and `\\?\C:\…` never `starts_with`-matches `C:\…`.
That the prefix really is stripped stays asserted on its own, so this does
not become the function agreeing with itself.

This also removes a second Windows-only trap: `temp_dir()` there can
return an 8.3 short path, which `canonicalize` expands, so the two sides
disagreed on the folder name as well as the prefix.

Same fault in the scenario's step definitions, where the comparison would
have failed only on the Strix Windows lane. That crate cannot reach
`rocm-core`, and a dependency for six lines of string handling is the
worse trade, so it strips the prefix locally with the reason recorded.

Refs: ROCm#315
Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>

* fix(install): give up on a parent component consistently across hosts

The guard against resolving a `..` past a missing directory never fired
on Windows, because the two platforms disagree about what such a path
means. Windows collapses `..` lexically, so `<root>/missing/..` "exists"
and canonicalizes to `<root>`; Unix walks the path through the filesystem
and finds nothing. The walk therefore stopped a level early on Windows,
resolved to the wrong folder, and re-attached the tail — recording a
different folder depending on the host, which is precisely what this
function exists to prevent.

Check for the parent component before asking whether the candidate
exists, so both hosts give up in the same place.

The give-up stays narrow: a `..` whose parent is really there is
unambiguous everywhere and still resolves, which is now pinned by its own
test so a future tightening cannot quietly leave ordinary paths
unresolved.

Found by the Windows lane; it does not reproduce on Linux.

Refs: ROCm#315
Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>

---------

Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix(install): resolve driver repo version and package release in plans (ROCm#307)

* fix(install): resolve driver repo version and package release in plans

The driver install plan stored the repo version and package release as
raw shell parameter-expansion templates (${ROCM_CLI_AMDGPU_VERSION:-7.2.4}
and ${ROCM_CLI_AMDGPU_PACKAGE_RELEASE:-70204}). Two problems followed.
The human-readable plan summary printed the version template verbatim on
its "repo_version:" line, leaking an unexpanded shell placeholder into
user-facing dry-run output. And the Debian/Ubuntu apt source line wrapped
the template in single quotes, so the shell never expanded it and the
literal placeholder would have been written into
/etc/apt/sources.list.d/amdgpu.list.

Resolve both templates once, at plan-build time, to their effective
values (the env var when set and non-empty, matching shell :- default
semantics, otherwise the documented default) and bake the concrete values
into every rendered URL, repo path, and command. The resolver is
generalized to resolve_shell_default_template and hardened to pass bare
${VAR} and nested-default shapes through unchanged rather than emitting a
partially rewritten value.

Add unit tests for the resolver (default, env override, empty-as-unset,
non-template pass-through, bare-var and nested-default pass-through) and
update every distro plan test to assert the concrete values, plus a
render-level regression test and an end-to-end scenario asserting the
dry-run summary shows the resolved version rather than the raw
placeholder. Tests that read these process env vars serialize on a shared
lock and save/restore prior values so they stay deterministic under
edition-2024 env semantics.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* test(install): guard the two remaining env-reading driver-plan tests

build_driver_install_plan now resolves the repo-version template via
std::env::var at the top of the function, so every test calling it reads
process env. The sweep that added ScopedTestEnv::with_amd_overrides_cleared()
to the other call sites missed windows_install_driver_is_validate_only and
wsl_install_driver_uses_rocdxg_guidance_without_dkms, leaving two unguarded
readers racing the guarded mutators in the same test binary. Add the guard to
both. No production change.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

---------

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix(cli): accept negative float flag values in space form (EAI-8243) (ROCm#306)

* fix(cli): accept negative float flag values in space form

The space form of negative-number float flags (e.g. `serve --temperature
-1`) was rejected by clap with a confusing "unexpected argument '-1'"
error, because clap parsed the leading-dash token as a flag rather than a
value. Only the equals form (`--temperature=-1`) reached the range
validator that reports the valid range.

Enable `allow_negative_numbers` on the affected float flags
(`--temperature` and `--top-p` on both `chat` and `serve`) so the space
form reaches the value parser and both forms validate identically,
surfacing a clear range-validation message instead of an unexpected
argument error.

Add regression tests covering both the space and equals forms for
`--temperature` and `--top-p` on `chat` and `serve`.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* fix(cli): extend negative-value fix to --max-tokens and add serve scenario

The negative-number-as-flag gotcha is a tokenizer-level ambiguity that
fires before any value parser runs, so it is not float-specific:
`--max-tokens -1` (space form) on both chat and serve was still rejected
as an unexpected argument while `--max-tokens=-1` reached parse_positive_u32.
Add allow_negative_numbers to --max-tokens on both commands so the space
form reaches the value parser and reports a clear error, matching the
--temperature/--top-p behavior fixed here.

Per AGENTS.md §3, the user-observable stderr change is now covered by an
ungated Gherkin scenario, @id:serve-negative-temperature-rejected, in
model_serving.feature. The value parser runs inside argument parsing
before engine selection or GPU pre-flight, so the scenario needs no GPU
and no engine and gates every PR (mirrors the ungated
@id:fix-position-argument-rejected precedent).

Also: reword the shared rationale comment to cover all three numeric value
flags (and note clap only treats a token as negative when the whole
remainder parses as one, so missing/malformed values still error at parse
time), give the chat regression test a symmetric comment, and extend both
space-form regression tests with the --max-tokens cases.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* test(e2e): number the negative-temperature serve scenario

The new scenario was the only unnumbered title in model_serving.feature;
every other scenario uses 'Scenario: <N> - <Title>'. Assign the next free
number (15) to keep the file consistent. No behavior change.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

---------

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix(serve): validate --device via clap possible values (exit 2) (ROCm#304)

* fix(serve): validate --device via clap possible values (exit 2)

Model `rocm serve --device` as a clap `ValueEnum` (`DevicePolicyArg`) so an
invalid value is rejected by clap's usage validation (exit code 2) with the
valid choices listed, instead of parsing as a free-form string and failing
later in application logic with a generic "unsupported device policy" error
(exit code 1).

This makes `--device` consistent with every other enum-style argument in the
CLI (`--engine`, config set-*, engines install, etc.), all of which use clap
possible values. The historical aliases (`auto`/`gpu` for gpu_required, `cpu`
for cpu_only) stay accepted for backward compatibility but are hidden from the
advertised list, and the intentional cpu_only app-level rejection (exit 1 with
a GPU-required message) is preserved.

Adds regression tests asserting invalid `--device` is a clap InvalidValue usage
error and that every value and alias still parses, and reworks the device
possible-values sync test to read clap's structural possible values rather than
a hand-written doc string.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* fix(serve): correct --device help text and hide cpu_only choice

The per-variant ValueEnum doc comments render in `serve --help`, shell
completions, and the invalid-value suggestion list. `gpu_preferred`
previously read "Prefer a ROCm GPU when one is available", which is
misleading: parse_device_policy maps gpu_preferred to GpuRequired and
rocm serve has no CPU fallback path. Reword it to state it behaves
identically to gpu_required.

cpu_only is always rejected (rocm serve requires GPU execution), so hide
it from the advertised choices with #[value(hide = true)] while keeping it
parseable so the deliberate rejection message is preserved.

Add device_policy_arg_maps_through_parse_device_policy to guard the
DevicePolicyArg::as_policy_str -> parse_device_policy mapping (gpu_required
and gpu_preferred resolve to GpuRequired; cpu_only is rejected), closing
the previously untested conversion path.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* docs(serve): stop advertising hidden cpu_only device value

Hiding `cpu_only` from `--device` help/completion left three surfaces still
presenting it as a real choice. Align them with what the CLI now advertises:

- README serve synopsis dropped `cpu_only` from the --device value list.
- Removed the '--gpu is ignored with --device cpu_only (the model runs on CPU)'
  sentence: cpu_only is rejected (exit 1), never runs on CPU, so the line
  advertised a fallback path that does not exist (AGENTS.md §6).
- Corrected the drifted test comment to note cpu_only is #[value(hide = true)]
  and that serve_device_help_lists_match_device_policy_names compares against
  the full DevicePolicy set (hidden entries included).

Doc/comment only; no behavior change.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

---------

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* fix(dash): launcher shows live serving instances; amd-smi detection off critical path (eai-8190) (ROCm#295)

* fix(dash): seed launcher front door with live serving instances

The launcher front door built an empty AppState, so it always rendered
the idle variant even when a model was actively serving. Read the
managed-service registry (the same authority `rocm services` reads)
once per hub-loop pass and seed the AppState's instances from it.

Also treat `Ready` as serving everywhere the dashboard counts running
instances (`is_serving()`), matching the `Running`+`Ready` treatment
already used elsewhere (e.g. home.rs) -- a served model reports
`Ready`, not `Running`, so the count previously undercounted actual
serving models.

Adds apps/rocm's direct dependency on rocm-dash-core (previously only a
transitive dep) so the launcher can build `Instance`s from the
registry's `DiscoveredService` records.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* fix(dash-daemon): run amd-smi detection off the run loop's critical path

Detecting amd-smi (`amd-smi version` plus the first `system_info()`)
can take up to ~15s on real hardware. Running it inline before the run
loop's first tick blocked managed-service discovery and the first
snapshot broadcast behind it, so an already-running model did not
surface in the dashboard until GPU detection finished -- a visible
~15-20s "0 models running" lag while `rocm services` already reported
it live.

Spawn detection in the background and adopt the result via a oneshot
channel the moment it lands, without ever blocking the loop while it
is in flight. The loop now starts ticking immediately, so serving
instances appear within one discovery tick; GPU metrics fill in once
detection completes.

Adds a regression test asserting on ordering (the instance must
surface in a snapshot whose gpu_system_info is still None) rather than
wall-clock timing, since a pure "arrived within Ns" check would be
flaky under subscriber starvation.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

* test(dash): exercise off-critical-path detection and launcher front door

Address review feedback on the amd-smi-off-critical-path change.

- Gate the "amd-smi unavailable" warning behind gpu_init_done so a healthy
  host never flashes it during the detection window; settle as unavailable
  (and say so once) if the detection task ever ends without a result.
- Add an amd_smi_skip_kfd_preflight test seam so the daemon regression test
  drives a fake amd-smi through the real detection path instead of
  short-circuiting on a GPU-less CI host (the /dev/kfd guard stays mandatory
  in production). The test now genuinely fails if detection moves back onto
  the critical path, and asserts the surfaced snapshot carries no premature
  "amd-smi unavailable" warning.
- Add direct unit tests for launcher_serving_instances (ready record maps to
  a live Instance; unbound :0 record is dropped) and a behavioural launcher
  scenario driving bare rocm through a PTY to prove the front door shows
  "Serving <model>" rather than "Idle" for a live registry service.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>

---------

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* Fix diagnose emitting invalid UNKNOWN render-group remediation (ROCm#302)

check_4_render_group built the render-group remediation command from the
/dev/kfd owner group obtained via `stat -c %G`. When the device GID has no
matching group name, stat prints the literal "UNKNOWN", and the existing
guard only rejected empty strings. That let UNKNOWN leak into the suggested
fix, producing `sudo usermod -a -G UNKNOWN,video "$USER"` in the plan,
summary, and --json output -- a command that fails because no such group
exists.

Reject "UNKNOWN" (case-insensitive) alongside empty values so the group
falls back to "render". This makes diagnose's fallback coincide with the
"render,video" that fix.rs hardcodes in the UNKNOWN/empty case; it does not
unify the two group sources, which are still computed independently and can
diverge when /dev/kfd has a real group name that is not "render".

Add a regression test covering both the "UNKNOWN" and "unknown" sentinel
casings falling back to the render group.

Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs(readme): reframe install channels around published release, document rocm examine, describe Configuration section

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs(readme): remove rocm model from command reference

Not one of the commands being hardened for this release; team decision
was to drop it from the reference for now rather than document it.

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs(conf): switch to rocm-ai flavor, enable repo and download buttons

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs(conf): revert repository/download header buttons

use_repository_button and use_download_button rely on rocm-docs-core
resolving a repository_url from the current git branch. GitHub
Actions' pull_request checkout leaves a detached HEAD on the
synthetic merge ref, so get_branch() returns an empty URL, and
sphinx_book_theme crashes trying to unpack it, failing the -W build.

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

* docs(conf): fix flavor fallback and pin repository buttons

- Broaden the known-warning suppression filter to also cover the
  "rocm-ai" flavor, which isn't in the published rocm-docs-core
  release yet and would otherwise fail the -W build even though
  rocm_docs.theme already falls back to "rocm" gracefully.
- Re-enable use_repository_button/use_download_button, pinning
  repository_url/repository_branch explicitly instead of letting
  rocm-docs-core infer them from the local git branch. CI's
  pull_request checkout leaves a detached HEAD on the synthetic merge
  ref, which resolves to an empty repository_url and crashes
  sphinx_book_theme's repository button; use_download_button was
  never actually affected by this, it only reads local source files.

Verified by building against the pinned rocm-docs-core==1.40.0 in a
clean venv (matching CI) -- build succeeds with 0 warnings.

Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>

---------

Signed-off-by: pmoutsia_amdeng <peter.moutsias@amd.com>
Signed-off-by: pmoutsias-amd <peter.moutsias@amd.com>
Signed-off-by: Eugene Volen <Eugene.Volen@amd.com>
Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Signed-off-by: Michael Roy <michael.roy@amd.com>
Signed-off-by: Roman Sirokov <roman.sirokov@amd.com>
Co-authored-by: Eugene Volen <150254791+volen-silo@users.noreply.github.com>
Co-authored-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Co-authored-by: Michael Roy <michael.roy@amd.com>
Co-authored-by: Roman <roman.sirokov@amd.com>
fredespi added a commit that referenced this pull request Sep 9, 2026
Brings the branch up to date with main and addresses the review findings that
depend on it.

Stale expectation rows deleted (their bugs are fixed on main); the scenarios
stay as guards:
- help-serve-example-names-a-resolvable-model, help-describes-the-default-command
  (#296 made the worked example 'rocm serve qwen' and relabelled bare 'rocm' the
  launcher)
- serve-rejects-no-advertised-device-policy (#304 hid cpu_only from the
  advertised list)
- diagnose-commands-name-a-real-group (#302 filters the UNKNOWN group lookup)

Verified in a Linux container on two hosts: 0 XPASS, 0 stale.

Other review fixes:
- advertised_device_policies reads clap's block rendering as well as the inline
  one, so the scenario keeps measuring the contract instead of tripping its own
  guard
- run_rocm_without_env deleted (no call sites)
- the services-stop comment now matches its expectations.toml row
- 'not the leading remedy' reworded to 'not offered as a cause', which is what
  the assertion checks
- the non-default device group is chosen from plausible device groups rather
  than whichever /etc/group lists first
- scenario numbers made unique and prefixed after main's renumbering
- new unit test rejects an expectations.toml row whose scenario no longer exists

Signed-off-by: fredespi <fredrik.espinoza@gmail.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.

2 participants