Skip to content

host: confirm VM exit before returning stop outcomes (SL2.10) - #1432

Merged
Pedro Henrique Penna (ppenna) merged 3 commits into
feature/nvx-refactorfrom
esaurez/issue1100-sl210-0c8e42ad-20261110
Nov 10, 2026
Merged

Pedro Henrique Penna (ppenna) merged 3 commits into
feature/nvx-refactorfrom
esaurez/issue1100-sl210-0c8e42ad-20261110

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1100. Clean Draft reconciliation of #1426 onto
feature/nvx-refactor at c52c7101d4f66313b5f00f23b88530c38e3d0b60.
The original PR and its checkpoint branch remain unchanged.

Scope

Return stop outcomes only after a verified process wait confirms exit.
Process::wait returns opaque Exited proof or None; vm::stop preserves
graceful/forced ordering and reports an unconfirmed exit as StillRunning.
Report errors remain separate from proved exit: only a missing report is
Ok(None), while unreadable or malformed reports retain their I/O causes.

Keep the four legacy lifecycle callers on wait_bool and preserve existing
best-effort report policies. Update the directly affected callers, both
public-API snapshots, documentation, and real-process tests. No report schema,
restart-proof process-open API, background service, native runtime, dependency,
or OpenVMM pin change. SL2.10b remains a separate successor.

This ports only the preserved donor range
c7e971607a0ea3b638800b4d90a3fd549685c42b..e4af86899218cde7ad3228b3a63aa678ed19f1c2.
The resulting production files are byte-identical to that donor, while the
current feature's restore-failure facts and listener fixes remain present.
The stale PR-recorded base is not treated as an implementation ancestor.
The pinned OpenVMM commit remains
14dc4116ec7e57567633c4b7b07892aca3a58522.

The append-only test-infrastructure correction uses compact, atomically created
adapter sandbox names so the unchanged real capture/restore cases can execute
under data-volume temporary directories. Production socket/path limits,
assertions, deadlines, hardware ignores, and guest code remain unchanged.

Size: 101 production lines across seven production files, 30 changed paths,
including the runtime adapter's ten production lines. Tests, docs, and generated
API snapshots are excluded from the core-line count.

Existing tests

All 50 modified tests/helpers are retained and adapted to typed wait/report
results without weakening assertions or changing deadlines, parallelism, or
hardware ignores. The POSIX executable-copy fixture uses an owned child, keeping
writable descriptors out of concurrent CLI children while preserving its
original premise and assertions.

