Files
fruix/docs/reports/phase19-generation-layout-freebsd.md

193 lines
6.1 KiB
Markdown

# Phase 19.2: explicit installed-system generation layout on FreeBSD
Date: 2026-04-04
## Goal
Phase 19.2 is about making Fruix's installed-system generation model more explicit.
The target here is not yet a full Guix-equivalent in-place `switch-generation` workflow.
The immediate goal is to stop relying mainly on harness knowledge and implicit symlink expectations by recording installed deployment state more explicitly on disk.
## Decision
Fruix now follows this design direction:
- keep Guix-like **semantics**
- do not mirror Guix's installed-system/profile layout **mechanically 1:1**
What Fruix preserves from Guix:
- immutable closure identity
- rollback-friendly deployment semantics
- explicit current deployment pointer
- GC-root-style retention links
- `/run/current-system` as the active runtime boundary
What Fruix intentionally changes:
- installed-system generation state is represented as a small metadata-bearing directory
- the generation model is recorded under a Fruix-native path
- deployment metadata and provenance are easier to inspect directly without reconstructing intent from symlink layout alone
## Implemented layout
Installed systems now record an explicit generation root under:
- `/var/lib/fruix/system`
Current validated initial layout:
```text
/var/lib/fruix/system/
current -> generations/1
current-generation
generations/
1/
closure -> /frx/store/...-fruix-system-...
metadata.scm
provenance.scm
install.scm
```
Installed systems now also create explicit retention roots under:
- `/frx/var/fruix/gcroots`
Current validated initial layout:
```text
/frx/var/fruix/gcroots/
current-system -> /frx/store/...-fruix-system-...
system-1 -> /frx/store/...-fruix-system-...
```
Important compatibility point:
- `/run/current-system` still points directly at the active closure in `/frx/store`
That means the new explicit generation model strengthens deployment metadata without changing the already-validated runtime contract used by activation, rc.d integration, and service startup.
## Code changes
### `modules/fruix/system/freebsd/media.scm`
Added explicit generation-layout helpers:
- generation metadata object writer
- generation provenance object writer
- generation layout population for staged rootfs trees
The system rootfs staging path now creates explicit generation state during rootfs population.
That affects:
- direct rootfs materialization
- direct image materialization
- direct installation targets
- target rootfs payloads staged inside installer images
- target rootfs payloads staged inside installer ISOs
The direct install path now also refreshes the generation layout after writing:
- `/var/lib/fruix/install.scm`
so the generation directory carries the same install metadata.
### Installer runtime path
The generated installer runtime script now also copies install metadata into:
- `/var/lib/fruix/system/generations/1/install.scm`
on the installed target.
This keeps direct-install and installer-mediated installs aligned.
## New validation harness
Added:
- `tests/system/run-phase19-generation-layout-qemu.sh`
This harness builds on the already-passing direct install validation from Phase 18.1 and then verifies the new explicit generation layout on the installed target image.
Passing validation:
- `PASS phase19-generation-layout-qemu`
Validated result summary:
```text
closure_path=/frx/store/882fb4a9fbb05f08e77de29f70ca50f3c01dd29141e72688d32770a3172747e7-fruix-system-fruix-freebsd
current_generation=1
current_link=generations/1
generation_closure=/frx/store/882fb4a9fbb05f08e77de29f70ca50f3c01dd29141e72688d32770a3172747e7-fruix-system-fruix-freebsd
gcroot_current=/frx/store/882fb4a9fbb05f08e77de29f70ca50f3c01dd29141e72688d32770a3172747e7-fruix-system-fruix-freebsd
gcroot_generation=/frx/store/882fb4a9fbb05f08e77de29f70ca50f3c01dd29141e72688d32770a3172747e7-fruix-system-fruix-freebsd
run_current_system_target=/frx/store/882fb4a9fbb05f08e77de29f70ca50f3c01dd29141e72688d32770a3172747e7-fruix-system-fruix-freebsd
generation_layout=explicit
generation_layout_validation=ok
```
The harness verified all of the following:
1. the installed target contains:
- `/var/lib/fruix/system`
2. the current generation pointer exists and resolves to:
- `generations/1`
3. the generation directory contains:
- `closure`
- `metadata.scm`
- `provenance.scm`
- `install.scm`
4. the generation closure link points at the installed closure in `/frx/store`
5. the generation metadata records:
- closure path
- install metadata path
6. the generation install metadata records:
- closure path
- materialized source provenance
7. explicit retention roots exist under:
- `/frx/var/fruix/gcroots/current-system`
- `/frx/var/fruix/gcroots/system-1`
8. those GC-root-style links point at the same active closure
9. `/run/current-system` still points directly at the active closure path
10. existing install boot validation remains intact
## Relationship to Guix
Fruix now has an explicit installed-system generation model, but it is still intentionally not a byte-for-byte clone of Guix's on-disk conventions.
The design choice is:
- preserve Guix's deployment semantics
- use a Fruix-native metadata-oriented representation where that improves clarity for operators and debugging
That decision is documented separately in:
- `docs/GUIX_DIFFERENCES.md`
## Current limitations
This phase does **not** yet add:
- multi-generation switching in place
- a `switch`/`reconfigure` command
- an operator-facing rollback command that flips from current to a previous installed generation without redeploy
- explicit `rollback` link management beyond the initial current-generation layout
Those belong to later Phase 19 work.
## Conclusion
Phase 19.2 is complete.
Fruix now has a clearer, explicit installed-system generation and retention-root model on FreeBSD:
- generation metadata is recorded under `/var/lib/fruix/system`
- retention links are recorded under `/frx/var/fruix/gcroots`
- `/run/current-system` remains stable as the runtime boundary
- and the model is documented in Fruix-native terms for Guix-familiar operators