orchestrator: add TrialBoot capability trait - #460
Merged
Merged
Conversation
chrysh
force-pushed
the
add-trial-boot
branch
12 times, most recently
from
September 8, 2026 20:28
964ef7a to
d883d29
Compare
chrysh
marked this pull request as ready for review
September 8, 2026 20:31
leongross
reviewed
Sep 10, 2026
chrysh
added a commit
to 9elements/openprot
that referenced
this pull request
Sep 14, 2026
Leon's review point on OpenPRoT#460: tests get read as examples, so the mock should use the conversion everyone already knows. `faulty` stays a named constructor because only one `From<&mut SlotRecord>` can exist. Assisted-by: Claude
chrysh
force-pushed
the
add-trial-boot
branch
3 times, most recently
from
September 14, 2026 20:08
5115b21 to
d92129f
Compare
Activating an update proposes a boot candidate and never commits it, whether the eRoT actuates that itself through Updatable::activate or a PLDM firmware device does it on the eRoT's behalf. Updatable's docs already name TrialBoot as the gate that resolves the proposal; this is that trait: is_pending, confirm, revert, no slot ids. One contract covers both implementors. A passive downstream device is judged from outside over its boot-complete line; the eRoT's own image is judged by the boot the trial started, so is_pending has to be answerable from durable state alone. The arming applies to the next boot only, so an unresolved trial falls back on its own, but the record stays pending until confirm or revert, which is how an orchestrator that rebooted mid-update finds it again. confirm moves slot metadata only. Raising the anti-rollback floor is SvnFloor::advance and happens later, so revert always has a bootable image to fall back to. Assisted-by: Claude
chrysh
force-pushed
the
add-trial-boot
branch
from
September 14, 2026 20:20
d92129f to
7ce8847
Compare
rusty1968
approved these changes
Sep 17, 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.
TL;DR: Trait-only PR.
TrialBootis the commit gate activation leaves open:keep an image that was activated but not committed once its boot was judged,
or throw it away.
Part of #377, 9elements#21.
Summary
Activating an update picks the staged image as the next thing to boot and
stops there, whether the eRoT does that itself through
Updatable::activateor a PLDM firmware device does it for the eRoT.
Updatable's docs alreadypoint at a
TrialBootcapability as the other half; that trait did notexist. This adds it to
orchestrator-capabilities:is_pending,confirm,revert.confirmandreverttake no arguments. A device has at most one trial openat a time, the one the last activation armed, so there is nothing to name,
and which slot is which stays behind the seam as it does in
Updatable.One contract, both implementations
The same trait covers a downstream device behind interposed flash and the
eRoT's own image. They differ in who judges the boot, not in what confirm or
revert means. A device that commits on its own, a PLDM firmware device
picking its own slot, has no
TrialBooton the eRoT side, the same splitSvnFlooralready makes.Three contract points:
is_pendingis answerable from stored state alone, because the image thatconfirms a self-update is not the image that armed it.
outlives it. An image that hangs, or an eRoT that loses power during the
trial, boots the confirmed slot again with no call from anyone; the record
stays open until
confirmorrevert, so an orchestrator that rebootedmid-update finds the trial again instead of losing it.
revertalso disarms. An orchestrator that drops an activation beforeresetting the device needs the next boot to run the confirmed slot even
though the trial image never booted.
Both calls are safe to repeat: with no trial open they succeed and do
nothing, matching
SvnFloor::advance.confirmmoves slot metadata only. Raising the anti-rollback floor isSvnFloor::advanceand happens later, on the UA's UpdateSecurityRevision(DSP0267 1.3.0, command 0x22), which is what keeps
revertable to fall backto an image that still boots. See #464.
Why not a method on
UpdatableFor self-update, staging and confirm run in different boots of different
images. The
Updatableinstance that staged the payload no longer existswhen
confirmruns. A method onUpdatablecannot model that.Also considered and rejected: the consuming-session shape of #459 (a
session's compile-time guarantee cannot cross a power cycle, which is the
boundary this trait exists to span), and a constructor returning
Option<Trial>(models only cold-boot recovery, not the downstream happypath where the trial opens mid-session).
Tests
Seven host tests, both implementations driven through one generic
apply_verdict<T: TrialBoot>so the shared contract is what is under test: ahealthy downstream trial becomes confirmed, one nobody confirms falls back
yet stays open, revert before the trial boots disarms the next boot, the eRoT
confirms from the boot its trial started, an eRoT trial that never confirms
falls back on the next reset, a replayed resolution is a no-op, errors
surface through the generic seam.
Not in this PR
The implementations. What backs the trial record durably is open
(#383, #384):
services/storageis still a stub, so theeRoT-side impl has nowhere to keep the record yet.