A contract here is a shared value shape or port that another source module interprets: domain enums, execution requests and results, and transport interfaces. Opaque service handles and simple re-exports are not included in the detailed inventory. The declaration boundaries are the domain, protocol, and application layers. crates/microvms-domain/src/error.rs:167, crates/protocol/src/exec.rs:219, crates/microvms-app/src/control/transport.rs:386.
Sections are ordered by distinct directly consuming production source paths found in the current tree, with related wire shapes grouped together. Test fixtures, fuzz harnesses, and re-export-only references do not contribute to ordering. Consumer citations identify imports or use sites; assumptions cite the code that interprets the shape. The source paths identify the owning layer even when adapters import the public re-exports. crates/microvms-core/src/lib.rs:97-100, crates/microvms-app/src/session/mod.rs:51-62.
ErrorKind: coarse failure classes
Section titled “ErrorKind: coarse failure classes”Producer: crates/microvms-domain/src/error.rs:166-201
Consumer(s):
bindings/microvms-js/src/errors.rs:70bindings/microvms-js/src/provision.rs:66bindings/microvms-js/src/session.rs:38bindings/microvms-py/src/errors.rs:28bindings/microvms-py/src/sandbox.rs:48bindings/microvms-py/src/session.rs:57crates/microvms-app/src/agents/mod.rs:48crates/microvms-app/src/control/artifact.rs:30crates/microvms-app/src/control/ensure.rs:54crates/microvms-app/src/control/image.rs:30crates/microvms-app/src/control/microvm.rs:50crates/microvms-app/src/control/mod.rs:115crates/microvms-app/src/control/project.rs:10crates/microvms-app/src/control/transport.rs:36crates/microvms-app/src/entropy.rs:27crates/microvms-app/src/names.rs:18crates/microvms-app/src/sandbox.rs:72crates/microvms-app/src/session/exec.rs:39crates/microvms-app/src/session/http.rs:133crates/microvms-app/src/session/keepalive.rs:37crates/microvms-app/src/session/mod.rs:64crates/microvms-app/src/session/proxy.rs:72crates/microvms-app/src/session/sse.rs:26crates/microvms-app/src/workspace.rs:32crates/microvms-cli/src/cli.rs:806crates/microvms-cli/src/commands/agent.rs:36crates/microvms-cli/src/commands/attached.rs:43crates/microvms-cli/src/commands/lifecycle.rs:36crates/microvms-cli/src/commands/local.rs:644crates/microvms-cli/src/exit.rs:50crates/microvms-cli/src/seam.rs:49crates/microvms-domain/src/names.rs:22crates/microvms-domain/src/provision.rs:8crates/microvms-edges/src/agents/bedrock.rs:41crates/microvms-edges/src/control/project.rs:11crates/microvms-edges/src/control/services.rs:33crates/microvms-edges/src/control/transport.rs:13crates/microvms-edges/src/entropy.rs:8crates/microvms-edges/src/identity.rs:9crates/microvms-edges/src/names.rs:14crates/microvms-edges/src/provision.rs:89crates/microvms-edges/src/session/forward.rs:88crates/microvms-edges/src/session/http.rs:48crates/microvms-edges/src/session/serve.rs:38crates/microvms-edges/src/session/shell.rs:54crates/microvms-edges/src/session/tunnel.rs:64
Shape:
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub enum ErrorKind { /// No handler claimed this — a bug in this crate, not the platform. Unexpected, /// Refused locally, before any AWS call. Every trap closure lands here. InvalidArg, /// Transient. Run the identical request again. Retryable, /// An identity is wrong or absent; waiting will not fix it. Credentials, /// The daemon rejected the request on its merits. Protocol, /// The image build was never scheduled — the `clientToken` replay signature. BuildWedged, /// The MicroVM reached a terminal state before RUNNING; read `stateReason`. LaunchDied, /// The MicroVM ended before the resume (the suspended window, the maximum duration, or a /// terminate), and it can't be resumed; launch a new one. The service refused the resume, /// and `GetMicrovm` reports the VM TERMINATING or TERMINATED. WindowClosed, /// A control-plane failure with no more specific class. Platform, /// A client-side deadline elapsed. The VM and the exec are untouched. Timeout, /// Interrupted after launch; teardown ran and any leak is named in the payload. Interrupted, /// A prerequisite is missing. Precondition, /// The sandbox worked and the command in it exited non-zero. /// /// Its own class because it is the one failure that means nothing is wrong with /// the platform, the credentials, or this client — a CI caller needs to tell /// "your tests failed" from "we never got a VM", and one shared class cannot say /// both. ExecFailed,}Assumptions consumers make:
- The CLI and Python binding match every variant to their own exit or exception representation.
crates/microvms-cli/src/exit.rs:172-187,bindings/microvms-py/src/errors.rs:132-147. - The Node catalog enumerates
ALLand derives code strings from each item; catalog membership depends on that array as well as the enum.bindings/microvms-js/src/errors.rs:198-202.
Drift risk: A variant change affects exhaustive adapters, while a catalog change affects enumeration independently. crates/microvms-cli/src/exit.rs:172-187, bindings/microvms-js/src/errors.rs:198-202.
Mitigation: review the enum, ALL, code strings, and adapter mappings together. crates/microvms-domain/src/error.rs:203-253.
Region: endpoint and pricing selection
Section titled “Region: endpoint and pricing selection”Producer: crates/microvms-domain/src/region.rs:56-151
Consumer(s):
bindings/microvms-js/src/agents.rs:37bindings/microvms-js/src/region.rs:25bindings/microvms-py/src/agents.rs:40bindings/microvms-py/src/control.rs:522bindings/microvms-py/src/region.rs:24bindings/microvms-py/src/sandbox.rs:48crates/microvms-app/src/adapters.rs:27crates/microvms-app/src/agents/mod.rs:49crates/microvms-app/src/agents/profile.rs:18crates/microvms-app/src/control/artifact.rs:435crates/microvms-app/src/control/connector.rs:40crates/microvms-app/src/control/mod.rs:136crates/microvms-app/src/control/transport.rs:37crates/microvms-app/src/names.rs:19crates/microvms-app/src/preflight.rs:40crates/microvms-app/src/sandbox.rs:73crates/microvms-cli/src/cli.rs:46crates/microvms-cli/src/commands/agent.rs:647crates/microvms-cli/src/commands/attached.rs:112crates/microvms-cli/src/commands/doctor.rs:17crates/microvms-cli/src/commands/mod.rs:623crates/microvms-cli/src/config.rs:463crates/microvms-cli/src/seam.rs:49crates/microvms-core/src/lib.rs:159crates/microvms-core/src/prelude.rs:36crates/microvms-domain/src/cost.rs:71crates/microvms-domain/src/names.rs:24crates/microvms-domain/src/preflight.rs:12crates/microvms-edges/src/adapters.rs:13crates/microvms-edges/src/agents/bedrock.rs:42crates/microvms-edges/src/control/services.rs:34crates/microvms-edges/src/control/transport.rs:14
Shape:
#[derive(Clone, Debug, Eq, Hash, PartialEq)]pub enum Region { #[deprecated(since = "1.3.0", note = "use `Region::US_EAST_1`; ...")] UsEast1, // UsEast2, UsWest2, EuWest1 and ApNortheast1, each deprecated the same way /// Any region outside the five above, by name. #[deprecated(since = "1.3.0", note = "parse the name ... and read it with `as_str`; ...")] Unlisted(String),}
impl Region { pub const US_EAST_1: Region = Region::UsEast1; // US_EAST_2, US_WEST_2, EU_WEST_1 and AP_NORTHEAST_1}
/// The regions AWS was measured running MicroVMs in: the 14 the Pricing API priced on/// 2026-10-24, in the order AWS launched them.pub const MEASURED_REGIONS: [&str; 14] = [/* "us-east-1", ... "eu-south-2" */];Assumptions consumers make:
- Consumers read a region with
as_strand compare regions by value. The deprecated variants appear only inregion.rs.crates/microvms-domain/src/region.rs:163-174. - The CLI parses
--regionwith core’sFromStrand doesn’t keep a region table of its own.--unlisted-regionis a deprecated spelling of the same flag.crates/microvms-cli/src/cli.rs:540-592. - The Python and Node
parsedelegate toFromStr, and the named factories return the domain constants.bindings/microvms-py/src/region.rs:40-165,bindings/microvms-js/src/region.rs:40-150. - The null-message denial classifier reads
is_measuredto decide whether to name the region or the IAM policy as the likely cause.crates/microvms-app/src/control/transport.rs:622-645. - Pricing retains the selected region in its rate table and exposes it by reference.
crates/microvms-domain/src/cost.rs:846-865.
Drift risk: MEASURED_REGIONS, the drift script’s PINNED_REGIONS, and the live-rates script’s MICROVM_REGIONS change together when AWS launches a region. A stale list refuses no region. It makes a null-message denial there cite the region as a cause, and it puts the wrong regions in the live-rates script’s empty-catalog message. crates/microvms-domain/src/region.rs:121-136, tools/check-model-drift.py:201-221, tools/check-live-rates.py:87-102.
Mitigation: tools/check-model-drift.py holds the emitted list equal to its pinned literal, and holds the deprecated MICROVM_REGIONS to the five. No check compares the list with AWS, so growing it follows a fresh Pricing API measurement recorded in docs/PLATFORM.md. tools/check-model-drift.py:977-997.
WireKind: specific daemon and transport outcomes
Section titled “WireKind: specific daemon and transport outcomes”Producer: crates/microvms-domain/src/error.rs:269-326
Consumer(s):
bindings/microvms-js/src/errors.rs:208bindings/microvms-py/src/errors.rs:176crates/microvms-app/src/agents/mod.rs:539crates/microvms-app/src/control/microvm.rs:390crates/microvms-app/src/session/complete.rs:18crates/microvms-app/src/session/exec.rs:39crates/microvms-app/src/session/files.rs:18crates/microvms-app/src/session/http.rs:33crates/microvms-app/src/session/mod.rs:64crates/microvms-app/src/session/proxy.rs:72crates/microvms-app/src/session/split.rs:57crates/microvms-app/src/session/sse.rs:26crates/microvms-app/src/workspace.rs:32crates/microvms-cli/src/exit.rs:50crates/microvms-edges/src/session/http.rs:13
Shape:
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub enum WireKind { /// 401: the presented bearer token is not the installed one. Fatal. Unauthorized, /// 400: malformed body, missing query key, bad mode, refused tar member. /// /// Never 404. A 404 here reads as a missing file, which is exactly how one /// defect hid for a review round. ProtocolError, /// 404: a genuinely absent exec id, file, or directory. NotFound, /// 409: well-formed, but the target is in the wrong state. Conflict, /// 410: stdin already saw EOF, or the child stopped reading. /// /// Distinct from [`WireKind::Conflict`], which is "you did not ask for stdin" /// and is fixed at start time. This one is a lifecycle fact. StdinClosed, /// 413: over a configured cap (body, tar members or bytes, stdin write). TooLarge, /// 408: the child did not drain its stdin pipe within the write timeout. /// /// Retryable, and the daemon deliberately keeps its stdin handle open so a /// retry can succeed. Some bytes may already have landed; reconciling that is /// the caller's problem, which is why it is a distinct variant. RequestTimeout, /// 503: the run hook has not landed, so the control API is closed. /// /// Not 404 and not a dropped connection. Retry: the platform is about to /// deliver the token. NotBootstrapped, /// 5xx other than 503 and 507: spawn failure, io failure, a panicking task. ServerError, /// 507: a write would take the target filesystem under the daemon's disk reserve. /// /// Not retryable, and that's why the daemon answers 507 rather than 500 /// (`crates/agentd/src/fs.rs`): an identical retry against a full disk fails the /// same way, and a retry loop keyed on a 5xx would repeat it. The body names the /// free and reserved bytes. The remedy is freeing space, then retrying. InsufficientStorage, /// The request never produced a status: connection refused, reset, timeout. /// /// Retryable because it says nothing about the daemon's state. A VM that has /// just reached RUNNING commonly refuses a connection or two before the proxy /// path is wired up. Transport, /// `CreateMicrovmAuthToken` failed. /// /// Retryable, and load-bearing rather than optimistic: proxy tokens expire at /// 60 minutes, so a long run *will* mint mid-flight, and a throttle at that /// moment must not kill a trial that is otherwise healthy. AuthTokenMint, /// A client-side wait or stream deadline elapsed. The exec is untouched. ExecTimeout, /// Output bytes are gone for good — the replay ring evicted them, or this /// subscriber lagged the live channel. OutputGap,}Assumptions consumers make:
- An unrecognized HTTP status becomes a coarse protocol failure; the client does not guess the nearest named wire condition.
crates/microvms-app/src/session/http.rs:113-133. - File existence maps only
NotFoundtofalse; other failures propagate.crates/microvms-app/src/session/files.rs:119-124. - Completion retries retryable failures but handles
ExecTimeoutthrough its deadline path.crates/microvms-app/src/session/complete.rs:156-161,crates/microvms-app/src/session/complete.rs:239-256.
Drift risk: Changing a status mapping can alter absence handling and retry decisions without changing request signatures. crates/microvms-app/src/session/files.rs:119-124, crates/microvms-app/src/session/complete.rs:239-256.
Mitigation: review consumers that branch on the affected variant alongside its mapping. crates/microvms-domain/src/error.rs:373-438.
SizeClass: discrete resource selection
Section titled “SizeClass: discrete resource selection”Producer: crates/microvms-domain/src/sizing.rs:118-125
Consumer(s):
bindings/microvms-js/src/cost.rs:41bindings/microvms-py/src/cost.rs:67bindings/microvms-py/src/sandbox.rs:44crates/microvms-app/src/agents/mod.rs:52crates/microvms-app/src/control/ensure.rs:55crates/microvms-app/src/control/image.rs:31crates/microvms-app/src/control/mod.rs:137crates/microvms-app/src/defaults.rs:28crates/microvms-cli/src/cli.rs:46crates/microvms-cli/src/commands/agent.rs:637crates/microvms-domain/src/cost.rs:72
Shape:
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub enum SizeClass { Mib512, Mib1024, Mib2048, Mib4096, Mib8192,}Assumptions consumers make:
- The CLI maps its memory arguments to exact enum variants.
crates/microvms-cli/src/cli.rs:463-479. - The cost calculation uses baseline CPU and memory accessors.
crates/microvms-domain/src/cost.rs:1586-1605. - The Node binding converts JavaScript numbers before delegating class selection to the domain.
bindings/microvms-js/src/cost.rs:374-400.
Drift risk: Changing the baseline meaning would change pricing and image identity for existing variants. crates/microvms-domain/src/cost.rs:1586-1605, crates/microvms-app/src/control/ensure.rs:166-184.
Mitigation: keep the resource table, conversion methods, and adapter mappings consistent. crates/microvms-domain/src/sizing.rs:139-155, crates/microvms-cli/src/cli.rs:463-479.
StartRequest: starting an exec
Section titled “StartRequest: starting an exec”Producer: crates/protocol/src/exec.rs:217-299
Consumer(s):
bindings/microvms-js/src/session.rs:303bindings/microvms-py/src/session.rs:606crates/agentd/src/exec.rs:89crates/agentd/src/exec_start.rs:63crates/agentd/src/routes.rs:601crates/microvms-app/src/agents/mod.rs:510crates/microvms-app/src/defaults.rs:37crates/microvms-app/src/session/complete.rs:98crates/microvms-app/src/session/mod.rs:520crates/microvms-app/src/workspace.rs:374crates/microvms-core/src/lib.rs:192
Shape: Source documentation comments omitted.
#[derive(Debug, Deserialize, JsonSchema, Serialize)]#[non_exhaustive]pub struct StartRequest { pub exec_id: String, pub command: Vec<String>, #[serde(default)] pub shell: Shell, #[serde(default)] pub cwd: Option<String>, #[serde(default)] pub env: HashMap<String, String>, #[serde(default)] pub user: Option<NameOrId>, #[serde(default)] pub group: Option<NameOrId>, #[serde(default)] pub timeout_sec: Option<f64>, #[serde(default)] pub stdin: bool, #[serde(default)] pub reap_group_on_exit: bool, #[serde(default, skip_serializing_if = "is_false")] pub poweroff_on_exit: bool, #[serde(default)] pub inherit_image_env: bool,}Assumptions consumers make:
- The daemon interprets command elements as an argument vector when
shellis false and rejects an empty vector in that branch.crates/agentd/src/exec_start.rs:460-469. - The Python adapter starts with
StartRequest::newand sets fields through builders, preserving defaults for fields it does not select.bindings/microvms-py/src/session.rs:807-832. - The application publishes client defaults by constructing a request with the same constructor.
crates/microvms-app/src/defaults.rs:35-37.
Drift risk: A new field needs consistent constructor defaults, adapter builders, and daemon interpretation. crates/protocol/src/exec.rs:505-551, bindings/microvms-py/src/session.rs:807-832.
Mitigation: review the request declaration and all construction paths together, then regenerate the wire schema. crates/agentd/src/routes.rs:601.
ExecResult: client completion state
Section titled “ExecResult: client completion state”Producer: crates/microvms-app/src/session/exec.rs:72-83
Consumer(s):
bindings/microvms-js/src/exec.rs:49bindings/microvms-py/src/exec.rs:52crates/microvms-app/src/agents/mod.rs:51crates/microvms-app/src/session/complete.rs:16crates/microvms-app/src/session/mod.rs:51crates/microvms-cli/src/commands/agent.rs:805crates/microvms-cli/src/commands/attached.rs:357
Shape:
#[derive(Debug)]pub struct ExecResult { pub exec_id: String, pub phase: protocol::exec::Phase, /// `None` while running. Present once the child has exited. pub outcome: Option<protocol::exec::Outcome>, /// What the client did when its own deadline expired, for a result /// [`super::complete::CompletionPlan::drive`] returned after one (BIND-9, BIND-10). /// `None` for every other result: a poll, a wait, an ack, and a run that finished in /// time. pub client_deadline: Option<super::complete::ClientDeadline>,}Assumptions consumers make:
- Completion accepts an acknowledgment as complete only when the phase is done and an outcome is present; otherwise it falls back to waiting.
crates/microvms-app/src/session/complete.rs:145-161. - The CLI renders both the raw outcome and the derived POSIX status, notes, and synthesized flag.
crates/microvms-cli/src/commands/attached.rs:706-737. - The Node wrapper exposes result fields through the application accessors.
bindings/microvms-js/src/exec.rs:102-126.
Drift risk: A new completion condition can be lost if an adapter renders only raw exit status. crates/microvms-cli/src/commands/attached.rs:706-737.
Mitigation: preserve both the outcome and application-derived status accessors in each adapter. bindings/microvms-js/src/exec.rs:102-126.
ExecEvent: output, gaps, and termination
Section titled “ExecEvent: output, gaps, and termination”Producer: crates/microvms-app/src/session/sse.rs:240-257
Consumer(s):
bindings/microvms-js/src/exec.rs:49bindings/microvms-py/src/exec.rs:52bindings/microvms-py/src/session.rs:883crates/microvms-app/src/session/complete.rs:17crates/microvms-app/src/session/exec.rs:37crates/microvms-app/src/session/split.rs:56crates/microvms-cli/src/commands/attached.rs:41
Shape:
#[derive(Debug)]pub enum ExecEvent { /// Output bytes, with the offset they start at. Output { stream: protocol::exec::StreamKind, offset: u64, data: Vec<u8>, }, /// A byte range that is gone for good. /// /// Surfaced as a typed event rather than logged, because the alternative is reading /// a truncated log as a complete one. `from` is inclusive and `to` exclusive, so /// `to` is where a cursor resumes. Gap { from: u64, to: u64 }, /// The terminal event. Its absence is what distinguishes a cut connection from a /// finished command — the byte sequences are otherwise identical. Exit(protocol::exec::ExitEvent),}Assumptions consumers make:
- The reconnect cursor advances to the end of delivered output bytes and past the end of a reported gap.
crates/microvms-app/src/session/exec.rs:655-687. - The split stream routes output by pipe, applies the chosen gap policy, and closes channels when its drive ends.
crates/microvms-app/src/session/split.rs:196-240. - The Node wrapper retains raw bytes and also provides text decoded with replacement for invalid UTF-8.
bindings/microvms-js/src/exec.rs:192-224.
Drift risk: A new variant requires every exhaustive stream consumer to decide how it affects delivery and completion. crates/microvms-app/src/session/split.rs:196-240, bindings/microvms-js/src/exec.rs:192-224.
Mitigation: review cursor advancement, gap handling, and adapter conversion together. crates/microvms-app/src/session/exec.rs:655-687.
PollResponse and Outcome: retained execution output
Section titled “PollResponse and Outcome: retained execution output”Producer: crates/protocol/src/exec.rs:431-438, crates/protocol/src/exec.rs:57-78
Consumer(s):
bindings/microvms-js/src/exec.rs:106bindings/microvms-py/src/exec.rs:91crates/agentd/src/exec.rs:88crates/agentd/src/routes.rs:615crates/microvms-app/src/session/exec.rs:85crates/microvms-cli/src/commands/attached.rs:717
Shape:
#[derive(Debug, Deserialize, JsonSchema, Serialize)]pub struct PollResponse { pub exec_id: String, pub phase: Phase, #[serde(skip_serializing_if = "Option::is_none")] #[serde(flatten)] pub result: Option<Outcome>,}#[derive(Clone, Debug, Default, Deserialize, JsonSchema, Serialize)]pub struct Outcome { /// Exit code, or `None` when the child died to a signal. pub exit_code: Option<i32>, /// Signal number that killed the child, when one did. pub signal: Option<i32>, /// The daemon execution deadline fired. Absent on older daemons, which cannot /// distinguish deadline expiry from other signal deaths. #[serde(default)] pub timed_out: bool, pub stdout: String, pub stderr: String, /// Set when either stream hit `max_output_bytes` and was cut. An explicit /// flag rather than a sentinel string in the output: a marker inside the /// bytes is indistinguishable from output that happens to contain it. pub truncated: bool, /// Set when the post-exit linger deadline expired with the pipes still open, /// meaning some grandchild is alive and may write more that nobody will see. /// Reported rather than hidden, because a harness that sees empty output from /// a command it knows produced some needs to be able to tell why. pub writers_may_be_alive: bool,}Assumptions consumers make:
- The application renames
resulttooutcomeand setsclient_deadlinetoNonefor responses read from the daemon.crates/microvms-app/src/session/exec.rs:85-93. - The daemon returns no result on a later poll of an acknowledged entry; the acknowledgment response itself can carry the released outcome.
crates/agentd/src/exec.rs:452-463,crates/agentd/src/exec.rs:922-929.
Drift risk: Adding an outcome field changes the flattened poll payload as well as the terminal outcome shape. crates/protocol/src/exec.rs:431-438.
Mitigation: preserve defaults for additive wire fields and review both schema and result conversion. crates/protocol/src/exec.rs:63-66, crates/microvms-app/src/session/exec.rs:85-93.
control::Transport: control-plane calls
Section titled “control::Transport: control-plane calls”Producer: crates/microvms-app/src/control/transport.rs:386-415
Consumer(s):
crates/microvms-app/src/control/mod.rs:153crates/microvms-core/src/prelude.rs:29crates/microvms-edges/src/control/transport.rs:11
Shape:
pub trait Transport: Send + Sync { /// The service region, when known, for diagnostics about ambiguous denials. /// Custom transports may leave this unknown without changing their behavior. fn region(&self) -> Option<&Region> { None }
/// Performs `call`, returning whatever the far side answered. /// /// A transport-level failure (no status at all) is an `Err`; a 4xx or 5xx is an /// `Ok(Reply)` carrying the status, because classifying a status is /// [`classify_failure`]'s job and a transport that classified would be a second /// place the taxonomy lives. fn send( &self, call: Call, ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Reply, Error>> + Send + '_>>;
/// Resolves the credentials the next [`Transport::send`] would sign with, sending nothing /// to the service (BIND-15's credentials check). /// /// Resolving may reach an SSO, credential-process, or instance-metadata source, none of /// which bills. The default answers `Ok`: a transport that does not sign (every scripted /// one) has nothing to resolve. fn resolve_credentials( &self, ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<(), Error>> + Send + '_>> { Box::pin(async { Ok(()) }) }}Assumptions consumers make:
- The retry policy expects a reply even for unsuccessful HTTP statuses, then classifies the status itself before deciding whether to retry.
crates/microvms-app/src/control/transport.rs:138-158. - The composition root supplies a shared transport to
ControlPlane::from_ports.crates/microvms-core/src/prelude.rs:146-157.
Drift risk: A transport that classifies HTTP failures itself can bypass the application retry policy. crates/microvms-app/src/control/transport.rs:386-402, crates/microvms-app/src/control/transport.rs:138-158.
Mitigation: return raw replies for HTTP responses and reserve transport errors for failures without a response. crates/microvms-app/src/control/transport.rs:393-398.
HttpBackend: guest HTTP and streaming
Section titled “HttpBackend: guest HTTP and streaming”Producer: crates/microvms-app/src/session/http.rs:156-177
Consumer(s):
Shape:
pub trait HttpBackend: Send + Sync { /// Sends one request and collects the whole body, whatever the status. /// /// Deliberately does not fail on a status: a conformance suite asserts on 401 and /// 409 as expected outcomes, and a client that could only reach them through an /// error would be a client that cannot test the protocol. fn send(&self, request: HttpRequest) -> BoxFuture<'_, Result<HttpResponse, Error>>;
/// Opens a streaming response, reading the status before any body byte. /// /// Status first so a 404 on an unknown exec id surfaces as `NotFound` rather than /// as an empty stream. `idle_timeout` bounds *silence* rather than duration: an SSE /// body is idle by design between chunks, so the useful bound is how long a gap may /// last. Without one, a half-open connection — the failure a NAT or proxy timeout /// produces, where no FIN ever arrives — hangs forever and the reconnect logic /// never runs. fn open_stream( &self, request: HttpRequest, idle_timeout: Duration, ) -> BoxFuture<'_, Result<OpenStream, Error>>;}Assumptions consumers make:
- The production backend captures the status and body without converting unsuccessful HTTP statuses into transport errors.
crates/microvms-edges/src/session/http.rs:116-136. - The session interprets the response status after its backend returns.
crates/microvms-app/src/session/mod.rs:168-176. - The streaming backend disables the overall request timeout and uses the supplied idle timeout for arriving chunks.
crates/microvms-edges/src/session/http.rs:140-179,crates/microvms-edges/src/session/http.rs:249-277.
Drift risk: Replacing idle timeouts with total-duration timeouts can cut off an active stream. crates/microvms-edges/src/session/http.rs:140-179, crates/microvms-edges/src/session/http.rs:249-277.
Mitigation: retain separate collected-response and streaming implementations with the status available before stream consumption. crates/microvms-app/src/session/http.rs:153-176.
Other contracts
Section titled “Other contracts”Errorcarries a coarse kind, an optional wire kind, a message, whether the service throttled the call, the attempts and total retry sleep of its control-plane call, and a source chain; adapters read it through methods.crates/microvms-domain/src/error.rs:32-159,bindings/microvms-py/src/errors.rs:154-183.Replypreserves control-plane status, raw body, and the service error type for application classification.crates/microvms-app/src/control/transport.rs:341-372,crates/microvms-edges/src/control/transport.rs:202-230.- The CLI JSON envelope has stable success and failure fields read by the conformance client.
crates/microvms-cli/src/envelope.rs:355-383,conformance/harness/envelope.py:46-67. TeardownReportrecords cleanup outcomes and retained resource identifiers.crates/microvms-app/src/sandbox.rs:517-550,crates/microvms-cli/src/commands/lifecycle.rs:1315-1335.StdinRequestcarries optional base64 bytes and a signal; the application serializes it for the daemon.crates/protocol/src/exec.rs:307-317,crates/microvms-app/src/session/exec.rs:760-773.
See also
Section titled “See also”These pages cite many of the same source files as this one.