Repository navigation
nvx-rs: make the host module's dependency graph acyclic - #909
Closed
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Closed
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The dependency guard can miss production cycles through imports and incorrectly count test-only references.
4 open issues
What changed in this PR
This PR removes dependency cycles between nvx::host modules, preparing for the finer-grained module split in #896 while preserving behavior and public API paths.
Changes:
- Moves inherited handles, VMM spawning, and required-file checks below their callers.
- Preserves public re-exports and corrects documentation links for moved items.
- Adds and documents a source-based dependency guard with synthetic self-tests.
| File | Description |
|---|---|
nvx-rs/tests/host_modules.rs |
Adds dependency scanning, cycle reporting, and self-tests. |
nvx-rs/src/host/supervisor/mod.rs |
Preserves public re-exports of moved items. |
nvx-rs/src/host/store/mod.rs |
Imports Launched directly from spawn. |
nvx-rs/src/host/spawn.rs |
Houses VMM spawning outside supervisor. |
nvx-rs/src/host/sandbox/plan.rs |
Imports file validation from artifacts. |
nvx-rs/src/host/sandbox/mod.rs |
Delegates file checks to artifacts. |
nvx-rs/src/host/platform/windows.rs |
Uses the relocated Inherited type. |
nvx-rs/src/host/platform/other.rs |
Uses the relocated Inherited type. |
nvx-rs/src/host/platform/mod.rs |
Declares the crate-visible inherit module. |
nvx-rs/src/host/platform/linux.rs |
Uses the relocated Inherited type. |
nvx-rs/src/host/platform/inherit.rs |
Houses inherited descriptor and handle support. |
nvx-rs/src/host/mod.rs |
Declares and documents private spawn. |
nvx-rs/src/host/cli/sandbox/mod.rs |
Redirects artifact-check imports. |
nvx-rs/src/host/cli/run.rs |
Redirects artifact-check imports. |
nvx-rs/src/host/artifacts.rs |
Houses shared required-file checks. |
nvx-rs/README.md |
Documents the dependency guard. |
doc/ci.md |
Includes the guard in CI documentation. |
Review effort: Balanced
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-897-logical-commits-fix
branch
from
October 26, 2026 20:27
7677559 to
cbaa574
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-897-logical-commits-fix
branch
from
October 26, 2026 20:42
cbaa574 to
b563477
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-897-logical-commits-fix
branch
from
October 26, 2026 20:54
b563477 to
2a6478d
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-897-logical-commits-fix
branch
from
October 26, 2026 22:37
2a6478d to
3181fc8
Compare
Inherited names a descriptor (Unix) or handle (Windows) of the caller that a VMM inherits. supervisor::child defined it, so the Linux, Windows, and other platform modules, whose spawns take the allowed descriptors or handles as Inherited values, imported it from crate::host::supervisor. That import made platform depend on supervisor, which depends on platform in turn, and is one of the three back-edges that tie eight of host's children into one cycle. Inherited, the alias Borrowed of what it borrows on each host, and their impls move unchanged into a new crate-visible module, host::platform::inherit, from which the platform modules import it, so that platform no longer references supervisor. Inherited stays public, and supervisor re-exports it, so that its only public path is still nvx::host::supervisor::Inherited, where the sandbox's prepared launches and the CLI keep naming it. supervisor::child, which spawns with it, imports it from its new module. The documentation of Inherited links to File and spawn by their paths, since neither is in scope in the new module. The Linux tests of supervisor::child import the descriptor types that the module imported for the moved impls. Part of #897. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
supervisor::child held the detached spawn of a VMM: VmmCommand, spawn,
and the Launched child that spawn returns. The store records a launched
VMM's identity from its Launched, so store imported
super::supervisor::Launched, while supervisor runs its launches through
the store's journal and imports store: another back-edge of the cycle
between host's children. The spawn itself needs neither of them; it
imports only platform, process, and protocol.
supervisor/child.rs moves with git mv to host/spawn.rs, a private child
of host, and store imports Launched from it, so that store no longer
references supervisor. supervisor re-exports VmmCommand, spawn, and
Launched as it did, so that their public paths stay
nvx::host::supervisor::{VmmCommand, spawn, Launched}. The overview of
host names the new private module.
The documentation of spawn linked to supervisor's launch as
super::launch, which from host/spawn.rs would name the module
host::launch instead, without a warning from cargo doc, so it links to
crate::host::supervisor::launch. Its links to Launch::record_process
were crate paths already, and stay documentation rather than references
from spawn to store. The four Linux tests of the spawn move with it,
from host::supervisor::child::tests to host::spawn::tests.
Part of #897.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
artifacts checks each artifact that it locates with require_artifact, which sandbox defined beside its public require_file, together with the helper that both share, require_existing. So artifacts imported crate::host::sandbox::require_artifact, while the sandbox's distro layers import artifacts::DISTRO_MANIFEST_SUFFIX: the last back-edge of the cycle between host's children. The two helpers move unchanged into artifacts, as pub(crate), so that artifacts no longer references sandbox. Only the documentation of require_existing, which described the check through require_file, now describes it itself. The public sandbox::require_file stays where it is, as it is, and calls artifacts::require_existing. The run and sandbox commands of the CLI import require_artifact from artifacts. sandbox no longer needs host::paths, which require_existing used, so the sandbox's tests, which reached paths through sandbox, import it themselves. With this and the previous two commits, the production references between host's children form no cycle, and the children stack in layers, each above the children that it references: network, paths, report, seal, and sys; platform; filesystem, nvxs, and process; session and spawn; store; artifacts; launch; supervisor; instance and sandbox; and cli. Part of #897. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved dependency-resolution gaps can hide production cycles, while block-local import leakage can incorrectly reject acyclic graphs.
5 open issues
Adjacent macro expansions hide rooted module dependencies · New String metavariables in serde paths hide dependencies · New Conditional child modules are incorrectly treated as unconditional · New Block-local imports leak into module-level bindings · New Imported globs miss dependencies in declared submodules · New
2 resolved since last review
Review effort: Balanced
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-897-logical-commits-fix
branch
from
October 26, 2026 22:53
3181fc8 to
12becfb
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-897-logical-commits-fix
branch
from
October 26, 2026 23:06
12becfb to
93510dc
Compare
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules and imports by name, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that names or may join a path from a module or from the macro's input, or that holds one in a string, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, as $vis $kind $name { ... } may be mod name { ... }, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules and imports by name, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that names or may join a path from a module or from the macro's input, or that holds one in a string, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules and imports by name, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; in the input of a macro that declares a module in a file of its own, a path = or a macro_use, of which a template may make an attribute of the module; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that names or may join a path from a module or from the macro's input, or that holds one in a string, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules and imports by name, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; in the input of a macro that declares a module in a file of its own, a path = or a macro_use, of which a template may make an attribute of the module, and in that of one that defines a macro, a macro_export outside its own attributes; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file, brings macros into scope, or exports a macro, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules and imports by name, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; in the input of a macro that declares a module in a file of its own, a path or a macro_use, of which a template may make an attribute of the module, and in that of one that defines a macro, a macro_export outside its own attributes; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file, brings macros into scope, or exports a macro, or one that its input completes before a macro_rules!, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, and before a group of an import, as $kind { self as root } may be, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules and imports by name, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; in the input of a macro that declares a module in a file of its own, a path or a macro_use, of which a template may make an attribute of the module, and in that of one that defines a macro, a macro_export outside its own attributes; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file, brings macros into scope, or exports a macro, or one that its input completes before a macro_rules!, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, and before a group that an import may hold, any but an empty one or one with a colon or a dot at its top level, which no import holds, as $kind { $path } may be use { crate::host }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; in the input of a macro that declares a module in a file of its own, a path or a macro_use, of which a template may make an attribute of the module; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, and before a group that an import may hold, any but an empty one or one that holds at its top level a token that no import holds, such as a colon, a dot, or a semicolon, as $kind { $path } may be use { crate::host }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, as $vis $kind $name { ... } may be mod name { ... }, and before a group that an import may hold, any but an empty one or one that holds at its top level a token that no import holds, such as a colon, a dot, a semicolon, or a keyword but as, as $kind { $path } may be use { crate::host }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that an import may hold, any but an empty one or one that holds at its top level a token that no import holds, such as a colon, a dot, a semicolon, or a keyword but as, as $kind { $path } may be use { crate::host }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that may expand to the group of an import, as $kind { $path } may to use { crate::host }, unlike $name { field: value } or $name { $($field: $value),* }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, past any :: before it in the input of a macro that it invokes, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, even past a visibility of its input, which may be empty, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that may expand to the group of an import, as $kind { $path } may to use { crate::host }, unlike $name { field: value } or $name { $($field: $value),* }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, past any :: before it in the input of a macro that it invokes, or that holds one in a string, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, even past a visibility of its input, which may be empty, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, or a block of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that may expand to the group of an import, as $kind { $path } may to use { crate::host }, unlike $name { field: value } or $name { $($field: $value),* }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, or a doc comment in a macro's input, of which Rust makes such a string, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; an identifier that is not ASCII, which Rust takes for any spelling that Unicode's NFC normalization makes alike; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, past any :: before it in the input of a macro that it invokes, or that holds one in a string, or in a doc comment in the input of a macro that it invokes, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, even past a visibility of its input, which may be empty, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, a block, or an expression of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that may expand to the group of an import, as $kind { $path } may to use { crate::host }, unlike $name { field: value } or $name { $($field: $value),* }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, or a doc comment in a macro's input, of which Rust makes such a string, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; an identifier that is not ASCII, in code or in a path of a string or a doc comment, which Rust takes for any spelling that Unicode's NFC normalization makes alike; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, past any :: before it in the input of a macro that it invokes, or that holds one in a string, or in a doc comment in the input of a macro that it invokes, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, even past a visibility of its input, which may be empty, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, a block, or an expression of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that may expand to the group of an import, as $kind { $path } may to use { crate::host }, unlike $name { field: value } or $name { $($field: $value),* }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
The fix of #897 in #910 moved require_artifact and require_existing from host::sandbox into host::artifacts, and the spawn of a VMM from host::supervisor into the private host::spawn. Their documentation still described them from where they had been: require_artifact and require_existing described themselves by sandbox::require_file, which itself calls require_existing, and the module documentation of host described spawn only in its paragraph on the layering of host. The independent fix of #897 in #909, which #910 superseded, worded both more precisely. Take its wording. require_artifact now refers to require_existing, beside it. require_existing states what it checks and how it fails: that the path is a regular file, following links, as require_file of nvx.py checks it, or else the error code that its caller passes and the message `{description} not found: {path}`, with the path spelled with its components alone, as Path::components reads them. The supervisor's entry in the module documentation of host now describes spawn: a private module, whose items supervisor re-exports, that starts the VMM detached, with no other descriptor or handle of the caller's. The paragraph on the layering of host no longer repeats this, and says only that the store builds on spawn. Only documentation changes: the public API, the messages, the error codes, and the tests stay the same. Validation at this commit, on dev: rustdoc with warnings denied; Clippy with warnings denied for all targets with all features, for Windows and Linux; cargo check for macOS; and the tests with all features on Windows (822), and the library's tests with all features on Linux (1237), pass. Part of #897. Part of #896. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 27, 2026
tests/host_modules.rs, which #910 added, keeps the direct children of nvx::host free of cycles. #909, an independent fix of #897 that #910 superseded, had a test that follows more of the code through which a child may name another, and that reports a cycle as #897 asks, with one reference for each of its dependencies. Fold it in, so that the test does what both did. The test now reads the crate's sources from src/lib.rs through every module that the crate declares, in a file of its own or inline, where it read src/lib.rs and the files beneath src/host/ alone, so it sees every module through whose imports a child may name another. A file beneath src/host/ that no mod declares still fails it. It still reads text, with std alone, and blanks comments and literals. It leaves out test-only code: what a cfg that requires test guards, directly, through a cfg_attr that applies attributes, not one in what another attribute takes as its arguments, or as the inner attribute of a module or a file, with the files of the modules that such code declares, and #[test] functions. It no longer takes an inline module for test-only code by its name, tests, alone. It leaves out guarded code only as far as its tokens show where that code ends, as before, and now also leaves out an element of a list, such as a field of a struct expression or a parameter of generics or of a closure, up to its first comma, >, |, or the end of the list, which it counted whole. The input of a macro, which need not be Rust, and whose attributes the macro may keep or drop, is production code throughout: no cfg in it leaves anything out, every path in its tokens counts, from any of them, past a :: before it, however the test reads the rest of it, as in a use tree that the macro takes apart, and so does every path in its strings, even one after doc =, which the macro need not take for documentation; and the test finds there what it refuses wherever it is, as an include! in a use tree, and every module that the input declares in a file of its own. So the test may find a dependency in test-only code, but never misses one in production code. A child depends on another when its production code names a path into the other: a crate::, super::, self::, or self::super:: path, or, now, one from a name that extern crate self as NAME, at the top level of the crate root's file, gives the crate root in the extern prelude, unless the module, defined once, declares a module or crate of that name, or imports one of the crate's modules under it, through modules, imports by name, and names that such a declaration without a cfg gives, in every configuration. Such a declaration in the crate root, which the test refused, is now followed; a child's import of the crate root or host itself still fails it. The path may be in a use tree, an expression, an attribute, or, with its escapes decoded, a string of an attribute or of a macro's input, or a doc comment in a macro's input, of which Rust makes such a string, but not in documentation that an attribute applies outside the input of a macro. It may go through the names that any module outside the children, not only the crate root and host, binds with its imports, by name, under an alias, or with a glob, which the test reads to a fixed point under every configuration, through a module's import of itself, under any alias, as often as a path goes through it, and a child's import of such a module depends on every child that the module's names stand for. A macro that a child exports is still an item of the crate root, in the namespace of macros. Code whose dependencies the test cannot follow fails it: a #[path] attribute anywhere in the crate, where only host's failed it; an identifier that is not ASCII, in code or in a path that the test reads in a string or a doc comment, which Rust takes for any spelling that Unicode's NFC normalization makes alike; include!, under any name that imports may give it, unless a macro_rules! of that name hides it, in the file or in a block, and through a path, which may name it whatever the crate defines; an import of host or the crate root itself in a child; a glob import of a child into a module outside them; a path through imports that alias one another in a cycle that lengthens it, which imports of different configurations may make; an inline module in the input of a macro, which may put the module's code in another module, or an alias of the crate root in the input of one in the crate root, which may join the extern prelude; a module that the input of a macro declares in a file of its own, where the input of a macro or a template holds a path or a macro_use anywhere, of which a template, maybe through other macros, may make an attribute that sets the module's file or brings its macros into scope; a macro_export anywhere in the input of a macro or in a template, of which a template may make an attribute that exports a macro at the crate root, from where the test cannot tell; a #[macro_use] attribute in host; and the template of a macro_rules! that declares or imports, that holds an attribute that sets a module's file or brings macros into scope, that aliases the crate root or a module above it, as $kind {crate as this} may, that names or may join a path from a module or from the macro's input, past any :: before it in the input of a macro that it invokes, or that holds one in a string, or in a doc comment in the input of a macro that it invokes, but documentation outside the input of a macro that it invokes, which resolve where the macro expands, that puts another file's code in with include!, that invokes a macro that its input names, which may be include!, that puts extern before an identifier or a token tree of its input, which may complete extern crate, even past a visibility of its input, which may be empty, that may make a keyword that declares of an identifier of its input, after a visibility of its input or none, or an item, a statement, a block, or an expression of its input, or at the end of a repetition, or anywhere in the input of a macro that it invokes, which may take any part of it for an item, as $vis $kind $name { ... } may be mod name { ... }, and before a group that may expand to the group of an import, as $kind { $path } may to use { crate::host }, unlike $name { field: value } or $name { $($field: $value),* }, or before the token that follows it when a repetition that it ends repeats, as $($kind)* may be use nvx, or that invokes a macro by name under local_inner_macros. A cycle fails the test, which now lists, for each dependency on one, the shortest cycle through it, with the first reference along each of its dependencies, under how to break it, where it listed each strongly connected component. Without a cycle, the children stack in layers, each above those that it depends on, which the test prints with --nocapture. On the dev that #910 fixed, at 12b5613, the test lists 13 cycles, each through one of the three dependencies that #910 removed. On this tree, it finds the same 51 dependencies as #909's test, in the same ten layers as before. The ten tests of #909 run beside the test's twelve, with their fixtures unchanged, in place of the test's previous thirteen: its two tests of the report, of strongly connected components and of one reference for each dependency, give way to one of the shortest cycle through each dependency, and its test of guarded code whose end the tokens do not show is renamed for what it now checks, that such code is test-only no further than its tokens show. Each of the 22 findings of #909's reviews reproduces as a fixture against the test, and passes; eight failed on the test before, and #909's tests pin them. A separate review of the fold, in five rounds, found nineteen more ways to misread code, and its fixes two more, each with a regression fixture that fails on the test before its fix. Two stay on purpose: a path-qualified include! fails the test, whatever it names, and a name that a glob brings in hides no name of the extern prelude, since what a glob brings in depends on visibility, which the test does not read. The module documentation of host and the README's testing section describe the test as it now is. Validation, on dev. The test's 22 tests pass. On Windows, the check-nvx-rs steps that run there pass: rustfmt; Clippy with warnings denied for all targets with all features, for the default-feature library, and for the library without default features; the tests with all features (831), with default features (686), and of the library without default features (201); the artifact-bundling test (18); rustdoc with warnings denied; the Rust 1.89 check; and the runtime adapter's protocol-only (39 tests) and host-only (84 tests) configurations. So do the check-aci-edge-sandboxes steps that run on Windows, with 168 and 89 tests and agent bundling, and the Markdown link check. On Linux, under WSL 2, the Linux steps of both actions pass too: the nvx tests with all features (1405), with default features (670), and of the library without default features (201), artifact bundling (19), the macOS check, the guest binaries' lint, tests (829), and build, the runtime adapter's guest-only configuration (106 tests) besides the others, and aci_edge_sandboxes's tests and its macOS check. Against dev, the lists of tests change only in this test's. Part of #897. Part of #896. Supersedes #909. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
deleted the
agents/issue-897-logical-commits-fix
branch
October 27, 2026 15:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Fixes #897. Part of #896.
The production references between the children of
nvx::hostformed one strongly connected component of eight children:artifacts,filesystem,launch,platform,process,sandbox,store, andsupervisor. This moves the three items that closed it below their users, so the graph is acyclic, and adds a guard test that keeps it acyclic. Behavior and the public API don't change.Commits
Inherited, itsBorrowedalias, and their impls move unchanged fromsupervisor::childinto a new crate-visiblehost::platform::inherit. The Linux, Windows, and other platform modules import it from there, soplatformno longer referencessupervisor.supervisorre-exports it, so its only public path is stillnvx::host::supervisor::Inherited.supervisor/child.rsmoves tohost/spawn.rswithgit mv(97% similarity).storeimportssuper::spawn::Launched, andsupervisorre-exportsLaunched,VmmCommand, andspawnas before. From the new file, the link[launch](super::launch)would silently point at the modulehost::launch, so it is nowcrate::host::supervisor::launch(nvx-rs: break the host module into finer-grained modules #896, invariant 6). The link tospawninInherited's documentation became acrate::path in commit 1.require_artifactandrequire_existingmove unchanged fromsandboxintoartifactsaspub(crate). The publicsandbox::require_filestays and callsartifacts::require_existing.cli/run.rsandcli/sandbox/mod.rsimportrequire_artifactfromartifacts.sandboxno longer needshost::paths, so the sandbox's tests, which reached it throughsandbox, import it themselves.nvx-rs/tests/host_modules.rsis a std-only integration test. It reads the crate's sources, following the module declarations fromsrc/lib.rs, and builds the graph of references as nvx-rs: break the host module into finer-grained modules #896 defines them:crate::,super::, andself::paths, and paths from a name thatextern crate self as NAME;gives the crate root, inusetrees, expressions, attributes, macro inputs, and the string arguments ofserdeattributes such aswith; plus paths through names that modules outside host's children import, by name or with a glob (crate::Artifacts,crate::guest_path,crate::resolve_guest_path). Such a name stands for every child that its imports name, under any configuration and through other such names and aliases, and an import of such a module stands for every child that the module's names and modules stand for. It skips comments, literals, and test-only code: the items, statements, fields, variants, match arms, and parameters thatcfg(test)marks, and the rest of a module or item after an inner#![cfg(test)]. Where it can't tell type arguments from comparisons, it may count test-only code, but it never skips production code. It expands no macros: a macro's input counts as production code, whatever itscfgattributes, with the paths that its strings hold. It fails loudly on what it can't follow instead of missing references:macro_rules!templates that declare or import, that name or may join a path from a module, a metavariable, or a repetition, or hold one in a string, that expand a token tree, or that complete aserdeattribute with a metavariable;#[path]attributes, conditional or not; glob imports of host's children; and imports that bind the crate root orhostitself, under any name, in host's children. On a cycle, it lists the shortest cycle through each edge that lies on one, with the first reference along each edge. Ten self-tests on synthetic crates pin what counts as a reference, where test-only code ends, the children that imports and aliases stand for, the refusals, and the report format. The test runs in check-nvx-rs's existingcargo teststeps, with no new dependency and no workflow change. The nvx-rs README anddoc/ci.mdmention it.Each commit passes fmt, Clippy, the Linux cross-check, and rustdoc with
-D warningson its own.Resulting layers
cargo test --test host_modules -- --nocaptureprints these layers, the same on Windows and Linux. They match the table in #897, withpathsin place ofpython, which #911 deleted.network,paths,report,seal,sysplatformfilesystem,nvxs,processsession,spawnstoreartifactslaunchsupervisorinstance,sandboxcliValidation
devand green here. With the guard added todev(12b56130), it fails and lists 13 cycles through the three back-edges (output below). After the three moves, it passes.RUSTC_BOOTSTRAP=1 cargo rustdoc --lib --all-features -- -Z unstable-options --output-format json) fordevand this branch onx86_64-pc-windows-msvcandx86_64-unknown-linux-gnu. A script walked it from the crate root through public modules and re-exports, globs included. For each reachable path it recorded the item's signature, generics, public fields, variants, inherent methods, and trait impls, with item IDs replaced by canonical paths and spans and docs ignored. The output is identical: 453 paths on Windows and 583 on Linux, 0 differences.cargo test -- --listwith all features and with default features betweendevand this branch. On Windows, the only change is the guard's eleven new tests. On Linux, the four Linux-only testshost::supervisor::child::tests::*becomehost::spawn::tests::*, and the guard adds its eleven tests. Nothing else changes. The coverage families and theartifactsbundling filter select the same tests.--lib, and--no-default-features, and with all features forx86_64-unknown-linux-gnu; tests with all features (700 library tests), with default features, and with no default features, all passing; rustdoc with-D warnings; the 1.89 MSRV check; and the macOS cross-check. On Linux (WSL): the library tests with all features, 1,237 passing, including the fourhost::spawntests.python scripts/check_markdown_links.pypassed.The guard on
dev(12b56130)Coordination with the template stack
At its head, the template and clone stack (#879 … #888) adds
host::template. Even with these moves,store → template(template::Lease) andsandbox → template(template::BlockGeometry) close a cycle, as #897 notes. If this PR lands first, the guard names those edges when the stack rebases.