Skip to content

nvx-rs slimming 2.4.2: activation holds no fence, and a capture is one guest call #1105

Closed

Description

Parent: #1082, in #1076. Needs: #1101, #1104. Unblocks: #1115, #1117, #1118, #1120, #1123, #1127, #1130, #1131.

Goal. guest::clone becomes guest::activation: Activation holds no fence, and apply starts no process and reports the publication and the gateway, so the init starts the announcer itself. A capture is one guest call, guest::snapshot::capture, which returns Continued or Restored(Repaired), or a CaptureFailure whose disposition is Resumed or MustEnd { status }.

Notes.

PRs, in order. Each PR has one goal, leaves dev green, and names in its description each old test of its area as kept, rewritten or retired, with each change that check_test_changes.py reports. Its tests follow the repository's test layout: a module's unit tests, and the code that only they use, sit in its tests.rs or tests/ and move with it. The estimates count core lines (code, not comments, docs or tests) and counted files; each PR records its measured values. Each PR does what its Scope says and no more: a case, input or layout that its Scope doesn't name, and whatever "Not in this PR" lists, is out of scope. Address every review comment within the scope, and ask before acting on one that asks for more. A PR whose measured core lines pass the stop that its Estimate names (twice the estimate, at most 600) stops and asks before continuing.

  1. SL7.3: Activation starts no process, and holds no fence.

    • Objective: Activation becomes a sans-I/O state machine with no admission fence, while applying an accepted record starts no process. The caller receives the publication and gateway needed to start ingress itself, and the root retains ownership of the view's binds.
    • Contents: guest::clone becomes guest::activation, with an alias until SL5.2. Activation drops its fence; apply uses view::apply with the record's DNS server and starts no announcer; Applied reports the publication and the gateway, loses announcer and announcer_mut (NetworkError loses its Announcer variant, and apply's system seam its announce and stop, so nothing but nvx-ingress start uses Announcer), and its into_parts returns (Root, MachineId), since the root holds the view's binds. The test adapter follows.
    • Scope:
      • Rename guest::clone to guest::activation, retaining a guest::clone alias until SL5.2; update the test adapter.
      • Remove the fence parameter and state from Activation.
      • Make activation application call view::apply with the record's DNS server and stop starting or stopping an announcer.
      • Add Applied::{publication, gateway}, remove announcer and announcer_mut, and make into_parts return (Root, MachineId).
      • Remove the announcer variant from NetworkError and the announce and stop operations from the application system seam.
    • Not in this PR:
      • Starting nvx-ingress from activation or adding a replacement process spawner: the init owns that work.
      • Deleting Announcer, PROGRAM or StartError; nvx-ingress start still uses them until SL6.13c.
      • Removing the guest::clone alias before SL5.2 deletes the test adapter.
      • Redesigning activation inputs, actions or transport behavior beyond removing the fence.
    • Approach: Rename the module with a temporary alias, delete the fence plumbing, and return the record's existing publication plus the template's gateway through Applied. Delegate view files to view::apply and remove only announcer-specific seam code; do not add a process callback or replacement fence abstraction.
    • Done when:
      • Activation holds no fence, and tests that encoded fence closing or opening are rewritten or retired by name.
      • Activation application starts no process and performs no announcer start or stop.
      • Applied::publication reports the record's publication, and Applied::gateway reports the template gateway.
      • Applied::into_parts returns (Root, MachineId), with the root retaining the view binds.
      • The test adapter builds through the temporary guest::clone alias.
    • Needs: SL7.2, in nvx-rs slimming 2.4.1: the guest's space becomes reference code, with runtime mounts, one switch and the view #1104; SL2.5b, in nvx-rs slimming 2.3.1: activation record v2 carries only what the guest applies #1101.
    • Estimate: 250 core lines, 3 counted files. Past 500 core lines, stop and ask before continuing.
  2. SL7.4a: A Fresh capture is one guest call.

    • Objective: A Fresh guest capture becomes one bounded call that performs the pre-request checks and reports whether the guest resumed or must end. It replaces the separate preparation and barrier protocol without freezing or inspecting caller-owned executions.
    • Contents: guest::snapshot::capture(devices: &Devices, disks: Disks, deadline: Instant) -> Result<Captured, CaptureFailure>, with the non-exhaustive Disks::Fresh: the mount checks, the time ABI's checks, the stall detectors, the generation ID and the request, with every step and wait before the request, the runtime lock's included, bounded by deadline; the request itself has no deadline. Its checks are strict: a violation of the time ABI's checks returns MustEnd with the violation's status, instead of stopping the VM. It neither freezes nor checks the guest's executions. Captured; CaptureFailure { stage, cause, disposition }, with the non-exhaustive CaptureStage, CaptureCause, and Disposition::{Resumed, MustEnd { status }}; a PortRelease at any stage is MustEnd, and keeps its cause. Devices, which names the devices by their MMIO windows instead of the space's Device, Mounted (origin, mount_point), Origin and MOUNT_TABLE_LIMIT move from activation into guest::snapshot. Disks::Fresh refuses a restore packet that carries network settings, which a platform restore never has, instead of dropping them; the repair uses the time core's host-clock correction as it is.
    • Scope:
      • Add guest::snapshot::capture(&Devices, Disks, deadline) -> Result<Captured, CaptureFailure> with non-exhaustive Disks::Fresh and Captured::Continued.
      • Run mount checks, strict time checks, stall-detector suppression, generation-ID reading and the capture request; bound every step and wait before the request, including the runtime lock, by deadline.
      • Leave the request itself without a deadline.
      • Add staged failures with CaptureFailure, non-exhaustive CaptureStage and CaptureCause, and Disposition::{Resumed, MustEnd { status }}. A strict time violation or PortRelease is MustEnd, and PortRelease stays the cause. Other pre-request failures are Resumed after successful detector restoration and MustEnd if restoration fails; request and release failures are MustEnd.
      • Move Devices, Mounted, Origin and MOUNT_TABLE_LIMIT from activation to snapshot; name devices by their MMIO windows, and reject Fresh restore network settings.
      • Document the caller's transport rule: after answering the capture request, send nothing until capture returns; after Continued or a Resumed failure, report on the same session.
    • Not in this PR:
      • Repairing a restored guest or returning Restored(Repaired); SL7.4b adds that final part.
      • Freezing, counting or validating guest executions: their caller keeps them still.
      • Deadlining the capture request while the host saves stopped processors.
      • Additional disk modes beyond non-exhaustive Disks::Fresh, or a general device-discovery abstraction.
      • Silently dropping restore network settings: a Fresh platform restore never carries them and this call refuses them.
    • Approach: Compose the existing mount checks, time checks, suppression, generation-ID and request code inside one snapshot function, using one caller deadline only before the request. Move the existing data types rather than wrapping them, and map existing failures directly to a stage, cause and disposition; do not add execution control or a capture coordinator.
    • Done when:
      • capture returns Captured::Continued when no snapshot was taken and the guest may continue.
      • Each pre-request step and wait, including the runtime lock, honors the caller's deadline; the request has no deadline.
      • Each failure reports its stage and disposition, and a strict time violation returns MustEnd with its status.
      • A PortRelease at any stage is MustEnd and remains the cause even when rollback also fails.
      • Fresh capture refuses restore network settings and neither freezes nor checks executions.
    • Needs: SL7.3, above.
    • Estimate: 400 core lines, 4 counted files. Past 600 core lines, stop and ask before continuing.
  3. SL7.4b: A restore is repaired before capture returns.

    • Objective: A restored guest is fully repaired before the single capture call returns. Successful restores return the repaired generation, CPU, memory and acknowledgement data; a repair failure tells the caller that the guest must end.
    • Contents: Captured::Restored(Repaired): the repair runs inside capture, and its failure is MustEnd { status }. Repaired (generation_id, cpus, memory, acknowledged_at) and the repair's failure detail (RepairError, RepairCause, RepairStage, RangeFault, RepairProgress) move from activation into guest::snapshot.
    • Scope:
      • Extend Captured with Restored(Repaired) and run the existing repair inside guest::snapshot::capture.
      • Move Repaired, with generation_id, cpus, memory and acknowledged_at, from activation into guest::snapshot.
      • Move RepairError, RepairCause, RepairStage, RangeFault and RepairProgress with the repair implementation into snapshot.
      • Map every repair failure to CaptureFailure with Disposition::MustEnd { status }.
      • Document the restored transport rule: after capture returns Restored, take the session's reset and attach again before receiving the activation record.
    • Not in this PR:
      • Changing repair order, retry behavior, status selection, CPU or memory operations: this PR moves the existing repair behind capture.
      • Returning an unrepaired restore or exposing a separate public repair step.
      • Changing the Fresh pre-request checks, deadline rules or PortRelease handling added by SL7.4a.
      • Renaming or cleaning up the repair types while moving them.
    • Approach: Call the existing repair immediately after the capture result identifies a restore, then return its existing Repaired value from Captured. Move the repair types intact and translate its current status into MustEnd; do not create another repair state machine, callback or public intermediate result.
    • Done when:
      • capture returns Captured::Restored(Repaired) only after inline repair succeeds.
      • The returned value reports the repaired generation ID, CPU count, memory size and acknowledgement time.
      • Every repair failure is returned as MustEnd { status }.
      • Tests that called repair separately are rewritten or retired, while their repair-result and failure coverage remains.
    • Needs: SL7.4a, above.
    • Estimate: 200 core lines, 2 counted files. Past 400 core lines, stop and ask before continuing.