File Retained tests/helpers
nvx-rs/src/error/tests.rs every_kind_has_a_code_of_its_own_spelling
nvx-rs/src/host/platform/windows/tests.rs a_launch_whose_vmm_exited_ends_while_a_process_spawned_in_its_window_holds_its_log
nvx-rs/src/host/process/tests.rs hosts_without_pidfds_poll_and_never_signal
nvx-rs/src/host/process/tests/linux.rs a_process_runs_until_its_last_thread_exits
nvx-rs/src/host/report/tests.rs reports_are_summarized_without_free_form_fields
nvx-rs/src/host/template/clone/tests/launch.rs VmmDir::end_and_wait, VmmDir::wait_exit, VmmDir::drop, a_clone_whose_launch_failed_before_it_began_launches_no_more_until_its_release, a_launch_whose_caller_crashes_once_its_vmm_started_ends_the_vmm_as_reattach_recovers_it, a_restore_whose_caller_crashes_before_its_commit_ends_its_vmm_as_reattach_recovers_it
nvx-rs/src/host/template/clone/tests/restore.rs assert_vmm_ended
nvx-rs/src/host/template/store/leases/tests.rs VmmDir::drop, a_clone_that_crashes_after_its_spawn_keeps_its_lease_until_its_unrecorded_vmm_exits, a_clone_that_crashes_after_recording_its_vmm_keeps_its_lease_until_reattach_ends_it
nvx-rs/src/host/vm/tests.rs spawn_caller_helper, an_unrelated_process_started_in_the_library_spawn_window_gets_no_vm_claim, current_cold_spawn_boots_a_guest_accepts_shell_input_and_exits_cleanly
nvx-rs/src/host/vm/tests/reattach.rs reattaching_returns_the_held_owned_child_and_authenticated_connection
nvx-rs/tests/checked_handoff.rs a_prepared_launch_hands_the_vmm_its_checked_images_alone, a_vmm_keeps_the_scratch_images_claim_once_its_launcher_is_gone
nvx-rs/tests/cli.rs a_stop_under_another_identity_never_ends_a_process_that_its_record_does_not_name, stop_reports_its_timeout_and_leaves_the_vm_running, a_sandbox_whose_openvmm_exited_reports_it_once_and_starts_again
nvx-rs/tests/cli/download.rs provision_and_deprovision_need_no_artifact_root
nvx-rs/tests/cli/lifecycle.rs check_lifecycle, recycled_process_id, lifecycle_of_a_sandbox_whose_upper_is_in_ram, stops_keep_an_outcome_report_that_the_caller_reads_whatever_its_umask
nvx-rs/tests/fake_openvmm.rs outcome_reports_of_another_runtime_are_never_read, records_that_name_another_process_never_end_it
nvx-rs/tests/store.rs kill, a_committed_launch_names_its_vm_for_another_build
nvx-rs/tests/supervisor.rs VmmDirectory::drop, check_vmm, long_stores_launch_with_a_short_working_directory, a_child_that_exits_wakes_its_waiter, a_process_that_is_not_a_child_wakes_its_waiters, a_restarted_launcher_finds_its_vmm_again_and_ends_it, a_reused_process_id_is_never_signaled, references_that_name_no_process_are_never_opened, an_unrecorded_vmm_that_serves_no_endpoint_is_never_signaled, a_vmm_in_its_orchestrators_job_ends_with_it, a_job_that_ends_its_vmm_wakes_the_waiters, a_process_that_this_user_may_not_terminate_is_waited_for_but_never_signaled
tests/runtime-adapter/tests/vm_clone.rs Early::activate, a_host_program_of_another_runtime_ends_the_clone_through_its_verified_identity, a_clone_whose_vm_exits_once_a_stop_found_it_fails_before_its_lease_is_released, a_run_whose_clone_s_vm_exits_during_its_execution_ends_with_the_clone_s_failure
tests/runtime-adapter/tests/common/mod.rs Sandbox::new: keep its atomic collision/retry and retained-directory behavior, shorten only its fixture name, and retain the scenario in creation errors

New coverage exercises self-exit and report outcomes, verified forced exit
after grace, and unconfirmed exit, plus missing, malformed, and unreadable reports.

Qualification status

This is a locally qualified scoped slice, still Draft and not merge-ready.
The exact candidate is adeb1d4778229fd23b64c2be6cd762df352de382.
The following checks ran against that exact final head with fresh, private
head/toolchain-specific targets; no initial-head NVX executable or target was reused.

  • Passed: source/submodule verification in both private remote checkouts,
    test layout, Markdown links, committed test-change inventory, and whitespace.
  • Passed on Linux and Windows: all three real-process stop tests, with no failed or
    ignored tests in that focused run.
  • Independent native Opus 5.5 review found no blocking defects in the complete
    final c52c7101..adeb1d47 slice, including the fixture correction. Its sole
    formatting blocker was fixed and all 26 changed Rust files passed the pinned
    formatting check. The review is read-only, not test evidence.
  • Passed on Linux (41 commands) and Windows (31): the applicable Rust feature/lint/documentation/
    MSRV matrices, native-source comparisons, and independent adapter
    configurations; Linux also checked both API snapshots, macOS, and the static
    musl guest binaries.
  • Passed on actual MSHV and WHP: seven exact hardware cases per backend, each
    with one pass, no failure or ignore: cold boot/shell/confirmed exit/report;
    four clone fatal paths; corrupt-layer assembly failure; and failed-mapping
    teardown. Cases ran serially and confirmed owned VMM teardown between cases.
  • Independent native, kernel, initramfs, distro, scratch, and guest-agent
    components retained their true origin and were reused only after complete
    current effective-input comparison and copied-byte verification on each host.
    Final-head CLI and test executables were built afresh.
  • Historical launcher and pre-VMM fixture failures remain preserved separately;
    none is counted as a pass. No assertion, deadline, hardware ignore, or
    production path limit was relaxed.
  • Pending: coordinator-admitted full public CI and ultimate-chain reconciliation.
    MSHV is not KVM coverage; KVM was not run. Other ignored hardware tests are
    not counted as passes.

No previous-head test result is transferred to this candidate. A native gitlink
match alone does not qualify a guest image. The exact qualified stop producer
has been reported for dependent work before completing SL2.10b or waiting for CI.
Existing checkpoint PRs remain open and unchanged.

Port the preserved SL2.10 implementation and coupled callers, API snapshots, docs and real-process tests onto feature c52c710 without changing legacy lifecycle policy.

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

Copilot-Session: 0c8e42ad-4102-451f-96f0-0a4ae0483d1a
@esaurez Enrique Saurez (esaurez) added the tests-modified Changes existing tests, test data, or test wiring label Nov 10, 2026
@github-actions

github-actions Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 50 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 helper fn end_and_wait in host::template::clone::tests::launch, impl VmmDir`` nvx-rs/src/host/template/clone/tests/launch.rs:362 nvx-rs/src/host/template/clone/tests/launch.rs:362
modified helper fn wait_exit in host::template::clone::tests::launch, impl VmmDir`` nvx-rs/src/host/template/clone/tests/launch.rs:372 nvx-rs/src/host/template/clone/tests/launch.rs:372
modified helper fn drop in host::template::clone::tests::launch, impl Drop for VmmDir`` nvx-rs/src/host/template/clone/tests/launch.rs:412 nvx-rs/src/host/template/clone/tests/launch.rs:412
modified helper fn assert_vmm_ended in host::template::clone::tests::restore nvx-rs/src/host/template/clone/tests/restore.rs:422 nvx-rs/src/host/template/clone/tests/restore.rs:422
modified helper fn drop in host::template::store::leases::tests, impl Drop for VmmDir`` nvx-rs/src/host/template/store/leases/tests.rs:2459 nvx-rs/src/host/template/store/leases/tests.rs:2459
modified helper fn check_lifecycle in cli/lifecycle (tests) nvx-rs/tests/cli/lifecycle.rs:550 nvx-rs/tests/cli/lifecycle.rs:550
modified helper fn recycled_process_id in cli/lifecycle (tests) nvx-rs/tests/cli/lifecycle.rs:1425 nvx-rs/tests/cli/lifecycle.rs:1428
modified helper fn kill in store (tests) nvx-rs/tests/store.rs:176 nvx-rs/tests/store.rs:176
modified helper fn drop in supervisor (tests), impl Drop for VmmDirectory`` nvx-rs/tests/supervisor.rs:449 nvx-rs/tests/supervisor.rs:449
modified helper fn check_vmm in supervisor (tests) nvx-rs/tests/supervisor.rs:1226 nvx-rs/tests/supervisor.rs:1234
modified helper fn new in common/mod (tests), impl Sandbox`` tests/runtime-adapter/tests/common/mod.rs:154 tests/runtime-adapter/tests/common/mod.rs:154
modified helper fn activate in vm_clone (tests), impl CloneControl for Early`` tests/runtime-adapter/tests/vm_clone.rs:2314 tests/runtime-adapter/tests/vm_clone.rs:2314
modified test fn every_kind_has_a_code_of_its_own_spelling in error::tests nvx-rs/src/error/tests.rs:50 nvx-rs/src/error/tests.rs:50
modified test fn a_launch_whose_vmm_exited_ends_while_a_process_spawned_in_its_window_holds_its_log in host::platform::windows::tests nvx-rs/src/host/platform/windows/tests.rs:1049 nvx-rs/src/host/platform/windows/tests.rs:1060
modified test fn hosts_without_pidfds_poll_and_never_signal in host::process::tests nvx-rs/src/host/process/tests.rs:259 nvx-rs/src/host/process/tests.rs:259
modified test fn a_process_runs_until_its_last_thread_exits in host::process::tests::linux nvx-rs/src/host/process/tests/linux.rs:112 nvx-rs/src/host/process/tests/linux.rs:112
modified test fn reports_are_summarized_without_free_form_fields in host::report::tests nvx-rs/src/host/report/tests.rs:4 nvx-rs/src/host/report/tests.rs:4
modified test fn a_clone_whose_launch_failed_before_it_began_launches_no_more_until_its_release in host::template::clone::tests::launch nvx-rs/src/host/template/clone/tests/launch.rs:1547 nvx-rs/src/host/template/clone/tests/launch.rs:1549
modified test fn a_launch_whose_caller_crashes_once_its_vmm_started_ends_the_vmm_as_reattach_recovers_it in host::template::clone::tests::launch nvx-rs/src/host/template/clone/tests/launch.rs:2299 nvx-rs/src/host/template/clone/tests/launch.rs:2301
modified test fn a_restore_whose_caller_crashes_before_its_commit_ends_its_vmm_as_reattach_recovers_it in host::template::clone::tests::launch nvx-rs/src/host/template/clone/tests/launch.rs:2332 nvx-rs/src/host/template/clone/tests/launch.rs:2334
modified test fn a_clone_that_crashes_after_its_spawn_keeps_its_lease_until_its_unrecorded_vmm_exits in host::template::store::leases::tests nvx-rs/src/host/template/store/leases/tests.rs:2623 nvx-rs/src/host/template/store/leases/tests.rs:2625
modified test fn a_clone_that_crashes_after_recording_its_vmm_keeps_its_lease_until_reattach_ends_it in host::template::store::leases::tests nvx-rs/src/host/template/store/leases/tests.rs:2654 nvx-rs/src/host/template/store/leases/tests.rs:2656
modified test fn spawn_caller_helper in host::vm::tests nvx-rs/src/host/vm/tests.rs:1088 nvx-rs/src/host/vm/tests.rs:1088
modified test fn an_unrelated_process_started_in_the_library_spawn_window_gets_no_vm_claim in host::vm::tests nvx-rs/src/host/vm/tests.rs:1139 nvx-rs/src/host/vm/tests.rs:1140
modified test fn current_cold_spawn_boots_a_guest_accepts_shell_input_and_exits_cleanly in host::vm::tests nvx-rs/src/host/vm/tests.rs:1195 nvx-rs/src/host/vm/tests.rs:1197
modified test fn reattaching_returns_the_held_owned_child_and_authenticated_connection in host::vm::tests::reattach nvx-rs/src/host/vm/tests/reattach.rs:229 nvx-rs/src/host/vm/tests/reattach.rs:229
modified test fn a_prepared_launch_hands_the_vmm_its_checked_images_alone in checked_handoff (tests) nvx-rs/tests/checked_handoff.rs:487 nvx-rs/tests/checked_handoff.rs:487
modified test fn a_vmm_keeps_the_scratch_images_claim_once_its_launcher_is_gone in checked_handoff (tests) nvx-rs/tests/checked_handoff.rs:717 nvx-rs/tests/checked_handoff.rs:718
modified test fn a_stop_under_another_identity_never_ends_a_process_that_its_record_does_not_name in cli (tests) nvx-rs/tests/cli.rs:978 nvx-rs/tests/cli.rs:978
modified test fn stop_reports_its_timeout_and_leaves_the_vm_running in cli (tests) nvx-rs/tests/cli.rs:1139 nvx-rs/tests/cli.rs:1141
modified test fn a_sandbox_whose_openvmm_exited_reports_it_once_and_starts_again in cli (tests) nvx-rs/tests/cli.rs:1186 nvx-rs/tests/cli.rs:1190
modified test fn provision_and_deprovision_need_no_artifact_root in cli/download (tests) nvx-rs/tests/cli/download.rs:165 nvx-rs/tests/cli/download.rs:165
modified test fn lifecycle_of_a_sandbox_whose_upper_is_in_ram in cli/lifecycle (tests) nvx-rs/tests/cli/lifecycle.rs:636 nvx-rs/tests/cli/lifecycle.rs:637
modified test fn stops_keep_an_outcome_report_that_the_caller_reads_whatever_its_umask in cli/lifecycle (tests) nvx-rs/tests/cli/lifecycle.rs:718 nvx-rs/tests/cli/lifecycle.rs:720
modified test fn outcome_reports_of_another_runtime_are_never_read in fake_openvmm (tests) nvx-rs/tests/fake_openvmm.rs:458 nvx-rs/tests/fake_openvmm.rs:458
modified test fn records_that_name_another_process_never_end_it in fake_openvmm (tests) nvx-rs/tests/fake_openvmm.rs:498 nvx-rs/tests/fake_openvmm.rs:498
modified test fn a_committed_launch_names_its_vm_for_another_build in store (tests) nvx-rs/tests/store.rs:497 nvx-rs/tests/store.rs:499
modified test fn long_stores_launch_with_a_short_working_directory in supervisor (tests) nvx-rs/tests/supervisor.rs:596 nvx-rs/tests/supervisor.rs:598
modified test fn a_child_that_exits_wakes_its_waiter in supervisor (tests) nvx-rs/tests/supervisor.rs:664 nvx-rs/tests/supervisor.rs:672
modified test fn a_process_that_is_not_a_child_wakes_its_waiters in supervisor (tests) nvx-rs/tests/supervisor.rs:691 nvx-rs/tests/supervisor.rs:699
modified test fn a_restarted_launcher_finds_its_vmm_again_and_ends_it in supervisor (tests) nvx-rs/tests/supervisor.rs:720 nvx-rs/tests/supervisor.rs:728
modified test fn a_reused_process_id_is_never_signaled in supervisor (tests) nvx-rs/tests/supervisor.rs:751 nvx-rs/tests/supervisor.rs:759
modified test fn references_that_name_no_process_are_never_opened in supervisor (tests) nvx-rs/tests/supervisor.rs:791 nvx-rs/tests/supervisor.rs:799
modified test fn an_unrecorded_vmm_that_serves_no_endpoint_is_never_signaled in supervisor (tests) nvx-rs/tests/supervisor.rs:851 nvx-rs/tests/supervisor.rs:859
modified test fn a_vmm_in_its_orchestrators_job_ends_with_it in supervisor (tests) nvx-rs/tests/supervisor.rs:1483 nvx-rs/tests/supervisor.rs:1491
modified test fn a_job_that_ends_its_vmm_wakes_the_waiters in supervisor (tests) nvx-rs/tests/supervisor.rs:1510 nvx-rs/tests/supervisor.rs:1518
modified test fn a_process_that_this_user_may_not_terminate_is_waited_for_but_never_signaled in supervisor (tests) nvx-rs/tests/supervisor.rs:1566 nvx-rs/tests/supervisor.rs:1574
modified test fn a_host_program_of_another_runtime_ends_the_clone_through_its_verified_identity in vm_clone (tests) tests/runtime-adapter/tests/vm_clone.rs:3882 tests/runtime-adapter/tests/vm_clone.rs:3882
modified test fn a_clone_whose_vm_exits_once_a_stop_found_it_fails_before_its_lease_is_released in vm_clone (tests) tests/runtime-adapter/tests/vm_clone.rs:3930 tests/runtime-adapter/tests/vm_clone.rs:3932
modified test fn a_run_whose_clone_s_vm_exits_during_its_execution_ends_with_the_clone_s_failure in vm_clone (tests) tests/runtime-adapter/tests/vm_clone.rs:5295 tests/runtime-adapter/tests/vm_clone.rs:5299

