docs(readme): add startup flow diagram - #15
Conversation
Adds a Mermaid flowchart covering all startup phases from PID 1 to switch_root, with inline release/debug branching at each error point. Includes a terminal-states legend and a note on the apply_boot_env_decision core_result capture invariant. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
JanZachmann
left a comment
There was a problem hiding this comment.
The visual and doc look good. I expected some undefined flows but everything looks consistent. So is there something special I need to review or is this was last specs say?
Imho, we haven't yet defined the behavior for how to handle certain situations. The README reflects the current status, and we may now have a basis for discussing changes to that behavior. |
JanZachmann
left a comment
There was a problem hiding this comment.
Review: does the diagram match the specs and cover all paths?
Scope note: this is a docs-only change (one Mermaid diagram + tables). The code-focused review agents (silent-failure, type-design, test-coverage) don't apply — the relevant review for the stated goal is spec ↔ README ↔ impl traceability. I checked the diagram against src/ (main.rs, lib.rs, mode/normal.rs, init_setup/, filesystem/resize_data.rs, recovery.rs) and all 10 files in docs/superpowers/specs/.
Verdict: the diagram is an accurate, lightly-abstracted picture of the current code. Two things block the "spec and docs match and cover all paths" goal: (1) one region of the flow has no backing spec, and (2) two specs are stale/contradictory relative to what the diagram now shows. Inline comments mark the per-node items.
Coverage matrix (suggested gap-visualization format)
This is the table format you asked about — a traceability matrix is the clearest way to show "all paths covered" at a glance. Rows = flow phases; a row is only green when diagram, spec, and impl all agree.
| Phase / node | In diagram | Backing spec | Impl | Status |
|---|---|---|---|---|
Early init (MOUNT_ESS, EARLY_ERR) |
yes | recovery-policy §2.5/§2.6 | main.rs:33-45 |
✅ |
| Logger init | yes | recovery-policy §2.6(3) | main.rs:50-62 |
✅ |
Config/RDEV/LAYOUT/CORE |
yes | boot-mode-dispatch, resize-data, preflight | lib.rs:149-170 |
✅ |
| Boot-env classify/apply (degraded) | yes | degraded-boot-mode, degraded-boot | lib.rs:179-182 |
✅ |
First-boot detect + update_pending |
yes | first-boot-detection, recovery-policy §2.5 | lib.rs:184-192 |
✅ |
init_setup / resize preflight |
yes (label issue) | preflight, resize-data, fsck-and-resize | init_setup/, resize_data.rs |
Fatal edge; specs #2/#4 stale on "resize fatal" |
BootMode dispatch |
yes (no fail edge) | boot-mode-dispatch, preflight | lib.rs:205 |
|
mount_remaining_partitions |
yes | resize-data, boot-mode-dispatch | normal.rs:51-57 |
✅ |
Overlays / fs-links / ODS runtime (OVL,LINKS) |
yes | none | normal.rs:59-69 |
❌ no spec |
write_first_boot_marker (resize_ok gate) |
yes | first-boot-detection, first-boot-retry | normal.rs:74 |
✅ |
switch_root |
yes | mentioned only (endpoint) | runtime::switch_root |
|
Fatal handler (FEB) |
yes (Fatal branch only) | recovery-policy | main.rs:74, recovery.rs |
✅ simplified |
Legend: ✅ diagram = spec = impl ·
Recommend keeping a trimmed version of this matrix in the README (or in a specs index) so the spec↔doc↔impl link is visible and stays maintained — that is what actually enforces "cover all paths" over time.
Spec-hygiene items (not visible in the diff, but block the goal)
- Stale spec:
2026-05-12-first-boot-mode-design.md(BootMode::FirstBoot,mode::first_boot::run) is superseded by2026-05-13-preflight-design.md. That flow exists in neither the diagram nor the code. Mark it superseded. - Contradiction:
resize-dataandpreflightspecs both state "resize failure is fatal".fsck-and-resize(#9) andfirst-boot-retry(#10) reclassify resize asContinueDegraded(never fatal). The diagram (ISETUPnon-fsck →BMODE, continue) and the code follow the latter — so the two earlier specs are stale and should be marked superseded, otherwise the spec set contradicts the README.
Not a gap (checked and ruled out)
Early-init error handling is spec-covered — recovery-policy §2.5 (early failure before boot env → not-pending → terminal) and §2.6 invariant 1 ("release never reaches Shell"). The diagram's EARLY_ERR release→halt / debug→emergency-sh split is exactly the fix that spec mandates.
Finding 1: ISETUP edge label was wrong — 'Other error → ContinueDegraded' implied all non-reboot errors are absorbed. Only ResizeData errors are absorbed by handle_result; non-ResizeData errors propagate as Fatal. Relabelled edge and added missing ISETUP -->|Fatal (non-resize)| FEB edge. Finding 3: FEB node understated its role. Renamed to 'Error handler / RecoveryClass?' and expanded edges to show RebootToApply as a distinct branch, making clear FsckRequiresReboot flows through this handler. Added 'Notes on error handling' prose section. Finding 4: persist_fsck_results was annotated only on FsckRequiresReboot edges, implying it only runs on the reboot branch. Moved annotation to the APPLY and MREM nodes where it actually runs (every mount path, including degraded boot). Finding 5: BMODE had no failure edge. Added BMODE -->|Fatal| FEB. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
The overlay, fs-link, and ODS setup steps have no dedicated design doc. Added a prose note explaining this is a faithful port from the legacy bash initramfs (fatal-on-fail matches the on_exit hook behaviour), with the OTA rollback path added by the Rust rewrite. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
8d771e4 to
a703fbf
Compare
JanZachmann
left a comment
There was a problem hiding this comment.
New findings — still-open points
The five earlier threads are verified against the code (and, for the overlay block, against the legacy bash initramfs in meta-omnect) and resolved. These three points were raised in the original review summary but not addressed in the diff — filing them as discrete findings so they're tracked against the PR goal (spec ↔ README match, all paths covered).
Finding B — stale superseded spec (spec hygiene) · open
docs/superpowers/specs/2026-05-12-first-boot-mode-design.md designs BootMode::FirstBoot + mode::first_boot::run. That design is superseded by 2026-05-13-preflight-design.md, and the flow exists in neither the diagram nor the code. The spec should carry a Superseded by 2026-05-13-preflight-design.md header note (or be removed), otherwise the spec set documents a flow that no longer ships.
Finding C — spec contradicts shipped behaviour: "resize failure is fatal" · open
2026-05-04-resize-data-design.md and 2026-05-13-preflight-design.md both state resize failure is fatal. 2026-05-27-fsck-and-resize-design.md and 2026-06-22-first-boot-retry-on-resize-failure.md reclassify resize as ContinueDegraded (never fatal) — which the diagram (ISETUP non-fsck → BMODE) and the code (resize_data.rs::handle_result) follow. The two earlier specs directly contradict the README and the code; mark them superseded or update the claim.
Finding A — diagram: FsckRequiresReboot edges bypass the error handler · open
See the inline comment. Cosmetic + spec-alignment; not blocking.
Findings B and C are spec-file changes outside this PR's diff — they may be better tracked as a separate issue/PR if this one stays scoped to the README diagram.
Finding B: 2026-05-12-first-boot-mode-design.md designed BootMode::FirstBoot which was superseded before implementation. Added 'Status: Superseded by 2026-05-13-preflight-design.md' header and prose note. Finding C: 2026-05-04-resize-data-design.md and 2026-05-13-preflight-design.md both stated resize failure is fatal, contradicting the shipped ContinueDegraded reclassification in 2026-05-27-fsck-and-resize-design.md. Added 'Status: Partially superseded' headers referencing the correcting documents, and an inline annotation on the specific table row in preflight-design.md. Specs retained for design history. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
|
Findings B and C — addressed in commit Finding B: Added Finding C: Added |
JanZachmann
left a comment
There was a problem hiding this comment.
Requesting changes for one open item.
Finding A — diagram reroute not in the branch. The reply on that thread credits commit 8d771e4, but 8d771e4 was force-pushed away and is not in the history (head 0fd10f16's parent is a703fbf). The diagram at head still routes FsckRequiresReboot straight to REBOOT (L60/L65/L73) while FEB -->|RebootToApply| REBOOT (L88) has no incoming edge. Please re-apply the 4-line reroute documented in the Finding A thread so REBOOT is reached only through FEB (matches the code and recovery-policy §2.6 invariant 2).
Resolved and not blocking:
- Findings 1–5 (diagram edges/labels, OVL/LINKS legacy annotation) — verified, threads resolved.
- Finding B (stale
2026-05-12-first-boot-modespec) — superseded header added in0fd10f16. - Finding C (resize-fatal contradiction) — partially-superseded headers added in
0fd10f16.
Once the diagram edit lands, this is good to merge.
…l finding) The FsckRequiresReboot edges from APPLY/ISETUP/MREM pointed straight at REBOOT, bypassing FEB, while FEB carried an orphan RebootToApply branch with no incoming edge. Redirect all three through FEB so the diagram matches the code (every error reaches handle_fatal_error) and the recovery-policy §2.6 invariant that the handler is the only reboot source. REBOOT is now reached exclusively via FEB. Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
JanZachmann
left a comment
There was a problem hiding this comment.
All findings resolved. Finding A is now applied in 455e66aa — the three FsckRequiresReboot edges route through FEB, and REBOOT is reached only via FEB -->|RebootToApply (e.g. FsckRequiresReboot)| REBOOT, matching the code and recovery-policy §2.6 invariant 2.
Summary: diagram findings 1–5 fixed and verified; OVL/LINKS spec gap annotated (backed by the legacy bash initramfs); Finding B (stale 2026-05-12-first-boot-mode spec) and Finding C (resize-fatal contradiction) marked superseded in 0fd10f16. Diagram now matches the implementation; spec set is consistent with the README. Approving.
JanZachmann
left a comment
There was a problem hiding this comment.
Follow-up: comment style — history-describing (non-evergreen) prose
One clear instance, one borderline. Flagging post-approval as a style nit — not re-blocking unless you want it fixed first.
-
README OVL/LINKS note (inline below) — narrates the bash→Rust migration ("ported from the legacy bash initramfs", "The Rust port preserves this behaviour and adds…"). The README is a living doc; it should state the current contract, not the porting history. Evergreen rewrite in the inline comment.
-
Spec status headers (
0fd10f16) — borderline, I'd leave them. "Superseded by…" / "Partially superseded…" headers and the← superseded: reclassified…table annotation are history by nature, but these are design-history documents where lifecycle metadata is conventional and stays true. If you want strict evergreen there too, replace the table annotation's narration with a plain corrected value (Resize failure → ContinueDegraded (non-fatal)).
The rest of the added prose ("Notes on error handling", "Notes on apply_boot_env_decision") is fine — current state and rationale, no history.
Minor: the "FsckRequiresReboot edges … flow through this handler — not via a separate mechanism" clause answers a past review point; trim the trailing clause and it reads as plain current-state.
Say the word and I'll convert this to REQUEST_CHANGES.
Finding D: 'FEB' (diagram node label) appeared in prose at line 132; replaced with 'the error handler'. Finding E: OVL/LINKS note narrated bash→Rust migration history which goes stale. Replaced with current-state contract: these steps abort the boot on any failure, reaching handle_fatal_error. Finding F: trimmed 'not via a separate mechanism' clause from the FsckRequiresReboot note — it answered a past review comment rather than describing current state. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
|
Findings D, E, F addressed in commit
Spec status headers left as-is — agreed these are conventional in design-history documents. |
Summary
Adds a Mermaid flowchart to the README that traces every startup phase from PID 1 to
switch_root, with inline release/debug branching at each error point.Reason
The README described implemented features but gave no overview of how they connect at runtime. The diagram makes the startup sequence, degraded-boot split, and recovery policy visible at a glance.
Content
FsckRequiresRebootalways routing to Reboot regardless of image typeods.degraded_boot=true)core_resultcapture invariantVerification
Diagram syntax validated; renders correctly on GitHub.