Repository navigation
nvx-rs: run the managed agent on the shared NVXS session's guest role - #639
Merged
Enrique Saurez (esaurez) merged 2 commits intoOct 20, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No blocking issues were identified in the session integration, descriptor writes, or updated control paths and regression tests.
No open issues 🎉
What changed in this PR
Moves the managed agent onto the shared NVXS guest session from #627, advancing #619 while retaining NVXC framing and broker-facing diagnostics.
Changes:
- Replaces inline NVXS handling with
GuestConnection. - Adapts dispatch and execution to session events and adds unbuffered descriptor writes.
- Adds regression tests for rejected records, stream closure, and resets; updates documentation.
| File | Description |
|---|---|
nvx-rs/src/guest/sys/fd.rs |
Implements unbuffered std::io::Write. |
nvx-rs/src/guest/mod.rs |
Documents descriptor write conventions. |
nvx-rs/src/guest/managed_agent/session.rs |
Wraps the shared session and maps diagnostics. |
nvx-rs/src/guest/managed_agent/mod.rs |
Updates the session module comment. |
nvx-rs/src/guest/managed_agent/exec.rs |
Handles session events during execution. |
nvx-rs/src/guest/managed_agent/dispatch.rs |
Uses session events and expands regression tests. |
nvx-rs/README.md |
Documents managed-agent use of GuestConnection. |
Review effort: Balanced
Enrique Saurez (esaurez)
marked this pull request as ready for review
October 20, 2026 16:09
Enrique Saurez (esaurez)
force-pushed
the
esaurez/a1-guest-g6-nvxs-session-20261020
branch
from
October 20, 2026 21:06
2be2c7d to
dd171e2
Compare
The managed agent decoded the control session's NVXS records itself, and tracked the broker's sequence numbers, the session's identity and the receive credit inline with NVXC decoding. Move it onto the guest role of the shared session, nvx::guest::nvxs::GuestConnection, so that the agent keeps only the NVXC frames that DATA records carry. Records that the shared session refuses report the stages and statuses that the agent reported before. The session also refuses records that OpenVMM's broker never sends: a RESET that neither names a new instance nor advances the epoch, DATA before the first RESET, and DATA beyond the receive window. FileDescriptor implements std::io::Write, without buffering, so that the connection writes the control console directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 086f45a6-c39c-4704-85ef-1fa7f8b8b672
Enrique Saurez (esaurez)
force-pushed
the
esaurez/a1-guest-g6-nvxs-session-20261020
branch
from
October 20, 2026 22:46
dd171e2 to
6af062f
Compare
The shared NVXS session refuses a record that takes the last sequence number of its direction, because none is left for the next record, but its SequenceOverflow error did not say which record that was. The managed agent therefore reported DATA at the last sequence number, which can follow a RESET at the second-to-last one, at the stage of a refused RESET, reset-ack, and without exec-record while a workload ran. SequenceOverflow now carries the type of the record that ran out of sequence numbers, as Unexpected and MissingIdentity do, and the agent reports DATA at the last sequence number as DATA out of sequence, at data-sequence with the record's sequence number. The C agent took such a record and expected sequence number 0 next. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 086f45a6-c39c-4704-85ef-1fa7f8b8b672
Enrique Saurez (esaurez)
deleted the
esaurez/a1-guest-g6-nvxs-session-20261020
branch
October 20, 2026 23:51
This was referenced Oct 21, 2026
This was referenced Oct 21, 2026
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.