Relocated unchanged: 0; added: 12. Compared the merge base c52c7101d4f6 with adeb1d477822.

Enrique Saurez added 2 commits November 10, 2026 02:29
Use the existing PID and atomic create-directory retry to retain unique fixture directories without a long diagnostic prefix. Keep the scenario name in creation errors. Capture and restore control sockets now fit approved data-volume temp roots without changing production limits, assertions, timeouts or skipped tests.

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

Copilot-Session: 0c8e42ad-4102-451f-96f0-0a4ae0483d1a
Apply the pinned rustfmt wrapping requested by the final-head review; fixture semantics and production source remain unchanged.

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

Copilot-Session: 0c8e42ad-4102-451f-96f0-0a4ae0483d1a

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 remain for the changes separating confirmed VM exits from report-reading failures.

No open issues 🎉

What changed in this PR

Implements SL2.10 of #1100 in NVX’s host library: VM stop outcomes require confirmed process exit, while report-reading failures remain separate. Legacy lifecycle behavior is preserved; restart-time exit proof remains deferred to SL2.10b.

Changes:

  • Adds opaque Exited proof, verified vm::stop, and StillRunning errors.
  • Distinguishes missing reports from read or parse failures, and updates callers, documentation, and API snapshots.
  • Adds real-process stop/report coverage, adapts existing tests, and adjusts executable-copy and temporary-directory fixtures.
