fwmanager: table-declared boot checkpoints replace BootMonitor - #23
Open
chrysh wants to merge 8 commits into
Open
fwmanager: table-declared boot checkpoints replace BootMonitor#23chrysh wants to merge 8 commits into
chrysh wants to merge 8 commits into
Conversation
A BootCheckpoint is timing policy plus its own evidence check: a capture-less fn handed the board's device context, so the channel underneath never leaks past the check and an unobservable checkpoint is unrepresentable. config.rs defines the schema (BootSignal is gone); the board table declares the checkpoints against its own context and error types. BootStatus stays as the shared vocabulary and absorbs the latch-cleared-by-reset contract; GpioBootMonitor keeps its behavior as a plain reader. BootWatch/WalkVerdict is the erased seam the orchestrator polls — timeout and retry-budget judgment lands with the walker that implements it. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
The embedded fn was the more general shape, but the generality went unused while its costs did not: the table stopped being pure data (unprintable, unvalidatable on mechanisms, never generatable), every check shared one &mut board context, and dispatch went indirect. A signal id is the same check defunctionalized: data in the table, an exhaustive match in the board's EvidenceReader — typically one per device, so each walk borrows only its own reader. Boot-evidence mechanisms per board are a closed set; when one can't be named, that is a new variant in that board's enum, not an API change. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
A device that knows it failed should end the wait early, and one that knows a retry is pointless should say so, instead of the orchestrator burning its window and budget to find out. BootStatus::Failed splits into FailedRetriable (consumes budget immediately) and FailedFatal (ends the boot regardless of budget). Timeouts stay the orchestrator's own judgment — hung devices report nothing — and channel trouble stays in the reader's Error, distinct from a device-reported verdict. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
A timeout is never on the wire: a hung endpoint reads Booting forever, and only the orchestrator's clock turns silence into a verdict. The message path carries the active verdicts (device failure codes) and channel trouble, each on its own channel. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
Retry re-arms the window, but the caller had no way to know until when — it would have had to reach into the checkpoint's timeout and do the walker's arithmetic itself. Retry now carries deadline_millis exactly like Waiting: one scheduling rule for both verdicts. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
Adapter crates cannot implement EvidenceReader themselves — a board's signal vocabulary G is not theirs to know. Show the intended shape on the trait: the board impl owns the match, the hardware binding is made once at construction, the signal id proves the right reader was wired. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
Failure reports identify a checkpoint by name, so a duplicate within a device would make them ambiguous — validate now rejects it at build time (str comparison by hand: == on &str is not const). Also state explicitly that max_retries=0 means the one attempt is all the device gets. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
Collaborator
Author
|
Addressed the review, one commit per point:
|
The signal field now says on the spot why it is an id and who resolves it, and validate points at the mock table, which demonstrates the board-local const fence for checks the generic validate cannot do (gpio line within the bank). Assisted-by: Claude:claude-fable-5 Signed-off-by: Christina Quast <christina.quast@9elements.com>
Collaborator
Author
|
Round two addressed in 2134206:
|
chrysh
marked this pull request as ready for review
August 5, 2026 20:54
Collaborator
Author
|
@rusty1968 @FerralCoder @embediver — review requested (GitHub only let me formally request @leongross here since this is the 9elements staging fork). This replaces the BootMonitor/BootWalk approach from OpenPRoT#395; once it settles here it goes upstream as one PR. |
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.
Traits and schema only — the walker implementing them follows in a separate PR, so this one stays reviewable on the contract alone.
What
BootMonitoris removed. ABootCheckpointnames its evidence as a board-defined signal id (signal: G, timeout, retry budget) — the schema names no signal kinds, and everything that is config is declared in the board device table (target/mock/devices.rs);config.rsonly defines what that configuration has to look like.EvidenceReader<G>resolves a signal id toBootStatus— board wiring, typically one per managed device, exhaustive match, direct dispatch.BootStatusgrows device-reported verdicts:FailedRetriable(consumes retry budget immediately instead of waiting out the window) andFailedFatal(ends the boot regardless of budget). Timeouts stay the observer's own judgment — hung devices report nothing; the reader tests pin this down with an MCTP-shaped mock where silence readsBootingforever.BootWatch/WalkVerdictis the erased seam the orchestrator polls:Waiting/Complete/Retry/Deadper device, free of device and error types.GpioBootMonitorkeeps its behavior as a plain reader (inherent method, no trait).Reading order
The first commit is the checkpoint-embedded-
fnvariant; the second defunctionalizes it into signal ids and records why (table stays pure data, borrows stay per-device, dispatch stays direct). The pair is kept deliberately as the design record — review the combined diff if you only want the endpoint. Commits three and four add the failure verdicts and the message-path reader tests.Supersedes
BootWalk/MonitorMapoverBootMonitor.await_bootwill need rework once this lands.Test
bazel test //services/fwmanager/...(13 api tests),bazel build //target/mock/...; device-tablevalidateruns in const context, so a bad table is a build error.Migration (for integrators)
BootMonitoris replaced byEvidenceReader<G>+BootStatus; the checkpoint schema changed shape:max_retries: 0= the single attempt is all the device gets.BootStatus::Failedsplit intoFailedRetriable/FailedFatal(device-reported verdicts; timeouts remain the observer's judgment).validate).WalkVerdict::Retrycarriesdeadline_millisof the re-armed window — schedule against it exactly likeWaiting.