Recipes

hmc_prepare_host_handoff: host-handoff tool with a kdive hold contract

Discovered from README cross-links · today

Security, Science & HardwareSoftware & DevOps

Adds a read-only host-handoff tool that places a hold before kdive takes over.

What they did

The author implemented ADR 0193's host-handoff tool, `hmc_prepare_host_handoff`, on top of the hold store added in #1851, and wrote the hold contract into the kdive Tier A contract. The `prepare` action resolves the partition, reads the handoff document, then places a hold (`hold=true` with a `consumer_label`) or reports an existing one, returning `{action, hold, document}`. `hold.hold_id` is returned only to the agent that placed the hold and never appears in the document; a repeat from the same agent and label returns the same hold, and `partition_guarded`/`partition_held` refusals pass through. Placement is the last step, so an earlier failure places nothing. The document carries `identity`, `references` (connection and agent id, no secrets), `observed` (state, RMC, resource figures, ADR 0011 ownership stamp, VIOS storage mappings, client network adapters), `declared` (the host's recorded provision request, including install profile, network, and for built media the login user and SHA-256 key fingerprints with that operation's state and outcome), `unverified` (OS, kernel, bootloader, kdump/fadump, SSH reachability, host identity, left to kdive's doctor/adopt), `unfenced`, and `unchecked_tools` computed from the served registry. Authorization per ADR 0329 requires policy to permit `hmc_get_lpar`, `hmc_list_lpar_ownership` and `hmc_get_vios_storage_detail`, admitting the first two for the partition; storage and adapter sections report `ok`, `unavailable` or `denied`. `release` needs only the tool's own grant, drops the hold by `hold_id` or from the placing agent, and returns a null document. Neither action writes to the HMC. Shared helpers were renamed (`_resources` to `read_resources`, `_admitter` to `admitter`), `store.ledger_request` became a read-only provision-record lookup, and registration touched `server.py`, `catalog.py`, the capability inventory, `operations.json`, `maturity.json` and its packaged projection, regenerated `docs/tools/`, and the tool-count and policy-inventory tests. Docs updated: ADR 0329, a design spec, a Holds section in `docs/kdive-tier-a-contract.md`, the H1 spec's handoff delegation row, `docs/mcp-server.md` and `CHANGELOG.md`.

How it went

Four test files cover placement, hold_id visibility, refusals, declared parsing, adapter sources, release paths, registration, denied sections, name-scoped grants, unchecked_tools, and hold coverage: after `prepare(hold=true)` through MCP, `hmc_power_lpar`, `hmc_reconfigure_lpar` and `hmc_decommission_lpar` refuse `partition_held` before any HMC write, pass with the `hold_id`, and pass after `release`; `prepare(hold=true)` refuses `partition_guarded` while a provision operation guards the partition. Locally at `d0b5ea33` the author ran `just static`, `just test-group` for all four groups, `just smoke`, `just build verify-artifacts`, and `uv run --no-sync prek run --all-files`. No live HMC run was done: `prepare` only reads, and no hardware claim is made.

Worth knowing

Everything is verified by unit and app tests only; there is no live HMC run, so real partition resolution, VIOS storage detail and adapter reads are unproven against hardware. `maturity.json` marks the tool implemented with no evidence. The hold contract only guards MCP power calls; library calls are explicitly not checked, so a caller bypassing MCP can act on a held partition. `unchecked_tools` is computed from the served registry, so it is only as complete as that registry. The change depends on the hold store from #1851 and on ADR 0329 policy grants being configured.

Wiring

The tool is registered in `server.py` and `catalog.py` (the primary-tool name now uses a constant), plus the capability inventory, `operations.json`, `maturity.json` (implemented, no evidence) and its packaged projection, with `docs/tools/` regenerated and tool-count and policy-inventory tests updated. It sits on the hold store from #1851. `prepare` first resolves the partition, then reads the handoff document, then places the hold as the final step. Authorization per ADR 0329 checks policy for `hmc_get_lpar`, `hmc_list_lpar_ownership` and `hmc_get_vios_storage_detail`, admitting the first two for the partition; the storage section calls `hmc_list_vios` then each VIOS's detail, and the adapters section calls `hmc_list_adapters` with the caller's selectors. `release` needs only the tool's own grant. Shared helpers were renamed: `operations/lpar/inspect.py`'s `_resources` to `read_resources` and `server_tools/lpar/inspect.py`'s `_admitter` to `admitter`; `store.ledger_request` is a read-only lookup of the provision record naming a partition. The kdive Tier A contract gains a Holds section: MCP power calls on a held partition need `hold_id`, library calls are not checked, and the named power tools are `hold_guarded`.

Try it yourself

Add a read-only host-handoff tool to this MCP server, following the pattern of the existing hold store. Implement `hmc_prepare_host_handoff` with two actions: `prepare` resolves the partition, reads a handoff document, then places a hold (`hold=true` plus a `consumer_label`) or reports an existing one, returning `{action, hold, document}`; `release` drops the hold by `hold_id` or from the placing agent and returns a null document. Return `hold.hold_id` only to the agent that placed the hold, never inside the document. Make placement the last step so earlier failures place nothing, and pass through `partition_guarded` and `partition_held` refusals. Build the document from `identity`, `references` (connection and agent id, no secrets), `observed` (state, RMC, resource figures, ownership stamp, VIOS storage mappings, client network adapters), `declared` (the recorded provision request with its state and outcome), `unverified` (OS, kernel, bootloader, kdump/fadump, SSH reachability, host identity), `unfenced`, and `unchecked_tools` computed from the served registry. Gate `prepare` on policy permitting `hmc_get_lpar`, `hmc_list_lpar_ownership` and `hmc_get_vios_storage_detail`, and report storage and adapter sections as `ok`, `unavailable` or `denied`. Neither action may write to the HMC. Register the tool in `server.py`, `catalog.py`, the capability inventory, `operations.json` and `maturity.json`, regenerate `docs/tools/`, and add tests for placement, hold_id visibility, refusals, declared parsing, release paths, registration, denied sections, and hold coverage of the power tools.

Source

Tools in this stack