File Description
tests/​runtime-adapter/​tests/​vm_clone.rs Adapts clone tests to typed exit results.
tests/​runtime-adapter/​tests/​common/​mod.rs Shortens atomically created sandbox directory names.
tests/​runtime-adapter/​src/​bin/​runtime-adapter-host.rs Adapts wait and report handling to the new APIs.
nvx-rs/​tests/​supervisor.rs Preserves supervisor assertions with typed exit results.
nvx-rs/​tests/​store.rs Updates cleanup helpers and exit assertions.
nvx-rs/​tests/​fake_openvmm.rs Updates verified-process lifecycle assertions.
nvx-rs/​tests/​cli/​lifecycle.rs Adapts lifecycle and recycled-process checks.
nvx-rs/​tests/​cli/​download.rs Copies the POSIX executable through an owned child.
nvx-rs/​tests/​cli.rs Adapts stop and restart exit assertions.
nvx-rs/​tests/​checked_handoff.rs Requires typed exit confirmation in handoff tests.
nvx-rs/​src/​host/​vm/​tests/​reattach.rs Updates reattachment exit confirmation.
nvx-rs/​src/​host/​vm/​tests.rs Adds real-process stop and report-result coverage.
nvx-rs/​src/​host/​vm.rs Adds confirmed stop outcomes and bounded stop sequencing.
nvx-rs/​src/​host/​template/​store/​leases/​tests.rs Adapts lease recovery and cleanup waits.
nvx-rs/​src/​host/​template/​clone/​tests/​restore.rs Updates restore cleanup exit assertions.
nvx-rs/​src/​host/​template/​clone/​tests/​launch.rs Adapts launch tests to wait and report results.
nvx-rs/​src/​host/​template/​clone/​records.rs Preserves best-effort report reads for legacy callers.
nvx-rs/​src/​host/​report/​tests.rs Tests missing, malformed, and unreadable reports.
nvx-rs/​src/​host/​report.rs Returns report-read errors with their underlying causes.
nvx-rs/​src/​host/​process/​tests/​linux.rs Preserves last-thread exit checks with typed results.
nvx-rs/​src/​host/​process/​tests.rs Updates polling fallback exit assertions.
nvx-rs/​src/​host/​process.rs Introduces opaque exit proof returned by wait.
nvx-rs/​src/​host/​platform/​windows/​tests.rs Adds a wait-only handle helper and updates exit checks.
nvx-rs/​src/​host/​instance/​locked.rs Preserves the legacy best-effort report policy.
nvx-rs/​src/​error/​tests.rs Includes StillRunning in error-code checks.
nvx-rs/​src/​error.rs Adds StillRunning and its code mappings.
nvx-rs/​README.md Documents confirmed stops, exit proof, and report errors.
nvx-rs/​public-api/​windows.txt Records new Windows public API symbols.
nvx-rs/​public-api/​linux.txt Records new Linux public API symbols.
doc/​usage.md Documents the still-running error code.

Review effort: Balanced

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

Labels

tests-modified Changes existing tests, test data, or test wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants