Skip to content

nvx-rs: delete NVXC v1 and FEATURES (SL4.4d) - #1545

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
feature/nvx-refactorfrom
agents/slim-sl4-4d-nvxc-v1-gone
Nov 12, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
feature/nvx-refactorfrom
agents/slim-sl4-4d-nvxc-v1-gone

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Leaving code only. This PR changes only code that this effort removes from NVX: NVXC v1's frames, FEATURES and GuestFeatures, with the fake OpenVMM's v1 handler, with the edits that remove references to them. Nothing that stays changes, and no later PR uses what it changes, so the size limits for kept code don't apply.

Part of #1129 (SL4.4d, "NVXC v1 and FEATURES are gone"). Parent #1089, umbrella #1076.

It needed SL4.4c (#1541), which has merged: it starts from 5715bb6d709, the tip after it. The restack also took in the guest chain (SL6.11b, SL6.11d and SL6.13b), which deleted the managed agent's sandbox mode, so this PR's edits of the agent now apply to its direct mode alone, and one test that the chain added moves to v2 (see Changes to existing tests).

What and why

Since SL4.4c, every NVX control path speaks NVXC v2, so v1's frames, its FEATURES request and GuestFeatures were compatibility code that only the guest agents and the fake OpenVMM still served, some of it under dead-code markers that SL4.4c left for this PR. As SL4.4d's Scope says, this PR deletes them, and v2 is NVXC's only version.

The protocol. protocol/app.rs loses v1's APP_MAGIC and APP_VERSION, APP_FEATURES, v1's codec (encode_app and decode_app) and ExitCategory, with SL4.4c's expect(dead_code) on ExitCategory::parse; protocol/exec.rs loses MAX_OUTPUT_BYTES, the 1 MiB output cap that only v1 applied; and protocol/features.rs, with GuestFeatures, its constants and SL4.4c's module-level allow, is deleted. The kind codes, AppFrame, APP_HEADER_LEN and the error categories that v2 shares with v1 stay: the guest loop and the fake still translate each v2 request into them, as SL4.4b made them do. Their gates narrow to the builds that still use them (AppFrame and APP_EXIT to the guest's).

The guest loop that nvx-init and the managed agent share (guest/managed_agent/session.rs, exec.rs and dispatch.rs) decodes v2 alone. A frame of another version fails to decode, as a malformed v2 frame does, so the session ends with the data-application diagnostic. The session's per-request version (v2, v2() and answer_in) goes, with v1's encoding of answers and a joined activation's READY in v1; the dispatch's FEATURES handler goes; an execution loses v1's output cap (output_bytes, output_limited and the output-limit ending) and v1's null standard input; and STOP during an execution no longer checks the version. The discard of an execution's output, which only the cap used, goes with Workload::discard, and then with nvx-init's Exec::discard (guest/init.rs), which the compiler flags as unused once its last caller goes.

The fake OpenVMM (testing/fake_openvmm.rs) serves v2 alone, as the flagged section below explains.

The public error code ErrorCode::GuestFeaturesMissing, which nothing reports since SL4.4c stopped asking for features, goes in the second commit: it is FEATURES handling, so this public-API removal stays inside leaving code. The public-API snapshots lose the variant, doc/usage.md's and the README's tables of codes lose its row, and ErrorKind::Unavailable's docs stop naming control features.

Docs. nvx-rs/README.md (the layout, nvx::protocol, "Guest protocol", the fake's tokens, the tests and the codes), doc/design/4.4-host-guest-control-interface.md (v1, FEATURES and the output limit go, with Table 4.5; 4.4.2 to 4.4.4 describe v2 alone; and Table 4.2's shutdown ends a running execution first, where v1 shut down only between executions), doc/guest-agent-guidelines.md (below), doc/design/4.3-isolation-and-resource-model.md, nvx-rs/tests/vectors/README.md, doc/usage.md and the case matrix (vm-lifecycle's row) follow.

The guest-agent guidelines (doc/guest-agent-guidelines.md, from SL7.9) said four things of nvx-init's executions that held only for v1; SL6.10c's review found the first two:

  • An execution's standard input is a pipe of the input that the host streams, which nvx-init closes after the input's end, not the null device.
  • None of the output of an execution that a session reset abandons reaches the new session, where they said that nvx-init discards it: nvx-init reads no more of it, and what it had already queued goes out before the reset's acknowledgement, in the earlier epoch, whose records OpenVMM's broker drops while it awaits that acknowledgement.
  • A shutdown while an execution runs kills its process group too, as a cancellation does, where v1 refused it.
  • A capture that nvx-init refuses while another process runs is refused as busy, a BUSY frame, where they said "with EBUSY", a status that BUSY doesn't carry.

Not in this PR, as the Scope says: changes to v2's framing, streaming, capture or restore, negotiation or a v1 fallback, cleanups of v2 code that stays, and unrelated guest, host or fake code. BOOT_CONTRACT_VERSION, CONTROL_CONTRACT_REVISION and their generated copies stay unchanged.

Done when

  • No NVXC v1, FEATURES or GuestFeatures code or caller remains. What still says FEATURES in nvx-rs/ is v2's docs and tests of its refusal, the CPUID leaves of the time code, and the vectors below.
  • The guest agents and the fake serve v2 alone, and a v1 peer is refused. New tests show it: guest::managed_agent::dispatch::tests::streams::a_request_of_version_1_ends_the_session (the agent ends the session of v1's PING vector, with the data-application diagnostic and EPROTO) and testing::fake_openvmm::tests::version_1_requests_end_the_session (the fake closes the connection after v1's PING, and after v1's FEATURES in a v2 frame). SL4.4b's version_2_has_no_features_request shows the agent's refusal of the latter, SL4.4c's ready_must_carry_the_protocol_version the host's refusal of another version, and SL4.4a's protocol::app::v2::tests::malformed_frames_are_refused the codec's refusal of v1's frames.
  • The fake-backed CLI tests pass through v2 without feature advertisement. The fake now ends the session of a FEATURES request, so each of them would fail if a host path sent one: tests/cli.rs passes 113 tests on Windows and 123 on Linux, with the rest of the CLI's tests.
  • Capture and restore pass with v1 gone, including an exec on the returned live session: the restore driver's a_lost_session_is_replaced_with_the_same_activate_message_and_the_live_session_returns, the CLI's restore tests (host::cli::sandbox::lifecycle::start::tests::restore, whose named and one-off restores run their workloads on the session that the restore returns), the guest's restored_ready_maps_and_first_exec_share_the_existing_start_transition, and every snapshot and restore scenario on MSHV, with snapshot-core and snapshot-tiers on WHP: their snapshot restore … --entrypoint and run --restore-snapshot run the workload on that session, then sandbox exec runs more.

Judgment calls

  • v1's vocabulary that v2 shares stays. v2 keeps v1's header and kind codes, and the guest loop and the fake name v2's requests with AppFrame and the APP_* kinds, so only v1's own items go; renaming that vocabulary would rewrite v2 code that stays.
  • The dispatch's payload checks stay. PING with a payload (the ping-payload diagnostic), STOP with one, and CANCEL's check are the dispatch's own validation of requests that stay, rather than v1 serving paths, so they stay byte for byte, as the Approach asks, though only v1 could reach them: v2's decoder refuses those payloads first. No test reached ping-payload before either. I can delete them here if you see them as v1 code.
  • request.input = true replaces session.v2() in place, so launch::direct_request and its test keep their input: false; folding it in would rewrite v2 code that stays.
  • Exec::discard goes with the cap: Workload::discard, which only the cap called, was its last caller, and Clippy flags it once that goes.
  • tests/vectors/nvxc-v1.txt stays unchanged, since its README's rule is that a vector changes only with a protocol version. v2's tests read its PING frame as the refused v1 peer, its EXEC and MAPS payloads, which v2 carries unchanged, and its NVXS records; its frames and its features payloads have no codec any longer, as the vectors' README and the README now say.
  • live_restored_init_activation stays ignored. I moved it to v2's frames, with the rest of host::restore::tests::live_init, whose gate returns to cli now that it needs no v1 code; it compiles, and its other tests pass, but it needs SL7.7b's hand-made snapshot and named host admission, which no script provides, so it did not run; the restore scenarios cover its path.

The fake OpenVMM (flagged, as the Scope asks)

Production (testing/fake_openvmm.rs), all of it v1 or FEATURES handling:

  • Session::request decodes v2 alone: a frame of another version decodes to nothing, so the session ends, as a malformed record ends it. Request::App loses its version flag, Session its v2 state, and send its v1 encoding.
  • The FEATURES handler goes, with GUEST_FEATURES, the guest_features and legacy_guest options, and their fake_guest_features and fake_legacy_guest tokens, which only v1's FEATURES answer read. A FEATURES request, now a kind that v2 doesn't have, ends the session.
  • v1's output cap goes: forward, which counted output against MAX_OUTPUT_BYTES, gives way to send, and the output-limit ending with it. exit takes v2's Outcome in place of ExitCategory, through whose mapping each v2 ending already passed unchanged, so every EXIT that the fake sends keeps its bytes.
  • While a workload runs, STOP and CANCEL no longer check the version, a refusal no longer swaps the version of its answer, and a workload's standard input no longer ends at once, as v1's did.

Tests (testing/fake_openvmm/tests.rs): the_current_guest_advertises_every_required_feature retires with FEATURES, version_2_workloads_send_output_past_the_cap_of_version_1 loses its v1 half, and version_1_requests_end_the_session is new.

Size

Measured: 90 core lines by #1076's rule (95 counting gate-only lines), in 5 counted files (estimate 0 and 5; leaving code has no limit): testing/fake_openvmm.rs 39, guest/managed_agent/session.rs 36, guest/managed_agent/exec.rs 11, protocol/mod.rs 2 and guest/managed_agent/dispatch.rs 2. Each line is code around a deleted v1 branch, state or name that the deletion forces: v2 paths that lose their version check or nesting, send calls in place of forward, and import and re-export lists that lose the deleted names. protocol/app.rs only narrows the gates of what stays (3 lines, with protocol/mod.rs's 2 for APP_EXIT) and loses v1's items; error.rs, guest/init.rs and protocol/exec.rs only lose code; guest/managed_agent/mod.rs changes only docs; and protocol/features.rs is deleted; so they don't count, nor do tests, docs, the vectors' README, the case matrix, the allowlist and the snapshots. The estimate's 0 core lines counted the deletions only.

Validation

The gates that the orchestration checkout's local_gates.py --files selects for these files (the adapter gates don't exist on feature/nvx-refactor), run from this branch's own action definitions, with Rust 1.95.0. This head, 675b0d9b3fa, has the tree of 59dea76bbf0, the restack that I resolved and validated before SL4.4c merged, on SL4.4c's pre-merge head d66994591e9, whose commits merged unchanged. Before the restack, the same gates, the MSHV default suite and the WHP scenarios passed at e316b6386c5 through ff40a5c22d7, which differed among themselves only in docs.

Where Check Result
Windows (workstation), at 59dea76bbf0 cargo fmt --all --check; cargo clippy --locked … -- -D warnings in 22 configurations: on the host, --all-targets --all-features, --lib, --lib --no-default-features alone and with serde, --lib --bins with cli and with testing, and --all-targets with the defaults, cli, testing and no default features; for x86_64-unknown-linux-gnu, --all-targets with all features, the defaults, no default features, cli, testing, guest, guest,testing, cli,guest and cli,testing; for x86_64-unknown-linux-musl, --all-targets and --lib --bins with guest passed
Windows, at 59dea76bbf0 cargo test --locked: --all-features, the defaults, --lib --no-default-features, and --lib with cli alone and with testing alone; cargo build --lib --no-default-features; the ignored openvmm_vectors and openvmm_cpu_profiles tests; RUSTDOCFLAGS="-D warnings" cargo doc --all-features; cargo +1.89 check --all-targets --all-features; public_api.py; check_test_layout.py; check_markdown_links.py; the case-matrix check (check_matrix.py … 99d2022085f) passed, 0 failed: lib 1061 (18 ignored), tests/cli.rs 113 and the other targets; the defaults' lib 687; 191; 1038 and 221; 3 and 1; the snapshots match
Linux/MSHV (nvx-mshv-test, kernel 6.18), at 59dea76bbf0 fmt; Clippy with -D warnings in 12 configurations, check-nvx-rs's six (--all-targets --all-features, --lib, --lib --no-default-features alone and with serde, and --lib --bins with cli and with testing) and --all-targets with guest, guest,testing, cli,guest, cli,testing, testing and cli; cargo test with --all-features, the defaults, and --lib without default features, with guest, with testing and with cli; cargo build --lib --no-default-features; doc; MSRV; the aarch64-apple-darwin check; public_api.py; check_test_layout.py; nvx.py check-guest-binaries --toolchain 1.95.0 (the musl Clippy and tests), build-guest-binaries and test-guest-binaries passed, 0 failed: lib 1764 (59 ignored), tests/cli.rs 123 and the other targets; the defaults' lib 682; 191; 855; 224; 1027; the musl lib 855; the guest binaries' 33
Linux/MSHV nvx.py test-microvm --backend mshv: the default suite, every scenario but smp-lapic, with 1, 2, 4 and 8 processors, and nvx-rs built from this head. Its Alpine initramfs, which holds the guest agents, came from nvx.py build-initramfs --guest alpine at this head (61a8f86e…), with CI run 43281528285's kernel and Ubuntu distro layer, from c0cf126efa2, whose kernel configuration this head keeps, and the scratch template and musl OpenVMM (14dc4116ec7, this base's pin) staged before, each checked by SHA-256 against its provenance, the layer's manifest, or the CI download passed: 58 runs, none skipped, with the public sandbox scenarios (sandbox-lifecycle's exec streamed all 2 MiB with an exit outcome), managed-lifecycle, vm-lifecycle, structured outcomes, workload identity, and every snapshot and restore scenario. A first attempt reused a release nvx-rs that an earlier run had built from older sources, whose snapshot capture has no --net, which untiered-network-policy caught; this run built it from this head
Windows/WHP (nvx-whp-test) nvx.py test-microvm --backend whp: the public sandbox and snapshot scenarios (sandbox-lifecycle, managed-exec-config, sandbox-proxy-only, sandbox-ram-upper, sandbox-gpt-layer, snapshot-core, snapshot-tiers and vm-lifecycle) and managed-lifecycle, with nvx-rs built from this head, that initramfs (copied from MSHV), the same kernel, distro layer and scratch template, and CI run 43185976865's Windows OpenVMM, whose provenance matches 43281528285's, each checked by SHA-256 on the host passed: 9 of 9; each restore ran its workload and its sandbox exec, and sandbox-lifecycle's exec streamed all 2 MiB

Not run: Linux/KVM, since one Linux backend runs the suite, and live_restored_init_activation (see the judgment calls). CI run 43292063425 ran the full matrix at this head and passed: 33 jobs, with the microVM shards, the guests and sandboxes, and the platform jobs on Linux/MSHV, Linux/KVM and Windows/WHP, and the debug kernel on MSHV. It skipped 9 jobs by design: publishing, performance records and the merge-group canceller, which only dev and merge groups run, OpenVMM's CI of the pinned revision, which this PR doesn't move, and the debug kernel on KVM and WHP.

A code-review subagent reviewed the whole diff; its one finding, that the README overstated what the vectors cover, is fixed.

Changes to existing tests

check_test_changes.py --base origin/feature/nvx-refactor lists 104 changes: 88 to test code and 16 to the fake OpenVMM, plus 6 additions. Each kept test checks what it checked, through v2, unless this list says otherwise.

  • Retired with v1 or FEATURES:
    • protocol::tests: frames_match_their_vectors (v1's codec), features_match_their_vectors, the_host_requires_every_feature, exit_categories_match_the_guest_agent (ExitCategory), guest_features_report_what_a_guest_lacks, guest_features_use_distinct_bits, feature_definitions_keep_their_wire_values (its pin of APP_MAPS moves to record_definitions_keep_their_wire_values), both_agent_modes_announce_the_host_mapping_table and layered_sandboxes_need_per_execution_environments_and_mapping_tables, with the helpers frame_kind and GuestFeatures' test impl (REQUIRED and contains), and the test hook of ExitCategory::parse.
    • guest::managed_agent::dispatch::tests: agent_advertises_the_control_features_of_its_mode_and_stops (FEATURES) and output_beyond_the_cap_ends_the_workload_after_the_reads_that_fit (v1's cap).
    • guest::managed_agent::session::tests::joined_activations_get_ready_in_their_own_versions, since a READY has one version now.
    • guest::managed_agent::tests::loopback::tests::output_limit_forwards_nothing_after_the_cap, with its helper run_exec_v1, which SL4.4c kept until this PR.
    • testing::fake_openvmm::tests::the_current_guest_advertises_every_required_feature.
    • tests/cli.rs's starts_ask_the_guest_for_no_features, which started guests that advertised no features (fake_guest_features=0) or refused the request (fake_legacy_guest=1): those tokens go with the fake's feature state, and every fake-backed CLI test now shows what it showed, since the fake ends the session of a FEATURES request.
  • Renamed, losing their v1 halves: agent_refuses_feature_payloads_and_unannounced_mapping_tables is agent_refuses_unannounced_mapping_tables, and version_2_serves_ping_and_the_mapping_table_beside_version_1 is version_2_serves_ping_and_the_mapping_table; version_2_workloads_send_output_past_the_cap_of_version_1 (the fake's) keeps its name and loses its v1 half.
  • v1 → v2 in the guest's harnesses. The dispatch harness (Harness::send, next_response and responses) frames requests in v2 and reads v2's answers, without READY's version byte; the runtime tests' receive, prelaunch_termination and only_stdout_prefix, and the session tests' Peer::app, activate_bytes and queue, do too (Peer::send gives way to send_v2). The tests that use them keep their names and checks: data_validation_diagnostics_preserve_the_c_failure_stage_and_status, refused_records_report_the_stage_at_which_the_c_agent_reported_them, data_before_the_first_reset_is_a_type_that_the_agent_does_not_take_yet, data_at_the_last_sequence_number_is_out_of_sequence and a_stream_that_ends_reports_a_read_failure_inside_a_record_or_not (dispatch), the three privileged_layered_runtime_* tests (runtime), a_version_2_execution_forwards_output_past_the_old_cap (streams), and a_replacement_session_joins_one_activation_and_caches_ready_without_reapplying, changed_record_or_workload_bytes_during_application_fail_without_ready, an_unread_output_stream_cannot_extend_the_activation_deadline, capture_refuses_active_execution_without_kill_and_validates_the_existing_flag and restored_capture_consumes_reset_and_acknowledges_the_existing_connection (session).
  • BUSY. v2 refuses a request during an execution with BUSY, where v1 sent an ERROR of EBUSY, so a_control_failure_after_a_lost_status_does_not_wait_again, a_lost_status_keeps_its_outcome_through_a_later_cancellation_or_timeout, a_running_workload_refuses_other_requests_and_ends_when_cancelled_or_late and the session tests that refuse a request expect it.
  • New inputs where v2 refuses v1's. a_request_that_fails_after_validation_reports_the_data_stage sent v1's STOP with a payload, which v2's decoder now refuses before validation ends, so it sends a restored agent's ACTIVATE, whose record fails to decode after the frame passes; direct_endings_do_not_wait_for_an_escaped_descendant_to_close_output loses its output-limit case, and the flood that drove it, with v1's cap.
  • The guest chain's restored-activation test. guest::managed_agent::session::tests::a_failed_restored_activation_gives_init_the_status_of_its_class, which 9dece3077ca added while v1 still ran, sends a request while a restored activation applies its record, to show that it fails the activation as the protocol's failure, with that class's status. It sent v1's PING, through the session tests' Peer::send, which goes with v1; it now sends v2's, and still checks that the activation fails with EPROTO and ACTIVATION_PROTOCOL.
  • protocol::tests: capture_requests_round_trip_both_kill_flags and activate_requests_round_trip_records_and_workload_identity check their payloads without v1's frames; decoders_reject_malformed_input keeps the outer header's half and loses its gate; record_definitions_keep_their_wire_values drops APP_VERSION and gains APP_MAPS and, in guest builds, the codes of APP_CAPTURE, APP_ACTIVATE and APP_EXIT; exec_extension_keeps_its_wire_values drops MAX_OUTPUT_BYTES.
  • nvx-init, end to end. host::restore::tests::live_init speaks v2's frames to nvx-init (its ACTIVATE and CAPTURE constants give way to v2's encoder) and sends STDIN_END after the EXEC, and its gate returns to cli; tests/vm_lifecycle.rs's frame and acknowledged send v2's PING and STOP and expect READY to carry version 2, which the case matrix's vm-lifecycle row now says.
  • guest::init::tests::exec::ending_failures_are_reported_and_discarding_preserves_the_first_cause sets the discard flag directly, since Exec::discard goes.
  • Test policy: the allowlist's seam for protocol/app.rs, SL4.4c's expect on ExitCategory::parse, goes (check_test_layout.py --tighten).

@ppenna Pedro Henrique Penna (ppenna) added tests-modified Changes existing tests, test data, or test wiring feat-nvx-refactor labels Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 104 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests.

Test code

Change What Before After
modified attributes the inner attributes of host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:1 nvx-rs/src/host/restore/tests/live_init.rs:1
modified helper fn send in guest::managed_agent::dispatch::tests, impl Harness`` nvx-rs/src/guest/managed_agent/dispatch/tests.rs:124 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:129
modified helper fn next_response in guest::managed_agent::dispatch::tests, impl Harness`` nvx-rs/src/guest/managed_agent/dispatch/tests.rs:149 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:154
modified helper fn responses in guest::managed_agent::dispatch::tests, impl Harness`` nvx-rs/src/guest/managed_agent/dispatch/tests.rs:166 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:165
modified helper fn receive in guest::managed_agent::dispatch::tests::runtime nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:204 nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:204
modified helper fn prelaunch_termination in guest::managed_agent::dispatch::tests::runtime nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:211 nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:210
modified helper fn only_stdout_prefix in guest::managed_agent::dispatch::tests::runtime nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:560 nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:530
modified helper fn app in guest::managed_agent::session::tests, impl Peer`` nvx-rs/src/guest/managed_agent/session/tests.rs:53 nvx-rs/src/guest/managed_agent/session/tests.rs:57
modified helper fn activate_bytes in guest::managed_agent::session::tests nvx-rs/src/guest/managed_agent/session/tests.rs:140 nvx-rs/src/guest/managed_agent/session/tests.rs:137
modified helper fn queue in guest::managed_agent::session::tests nvx-rs/src/guest/managed_agent/session/tests.rs:442 nvx-rs/src/guest/managed_agent/session/tests.rs:409
modified helper type AnyError in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:25 nvx-rs/src/host/restore/tests/live_init.rs:25
modified helper struct OwnedVm in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:29 nvx-rs/src/host/restore/tests/live_init.rs:27
modified helper impl Drop for OwnedVm in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:30 nvx-rs/src/host/restore/tests/live_init.rs:28
modified helper fn drop in host::restore::tests::live_init, impl Drop for OwnedVm`` (it now compiles where any ( target_os = "linux" , windows ) and `feature = "cli"` and `feature = "host"` and `test` hold, not where `any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) )` and `any ( target_os = "linux" , windows )` and `feature = "cli"` and `feature = "host"` and `test` did) nvx-rs/src/host/restore/tests/live_init.rs:31 nvx-rs/src/host/restore/tests/live_init.rs:29
modified helper fn require in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:46 nvx-rs/src/host/restore/tests/live_init.rs:44
modified helper fn backend in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:54 nvx-rs/src/host/restore/tests/live_init.rs:52
modified helper fn private_directory in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:62 nvx-rs/src/host/restore/tests/live_init.rs:60
modified helper fn create_export in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:74 nvx-rs/src/host/restore/tests/live_init.rs:72
modified helper fn ready in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:88 nvx-rs/src/host/restore/tests/live_init.rs:86
modified helper fn workload in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:102 nvx-rs/src/host/restore/tests/live_init.rs:101
modified helper fn execute in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:111 nvx-rs/src/host/restore/tests/live_init.rs:110
modified helper fn check_restored_console in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:145 nvx-rs/src/host/restore/tests/live_init.rs:146
modified helper fn run in host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:160 nvx-rs/src/host/restore/tests/live_init.rs:161
modified helper fn frame in vm_lifecycle (tests) nvx-rs/tests/vm_lifecycle.rs:106 nvx-rs/tests/vm_lifecycle.rs:106
modified helper fn acknowledged in vm_lifecycle (tests) nvx-rs/tests/vm_lifecycle.rs:125 nvx-rs/tests/vm_lifecycle.rs:127
modified imports the imports of guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1
modified imports the imports of guest::managed_agent::session::tests nvx-rs/src/guest/managed_agent/session/tests.rs:1 nvx-rs/src/guest/managed_agent/session/tests.rs:1
modified imports the imports of guest::managed_agent::tests::loopback::tests nvx-rs/src/guest/managed_agent/tests/loopback/tests.rs:1 nvx-rs/src/guest/managed_agent/tests/loopback/tests.rs:1
modified imports the imports of host::restore::tests::live_init (it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests/live_init.rs:1 nvx-rs/src/host/restore/tests/live_init.rs:1
modified imports the imports of protocol::tests nvx-rs/src/protocol/tests.rs:14 nvx-rs/src/protocol/tests.rs:14
modified module mod live_init in host::restore::tests (moved, and it now compiles where any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test hold, not where any ( feature = "testing" , all ( feature = "guest" , target_os = "linux" , target_arch = "x86_64" ) ) and any ( target_os = "linux" , windows ) and feature = "cli" and feature = "host" and test did) nvx-rs/src/host/restore/tests.rs:12 nvx-rs/src/host/restore/tests.rs:5
modified test fn ending_failures_are_reported_and_discarding_preserves_the_first_cause in guest::init::tests::exec nvx-rs/src/guest/init/tests/exec.rs:295 nvx-rs/src/guest/init/tests/exec.rs:295
modified test fn agent_refuses_feature_payloads_and_unannounced_mapping_tables in guest::managed_agent::dispatch::tests (renamed to agent_refuses_unannounced_mapping_tables) nvx-rs/src/guest/managed_agent/dispatch/tests.rs:352 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:371
modified test fn data_validation_diagnostics_preserve_the_c_failure_stage_and_status in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:929 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:943
modified test fn a_request_that_fails_after_validation_reports_the_data_stage in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:970 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:984
modified test fn direct_endings_do_not_wait_for_an_escaped_descendant_to_close_output in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1358 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1379
modified test fn a_control_failure_after_a_lost_status_does_not_wait_again in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1509 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1508
modified test fn a_lost_status_keeps_its_outcome_through_a_later_cancellation_or_timeout in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1591 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1590
modified test fn a_running_workload_refuses_other_requests_and_ends_when_cancelled_or_late in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2032 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:1976
modified test fn refused_records_report_the_stage_at_which_the_c_agent_reported_them in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2157 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2096
modified test fn data_before_the_first_reset_is_a_type_that_the_agent_does_not_take_yet in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2234 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2173
modified test fn data_at_the_last_sequence_number_is_out_of_sequence in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2245 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2184
modified test fn a_stream_that_ends_reports_a_read_failure_inside_a_record_or_not in guest::managed_agent::dispatch::tests nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2263 nvx-rs/src/guest/managed_agent/dispatch/tests.rs:2202
modified test fn privileged_layered_runtime_delivers_a_fragment_collected_status_before_driver_events in guest::managed_agent::dispatch::tests::runtime nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:307 nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:299
modified test fn privileged_layered_runtime_keeps_helper_policy_and_first_error_during_failed_start in guest::managed_agent::dispatch::tests::runtime nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:418 nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:394
modified test fn privileged_layered_runtime_delivers_a_write_collected_status_before_driver_events in guest::managed_agent::dispatch::tests::runtime nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:681 nvx-rs/src/guest/managed_agent/dispatch/tests/runtime.rs:651
modified test fn version_2_serves_ping_and_the_mapping_table_beside_version_1 in guest::managed_agent::dispatch::tests::streams (renamed to version_2_serves_ping_and_the_mapping_table) nvx-rs/src/guest/managed_agent/dispatch/tests/streams.rs:149 nvx-rs/src/guest/managed_agent/dispatch/tests/streams.rs:150
modified test fn a_version_2_execution_forwards_output_past_the_old_cap in guest::managed_agent::dispatch::tests::streams nvx-rs/src/guest/managed_agent/dispatch/tests/streams.rs:393 nvx-rs/src/guest/managed_agent/dispatch/tests/streams.rs:404
modified test fn a_replacement_session_joins_one_activation_and_caches_ready_without_reapplying in guest::managed_agent::session::tests nvx-rs/src/guest/managed_agent/session/tests.rs:152 nvx-rs/src/guest/managed_agent/session/tests.rs:149
modified test fn changed_record_or_workload_bytes_during_application_fail_without_ready in guest::managed_agent::session::tests nvx-rs/src/guest/managed_agent/session/tests.rs:259 nvx-rs/src/guest/managed_agent/session/tests.rs:225

... and 38 more, which the job's summary lists.

Test doubles

Change What Before After
modified helper struct Options in testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:367 nvx-rs/src/testing/fake_openvmm.rs:350
modified helper fn parse in testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:1354 nvx-rs/src/testing/fake_openvmm.rs:1333
modified helper enum Request in testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:2580 nvx-rs/src/testing/fake_openvmm.rs:2550
modified helper struct Session in testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:2656 nvx-rs/src/testing/fake_openvmm.rs:2625
modified helper fn send in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:2687 nvx-rs/src/testing/fake_openvmm.rs:2653
modified helper fn request in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:2731 nvx-rs/src/testing/fake_openvmm.rs:2695
modified helper fn run in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:2762 nvx-rs/src/testing/fake_openvmm.rs:2720
modified helper fn interrupt in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:2814 nvx-rs/src/testing/fake_openvmm.rs:2768
modified helper fn exec_script in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:2858 nvx-rs/src/testing/fake_openvmm.rs:2807
modified helper fn exit in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:3085 nvx-rs/src/testing/fake_openvmm.rs:3013
modified helper fn serve_client in testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:3126 nvx-rs/src/testing/fake_openvmm.rs:3025
modified imports the imports of testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:199 nvx-rs/src/testing/fake_openvmm.rs:194
modified test fn version_2_workloads_send_output_past_the_cap_of_version_1 in testing::fake_openvmm::tests nvx-rs/src/testing/fake_openvmm/tests.rs:1277 nvx-rs/src/testing/fake_openvmm/tests.rs:1267
removed helper const GUEST_FEATURES in testing::fake_openvmm nvx-rs/src/testing/fake_openvmm.rs:234
removed helper fn forward in testing::fake_openvmm, impl < S : Read + Write + Pending > Session < '_ , S >`` nvx-rs/src/testing/fake_openvmm.rs:3109
removed test fn the_current_guest_advertises_every_required_feature in testing::fake_openvmm::tests nvx-rs/src/testing/fake_openvmm/tests.rs:30

Relocated unchanged: 0; added: 6. Compared the merge base 5715bb6d709d with 675b0d9b3fa3.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues are recorded for the v2-only protocol cleanup.

No open issues 🎉

What changed in this PR

Completes the NVXC v2 migration for #1129 by removing v1 compatibility code after the host switched to v2. The guest agents and fake OpenVMM now serve only v2, preserving its existing streaming, capture, and restore behavior.

Changes:

  • Deletes v1 codecs, FEATURES, GuestFeatures, and the unused public GuestFeaturesMissing error code.
  • Removes guest and fake-OpenVMM version selection and v1-only output limits.
  • Migrates remaining tests to v2, adds v1-rejection coverage, and updates documentation and API snapshots.
File Description
scripts/​test-layout-allowlist.json Removes the retired v1 test-hook allowance.
nvx-rs/​tests/​vm_lifecycle.rs Uses v2 frames and versioned readiness replies.
nvx-rs/​tests/​vectors/​README.md Clarifies the retained v1 vectors’ role.
nvx-rs/​tests/​cli.rs Retires tests using removed feature-advertisement options.
nvx-rs/​src/​testing/​fake_openvmm/​tests.rs Adds v1 rejection checks and removes v1-only cases.
nvx-rs/​src/​testing/​fake_openvmm.rs Removes v1 serving paths, feature state, and output caps.
nvx-rs/​src/​protocol/​tests.rs Removes v1 tests while retaining shared payload checks.
nvx-rs/​src/​protocol/​mod.rs Removes obsolete modules and re-exports.
nvx-rs/​src/​protocol/​features.rs Deletes GuestFeatures and its supporting code.
nvx-rs/​src/​protocol/​exec.rs Deletes the v1 output-limit constant.
nvx-rs/​src/​protocol/​app.rs Deletes v1 framing and exit categories; retains shared definitions.
nvx-rs/​src/​host/​restore/​tests/​live_init.rs Migrates live restore exchanges to v2.
nvx-rs/​src/​host/​restore/​tests.rs Removes the live tests’ v1-specific feature gate.
nvx-rs/​src/​guest/​managed_agent/​tests/​loopback/​tests.rs Deletes the v1 helper and output-cap regression test.
nvx-rs/​src/​guest/​managed_agent/​session/​tests.rs Migrates session checks to v2 readiness and busy replies.
nvx-rs/​src/​guest/​managed_agent/​session.rs Uses v2 exclusively for requests and replies.
nvx-rs/​src/​guest/​managed_agent/​mod.rs Updates module documentation for v2-only operation.
nvx-rs/​src/​guest/​managed_agent/​exec.rs Removes version branches and v1 output-cap handling.
nvx-rs/​src/​guest/​managed_agent/​dispatch/​tests/​streams.rs Adds guest-side v1 rejection coverage.
nvx-rs/​src/​guest/​managed_agent/​dispatch/​tests/​runtime.rs Migrates runtime test traffic to v2.
nvx-rs/​src/​guest/​managed_agent/​dispatch/​tests.rs Updates the harness and retires v1-only cases.
nvx-rs/​src/​guest/​managed_agent/​dispatch.rs Deletes the FEATURES handler.
nvx-rs/​src/​guest/​init/​tests/​exec.rs Sets discard state directly after helper removal.
nvx-rs/​src/​guest/​init.rs Deletes the unused discard helper.
nvx-rs/​src/​error.rs Removes GuestFeaturesMissing and its mappings.
nvx-rs/​README.md Documents v2-only behavior and revised test coverage.
nvx-rs/​public-api/​windows.txt Records the removed public error variant.
nvx-rs/​public-api/​linux.txt Records the removed public error variant.
doc/​usage.md Removes the obsolete error-code entry.
doc/​design/​4.4-host-guest-control-interface.md Describes v2-only protocol behavior without feature negotiation.
doc/​design/​4.3-isolation-and-resource-model.md Removes the account-feature advertisement reference.
doc/​acceptance-case-matrix.md Records the lifecycle test’s migration to v2.

Review effort: Balanced

Base automatically changed from agents/slim-sl4-4c-nvxc-v2-host to feature/nvx-refactor November 12, 2026 19:33
Since SL4.4c, every NVX control path speaks NVXC v2, so version 1's
frames, its FEATURES request and GuestFeatures were compatibility code
that only the guest agents and the fake OpenVMM still served. SL4.4d
(#1129) deletes them, and v2 is NVXC's only version.

The protocol loses v1's magic and version, APP_FEATURES, the v1 codec
(encode_app and decode_app), ExitCategory, GuestFeatures with its
module, and MAX_OUTPUT_BYTES, the 1 MiB cap that only v1 applied, with
the dead-code markers that SL4.4c left on them. The kind codes and error
categories that v2 shares stay, since the guest loop and the fake still
name v2's requests and answers with them; their gates narrow to the
builds that still use them.

The guest loop that nvx-init and the managed agent share decodes v2
alone: a frame of another version fails as a malformed request does,
which ends the session with the data-application diagnostic. The
session's per-request version, the FEATURES handler, v1's output cap
and null standard input, and the BUSY answer to a v1 STOP during an
execution go. The discard of an execution's output, which only the cap
used, goes with nvx-init's Exec::discard.

The fake OpenVMM serves v2 alone: its v1 handler, its output cap, its
feature state and the fake_guest_features and fake_legacy_guest tokens
go, and a frame of another version ends its session.

The guest's dispatch, session and runtime test harnesses speak v2, the
tests of v1 alone retire, and new tests show that the guest agent and
the fake end the session of a v1 peer. tests/vm_lifecycle.rs and the
live restore test speak v2's frames to nvx-init. The protocol's docs,
the design of the control interface, the guest-agent guidelines, the
vectors' README and the case matrix follow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ErrorCode::GuestFeaturesMissing reported a guest image that lacked the
control features of NVXC v1's FEATURES request, which SL4.4c stopped
sending and the previous commit deletes. Nothing reports the code any
longer, so SL4.4d (#1129) deletes it, a public API removal inside
leaving code, with its row in the README's and doc/usage.md's tables of
codes, and the mention of control features in ErrorKind::Unavailable.
The public API snapshots lose the variant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues are recorded for the v2-only protocol migration and removal of obsolete v1 compatibility code.

No open issues 🎉

Review effort: Balanced

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

Labels

feat-nvx-refactor tests-modified Changes existing tests, test data, or test wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants