Skip to content

doc: describe only the final nvx library in a guide and the READMEs (SL6.10a) - #1555

Draft
Pedro Henrique Penna (ppenna) wants to merge 13 commits into
feature/nvx-refactorfrom
agents/slim-sl6-10a-library-guide
Draft

Pedro Henrique Penna (ppenna) wants to merge 13 commits into
feature/nvx-refactorfrom
agents/slim-sl6-10a-library-guide

Conversation

@ppenna

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

Copy link
Copy Markdown
Contributor

Part of #1130 (SL6.10a, "The library's guide describes only the final public library"). Parent #1090, umbrella #1076.

Stacked on #1552 (SL6.8c).

What and why

The landing page and the crate README still presented nvx as "the NVX mechanics" with the supervision of NVX's microVMs, laid out the split platform, store and supervisor modules, listed exec among the modules without default features, kept an uncompiled copy of lib.rs's example, and gave modules that leave the public API, or the crate, rows and long sections of their own. Nothing told a program that uses the library what it owns now that the library keeps no stores, drives no restore and applies no path or image rules. This PR does SL6.10a's Scope and no more, and writes for the final public library: the stack below it (SL6.6c, SL6.7b, SL6.6d, SL6.5a2, SL6.5b, SL6.8c), the tip of feature/nvx-refactor (SL6.11b #1542, SL6.14, SL4.4b), and the slices that merge before it, SL6.11d (#1547), SL6.13b (#1548), SL4.4c (#1541) and SL4.4d (#1545). Each statement was checked against the code of this branch and, where it concerns those slices, against their branches.

  • doc/library.md (new, the one guide): a host program's three workflows, each linked to code that CI compiles through the public API alone rather than a copy of it:
    • Cold boot: vm::create_private_dir, VmDir::open, vm::create, vm::spawn (or Prepared::into_command for a launcher of the caller's own), transport::connect_verified and HostConnection::attach, vm::stop. Linked: the example of the crate documentation in nvx-rs/src/lib.rs (a rustdoc test), cold_boot and stop in nvx-rs/examples/host-workflows.rs (compile-only), and external-launch.
    • Restore from a strict snapshot, with the capture that makes one: finish_capture, Snapshot::open, the caller's per-snapshot lock on Linux, vm::create(.., Some(&snapshot), ..), Prepared::activation_record, a RestoreMachine that the program drives with its own I/O, and the guest's Activation. Linked: capture and restore in host-workflows, capture and activate in guest-workflows.
    • Reattach after a restart: SavedVm, vm::reattach, vm::verify, RuntimeMismatch. Linked: reattach in host-workflows, and the rustdoc test of host::transport.
    • What the caller owns, in bounded lists, in place of the removed stores, clone driver and path and image rules: paths and image checks, durable state, locks, I/O, timing, recovery, outputs and process lifecycle, each from the rustdoc and code of host::{vm, snapshot, restore, filesystem, transport, process} (for example the Linux per-snapshot lock, the Windows spawn's inheritance window and windows_breakaway, ExportPlan's paths-only race and rechecks, RestoreError's attribution, StillRunning).
  • nvx-rs/README.md, slimmed to the final public library:
    • The intro names the library's mechanisms and what it leaves to its users, links the guide and the guest-agent guidelines, and names NVX's programs, NVXC and the code that only they use as private users of the library, whose binaries call hidden mains. Features come first (exec gone).
    • The layout's tree and the module table describe the final public modules: guest::{exec, spawn, process, cgroup, entry} are gone; guest::{root, view, gpt}, the mapper and an activation's application are nvx-init's space, private to the crate, which a short nvx-init's space section under the guest binaries describes and the guidelines detail; host::platform is private and host::report a module of its own; nvx::protocol::maps and nvx::Error gain rows. The table keeps the convention of .github/copilot-instructions.md: 36 rows, each one line of at most 200 characters that links its section after the table, above the floor of 30 that guest: delete the process modules and cgroups (SL6.11b) #1542 set (test_readme_gives_each_module_a_short_row_and_a_section). It lists no private module.
    • The module sections keep each module's contracts and leave the rest to the rustdoc; the paragraph on the split platform, store and supervisor layout goes. nvx::protocol says that NVXC is private and speaks version 2 alone, as SL4.4c and SL4.4d make it; ExportPlan holds paths only; nvx::Error has no public codes or constructors, and library callers tell errors apart by their kinds alone (the old text also had them match message fragments, which Error's rustdoc reserves to the CLI's callers). The uncompiled Example gives way to the guide.
    • Kept as they were, since other documents link them (doc/usage.md, doc/ci.md, doc/contribute.md, the repository instructions) and the slices that change them keep them current: the CLI's sections (Egress policy files through Scenario tests), the table of error codes, the binaries' table and Testing; only a stale sentence on an API change of the now-private host::sandbox goes. The table of error codes keeps guest-features-missing, which error::tests::the_readme_documents_every_code_with_its_kind reads at this base, until SL4.4d's own commit removes it, and the Unavailable kind's meaning already reads as SL4.4d leaves it.
  • README.md: the landing page's note on integration and its usage list link the guide, its crate entry describes the library and NVX's programs in it, and the guest-agent guidelines join the list. No other root section changes.

Rebase at my turn. The README conflicts with the tip, SL6.13b, SL4.4c and SL4.4d's README edits; I will keep this structure, take their changes to the sections kept above, and check every statement again against the rebased code. At this stack base, whose test still has the floor of 40, test_readme_gives_each_module_a_short_row_and_a_section fails (36 rows): it passes on the tip's floor of 30, which the rebase brings.

Case matrix. No test changes. Its Docs row for the README's Example already records the fate (rewritten; "the library's guide (SL6.10a) replaces the example"), so no row changes.

Not in this PR, per #1130: CLI reference material (SL6.10d), design pages (SL6.10b, SL6.10c), other guides or a cookbook, build and CI docs (SL6.10e, SL6.10f), the rustdoc (SL6.10g), the migration guide (SL6.10h), and examples beyond cold boot, restore and reattach.

Size. 0 core lines and 0 counted files (estimate 0): two READMEs and one new guide. BOOT_CONTRACT_VERSION, CONTROL_CONTRACT_REVISION and the public API are unchanged.

Validation

local_gates.py (dev's) selects markdown-links, test-layout, test-changes, the nvx-rs checks and validate-nvx for these files; the ones that the change affects ran from this branch's action definitions, on Windows, at 761fc1a1338; the later fold of Copilot's finding changed only prose, after which the link check ran again:

Check Result
python scripts/check_markdown_links.py, at each of the three commits (git rebase --exec) Passed
python scripts/check_test_layout.py Passed
python scripts/check_test_changes.py --base origin/agents/slim-sl6-8c-error-codes-private 0 changes to existing tests
cargo test --locked --lib --manifest-path nvx-rs/Cargo.toml -- error::tests (reads the README's error codes through include_str!) 5 passed
validate-nvx (Windows): compileall and the unittest list compileall passed; 1803 tests, all passed but the expected test_readme_gives_each_module_a_short_row_and_a_section: 36 rows against this base's floor of 40, which the tip's floor of 30 replaces
The module-table test's checks with the tip's floor of 30 (rows of at most 200 characters, links to sections after the table, GitHub anchors) Passed: 36 rows
Anchors that this PR links in other documents (guest-agent-guidelines.md#ownership, #build-the-space, #the-hosts-mapping-table, ci.md#cratesio-releases, run.md#run-openvmm-directly), on the tip, SL6.13b and SL6.10c/e/f's branches Present
Claims review A code-review agent checked every statement of the guide and of the rewritten README parts against nvx-rs/src, the examples, the public-API snapshots and the pending branches. Its five findings are folded: a VM outlives its program on Windows only with windows_breakaway when the program runs in a job; vm::stop returns the report's read apart from the exit; KeyIdentity digests the key's compatibility prefix; bytes_read counts reaped children on Linux; library callers classify errors by kind alone. Copilot's finding is folded too: the program sends the mapping table only when it holds a mapping, since encode_maps_payloads refuses an empty one

nvx-rs/README.md is not the crate's documentation (lib.rs doesn't include it), so no doc test or cargo doc output changes, and nothing here is guest-gated: no Linux host, build or microVM run.

SL6.7b (#1124) makes host::sandbox private to the CLI. Twelve of its
items have no caller in any NVX program, only in the public API and in
the module's own tests, so they would be dead once private. This change
deletes them first, as SL6.6c (#1122) records:

- MountAccess::from_name, MountOwner::from_name and
  MountKind::from_name, with their helper setting_from_name, which read
  a share's settings by name, as a recorded share gave them. The CLI
  maps the choices of --mount-owner itself and records a sandbox's
  export plan, not its shares' settings.
- SandboxMount's accessors guest_target, access, policy, owner and
  kind, and absolute and absolute_policy_paths, which called
  absolute_with and absolute_policy_paths_with with the current
  directory. plan_mounts and the checks of host paths call those
  variants, whose docs now say what the wrappers' said, and read the
  fields; host_path stays for sandbox_mounts. plan_mounts' docs no
  longer name absolute, and say how making a host path absolute fails.
- SandboxOptions::new, the options of an operation with the defaults of
  nvx-rs sandbox, which the CLI builds field by field instead.

The tests keep what they check of the code that stays:

- The share tests compare whole shares with the shares that
  SandboxMount::new makes, or read the fields that the mount module
  shows them, and make shares absolute with absolute_with and
  absolute_policy_paths_with and the current directory, as the deleted
  wrappers did.
- The option tests build their options with a helper of their own,
  defaults, which holds what SandboxOptions::new did, and compare the
  shares of sandbox_mounts with whole shares, policies included.
- The checks of from_name's refusals go with it: they were the only
  callers of what they checked.

The public API snapshots lose 21 lines on each platform, the eleven
public methods at both of their paths and SandboxOptions::new, and gain
none.

Part of #1122 (SL6.6c).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.7b (#1124) makes host::network::policy and host::sandbox private
to the CLI. Two of the CLI's scenario tests reached them through their
public paths, which they cannot once those are private, so they drive
the nvx-rs binary alone, with the same expectations:

- egress_compile_prints_the_library_lowering compared what
  `nvx-rs egress compile` printed with the rules of
  compile_policy_file, and its refusals with the reader's error. It
  keeps every case's native rules, error code and message fragments,
  which the binary must print, and the grammar, model and property
  tests of host::network::policy check the reader's own rules and
  refusals.
- two_share_command_line_room spells the tag of OpenVMM's virtio-fs
  device, `microvm`, as the lifecycle tests do, in place of MOUNT_TAG,
  and cold_run_expected splits a fixture's --mount and --mount-child
  values as OpenVMM reads them, with a helper of its own, in place of
  parse_mount_value: independently of the CLI's parser, as its
  documentation says.

Part of #1124 (SL6.7b).

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

host::network::policy and host::sandbox were public API of nvx,
although only NVX's CLI reads egress policy files and the options of
nvx-rs sandbox and nvx-rs run: the policy-file reader and its limits,
the rules that it compiles, the --mount syntax, the shares that it
requests and their plan, the checks of the options, and the sandbox's
defaults. They become crate-private where they are, gated by the
features of their users, with no change of behavior:

- host::network::policy becomes a pub(crate) module that only the cli
  feature builds, with its JSON reader, compile_policy_file,
  compile_policy_bytes, compile_policy and CompiledEgressPolicy, and
  its limits, MAX_RULES_PER_ACTION, MAX_POLICY_FILE_SIZE and
  MAX_JSON_DEPTH. The lowering already takes MAX_RULES directly, and
  the shared normalization stays public: EgressRule, Destination,
  PortSelector and NetworkPolicy::native_egress_rules.
- host::sandbox becomes pub(crate). Its options module, with
  SandboxOptions, PolicyPathOption, SandboxOperation and the checks of
  the options, takes cli, and so do, in its mount module, the --mount
  syntax, SandboxMount, the mount types and limits, plan_mounts and
  plan_mounts_with, the checks of host paths and path_text, and, at
  its root, the defaults, parse_workload_identity, parse_decimal,
  has_kernel_separator and require_file. What the crate uses outside
  the CLI stays ungated: block_geometry and BlockGeometry, which
  host::vm and host::snapshot read, MOUNT_TAG, which a snapshot's key
  names, refused and os_error.
- host::sandbox no longer re-exports the mount types, nor its mount
  module the reserved targets of protocol::share or
  validate_mount_target, which nothing reads at those paths once they
  are private. The sandbox's tests import the mount types from the
  mount module, and validate_mount_target through the mount module's
  tests, as they do validate_mount_host_paths_with.
- What these users leave to the CLI takes cli too:
  host::artifacts::require_existing, which only require_file and the
  CLI's require_artifact call, and host::paths::resolve, with
  without_verbatim_prefix and its two tests, which only the CLI and the
  checks of shares call.

The unit tests of host::network::policy and host::sandbox, and the two
host::paths tests of resolve, take cli with their modules, so the
all-features tests run them as before.

The public API snapshots lose 132 lines on each platform, every path
under nvx::host::sandbox and nvx::host::network::policy, and gain none.
The docs of host, host::network and host::sandbox, and the doc links of
openvmm_arguments, Destination and the lowering, name the reader and
the profile as the CLI's; the README drops the two modules' rows and
sections and holds their details in Egress policy files and Sandbox
input contract.

Part of #1124 (SL6.7b).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.5a2 (#1125) makes the export planner crate-private and gates it
with cli. Five of its items have no caller in any NVX program, only in
the public API and in tests, so the warning-denied build of the cli
feature would find them dead once they are private. This deletes them
first, so that SL6.5a2 stays visibility-only:

- resolve_guest_path, with its re-exports at nvx:: and
  nvx::host::filesystem::, which gave the guest path of a host path
  once resolved, or as spelled when it did not resolve. No NVX program
  translates a host path that way. guest_path, the convention itself,
  stays public at both paths.
- Target::Convention, with its branch of resolve_mapping, which
  derived a mapping's target from its resolved host path, and
  Mapping::convention, which mapped a list's paths there. NVX's
  callers, nvx-rs run and the sandbox's shares, give every target.
  resolve_mapping takes the target that the mapping gives, and checks
  it as before.
- ExportRequest::new, and PathList::EMPTY, which only it used. The CLI
  builds its requests field by field.

The docs of host::filesystem and of plan say that the caller gives
each target, which guest_path may derive, and the README's filesystem
section follows.

The tests keep what they checked of the code that stays:

- host::filesystem's tests place each path of their plan helper at
  the guest path that guest_path derives from the resolved host path,
  as the convention did, with a convention helper, and build their
  requests directly: plain_request holds what ExportRequest::new did.
- resolved_guest_paths_canonicalize_temp_directory_case_aliases
  retires with resolve_guest_path. On Windows,
  spellings_of_one_object_share_its_guest_path now takes its case, the
  object's whole path in capitals, that of the temporary directory
  included, whose guest path as spelled is not the resolved path's: it
  plans to the object's one child, at the resolved path's guest path.
- planned_boot_shares_keep_table_sources_targets_access_and_file_kind
  and the security checklist build their requests directly, the
  checklist through a helper that takes the owner, which
  the_caller_owner_is_refused_on_windows sets.

The public API snapshots lose 6 lines on each platform, the five items
with resolve_guest_path at both of its paths, and gain none.

Part of #1122 (SL6.6d).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.5a2 (#1125) makes the export planner and its host rechecks private
to the CLI. Two integration tests reached them through their public
paths, which they cannot once those are private, so each case moves
beside its owner or drives the nvx-rs binary alone, with the same
assertions:

- The security checklist's four checks of an export, which only the
  CLI plans and checks again before a start,
  an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves,
  an_export_refuses_a_read_only_path_inside_a_writable_directory,
  the_caller_owner_is_refused_on_windows and
  an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start,
  move unchanged to the unit tests of host::filesystem, where
  plan_blockless plans their mappings into the blockless root, as the
  checklist's plan did.
- cold_run_expected planned the shares of a cold-run fixture through
  filesystem::plan before it lowered them through the public VM
  contract. fixture_export now builds the fixture's ExportPlan as
  host::filesystem documents an export, independently of the CLI's
  planner, as of its parser and token renderer, so the dry-run and
  one-shot tests compare the CLI's command line with an export that
  they derive on their own.

The case matrix names the moved checklist tests where they now are.

Part of #1125 (SL6.5a2).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The export planner was public API of nvx, although path resolution,
the protected and reserved targets, the allow, deny and write rules,
aliases and the host rechecks before a start are the CLI's policy:
only nvx-rs run and the sandbox's shares plan exports, and only the
CLI checks a recorded export again before it starts a VM. They become
crate-private where they are, gated by cli, with no change of
behavior:

- host::filesystem's plan, ExportRequest, Mapping, Target and PathList
  become pub(crate) and take cli, with the helpers that only they use:
  resolve_mapping, check_targets, shows, Mapped and
  unsupported_inspection in the module, identity and
  canonicalize_lenient in host_path, check_root and check_policy_paths
  in limits, and the resolution and checks of policy paths in policy.
- ExportPlan::verify, the host recheck before each start, becomes
  pub(crate) and takes cli, with bound, changed_object, uninspected,
  loops, check_caller_roots and CALLER_OWNER_ON_WINDOWS, which only it
  and the planner use. The CLI keeps the identity pins, and calls
  verify before each launch as before.
- What stays public doesn't change: ExportPlan with its children,
  binds, owner and identities, check, openvmm_arguments, kernel_token
  and guest_table, ReservedTargets, Owner, FileIdentity, the
  constants, and guest_path, at nvx::host::filesystem:: and nvx::.
  host::paths is already crate-private; resolve, which only the CLI
  calls, took cli in SL6.7b, and the rest serves host::vm,
  host::snapshot and the VM directory too, so it stays ungated.

The 27 unit tests of the planner and of verify in host::filesystem
take cli with their 11 helpers, so the all-features tests run them as
before; the six tests of guest_path, within, outermost, the
whole-volume refusal, the reserved targets and check run without it.

The public API snapshots lose 20 lines on each platform, the planner's
items with their fields and ExportPlan::verify, and gain none. The
docs of host and host::filesystem, and those of ExportPlan and check,
name the planner and the recheck as the CLI's, and the README's
filesystem section and module row follow.

Part of #1125 (SL6.5a2).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ExportPlan, the public description of a VM's export, combined the host
paths with the file identities that only the CLI's store needs: each
child's denied_identities, each bind's identity, and FileIdentity, with
check's rules that a recorded plan pins each object that a workload
could move. The paths are what nvx lowers; the identities are the CLI's
recheck of its own records before each start.

The CLI now owns PlannedExport { description: ExportPlan, pins: Pins },
crate-private and cli-gated beside the planner and the verifier that
SL6.5a2 made private:

- The planner returns a PlannedExport: the description, and the pins
  of each child's denied paths and of each bind, in their orders,
  which it computes as before. The binds keep their pins as they are
  sorted.
- PlannedExport::check runs ExportPlan::check, then the pin rules that
  moved out of it: a slot for each child and each of its denied paths,
  one for each bind, and the identity of each denied or mapped object
  strictly inside a part that the guest may write, with the same
  messages. PlannedExport::verify is the old ExportPlan::verify, which
  reads the identities from the pins.
- The sandbox's config.json keeps the description under export, paths
  only, where CI's share checks read it, and records the pins beside it
  under export_pins, as it records each image beside its binding.
  Config::new requires the field and refuses an export without pins or
  pins without an export as malformed; Config::check checks and
  verifies the pair before vm_config passes the description to the VM.
  plan_mounts, provision's ProvisionConfig and check_images carry the
  PlannedExport; nvx-rs run, which launches its plan at once and never
  again, keeps the description and checks no pins, as before.

nvx's public API loses FileIdentity, ExportChild::denied_identities,
Bind::identity, and ExportPlan::openvmm_arguments and kernel_token,
which only VmConfig's lowering calls and which become pub(crate);
lowering is unchanged. ExportPlan::check stays structural and needs no
identity data. host::filesystem documents what the caller keeps stable:
the launch race, the writable-part recheck and durable denials.

A configuration that an earlier build wrote has no export_pins, so a
start refuses it as "sandbox configuration has no export pins;
deprovision the sandbox and provision it again", as for every field
that the record gained before; nothing is migrated, and the format
stays 10.

Tests: the planner's and verifier's unit tests read the pins from the
PlannedExport, and narrowed_writes_pin_only_what_lies_in_writable_paths
also checks the new slot rules; ExportPlan's own tests and fixtures,
in host::config, host::vm, the restore tests and tests/cli/openvmm.rs,
build plans without identities. A new state test records an export
with its pins, reads both back, and refuses a moved, a gone and an
uninspectable pinned object at Config::check. The CLI's lifecycle
tests expect export_pins in each record, and malformed_configuration
refuses a record without it, an export without pins, and pins without
an export.

Part of #1125 (SL6.5b).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.8c (#1126) makes ErrorCode and Error's constructors crate-private.
Once they are, the warning-denied build of the cli feature, which
builds every code of the crate that makes errors, finds three codes and
one constructor that nothing makes or calls any more: only the public
API and the tests named them. This deletes them first, so that the
change of visibility leaves every feature set's build clean:

- template-ineligible and template-tombstoned, which the template store
  reported until it left (SL6.2a, #1121), and sandbox-leased, which
  the sandbox store reported until it left (SL6.1, #1121). No NVX
  program reports them, so the CLI prints the same code for every
  error that it reports.
- Error::not_found, which nothing calls.

The README's and doc/usage.md's tables of the codes lose the three
rows, as the test that compares the README with ErrorCode::ALL, and the
test that compares the two tables, require.

The public API snapshots lose 4 lines on each platform, the four items,
and gain none.

Part of #1126 (SL6.8c).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.8c (#1126) makes Error's constructors and ErrorCode crate-private,
and ErrorCode::ALL, which only tests read, goes once the warning-denied
builds find it unused. Two tests reached them, which they cannot once
those are private, so each keeps its assertions without them:

- cold_run_expected, which projects a cold-run fixture onto the public
  VM contract, built nvx's Unsupported errors for the two fixtures that
  it cannot project. It now refuses them with errors of its own, as a
  caller that built nvx's errors must, and still passes on the public
  contract's own errors. The dry-run and one-shot tests show either
  only when they report an unexpected refusal.
- The error module's tests list the codes themselves, in the order of
  the README's table, in place of ErrorCode::ALL, for
  codes_are_unique_lowercase_words_joined_by_hyphens and
  the_readme_documents_every_code_with_its_kind. They make their errors
  with Error::new and Error::unavailable, which every feature set
  builds, in place of Error::io and Error::unsupported, which only the
  host and guest builds will: errors_keep_their_kind_message_and_cause
  and codes_determine_kinds check the same kinds, codes, messages and
  causes.

Part of #1126 (SL6.8c).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Callers act on nvx's failures by an error's kind, message and source,
but ErrorCode, Error::code and Error's constructors were public: the
codes, which serve the CLI's output, were part of the library's API,
and any caller could fabricate nvx's errors. They become crate-private
where they are, so that nvx alone makes its errors, and its public
error is Error, ErrorKind and Result:

- ErrorCode, with as_str and kind, and Error::code become pub(crate),
  and the crate root re-exports ErrorCode to the crate only, for the
  host and the CLI, which name it there. ErrorCode loses
  #[non_exhaustive], which only bound other crates, and ErrorCode::ALL,
  which only tests read.
- Error::new, its constructor of each kind, and with_source become
  pub(crate), gated by the features of their callers: unsupported and
  io build with the host or the guest, exited, protocol, timed_out and
  other with the host, and new, unavailable and with_source with every
  feature set.
- The CLI keeps its codes, and prints each error's code with the same
  messages and exit statuses. Most finer codes come from the CLI alone,
  and the CLI reads Error::code, as nvx-init and tests do, so the
  builds without the cli feature allow both to be unused.
- Error keeps kind, message, into_parts, its display and its source,
  and ErrorKind its variants, as_str and its display. Their docs, and
  those of SnapshotKey::from_bytes and SnapshotManifest::parse, name
  kinds and no codes, and the docs of the CLI's hidden module no longer
  link the private ErrorCode.

The README's Errors section describes the error by its kind, which only
nvx makes, and its Error codes section the codes that the CLI prints,
which the library keeps private. doc/usage.md, and a comment of the
test that compares the two tables, follow.

The public API snapshots lose 42 lines on each platform, ErrorCode with
its variants and methods, and Error's constructors and code, and gain
none.

Part of #1126 (SL6.8c).

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.

🟡 Changes recommended

The documented restore sequence omits skipping MAPS when no exports are configured, so following it unconditionally would fail an otherwise valid restore because encoding an empty mapping table returns an error.

1 open issue
What changed in this PR

Updates the documentation for the final public nvx library, separating its microVM mechanisms from caller-owned state and policy and NVX’s private programs.

Changes:

  • Adds one library guide covering cold boot, snapshot restore, and reattachment, linked to compiled examples.
  • Slims the crate README to the final public API and clarifies caller responsibilities.
  • Adds library-guide and guest-agent-guideline links to the repository landing page.
File Description
README.md Updates the crate description and links the library and guest-agent guides.
nvx-rs/​README.md Documents the final public modules and separates private implementation details.
doc/​library.md Introduces the three host workflows and caller-owned responsibilities.

Review effort: Balanced

Comment thread doc/library.md Resolved
The library keeps no stores, drives no restore and applies no path or
image rules any more, and nothing told a program that uses it what it
owns in their place, or how its workflows go: the crate README's one
example, a cold boot, was an uncompiled copy of lib.rs's, and the other
workflows lived only in the compile-only host-workflows example.

doc/library.md follows a host program through a cold boot, a restore
from a strict snapshot, with the capture that makes one, and a reattach
after the program restarts, and links each to code that CI compiles
through the public API alone: the example of the crate documentation in
lib.rs, cold_boot, stop, capture, restore and reattach in
host-workflows, capture and activate in guest-workflows, the example of
host::transport, and external-launch. It then states, in bounded lists,
what the program owns in place of the removed stores, driver and
policies: paths and image checks, durable state, locks, I/O, timing,
recovery, outputs and process lifecycle, each checked against the
rustdoc and code of host::vm, host::snapshot, host::restore,
host::filesystem, host::transport and host::process.

Docs only: 0 core lines, no counted files.

Part of #1130 (SL6.10a).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The README still introduced the crate as the NVX mechanics and their
supervision, laid out the split platform, store and supervisor modules,
listed exec among the modules without default features, kept an
uncompiled copy of lib.rs's example, and gave modules that leave the
public API, or leave the crate, rows and long sections of their own.

It now opens with the library's mechanisms and what it leaves to its
users, links the library guide and the guest-agent guidelines, and
names NVX's programs, with NVXC and the code that only they use, as
private users of the library, whose binaries call hidden mains. Its
features come first, and its layout and module table describe the
final public modules: guest::{exec, spawn, process, cgroup, entry} are
gone; guest::{root, view, gpt}, the mapper and the application of an
activation are nvx-init's space, private to the crate, which a short
section under the guest binaries describes and the guidelines detail;
host::platform is private and host::report a module of its own; and
nvx::protocol::maps and nvx::Error gain rows. The table keeps one line
of at most 200 characters for each of its 36 modules, above the floor
of 30 that #1542 set. The module sections keep each module's contracts
and leave the rest to its rustdoc. NVXC is private and speaks version 2
alone, as SL4.4c and SL4.4d make it; library callers tell errors apart
by their kinds alone; and the Example gives way to the guide, whose
links reach compiled code.

The CLI's sections, the table of error codes, the binaries' table and
the tests stay as they were but for one stale sentence on an API
change: other documents link them, SL6.10d owns the CLI reference, and
the slices that change them keep them current. The table of error codes
keeps guest-features-missing, which a unit test of the base reads, until
SL4.4d removes it.

Docs only: 0 core lines, no counted files.

Part of #1130 (SL6.10a).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The landing page described the nvx crate as the NVX mechanics with the
supervision of NVX's microVMs, and had no link for a program that runs
microVMs through the library, nor for the authors of guest inits.

Its note on integration and its list of usage documents now link the
library guide, its crate entry describes the library and NVX's programs
in it, and the guest-agent guidelines join the list.

Docs only: 0 core lines, no counted files.

Part of #1130 (SL6.10a).

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.

🔵 Needs a closer look

The documentation targets several pending stacked branches rather than this snapshot, requiring maintainer verification of API and protocol claims against the integrated tree after the planned rebase.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/slim-sl6-8c-error-codes-private branch from 5d18353 to b92df2b Compare November 12, 2026 22:31
Base automatically changed from agents/slim-sl6-8c-error-codes-private to feature/nvx-refactor November 12, 2026 22:48
@github-actions github-actions Bot added the tests-modified Changes existing tests, test data, or test wiring label Nov 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 467 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::network::policy::json::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/json/tests.rs:1 nvx-rs/src/host/network/policy/json/tests.rs:1
modified attributes the inner attributes of host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:1 nvx-rs/src/host/network/policy/tests.rs:1
modified attributes the inner attributes of host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:1 nvx-rs/src/host/network/policy/tests/generator.rs:1
modified attributes the inner attributes of host::network::policy::tests::grammar (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/grammar.rs:1 nvx-rs/src/host/network/policy/tests/grammar.rs:1
modified attributes the inner attributes of host::network::policy::tests::model (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/model.rs:1 nvx-rs/src/host/network/policy/tests/model.rs:1
modified attributes the inner attributes of host::network::policy::tests::properties (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/properties.rs:1 nvx-rs/src/host/network/policy/tests/properties.rs:1
modified attributes the inner attributes of host::sandbox::mount::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/sandbox/mount/tests.rs:1 nvx-rs/src/host/sandbox/mount/tests.rs:1
modified attributes the inner attributes of host::sandbox::options::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/sandbox/options/tests.rs:1 nvx-rs/src/host/sandbox/options/tests.rs:1
modified attributes the inner attributes of host::sandbox::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/sandbox/tests.rs:1 nvx-rs/src/host/sandbox/tests.rs:1
modified attributes the inner attributes of host::sandbox::tests::specification (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/sandbox/tests/specification.rs:1 nvx-rs/src/host/sandbox/tests/specification.rs:1
modified helper fn restored_config in host::cli::sandbox::lifecycle::start::tests::restore nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:239 nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:239
modified helper fn export in host::config::tests nvx-rs/src/host/config/tests.rs:85 nvx-rs/src/host/config/tests.rs:85
modified helper struct FilesystemPolicy in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:9 nvx-rs/src/host/filesystem/tests.rs:12
modified helper fn root in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:40 nvx-rs/src/host/filesystem/tests.rs:92
modified helper fn canonical in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:58 nvx-rs/src/host/filesystem/tests.rs:111
modified helper fn sources in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:62 nvx-rs/src/host/filesystem/tests.rs:116
modified helper fn option_values in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:70 nvx-rs/src/host/filesystem/tests.rs:125
modified helper fn second_volume in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1046 nvx-rs/src/host/filesystem/tests.rs:1104
modified helper fn at in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1080 nvx-rs/src/host/filesystem/tests.rs:1140
modified helper struct Members in host::network::policy::json::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/json/tests.rs:206 nvx-rs/src/host/network/policy/json/tests.rs:206
modified helper impl < 'de > IntoDeserializer < 'de , serde : : de : : value : : Error > for Members in host::network::policy::json::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/json/tests.rs:208 nvx-rs/src/host/network/policy/json/tests.rs:208
modified helper type Deserializer in host::network::policy::json::tests, impl < 'de > IntoDeserializer < 'de , serde : : de : : value : : Error > for Members`` (it now compiles where feature = "cli" and `feature = "host"` and `test` hold, not where `feature = "host"` and `test` did) nvx-rs/src/host/network/policy/json/tests.rs:209 nvx-rs/src/host/network/policy/json/tests.rs:209
modified helper fn into_deserializer in host::network::policy::json::tests, impl < 'de > IntoDeserializer < 'de , serde : : de : : value : : Error > for Members`` (it now compiles where feature = "cli" and `feature = "host"` and `test` hold, not where `feature = "host"` and `test` did) nvx-rs/src/host/network/policy/json/tests.rs:215 nvx-rs/src/host/network/policy/json/tests.rs:215
modified helper fn compile in host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:25 nvx-rs/src/host/network/policy/tests.rs:25
modified helper fn compile_text in host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:40 nvx-rs/src/host/network/policy/tests.rs:40
modified helper fn message in host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:45 nvx-rs/src/host/network/policy/tests.rs:45
modified helper fn action in host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:52 nvx-rs/src/host/network/policy/tests.rs:52
modified helper fn merged in host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:61 nvx-rs/src/host/network/policy/tests.rs:61
modified helper fn address_only in host::network::policy::tests (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests.rs:352 nvx-rs/src/host/network/policy/tests.rs:352
modified helper const IPV4_NEIGHBORHOOD in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:28 nvx-rs/src/host/network/policy/tests/generator.rs:28
modified helper const IPV6_NEIGHBORHOOD in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:30 nvx-rs/src/host/network/policy/tests/generator.rs:30
modified helper const NEIGHBORHOOD in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:32 nvx-rs/src/host/network/policy/tests/generator.rs:32
modified helper fn network in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:38 nvx-rs/src/host/network/policy/tests/generator.rs:38
modified helper enum Ipv4Prefix in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:69 nvx-rs/src/host/network/policy/tests/generator.rs:69
modified helper enum Ipv6Form in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:80 nvx-rs/src/host/network/policy/tests/generator.rs:80
modified helper fn spelling in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:96 nvx-rs/src/host/network/policy/tests/generator.rs:96
modified helper fn spell in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:122 nvx-rs/src/host/network/policy/tests/generator.rs:122
modified helper fn exception in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:172 nvx-rs/src/host/network/policy/tests/generator.rs:172
modified helper fn subnet in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:185 nvx-rs/src/host/network/policy/tests/generator.rs:185
modified helper fn destination in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:196 nvx-rs/src/host/network/policy/tests/generator.rs:196
modified helper fn port_range in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:217 nvx-rs/src/host/network/policy/tests/generator.rs:217
modified helper fn selector in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:231 nvx-rs/src/host/network/policy/tests/generator.rs:231
modified helper fn rule in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:267 nvx-rs/src/host/network/policy/tests/generator.rs:267
modified helper fn action in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:294 nvx-rs/src/host/network/policy/tests/generator.rs:294
modified helper fn policy in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:311 nvx-rs/src/host/network/policy/tests/generator.rs:311
modified helper fn crowd in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:326 nvx-rs/src/host/network/policy/tests/generator.rs:326
modified helper fn wide_crowd in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:356 nvx-rs/src/host/network/policy/tests/generator.rs:356
modified helper fn crowded_policy in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:378 nvx-rs/src/host/network/policy/tests/generator.rs:378
modified helper fn breakages in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:394 nvx-rs/src/host/network/policy/tests/generator.rs:394
modified helper fn mutated in host::network::policy::tests::generator (it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/network/policy/tests/generator.rs:417 nvx-rs/src/host/network/policy/tests/generator.rs:417

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

Relocated unchanged: 0; added: 11. Compared the merge base 8ae0617b1ebd with e223dd7828b2.

This branch has not been deployed

No deployments
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