Tests. capture returns Captured::Continued when no snapshot was taken, and the guest goes on; on a restore, it returns Captured::Restored(Repaired) only once the inline repair has succeeded, and Repaired::{generation_id, cpus, memory, acknowledged_at} report that repair. Each capture stage's failure has its disposition. A PortRelease at any stage is MustEnd, and keeps its cause, even if a rollback also fails. Every step and wait before the request, the runtime lock's included, honors the deadline, and the request itself has none. A violation of the time ABI's checks returns MustEnd with the violation's status, instead of stopping the VM. The repair runs inside capture, and its failure is MustEnd. Activation holds no fence; apply starts no process; Applied::publication reports the record's publication, and Applied::gateway the RootTemplate's gateway; and Applied::into_parts returns (Root, MachineId), while the root keeps the view's binds. The tests that encode the fence, the announcer's start or the separate repair are rewritten or retired by name, for example a_clone_bootstraps_takes_one_activate_and_opens_the_fence_once_ready, a_network_that_publishes_the_workload_s_listeners_starts_their_announcer_to_its_gateway, the_fence_closes_before_the_checks_and_the_detectors_are_suppressed_before_the_capture, a_restored_clone_gets_the_fence_closed_with_the_detectors_suppressed and a_clone_is_reseeded_then_acknowledged_once_and_reentry_returns_the_same_clone. The test adapter follows the rename.

Done when: every PR above has merged, with dev green.

Activity

  1. esaurez commented on Nov 10, 2026

    @esaurez
    ContributorAuthor

    Workstream source/progress checkpoint - 2026-11-10 UTC

    Checked boxes below mean merged scope, not merely an implemented first iteration. Implementation branches are source checkpoints, not automatic qualification, Ready or merge approval. Some starting inputs are frozen/anonymous commits rather than standalone branches; their exact SHAs and known merged producer refs are recorded explicitly.

    The original technical scope remains authoritative, supplemented only by any portable technical clarification in this issue. No machine-specific execution policy is part of this checkpoint.

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

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions