Repository navigation
ROCMAI-83: extract common.rs, webhook.rs, and cli.rs from apps/rocmd/src/lib.rs - #479
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The architecture document incorrectly reports the still-open persistence.rs extraction as already present.
Review effort: Balanced
Findings: 1
What changed in this PR
Extracts shared daemon helpers from lib.rs into common.rs without intended behavior changes.
Changes:
- Moves shared snapshot, command, healthcheck, and argument utilities.
- Relocates eight associated unit tests.
- Updates daemon architecture documentation.
| File | Description |
|---|---|
apps/rocmd/src/common.rs |
Adds shared helpers and tests. |
apps/rocmd/src/lib.rs |
Repoints callers to common. |
docs/architecture.md |
Updates modularization status. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| ### `apps/rocmd` — background daemon | ||
|
|
||
| `lib.rs` is **not yet modularized** — see EAI-7768. | ||
| `lib.rs` modularization is in progress (ROCMAI-83, Phase 5 of EAI-7768's sequencing). Extracted so far: `persistence.rs` (`record_event`/`load_managed_services`, the automation-event/audit-log and managed-service-registry I/O shared across the daemon's sandbox, MCP, service-lifecycle, and watcher code) and `common.rs` (helpers shared across ≥2 of those remaining clusters: GPU/amd-smi snapshotting, the bridge-snapshot diagnostic, `CommandCapture`/command-timeout plumbing, and small arg/healthcheck/endpoint-key utilities). Still pending: `cli.rs`, `sandbox.rs`, `mcp.rs`, `service.rs`, `webhook.rs`, and `watchers.rs` — each landing as its own PR. |
There was a problem hiding this comment.
Addressed in 195678b: this branch is now rebased/restacked on top of #477 (rocmai-83-persistence) per AGENTS.md §11 (stacked PRs stay draft until the dependency merges), and the PR has been moved back to draft. By the time this PR's own commit lands, persistence.rs genuinely exists in the branch's history alongside common.rs, so the doc line is now accurate for this branch's actual content rather than describing a sibling PR's files.
Note: GitHub won't let this fork-based PR's base ref point at rocmai-83-persistence directly (that branch only exists on the fork, not on ROCm/rocm-cli), so the base field still shows main even though the branch is rebased on #477's commits — flagging in case that needs a different fix (e.g. pushing the branch to the upstream repo).
r0x0r
left a comment
There was a problem hiding this comment.
Review: code is clean; holding approval on one doc line
The extraction itself verified as pure code motion and I have no concerns with it. One issue in docs/architecture.md is the only thing between this and an approval, and it is a one-line fix.
The doc hunk describes a state this branch is not in
The new text reads "Extracted so far: persistence.rs (…) and common.rs (…)", but apps/rocmd/src/persistence.rs does not exist in this branch — git ls-tree pr-head apps/rocmd/src/ returns only common.rs, lib.rs, main.rs. record_event and load_managed_services are still sitting in lib.rs at lines 4890 and 5004 here.
This matters more than a normal doc nit because of how the five PRs in this phase interact, which is not visible from inside any one of them:
- All five rewrite the same single line of
docs/architecture.md, and all five are branched independently frommain. Four of them are therefore guaranteed to conflict on that line. - Each one's text is a cumulative prefix that assumes the whole earlier sequence has already merged. That only resolves to a true statement if they merge in exactly the order 477 → 479 → 480 → 481 → 483.
- The failure case is quiet rather than loud: if this PR merges before #477, there is nothing on that line to conflict with, so it applies cleanly and
mainends up asserting thatpersistence.rsexists when it does not. The conflict that would have caught it only appears once something else has touched the line.
docs/architecture.md opens by saying it is updated in the same PR as the code it documents and that "a stale-but-plausible-looking note is worse than an explicit prompt to check" — a concrete filename plus a symbol list for a file that is not there is exactly that.
Either of these resolves it:
- Scope the hunk to this branch — say
common.rsonly, and let #480/#481/#483 each append their own module as they land. Self-consistent regardless of merge order, and the conflicts become trivial appends rather than whole-line rewrites. - Keep the cumulative text but gate the merge order, stating the dependency in the PR body (
Depends on #477) so it cannot land first.
(1) is the more robust of the two; (2) relies on reviewers remembering the order at merge time.
Verified clean
- Pure code motion — every moved symbol compared against its original on
main: error handling,?propagation,.context(...)strings, timeout constants, match arms, and the#[must_use]onapply_endpoint_key_envall preserved verbatim. - No silent CPU fallback introduced (AGENTS.md §6) — I looked at this specifically, since this PR moves the GPU-snapshot path.
gather_gpu_snapshot_for_configis byte-identical; theconfig.telemetry.local_inspection_enabled()gate and theamd_smi_available: falsenote-only branch are unchanged, andcapture_amd_smi_jsonkeeps its early return on!output.status.success(). - Call sites — all 15 moved symbols repointed to
common::; no missed site. - Imports — all 15 dropped from
lib.rsare genuinely unreferenced there.TcpStreamlooked like a survivor on a first pass but both remaining uses are fully-qualifiedstd::net::TcpStreamin test code, so there is no missing-import failure under-D warnings. I checked this one by hand rather than trusting the grep. - Visibility —
pub(crate)throughout,CommandCapture's four fields included;find_engine_plugin_binarycorrectly#[cfg(test)]-gated;rocmd_engine_inventorycorrectly stays private to the module. - Tests — 130 test attributes conserved across the branch (122 + 8), matching the claimed 8 moved exactly.
- The ≥2-cluster rule holds for every item — I was ready to flag anything in here used by only one cluster, since that would contradict the module's own stated admission criterion, but each one checks out:
update_check_message(sandbox + watchers),gather_gpu_snapshot_for_config(MCP + watchers),CommandCapture(sandbox + MCP),engine_healthcheck_ready(watchers + service lifecycle),optional_arg(three clusters). Defining the module by a stated rule and then actually honouring it is what keepscommon.rsfrom becoming a junk drawer, which is the usual fate of a module with that name. - Leak scan (AGENTS.md §2) — the one hit is a pre-existing comment containing the English word "private", moved verbatim. Clean.
Non-blocking: test-helper duplication
temp_app_paths, unique_test_root and workspace_test_artifact_dir are byte-identical copies in both common.rs and lib.rs test modules. Same note as on #477: #483 makes a third copy, and Phase 5 has seven target modules, so this ends around eight copies that can each drift independently. One #[cfg(test)] mod test_support; now is cheaper than reconciling them later.
🤖 by agent-hub on AMD AgentHub
7c31085 to
195678b
Compare
|
Addressing the review (195678b):
|
|
🔴 Automated review · pr-review-watcher · b7f2199 This automation never files a GitHub approval, so no approving review will Round 3, a full review of SummaryThis PR moves the helpers shared by more than one part of the daemon out of
Blocking: 0 · Non-blocking: 7. Previous round's items. The admission-rule mismatch has been non-blocking since the last round. Most of it is fixed: the four single-caller helpers went back to CI. One check failed:
A re-run once the lane is healthy should clear it. 🚫 Blocking (must fix before merge)None. Non-blocking
|
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 195678b
Requesting changes for one defect: docs/architecture.md:34 still cites cli.rs, sandbox.rs, mcp.rs, service.rs, webhook.rs and watchers.rs in backticks under the apps/rocmd heading, and none of those files exist there. That keeps "Architecture doc path citations are current" red. It also fails windows-build-and-test, through the architecture_doc::tests::run_passes_against_the_real_doc test.
To resolve: name the pending modules without backticks, or drop the list. Also rebase onto main and retarget there now that #477 has merged. Details are in the review comment on this PR.
195678b to
b843952
Compare
|
Update since the reply above: mid-batch, #477 was squash-merged into This branch has been corrective-rebased directly onto Ready for another look. |
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · b843952
Requesting changes for one defect. The rule this PR states for common.rs, "helpers shared across ≥2 of those remaining clusters" (in docs/architecture.md:34 and the commit message), does not match the code. parse_gpu_indices_arg, engine_healthcheck_ready and print_bridge_snapshot each have a single caller. run_rocm_capture_for_paths, which the sandbox and MCP code both use, stays in lib.rs. docs/architecture.md is what the remaining extraction PRs follow, so the stated rule needs to be true.
To resolve, choose one: reword the architecture line (and the PR text) to the rule actually applied, or move the helpers so the rule holds. Either way, add one sentence that sets the cluster boundaries. The earlier change request, about module files cited in the doc that do not exist, is resolved at this head and has been withdrawn. Details are in the review comment on this PR.
r0x0r
left a comment
There was a problem hiding this comment.
Re-checked this at b843952 after the restack. The extraction itself is clean and my original objection is resolved — I verified it as pure code motion rather than reading the diff: function bodies are identical, the item sets before and after match exactly (nothing lost, nothing added, tests included), doc-comment counts are unchanged, and the attribute census reconciles. The only deltas are pub(crate) markers, module re-qualification, rustfmt reflow and the SPDX header. The pub(crate) additions aren't a widening either — these were private items in the crate root, which was already crate-wide reachability.
docs/architecture.md now reads correctly for this point in the stack, so the doc line I held on is genuinely fixed.
One thing to sort before this is marked ready: CI has never run on this head. The only check present on b843952 is the Read the Docs build. The last real run was on the pre-restack sha 195678b5, and it failed the xtask architecture_doc gate on exactly the wording I'd complained about — six not-yet-existing .rs files. That failure is moot now, but the gate has never been exercised against the corrected text, so we have no signal that it passes.
Two related notes:
- The branch is 1 ahead / 5 behind
main. - The standing
CHANGES_REQUESTEDfrom the automated reviewer is pinned to195678b5and no longer reflects this head — I don't think it should be read as live.
A rebase onto main and a re-push would get CI onto the real head. Worth doing here first rather than downstream: #480, #481 and #483 all stack on this one and inherit the same gap.
Leaving this as a comment rather than a block — there's no code defect here, just a missing signal.
Second PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the helpers shared across >=2 of the still-inline sandbox/mcp/service/ watchers clusters into their own module, ahead of extracting those clusters themselves. Covers GPU/amd-smi snapshotting, the bridge-snapshot diagnostic, CommandCapture/command-timeout plumbing, and small arg/healthcheck/endpoint-key utilities. No behavior change; call sites repointed to common::. The 8 tests that exercise these helpers directly (not mixed with a not-yet-extracted cluster's own logic) moved into common.rs's own #[cfg(test)] mod in this same PR. Review fixup: four helpers with exactly one caller (parse_gpu_indices_arg, optional_arg, engine_healthcheck_ready, print_bridge_snapshot) moved back to lib.rs next to their callers, since they didn't meet the module's own >=2-cluster admission rule. run_rocm_capture/run_rocm_capture_for_paths, genuinely shared by the sandbox and MCP clusters, moved into common.rs to match it. docs/architecture.md now states the admission rule explicitly. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
b843952 to
b7f2199
Compare
|
Fixed the branch mismatch flagged above: the round-2 fix (previously Rebased that fix onto current Re-verified on the rebased tree: |
|
Round 3 is in the review report above (#479 (comment)), updated in place. The PR head has moved to |
r0x0r
left a comment
There was a problem hiding this comment.
Approving — the extraction holds up as pure code motion
I verified this mechanically rather than reading the diff by eye, because "pure code motion" is exactly the claim that's easy to assert and hard to eyeball across 700 moved lines. What I checked:
- Every moved item is byte-identical to its pre-move body, apart from the three expected deltas:
fn→pub(crate) fn,persistence::→crate::persistence::, androcm_core::daemon_binary_path()→daemon_binary_path()(now covered by the import). - Nothing was lost and nothing was duplicated. The item set before the change equals the item set after across
lib.rs+common.rs, with an empty intersection between the two files — so a mis-repointed call site couldn't have silently resolved to a leftover copy; it would have been a compile error. - All 16 touched functions in
lib.rsdiffer only bycommon::qualification on the call sites. - All 8 moved tests have identical bodies (one drops a now-redundant
super::), and the count reconciles: 127 → 119 + 8. - No silent name re-resolution is possible here. There are no glob imports anywhere in
apps/rocmd/src, andcommon.rs's trait-import set is a strict subset oflib.rs's — a subset can only lose a candidate, which is a compile error, never a quiet change of which method wins.cfg(test)gating survived intact on all four sites, and no moved item carries a platform cfg.
A couple of things I went looking for and that did not hold up as problems: gather_gpu_snapshot ends up pub(crate) with no callers outside common.rs, but it had exactly one caller before the move too (its own sibling), so no call site was dropped — it's just wider than it needs to be. And the failing E2E tests (MI300X) lane is vLLM Engine core initialization failed on the GPU host, which this change can't reach.
One non-blocking note, left inline
The admission rule the doc hunk adds is contradicted by two helpers in the module it describes. Not worth holding the merge over, but worth a follow-up so the next cluster PR isn't working from a rule the tree already disagrees with.
This reflects a read of the diff and the surrounding code, not a runtime check — the E2E lane above is still worth a re-run before merge.
Review fixup: run_rocm_capture, wait_for_port, healthcheck_response_ready and healthcheck_response_recoverable each have exactly one still-inline caller cluster (MCP for the first, the recovery/watcher pipeline for the rest), so none meet common.rs's own >=2-cluster admission rule. Moved back to lib.rs next to their callers, matching the round-2 precedent for parse_gpu_indices_arg/optional_arg/engine_healthcheck_ready/ print_bridge_snapshot. Their tests moved along with them. As a side effect, run_rocm_capture_for_paths is now called directly by both the sandbox cluster (run_sandbox_tool) and the MCP cluster (run_rocm_capture), so the commit message's "genuinely shared by the sandbox and MCP clusters" claim is now accurate. gather_gpu_snapshot, run_command_with_timeout and engine_request dropped pub(crate): nothing outside common.rs calls them, same as before the move. find_engine_plugin_binary moved inside its own #[cfg(test)] mod, since only a test in that module calls it. docs/architecture.md: clarified that a helper also qualifies for common.rs when it's reached by a second cluster transitively through another common.rs helper that itself has direct >=2-cluster usage (covers bridge_engine_inventory via build_bridge_snapshot and apply_endpoint_key_env via engine_request). Signed-off-by: Jussi Elo <jussi.elo@amd.com>
|
Addressed in e403350:
Not changing: the
|
parse_gpu_indices_arg and optional_arg were moved back to lib.rs in the "Review fixup" of 1845df3 (common.rs's own extraction PR, #479) since they didn't meet the module's >=2-caller admission rule, but the doc's "small arg/healthcheck/endpoint-key utilities" wording wasn't updated to match. Drop "arg/" — common.rs has no arg-parsing helpers; the healthcheck/endpoint-key claims are accurate. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
…ions common.rs already landed on main via ROCm#479. Rebasing this stack onto current main surfaces that ROCm#479's own review fixup deliberately kept print_bridge_snapshot, parse_gpu_indices_arg, and engine_healthcheck_ready in lib.rs rather than common.rs, per the admission rule docs/architecture.md states: a helper earns a place in common.rs only once a second still-inline cluster calls it directly, otherwise it stays with its one caller. Grepping call sites on this branch confirms that rule still applies: print_bridge_snapshot has one caller (cli.rs, once extracted), parse_gpu_indices_arg and engine_healthcheck_ready each have one caller (service.rs), so none of the three move here. optional_arg is the one exception --- called from both service.rs and watchers.rs --- so it is the only addition common.rs needs from this branch's original (pre-ROCm#479) common.rs commit. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
Fourth PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the Cli/Command clap definitions, SandboxToolArg/SandboxToolPolicy, and the top-level dispatch (run_cli/run_bin_cli/run_from_args) into their own module, following the mechanical-relocation pattern (thin dispatch; call sites into not-yet-extracted clusters stay crate::- qualified until those land). lib.rs re-exports run_bin_cli/ run_from_args via pub use so the crate's only two external call sites are untouched. No behavior change. SandboxToolArg/SandboxToolPolicy are consumed pervasively by the still-inline sandbox.rs cluster (and its test suite), so every one of those ~89 call sites is repointed to cli::SandboxToolArg/cli::SandboxToolPolicy. The 4 tests that exercise Cli/Command parsing directly (not mixed with sandbox/mcp/webhook/service domain logic that happens to share a name prefix or construct these types as a parameter) moved into cli.rs's own #[cfg(test)] mod in this same PR. Rebase note (main now at f9a8011): print_bridge_snapshot also moves here. It was never actually in common.rs on main -- ROCm#479's own review fixup kept it in lib.rs (single caller, per the admission rule this stack's architecture.md entry states), and cli.rs is that one caller. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
Sixth PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the MCP stdio server, tool schema table, tool dispatch, and the rocm-subprocess capture/argv-building helpers behind the MCP tools into their own module. No behavior change. `CommandCapture` and `run_command_with_timeout` were independently claimed by this PR and by the already-landed common.rs extraction (both authored against the pre-stack monolith, unaware of each other); common.rs keeps ownership since it landed first in the merge order, so mcp.rs now imports both from `crate::common` instead of redefining them. The other crate-root reach-backs this module needed (`build_bridge_snapshot`, `gather_gpu_snapshot_for_config`, `bridge_engine_inventory`, `load_managed_services`) are now reached via `crate::common`/ `crate::persistence`, since those modules landed earlier in this stack; `stop_managed_service` stays reached via bare `crate::` since it has not moved out of lib.rs yet. `cli.rs`'s MCP dispatch arms and sandbox.rs's `run_rocm_capture_for_paths` import (both landed before this PR, so both still reached into lib.rs directly) are repointed to `crate::mcp::`. 15 tests that exercise this module's own logic (MCP tool-schema/ dispatch shape, read-only-verb classification, install_sdk/ install_engine/launch_server/watcher_enable argv building, and read_tail_lines) moved into mcp.rs's own #[cfg(test)] mod in this same PR, reusing `crate::test_support::workspace_test_artifact_dir` instead of a second local copy. Tests that share a name prefix or construct these types but actually exercise Cli parsing, run_daemon, or watcher-domain logic stayed in lib.rs for their own later PRs. Rebase note (main now at f9a8011): main gained a test since this commit was authored (install_sdk_rejects_system_prefix_reached_by_escaping_home, ROCm#491) that belongs here by the same rule as this commit's other ~15 -- moved into mcp.rs's own test module alongside its sibling install_sdk_rejects_system_prefix_without_ack. Also: run_rocm_capture/run_rocm_capture_for_paths were independently duplicated into this commit's own mcp.rs (same pre-stack-aware-of-each- other story as the CommandCapture/run_command_with_timeout duplication already called out above) and into common.rs via ROCm#479. common.rs keeps ownership since it landed first; mcp.rs's ten call sites now go through common::run_rocm_capture instead of a local redefinition, and sandbox.rs's now-stale `use crate::mcp::run_rocm_capture_for_paths` (from when mcp.rs was this function's owner, pre-ROCm#479) is dropped in favor of its existing common::-qualified calls. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
Second PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the helpers shared across >=2 of the still-inline sandbox/mcp/service/ watchers clusters into their own module, ahead of extracting those clusters themselves. Covers GPU/amd-smi snapshotting, the bridge-snapshot diagnostic, CommandCapture/command-timeout plumbing, and small arg/healthcheck/endpoint-key utilities. No behavior change; call sites repointed to common::. The 8 tests that exercise these helpers directly (not mixed with a not-yet-extracted cluster's own logic) moved into common.rs's own #[cfg(test)] mod in this same PR. Review fixup: four helpers with exactly one caller (parse_gpu_indices_arg, optional_arg, engine_healthcheck_ready, print_bridge_snapshot) moved back to lib.rs next to their callers, since they didn't meet the module's own >=2-cluster admission rule. run_rocm_capture/run_rocm_capture_for_paths, genuinely shared by the sandbox and MCP clusters, moved into common.rs to match it. docs/architecture.md now states the admission rule explicitly. Signed-off-by: Jussi Elo <jussi.elo@amd.com> Signed-off-by: Juho Vainio <juho.vainio@amd.com>
docs/architecture.md's backtick-quoted path citations (e.g. `main.rs`) are now explicit relative markdown links, checked by the lychee gate added in ROCm#579 instead of xtask/src/architecture_doc.rs's hand-rolled parser. That parser existed to disambiguate a bare citation against the repo's 17 files named main.rs/lib.rs; a link carries its own full path, so there's nothing left to disambiguate. Deletes the ~1,500-line parser along with the heuristics it kept growing (possessive-owner chains, sentence-boundary detection, an abbreviation list, a prose-slash-word list) and its CI job/prek hook — the root cause behind ROCm#492, ROCm#440, and ROCm#524. Drops a stale "arg/" from apps/rocmd's common.rs entry as a drive-by: parse_gpu_indices_arg/optional_arg moved back to lib.rs in ROCm#479's review fixup and the doc wording was never updated. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
docs/architecture.md's backtick-quoted path citations (e.g. `main.rs`) are now explicit relative markdown links, checked by the lychee gate added in ROCm#579 instead of xtask/src/architecture_doc.rs's hand-rolled parser. That parser existed to disambiguate a bare citation against the repo's 17 files named main.rs/lib.rs; a link carries its own full path, so there's nothing left to disambiguate. Deletes the ~1,500-line parser along with the heuristics it kept growing (possessive-owner chains, sentence-boundary detection, an abbreviation list, a prose-slash-word list) and its CI job/prek hook — the root cause behind ROCm#492, ROCm#440, and ROCm#524. Drops a stale "arg/" from apps/rocmd's common.rs entry as a drive-by: parse_gpu_indices_arg/optional_arg moved back to lib.rs in ROCm#479's review fixup and the doc wording was never updated. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
Sixth PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the MCP stdio server, tool schema table, tool dispatch, and the rocm-subprocess capture/argv-building helpers behind the MCP tools into their own module. No behavior change. `CommandCapture` and `run_command_with_timeout` were independently claimed by this PR and by the already-landed common.rs extraction (both authored against the pre-stack monolith, unaware of each other); common.rs keeps ownership since it landed first in the merge order, so mcp.rs now imports both from `crate::common` instead of redefining them. The other crate-root reach-backs this module needed (`build_bridge_snapshot`, `gather_gpu_snapshot_for_config`, `bridge_engine_inventory`, `load_managed_services`) are now reached via `crate::common`/ `crate::persistence`, since those modules landed earlier in this stack; `stop_managed_service` stays reached via bare `crate::` since it has not moved out of lib.rs yet. `cli.rs`'s MCP dispatch arms and sandbox.rs's `run_rocm_capture_for_paths` import (both landed before this PR, so both still reached into lib.rs directly) are repointed to `crate::mcp::`. 15 tests that exercise this module's own logic (MCP tool-schema/ dispatch shape, read-only-verb classification, install_sdk/ install_engine/launch_server/watcher_enable argv building, and read_tail_lines) moved into mcp.rs's own #[cfg(test)] mod in this same PR, reusing `crate::test_support::workspace_test_artifact_dir` instead of a second local copy. Tests that share a name prefix or construct these types but actually exercise Cli parsing, run_daemon, or watcher-domain logic stayed in lib.rs for their own later PRs. Rebase note (main now at f9a8011): main gained a test since this commit was authored (install_sdk_rejects_system_prefix_reached_by_escaping_home, moved into mcp.rs's own test module alongside its sibling install_sdk_rejects_system_prefix_without_ack. Also: run_rocm_capture/run_rocm_capture_for_paths were independently duplicated into this commit's own mcp.rs (same pre-stack-aware-of-each- other story as the CommandCapture/run_command_with_timeout duplication already called out above) and into common.rs via ROCm#479. common.rs keeps ownership since it landed first; mcp.rs's ten call sites now go through common::run_rocm_capture instead of a local redefinition, and sandbox.rs's now-stale `use crate::mcp::run_rocm_capture_for_paths` (from when mcp.rs was this function's owner, pre-ROCm#479) is dropped in favor of its existing common::-qualified calls. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
docs/architecture.md's backtick-quoted path citations (e.g. `main.rs`) are now explicit relative markdown links, checked by the lychee gate added in ROCm#579 instead of xtask/src/architecture_doc.rs's hand-rolled parser. That parser existed to disambiguate a bare citation against the repo's 17 files named main.rs/lib.rs; a link carries its own full path, so there's nothing left to disambiguate. Deletes the ~1,500-line parser along with the heuristics it kept growing (possessive-owner chains, sentence-boundary detection, an abbreviation list, a prose-slash-word list) and its CI job/prek hook — the root cause behind ROCm#492, ROCm#440, and ROCm#524. Drops a stale "arg/" from apps/rocmd's common.rs entry as a drive-by: parse_gpu_indices_arg/optional_arg moved back to lib.rs in ROCm#479's review fixup and the doc wording was never updated. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
…d/src/lib.rs (ROCm#487) * ROCMAI-83: extract mcp.rs from apps/rocmd/src/lib.rs Sixth PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the MCP stdio server, tool schema table, tool dispatch, and the rocm-subprocess capture/argv-building helpers behind the MCP tools into their own module. No behavior change. `CommandCapture` and `run_command_with_timeout` were independently claimed by this PR and by the already-landed common.rs extraction (both authored against the pre-stack monolith, unaware of each other); common.rs keeps ownership since it landed first in the merge order, so mcp.rs now imports both from `crate::common` instead of redefining them. The other crate-root reach-backs this module needed (`build_bridge_snapshot`, `gather_gpu_snapshot_for_config`, `bridge_engine_inventory`, `load_managed_services`) are now reached via `crate::common`/ `crate::persistence`, since those modules landed earlier in this stack; `stop_managed_service` stays reached via bare `crate::` since it has not moved out of lib.rs yet. `cli.rs`'s MCP dispatch arms and sandbox.rs's `run_rocm_capture_for_paths` import (both landed before this PR, so both still reached into lib.rs directly) are repointed to `crate::mcp::`. 15 tests that exercise this module's own logic (MCP tool-schema/ dispatch shape, read-only-verb classification, install_sdk/ install_engine/launch_server/watcher_enable argv building, and read_tail_lines) moved into mcp.rs's own #[cfg(test)] mod in this same PR, reusing `crate::test_support::workspace_test_artifact_dir` instead of a second local copy. Tests that share a name prefix or construct these types but actually exercise Cli parsing, run_daemon, or watcher-domain logic stayed in lib.rs for their own later PRs. Rebase note (main now at f9a8011): main gained a test since this commit was authored (install_sdk_rejects_system_prefix_reached_by_escaping_home, moved into mcp.rs's own test module alongside its sibling install_sdk_rejects_system_prefix_without_ack. Also: run_rocm_capture/run_rocm_capture_for_paths were independently duplicated into this commit's own mcp.rs (same pre-stack-aware-of-each- other story as the CommandCapture/run_command_with_timeout duplication already called out above) and into common.rs via ROCm#479. common.rs keeps ownership since it landed first; mcp.rs's ten call sites now go through common::run_rocm_capture instead of a local redefinition, and sandbox.rs's now-stale `use crate::mcp::run_rocm_capture_for_paths` (from when mcp.rs was this function's owner, pre-ROCm#479) is dropped in favor of its existing common::-qualified calls. Signed-off-by: Jussi Elo <jussi.elo@amd.com> * ROCMAI-83: extract service.rs from apps/rocmd/src/lib.rs Seventh PR of Phase 5 (rocmd modularization, ROCMAI-27): pull the managed-service PID lifecycle (stop/terminate/descendant-pid discovery), run_daemon's foreground loop, supervise_service's spawn-and-recover path, and serve-log startup-phase polling into their own module. Non-contiguous in the source (the startup-phase/ shutdown-signal helpers sit far from the rest, separated by the whole test block) -- both halves moved in this PR. No behavior change. Reaches back into still-crate-root items (load_managed_services, record_event, start_local_webhook_source, receive_local_webhook_event, evaluate_watchers/evaluate_watchers_for_ events/reconcile_watcher_snapshots, WATCHER_TICK_INTERVAL, parse_gpu_indices_arg/optional_arg/ensure_public_service_has_endpoint_ key/apply_endpoint_key_env/engine_healthcheck_ready, load_service_record) via crate::, since the modules that will eventually own those (persistence.rs/webhook.rs/watchers.rs/ common.rs) are separate, independent PRs not present on this branch. 13 tests that exercise this module's own logic (the supervise key-guard regression tests, run_daemon's automation-loop gate, stop_managed_service, descendant-pid discovery, startup-phase log parsing, engine_serve_http_args) moved into service.rs's own sandbox/mcp-domain tests that construct ManagedServiceRecord or call stop_managed_service merely as setup stayed in lib.rs for watchers.rs/other PRs. Stacked on rocmai-83-mcp (ROCMAI-83 Phase 5 batch, AGENTS.md §11): rebased service.rs's crate:: reaches onto the sibling modules already landed by the predecessor PRs (persistence.rs, common.rs, webhook.rs), leaving only the references still owned by lib.rs (evaluate_watchers*, reconcile_watcher_snapshots, WATCHER_TICK_INTERVAL, load_service_record) until watchers.rs lands. Deduped the test-only temp_app_paths/ unique_test_root helpers in favor of the shared crate::test_support module, and repointed cli.rs/mcp.rs/sandbox.rs's stale crate::-root calls to service::stop_managed_service/run_daemon/supervise_service/ print_status now that this module owns them. Rebase note (main now at f9a8011): parse_gpu_indices_arg and engine_healthcheck_ready move here too, not to common.rs. Per this stack's admission rule (a helper earns common.rs only once a second still-inline cluster calls it directly), both have exactly one caller and it is this module (service.rs:... supervise_service, wait_for_service_ready), so common.rs is the wrong home for them even though an earlier draft of this stack put them there. Signed-off-by: Jussi Elo <jussi.elo@amd.com> * ROCMAI-83: extract watchers.rs from apps/rocmd/src/lib.rs Eighth and final PR of Phase 5 (rocmd modularization, ROCMAI-27): pull event collection/dispatch for all built-in watchers (TheRock update, GPU metrics/thermal-pressure, cache-warm, driver-upgrade, server-recover), managed-service recovery classification, and automation-proposal queuing into their own module. Non-contiguous in the source: most of the cluster is one block, but queue_proposal/queue_proposal_with_arguments/proposal_tool_for_action/ proposal_arguments_for_action sit sandwiched between record_event and load_managed_services (persistence.rs territory, stays in lib.rs on this branch), and detached_rocmd_command sits at the tail of the file right before the test module. All three sub-blocks moved in this PR. Watcher-only consts (SERVER_RECOVER_BACKOFF_MS, SERVER_TRANSIENT_STALE_MS, ENDPOINT_HEALTH_TIMEOUT, THEROCK_UPDATE_INTERVAL_MS, GPU_METRICS_INTERVAL_MS, and the GPU thermal/VRAM pressure thresholds) moved with it, since nothing else in lib.rs used them. No behavior change. Reaches back into items owned by sibling modules (record_event/load_managed_services via crate::persistence, run_sandbox_tool/SandboxToolArg/SandboxToolPolicy via crate::sandbox/crate::cli, update_check_message/ record_notification_audit via crate::sandbox, and the engine-healthcheck/endpoint-key/wait_for_port/optional_arg/ gather_gpu_snapshot_for_config family via crate::common) and one webhook-domain type (LocalWebhookEventRequest/ local_webhook_event_from_request via crate::webhook). 34 tests that exercise this module's own logic (event-collector/gpu/ cache-warm/driver-upgrade/server-recover dispatch, therock-update handling, watcher-policy mode mapping, recovery-reason classification) moved into watchers.rs's own #[cfg(test)] mod in this same PR. Tests that are fundamentally about Cli parsing, run_daemon, sandbox-tool dispatch shape, or the persistence-layer record_event itself stayed in lib.rs for their own PRs. This completes Phase 5 of the rocm-cli modularization effort (ROCMAI-27): lib.rs is now top-level glue -- module declarations and the two externally-consumed entry points re-exported from cli.rs. Stacked on rocmai-83-service (ROCMAI-83 Phase 5 batch, AGENTS.md §11): rebased watchers.rs's crate:: reaches onto all seven sibling modules now landed by the predecessor PRs (persistence.rs, common.rs, webhook.rs, cli.rs, sandbox.rs, mcp.rs, service.rs) -- this is the last PR in the stack, so no reach-back is left unresolved. Repointed service.rs's stale crate::-root calls (evaluate_watchers, evaluate_watchers_for_events, reconcile_watcher_snapshots, load_service_record) and webhook.rs's stale crate::payload_string call to watchers::, now that this module owns them; fixed sandbox.rs's `use crate::{ARTIFACT_PREFETCH_TIMEOUT, restart_managed_service}` to import restart_managed_service from crate::watchers instead. Deduped the test-only temp_app_paths/unique_test_root/workspace_test_artifact_dir trio in watchers.rs's test module in favor of the shared crate::test_support module. Updated docs/architecture.md: all eight `apps/rocmd` modules are now listed as extracted, with no "still pending" clause remaining. Signed-off-by: Jussi Elo <jussi.elo@amd.com> --------- Signed-off-by: Jussi Elo <jussi.elo@amd.com>

Summary
Second, third, and fourth PRs of Phase 5 (ROCMAI-83, part of the modularization epic ROCMAI-27), consolidated into one PR. Pulls
common.rs,webhook.rs, andcli.rsout ofapps/rocmd/src/lib.rs. These three were originally opened separately as #479/#480/#481; consolidated here to cut down the PR count for this phase, since all three are either genuinely standalone utility code or thin mechanical dispatch with no domain-logic interdependencies worth reviewing apart.common.rs — helper groups shared across ≥2 of the still-inline
sandbox/mcp/service/watchersclusters:gather_gpu_snapshot*,capture_amd_smi_json,run_command_with_timeout) — used by sandbox, mcp, and watchersbuild_bridge_snapshot/print_bridge_snapshot/bridge_engine_inventory/rocmd_engine_inventory) — used by the CLI'sBridgeSnapshotcommand and the MCP dispatcherCommandCapture+ its construction plumbing — constructed in both sandbox and MCP codeoptional_arg,wait_for_port,parse_gpu_indices_arg, and the engine-healthcheck/endpoint-key-guard family — used by bothserviceandwatchersThis module wasn't in the original ticket (which only named
persistence.rs) — these cross-cutting dependencies surfaced during boundary verification against currentmain. Addingcommon.rskeeps each later cluster PR from having to reach across into a sibling cluster file.webhook.rs — the local webhook source: axum routes, request validation, watcher-kind allow-list. Fully self-contained except one call into
payload_string, which stays at the crate root untilwatchers.rsis extracted (#487) and will need to re-point that one call site.cli.rs — the
Cli/Commandclap definitions,SandboxToolArg/SandboxToolPolicy, and the top-level dispatch (run_cli/run_bin_cli/run_from_args). Follows the mechanical-relocation pattern (perdocs/architecture.md's convention) rather than full domain extraction:run_cliis thin dispatch, and its match arms call into clusters that haven't been extracted yet (sandbox,mcp,service,watchers) viacrate::-qualified paths, updated as each lands in #483/#487.lib.rsre-exportsrun_bin_cli/run_from_argsviapub use cli::{...};— the crate's only two externally-consumed symbols are untouched.SandboxToolArg/SandboxToolPolicyare consumed pervasively by the still-inlinesandbox.rscluster and its test suite — all call sites repointed tocli::SandboxToolArg/cli::SandboxToolPolicy.common::.../webhook::.../cli::....#[cfg(test)] modin this same PR.docs/architecture.mdupdated in this PR.Targets
maindirectly (not stacked on a sibling PR branch) so this PR can't be silently auto-closed if an intermediate branch gets deleted — the merge order relative to #483 and #487 is documented, not structural.Supersedes #480 and #481, which are closed in favor of this PR.
Test plan
cargo build(rocmd, androcm+rocmdtogether to confirm the external API surface is untouched)cargo clippy --workspace --all-targets -- -D warningscargo test -p rocmd— 130 tests, same count as before this change (129 passed + 1 pre-existing ignored)cargo xtask manifest --checkcargo fmt/ prek hooks cleantests/e2e-cucumber(CI)