# 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