Repository navigation
fix(core): let the service decide a resume past the suspended window (#597) - #601
Merged
Merged
Conversation
laithalsaadoon
added a commit
that referenced
this pull request
Oct 12, 2026
CI's mutation testing on #601 found both arms of classify's suggestion match unguarded: deleting (Exit::LaunchDied, _) or (Exit::WindowClosed, _) left every test passing. The test asserts each exit's suggestion. Locally, the change's 13 mutants against origin/docs/one-current-fact: 9 caught, 4 unviable, 0 missed.
laithalsaadoon
force-pushed
the
docs/one-current-fact
branch
2 times, most recently
from
October 12, 2026 20:59
aa5c8c8 to
e60b136
Compare
Sandbox::resume refused with ERR_WINDOW_CLOSED before any call once suspendedDurationSeconds had passed since the sandbox's own suspend() (require_open_suspended_window, STATE-12). The service doesn't hold an explicit suspend to that window: measured 2026-10-12 in us-east-1, API 2025-09-09, a VM suspended with SuspendMicrovm and a 60 s window was still SUSPENDED 1283 s later, and ResumeMicrovm brought it to RUNNING. The window ends a VM the idle policy suspended, and ResumeMicrovm then answers ValidationException "has been terminated and its state cannot be changed." Sandbox::resume no longer keeps a suspend time or checks a window, and every resume goes to the service. ControlPlane::resume reads the VM with GetMicrovm after a 400 refusal: TERMINATING or TERMINATED is ERR_WINDOW_CLOSED naming the state and stateReason, and any other answer, or a failed read, keeps the service's error. The CLI resume and both bindings' ControlPlane.resume share it, so `microvm resume` on an ended VM exits 8 (ERR_WINDOW_CLOSED) where it exited 9 (ERR_PLATFORM). After a WindowClosed refusal the sandbox records the VM TERMINATED and terminated, so the next resume is refused before any call (STATE-11); a refusal for a live VM leaves it SUSPENDED. STATE-12, the client model and its conformance replay state the new rule: the platform ends a suspended VM as its own action, and a resume of an ended VM reaches the service and comes back refused. The --suspended-sec help, the resume and exit-code docs, the CLI README, the WindowClosed docs in the domain crate and both bindings, the generated stubs and manifest, and the debugging guide, contract map, CLI reference and three operations pages change with it. Verified offline only: no live run. Fixes #597
The CLI's `guards::parity::the_cli_answers_the_shared_case_corpus_against_its_fakes` spawns microvms-core's `parity-tunnel-peer` example from the test binary's target directory. A mutant's `cargo test -p microvms-cli` never builds another package's example, so a change with mutants in microvms-cli failed cargo-mutants' unmutated baseline (exit 4, "build the fixture with mise run parity:fixtures"), as shard 3 of 4 did on #600. `ci:mutants` now depends on `parity:fixtures`, which builds the example into the target the `--in-place` run tests from. Shard 3 of 4 run locally with this: baseline ok in 31 s build + 9 s test, 1 mutant, unviable.
CI's mutation testing on #601 found both arms of classify's suggestion match unguarded: deleting (Exit::LaunchDied, _) or (Exit::WindowClosed, _) left every test passing. The test asserts each exit's suggestion. Locally, the change's 13 mutants against origin/docs/one-current-fact: 9 caught, 4 unviable, 0 missed.
ControlPlane::resume maps a refused resume of a VM that GetMicrovm reports TERMINATING or TERMINATED to ERR_WINDOW_CLOSED. Its message said the VM "terminated while suspended" and named the suspended window as the cause, but the mapping only knows the VM is dead. Measured 2026-10-12 in us-east-1: a VM ended with `microvm terminate` (stateReason "Success.") and one the service ended (stateReason "MicroVM exceeded maximum lifetime.") both still read TERMINATED about 4 h later, and ResumeMicrovm refused both with the same ValidationException. So a VM the user terminated, or one that hit its maximum duration while RUNNING, exited 8 with a false cause and a --suspended-sec remedy. The message also dropped the service's refusal and doubled the stateReason's period. - The message now says the VM can't be resumed, that the service refused ResumeMicrovm, and the state and stateReason GetMicrovm reports, in parentheses so a stateReason's own period isn't doubled. It names no cause and says to launch a new VM. - The refusal is attached as the error's source. - WindowClosed now means the VM ended before the resume (the suspended window, the maximum duration, or a terminate), and it can't be resumed: in the ErrorKind doc, the exit table's meaning, the CLI hint (which no longer names --suspended-sec), the resume help, WindowClosedError and both bindings' ControlPlane.resume docs. docs/manifest.json, microvms.pyi and index.d.ts are regenerated. The code and exit 8 stay. - A new test covers a VM a terminate ended: the exact neutral message, no doubled period, and the refusal as the source. The seeded fault resume-window-closed-drops-the-refusal removes the source and the test fails. - The fail-to-pass patches are regenerated against the merge base, since they reverse every product hunk.
…uspended The Sandbox.resume docs in both bindings, the core Sandbox docs and the client model said a resume of a VM that terminated while suspended gets WindowClosed, which reads as covering a VM the idle policy suspended. Nothing updates a Sandbox's lifecycle when the platform idle-suspends its VM: the sandbox still holds it as RUNNING, so Sandbox::resume refuses with InvalidArg before any call (STATE-7) and never asks the service. That refusal is unchanged here. - The docs now say a sandbox doesn't see an idle suspend, that the suspend reaches a caller only through Sandbox::adopt, which reads the state from the service, or ControlPlane::resume, which holds no lifecycle, and that WindowClosed is the service's answer once a resume reaches it, whatever ended the VM. That's in Sandbox::resume and the module docs in crates/microvms-app, both bindings' Sandbox.resume with microvms.pyi and index.d.ts regenerated, the control-plane test's doc, and the client model's module docs, whose SuspendedVmEnded is the platform ending a VM the client suspended. - The drop warning said "The VM bills until its maximumDurationInSeconds ceiling" about the lifecycle the sandbox last saw, which tells the owner of a VM the platform already ended that it still bills. It now names the state as the last one the sandbox saw, says the platform may have suspended or ended the VM since, and says a VM that's still live bills until it ends. The drop test asserts that wording. - docs/insights/debugging-guide.md's sandbox.rs citation follows the lines, and the fail-to-pass patches are regenerated.
clock.rs's module docs still said Sandbox times the suspended window on the plane's clock, and that a monotonic clock matters because a wall clock stepping backward would reopen a closed window. #597 removed that window check, so the docs now say what the clock serves: Sandbox waits on the plane's clock so a deadline isn't measured on one clock while the polls sleep on another, and Clock::elapsed is monotonic because a wait's deadline and a proxy token's age are durations. The fail-to-pass patches are regenerated, since they reverse every product hunk.
…mised; a Sandbox doesn't see an idle suspend The 2026-10-12 re-measure held the idle policy fixed: two VMs suspended with SuspendMicrovm under the idle case's own policy resumed about 910 s into a 60 s window. AWS documents the window for any suspended VM, so the resume and --suspended-sec help, the CLI reference, the changelog and two site pages say the explicit case is measured behavior AWS doesn't promise. The client no longer depends on either answer: every resume goes to the service. recover-a-leaked-vm.md and long-lived-vm.md now say ERR_WINDOW_CLOSED for an idle-suspended VM comes from `microvm resume` and ControlPlane.resume, and that a Sandbox that launched the VM refuses its own resume first (#603). docs/behavior/processes.md no longer describes the suspend stamp and window check this change removed, and its line references point at the current code.
laithalsaadoon
force-pushed
the
fix/resume-explicit-suspend-window
branch
from
October 12, 2026 21:57
3330dc6 to
4384885
Compare
laithalsaadoon
marked this pull request as ready for review
October 12, 2026 22:21
35 of 45 tasks
bonk-ai Bot
added a commit
that referenced
this pull request
Oct 13, 2026
tech-debt.md loses items 5 (napi generator pin, fixed by #576) and 10 (lifecycle commentary, fixed by #579) and the bullets that cited them; item 8 now names #576's agreement test and the proof-runner copy it leaves out. debugging-guide.md drops the Serve-not-Future entry that #583's accept loop retired. 15 citations #600 and #601 moved on those pages are re-pointed by exact text match. The see-also footers on 19 pages drop their hand-written citation counts (AGENTS.md, Counts in docs), and .vale/warnings.json lowers 25 ceilings to this tree's counts. docs:check EXIT=0 (240 s), prose:check EXIT=0 (0 errors, 4069 warnings).
2 tasks done
bonk-ai Bot
added a commit
that referenced
this pull request
Oct 13, 2026
…607) tech-debt.md loses items 5 (napi generator pin, fixed by #576) and 10 (lifecycle commentary, fixed by #579) and the bullets that cited them; item 8 now names #576's agreement test and the proof-runner copy it leaves out. debugging-guide.md drops the Serve-not-Future entry that #583's accept loop retired. 15 citations #600 and #601 moved on those pages are re-pointed by exact text match. The see-also footers on 19 pages drop their hand-written citation counts (AGENTS.md, Counts in docs), and .vale/warnings.json lowers 25 ceilings to this tree's counts. docs:check EXIT=0 (240 s), prose:check EXIT=0 (0 errors, 4069 warnings). Co-authored-by: bonk-ai[bot] <269762587+bonk-ai[bot]@users.noreply.github.com>
bonk-ai Bot
added a commit
that referenced
this pull request
Oct 14, 2026
604 path:line citations on 15 hand-written pages pointed a few lines off after #600 and #601 moved their source lines. Each move is the doc line's blame-commit block found at HEAD by exact text and by git's own diff line mapping, or a read-only audit against the sentence for the 20 rows neither settled. state-machines.md's VmState section now says what ResumeRequested does after SuspendedVmEnded (client.rs:494-499, 509-512): the service refuses the request and the model writes Terminated.
2 tasks done
bonk-ai Bot
added a commit
that referenced
this pull request
Oct 14, 2026
604 path:line citations on 15 hand-written pages pointed a few lines off after #600 and #601 moved their source lines. Each move is the doc line's blame-commit block found at HEAD by exact text and by git's own diff line mapping, or a read-only audit against the sentence for the 20 rows neither settled. state-machines.md's VmState section now says what ResumeRequested does after SuspendedVmEnded (client.rs:494-499, 509-512): the service refuses the request and the model writes Terminated. Co-authored-by: bonk-ai[bot] <269762587+bonk-ai[bot]@users.noreply.github.com>
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.
What and why
Sandbox::resumerefused withERR_WINDOW_CLOSEDoncesuspendedDurationSecondshad passed since the sandbox's ownsuspend(). It refused before any call to the service, inrequire_open_suspended_window(crates/microvms-app/src/sandbox.rs, STATE-12). The service didn't apply that window to an explicit suspend. On 2026-10-12 in us-east-1, two VMs withmaxIdleDurationSeconds60 andsuspendedDurationSeconds60, suspended withSuspendMicrovm, were stillSUSPENDED906 and 917 seconds later, andResumeMicrovmbrought both toRUNNING; a third, with a 3600-second idle limit, resumed after 1283 seconds. So the client refused resumes that the service would have honored. AWS's IdlePolicy reference describes the window for any suspended VM, so the explicit case is measured behavior AWS doesn't promise, and the client now depends on neither answer: the service decides. The window does end a VM that the idle policy suspended. That VM wasTERMINATEDabout 60 seconds after it suspended, andResumeMicrovmthen returned aValidationExceptionsaying the VM "has been terminated and its state cannot be changed."Before this change, a resume past the window of the sandbox's own suspend failed with
ERR_WINDOW_CLOSEDbefore any call, even though the service would have resumed the VM. After it, every resume goes to the service, andERR_WINDOW_CLOSEDreports a resume the service refused for a VM that had already ended, whatever ended it.Sandbox::resumeno longer records when it suspended the VM, and it doesn't check a window. Thesuspended_atfield andrequire_open_suspended_windoware removed.ControlPlane::resume(crates/microvms-app/src/control/microvm.rs) reads the VM withGetMicrovmwhen the service refuses a resume with a 400. If the VM is TERMINATING or TERMINATED, the error becomesERR_WINDOW_CLOSED, its message names the state andstateReason, and the service's refusal is its source. The message names no cause and says to launch a new VM, because a VM a terminate ended gets the same refusal as one the service ended. For any other state, or when the read fails, the caller gets the service's own error. The check reads the VM's state and doesn't match the message text.resumecommand and both bindings'ControlPlane.resumecallControlPlane::resume, so they get the same mapping.microvm resumeon an ended VM now exits 8 (ERR_WINDOW_CLOSED). Before this change it exited 9 (ERR_PLATFORM). The changelog fragment says so.WindowClosedrefusal, the sandbox records the VM as TERMINATED and as terminated, so a second resume is refused before any call (STATE-11). A refusal for a VM that's still alive leaves the sandbox SUSPENDED, and the next resume goes to the service again.Sandboxdoesn't see a suspend the idle policy makes, so it still holds that VM as RUNNING and its resume is refused before any call (STATE-7), as on main. The docs say so, and say the suspend reaches a caller only throughSandbox::adoptorControlPlane::resume. TheDropwarning names the state as the one the sandbox last saw, and says only that a VM that's still live bills.SuspendedVmEndedaction, which is the platform ending a suspended VM, and a resume of that VM reaches the service and is refused. The model-conformance test replays the new paths againstSandbox.--suspended-sechelp on both commands, theresumecommand doc, and theERR_WINDOW_CLOSEDexit meaning and hint, which now says the VM ended before the resume (the suspended window, the maximum duration, or a terminate) and names no flag;WindowCloseddoc in microvms-domain;WindowClosedError,ControlPlane.resume, andSandboxdocs in both bindings, withmicrovms.pyiandindex.d.tsregenerated;ERR_WINDOW_CLOSEDfor an idle-suspended VM comes frommicrovm resumeandControlPlane.resume, and that aSandboxrefuses its own resume first (A Sandbox never sees a platform idle suspend, so resume refuses from RUNNING #603);Verified offline only. No live run exercises this change.
Size: 841 changed lines of product code. 515 of them are unit tests, almost all in sandbox.rs and control/microvm.rs. They replace the STATE-12 tests that held the old rule and add the refusal tests. The other 326 lines are the fix and the doc comments that stated the old rule on each surface. If the docs were split from the fix, one pull request would ship docs that contradict the code.
Fixes #597
Evidence
mise run checkexits 0: 1,804 Rust tests passed, 0 failed, 28 ignored; prose 0 errors, 4,084 warnings, under every ceiling;guards:list1,333 faults.mise run docs:checkexits 0: 223 site tests, CSpell 0 issues.fail-to-pass.py'sfix_patchagainst f410ec2.guards:firethen fired 7 of 7 (the six entries andresume-window-closed-drops-the-refusal).ERR_WINDOW_CLOSEDmessage and meaning), ecd4d60 (what aSandboxsees of an idle suspend, and theDropwarning) and 0499612 (clock.rs's docs). On 0499612:mise run checkexits 0 in 301 s on 2026-10-12.cargo test --allreports 1804 passed, 0 failed, and 28 ignored.prose:checkreports 0 errors and 4,080 warnings, under every ceiling, andguards:listreports 1333 faults registered.mise run ci:mutants -- --base 3330dc6 -- --in-placetested the 12 mutants in the fixes' lines: 9 caught, 3 unviable, 0 missed. Over the whole diff, with--base origin/docs/one-current-fact, it tested 16: 12 caught, 4 unviable, 0 missed.mise run guards:firefires the new fault and the six FAIL_TO_PASS entries, 7 of 7; Guards has the output.microvms.pyi,index.d.tsand docs/manifest.json are regenerated withmise run stubs,mise run dtsandmise run manifest, andcheckrunsstubs:check,dts:checkandmanifest:check.bindings:py,bindings:jsanddocs:checkweren't run again after the fixes. The fixes change the bindings' doc comments and theWindowClosedErrordocstring, and no binding code.Before the review fixes:
Mutation testing: the first CI run on fix(core): let the service decide a resume past the suspended window (#597) #601 found two survivors in
classify's suggestion match (crates/microvms-cli/src/exit.rs, deleting the(Exit::LaunchDied, _)or(Exit::WindowClosed, _)arm). 3330dc6 addsa_died_launch_and_a_closed_window_each_carry_their_remedy. On 3330dc6, run locally againstorigin/docs/one-current-fact,mise run ci:mutants -- --in-placetested the diff's 13 mutants: 9 caught, 4 unviable, 0 missed.mise run checkon 3330dc6: exit 0, 1,803 Rust tests, 0 failed.Before feat(example): Codex SDK in a Strands Box on a MicroVM, on bedrock-runtime #594 and docs: one current answer per platform fact, and a prose rule that holds it #598 merged, this was stacked on docs: one current answer per platform fact, and a prose rule that holds it #598, which was stacked on feat(example): Codex SDK in a Strands Box on a MicroVM, on bedrock-runtime #594, all three rebased on main 78e5f1d. docs: one current answer per platform fact, and a prose rule that holds it #598 rewrites docs/PLATFORM.md and docs/SUSPEND-RESUME.md to the 2026-10-12 suspended-window fact and edits the same three operations pages. This branch keeps its client wording in those pages, and it rewrites the two sentences of site/authored/learn/tutorial/long-lived-vm.md that described the old up-front refusal. On the stacked tree at c3f7bc1,
mise run checkexits 0 (1,802 Rust tests, 0 failed; prose 0 errors, 4,080 warnings, with docs: one current answer per platform fact, and a prose rule that holds it #598's correction-trail rule active), andmise run docs:checkexits 0 (223 site tests, CSpell 0 issues).c3f7bc1 is feat(agentd): an image-set default user for execs that omit
user(#595) #600's ccdb6a4:ci:mutantsbuilds the parity tunnel fixture first, because this change has mutants in microvms-cli, whose parity test spawns that fixture. The identical commit on both branches merges cleanly.mise run checkexits 0 in 326 s on 2026-10-12. That run was before the review fixes, and before a one-line citation fix in docs/insights/debugging-guide.md. After the fix,prose:check,trace:check,fail-to-pass:check,changelog:check, andparity:checkexit 0 again.cargo test --allreports 1802 passed, 0 failed, and 28 ignored.cargo fmt --all -- --checkandcargo clippy --all-targets -- -D warningspass inlint.prose:checkreports 0 errors and 4113 warnings, under every ceiling.guards:listreports 1331 faults registered.mise run bindings:pyreports 512 passed and 1 skipped.mise run bindings:jsreports 382 tests, with 381 passing, 1 skipped, and 0 failing.mise run docs:checkexits 0, and CSpell finds 0 issues in 22 files.mise run specexits 0.mise run spec:coreexits 1 on one error, the word "never" in TRAP-4. The same command on main's spec file at 78e5f1d fails with the same error, and STATE-12's new sentence raises no error.The model-conformance replay drives 940 of 1061 walked paths against
Sandbox, with 7713 sandbox calls. It skips 121 paths where a completion arrives after another step, as before.Parity
microvms.pyi,index.d.ts).mise run parity:checkpasses. Theresumeandresume-by-idrows in verify/parity/capabilities.toml don't change, because the behavior lives in core'sControlPlane::resume, which every surface calls.No parity case covers the refusal, because the Python and TypeScript parity runners can't script a control plane.
Guards
mise run fail-to-pass -- --emit resume-windowran against the merge base 78e5f1d. It proves six tests, which fail with the fix taken out and pass with it in. It wrote their entries into verify/guards/faults/resume-window.toml with their patches. Each patch reverses every product hunk of the branch, so the review fixes regenerate all six with the script's ownfix_patchagainst 78e5f1d, and all six fire again on 0499612's tree.The fire on 0499612, after the review fixes, with the new hand-written fault:
sandbox::tests::a_resume_past_the_window_of_an_explicit_suspend_reaches_the_service_and_resumesis the regression test for core: resume refuses an explicitly suspended VM past suspendedDurationSeconds, which the service still resumes #597. It suspends with a 60-second window and advances the clock 1283 seconds. The resume then reaches the service and succeeds.sandbox::tests::an_adopted_vm_resumes_past_the_reported_window_through_the_servicereplaces the test that refused an adopted VM's resume past its reported window.sandbox::tests::a_resume_the_service_refuses_for_an_ended_vm_is_window_closed_and_recordedchecks theERR_WINDOW_CLOSEDerror, the TERMINATED state, and that a second resume is refused before any call.control::microvm::tests::a_resume_refused_for_a_vm_that_terminated_while_suspended_is_window_closedchecks the mapping for both TERMINATING and TERMINATED.control::microvm::tests::a_resume_refused_for_a_vm_a_terminate_ended_names_no_cause_and_keeps_the_refusalchecks a VM a terminate ended (stateReason"Success."): the exact message, which names no cause and doubles no period, and the service's refusal as the error's source.guards::history::a_resume_of_a_vm_the_service_ended_exits_window_closed_and_records_no_resumechecks that the CLI exits 8 and records no resume.every_walked_path_of_the_client_model_replays_against_the_sandboxreplays the model's new STATE-12 paths.Three new tests pass with the fix taken out, so FAIL_TO_PASS doesn't claim them. They are
a_resume_refused_for_a_live_or_unreadable_vm_keeps_the_services_answer,a_resume_denied_for_its_credentials_reads_no_state, anda_resume_refused_for_a_live_vm_leaves_the_sandbox_suspended_and_resumable. They hold behavior that main already had.Five hand-written faults, each fired with
mise run guards:fire -- --only <id>:model-client-state-12-refused-resume-unrecordedis new in verify/guards/faults/agentd-model.toml. It leaves the model's VM SUSPENDED after the service refuses a resume for an ended VM, and the property "STATE-12 a resume refused for an ended VM leaves it TERMINATED and recorded terminated" fails. It printedfired: model-client-state-12-refused-resume-unrecorded.model-client-state-12-resume-refused-locallyis new in the same file. It puts the removed check back into the model, so the client refuses a resume from SUSPENDED for a VM the platform ended. The property "STATE-12 a resume from SUSPENDED reaches the service" fails. It printedfired: model-client-state-12-resume-refused-locally.model-conformance-client-resume-resends-payloadin verify/guards/faults/model-conformance-client.toml now anchors on the new resume block. The fault sends the run hook's payload again after a resume, and the replay reports "run-hook payloads: sandbox 2, model 1". It printedfired: model-conformance-client-resume-resends-payload.model-conformance-client-skips-movedin the same file now anchors on the planner's remaining skip, because the planner no longer skips a closed window. The fault stops skipping a completion that arrives after another step, and the planner fails on the pinned skip set before it replays anything. It printedfired: model-conformance-client-skips-moved.resume-window-closed-drops-the-refusalis new in verify/guards/faults/resume-closed-window.toml. It removes the.with_source(refused)that attaches the service's refusal, and the terminate test fails on "the refusal is the source". It printedfired: resume-window-closed-drops-the-refusal.After each fire, the tool printed "restored, every command passes again". verify/guards/unregistered.txt loses two lines. One is the replaced
an_adopted_vm_refuses_a_resume_past_the_reported_window. The other isthe_lifecycle_watch_follows_every_transition, which had a STATE-12 note attached by mistake and no longer carries it.Follow-ups
ERR_WINDOW_CLOSEDwith the state fromGetMicrovm. It would also resume an explicit suspend past its window. verify/spec/traced/STATE.toml waives the live check until the suite runs one.mise run spec:corefails on main because of the word "never" in TRAP-4. This change doesn't touch TRAP-4.Sandboxwhose VM the idle policy suspended still holds it as RUNNING, soSandbox::resumerefuses from RUNNING withERR_INVALID_ARG(STATE-7) and never asks the service. That's main's behavior, and this change only documents it; A Sandbox never sees a platform idle suspend, so resume refuses from RUNNING #603 tracks it.Platform claims
This changes claims about AWS behavior in the CLI help, the CLI README, the binding docs, the debugging guide, three site operations pages, and the long-lived VM tutorial. docs/PLATFORM.md carries the same measurement through #598, merged as f410ec2. The claims come from the measurement in #597. It was taken on 2026-10-12 in us-east-1 against API version 2025-09-09, with one VM per case and
autoResumeEnabledset to false.maxIdleDurationSeconds60 andsuspendedDurationSeconds60, left the VMTERMINATEDabout 60 seconds after it suspended. ItsstateReasonwas "MicroVM exceeded maximum lifetime."ResumeMicrovmthen returned aValidationExceptionsaying the VM "has been terminated and its state cannot be changed."SuspendMicrovmwithin 10 seconds ofRUNNING, on two VMs with the idle case's own policy (maxIdleDurationSeconds60,suspendedDurationSeconds60), left bothSUSPENDED906 and 917 seconds later withstateReasonnull.ResumeMicrovmwas accepted, and both wereRUNNINGwithin 20 seconds. A review of docs: one current answer per platform fact, and a prose rule that holds it #598 asked for this run, because the first explicit-suspend VM hadmaxIdleDurationSeconds3600; that VM wasSUSPENDED1283 seconds later and resumed too.suspendedDurationSecondsas the longest a MicroVM can remain suspended, with no exception for an explicit suspend, so the help and docs call the explicit case measured behavior AWS doesn't promise.GetMicrovmstill answered TERMINATED for the idle-suspended VM and for one ended withmicrovm terminate(stateReason"Success."), andResumeMicrovmrefused both with the sameValidationException. So the refusal doesn't say what ended a VM, andERR_WINDOW_CLOSEDnames no cause.SUSPENDEDat 240 seconds.Scope
(see
docs/STRATEGY.md).