The managed agent decoded the control session's NVXS records itself: it checked each record's header, tracked the broker's sequence numbers, the session's identity and the receive credit, and did all of it inline with
NVXCdecoding. This PR moves the agent onto the guest role of the shared NVXS session from #627,nvx::guest::nvxs::GuestConnection. The agent now keeps only theNVXCframes that DATA records carry. The wire format is unchanged, and so are the agent's records and diagnostics for everything that OpenVMM's broker sends.Part of #619
Refs #535
What changed
guest::managed_agent::session:Sessionwraps aGuestConnectionover the control console's descriptor.next_eventreturns the broker's RESET or a DATA payload.acknowledgeanswers a RESET with NVX's receive window.accept_requestdecodes theNVXCrequest, then credits the payload back before the agent serves it, as before.send_appsends each frame in one DATA record, and refuses a frame that one record cannot hold.outer-read,outer-type,reset-ack,data-sequence,data-identity,data-applicationordata-credit, thendata. The diagnostics that the host and the tests read stay the same.dispatchandexectake events from the session instead of decoding records. Their stage reporting is now inreport_failureandreport_control_failure.protocol::nvxs:SessionError::SequenceOverflownames the type of the record that ran out of sequence numbers, asUnexpectedandMissingIdentitydo, so that the agent can tell DATA from a RESET at the last sequence number.guest::sys::FileDescriptorimplementsstd::io::Write, with onewritesystem call per call and no buffering, so the connection writes the control console directly.std::io::Writeimplementation, and the crate README'snvx::guest::nvxsrow names the managed agent as a user.Behavior
The shared session checks a few things that the agent didn't, in records that OpenVMM's broker never sends:
reset-ackinstead of being acknowledged.data-sequence, because it leaves no sequence number for the broker's next record.outer-type5, instead of a sequence or identity failure.data-window. The agent credits each record back before it serves it, so the broker never sends such a record.Sizes
I built the guest binaries and the Alpine initramfs natively on Linux, the same way at #629's head, d4ab821, which
devmerged as 401c95a with the same guest inputs, and with this change on top of it. The binaries use theguestprofile, which strips them.nvx-managed-agentinitramfs.cpio.gz(Alpine)The other guest binaries keep their sizes.
Not in this PR
#619 also gives G6 the runtime adapter's guest half: the adapter's own framing over the guest role. That follows in #640, stacked on this one.
Validation
nvx-rsCLI built from the same tree:python scripts\nvx.py test-microvm --backend whp, the default suite. Every scenario passes. That includesmanaged-lifecycle, which covers authenticated sessions, reconnects across a reset, refused working directories, the workload identity and stop.--scenario managed-exec-config --scenario sandbox-lifecycle. Both pass.dev's own initramfs too, in 5 of 8 runs, so where it stopped the suite, I ran the remaining scenarios on their own, and managed-lifecycle again until it passed. One earlier run on this change also stopped when the host's IPv6 egress probe server failed, in a scenario whose guest runs shell probes without the agent; that scenario passes in every other run.nvx-rswithNVX_BUNDLE=skip:cargo fmt --all --checkcargo clippy --locked --all-targets --all-features -- -D warningscargo clippy --locked --lib --no-default-features -- -D warningscargo test --locked --all-features, thencargo test --lockedbundledtestcargo doc --locked --no-deps --all-features, withRUSTDOCFLAGS=-D warningscargo +1.89 check --locked --all-targets --all-featurescargo check --locked --all-targets --all-features --target aarch64-apple-darwinpython3 scripts/nvx.py check-guest-binaries --toolchain 1.95.0build-guest-binaries, thentest-guest-binariescheck-nvx-rsruns them: protocol-only and host-only on both OSes, and guest-only on Linux.aci_edge_sandboxes, on both OSes: its fmt, Clippy, test, doc and MSRV steps, andtest-agent-bundling. On Linux, its macOS check too.python scripts/nvx.py verifyandpython scripts/check_markdown_links.py.Everything passes except one environmental failure on Linux, where my shell runs as root. The CLI golden test's caller-owned-share scenario refuses its temporary share because UID 0 owns it, as
--mount-owner callerrequires.devfails the same way there, and CI runs the test unprivileged.I didn't run KVM or MSHV myself: this machine's nested KVM can't boot OpenVMM's built-in CPU profile. CI runs the KVM, MSHV and WHP matrix, which adds the public sandbox acceptance and managed-lifecycle on the Ubuntu and Azure Linux guests, built from this change.