Validate FreeBSD base rollback workflow

This commit is contained in:
2026-04-03 10:42:38 +02:00
parent 72f89c51b5
commit 03fbd9bf08
6 changed files with 784 additions and 0 deletions

View File

@@ -3538,3 +3538,89 @@ Current assessment:
- Phase 15.1 is complete
- Fruix now models the FreeBSD base as an explicit declarative system input instead of leaving it implicit in the builder host alone
- the next step is to use that new declaration to prove side-by-side base versions and rollback-friendly rebuild/redeploy behavior
## 2026-04-03 — Phase 15.2: validated side-by-side base versions and rollback-friendly redeploy
Completed work:
- wrote the Phase 15.2 report:
- `docs/reports/phase15-base-upgrades-freebsd.md`
- added validation harnesses:
- `tests/system/run-phase15-base-coexistence.sh`
- `tests/system/run-phase15-base-rollback-qemu.sh`
- `tests/system/run-phase15-base-rollback-xcpng.sh`
- used two explicit declarative base identities against the current validated native Phase 14 package split:
- current base:
- `name=stable-default`
- `version-label=15.0-STABLE`
- `release=15.0-STABLE`
- `branch=stable/15`
- candidate base:
- `name=stable-canary`
- `version-label=15.0-STABLE-p1`
- `release=15.0-STABLE`
- `branch=stable/15`
- both declarations still use the same local `/usr/src`, but now produce distinct declared base/store/deployment identities
Validation:
- side-by-side base-coexistence harness passes:
- `tests/system/run-phase15-base-coexistence.sh`
- workdir: `/tmp/phase15-2-coexist-1775202833`
- result: `PASS phase15-base-coexistence`
- confirmed:
- `current_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd`
- `candidate_closure=/frx/store/dc40b1b7a76084e140d0457f3b7f6c5d4acc185f0d6cee0b161c9775d5fb3bec-fruix-system-fruix-freebsd`
- `current_base_version_label=15.0-STABLE`
- `candidate_base_version_label=15.0-STABLE-p1`
- `side_by_side_base_versions=ok`
- `rollback_rebuild_path=ok`
- this also confirmed that:
- both closures exist side by side in `/frx/store`
- rebuilding the current declaration returns the exact original current closure path
- current native base stores remain separate from candidate native base stores
- local QEMU rollback harness passes:
- `tests/system/run-phase15-base-rollback-qemu.sh`
- workdir: `/tmp/phase15-2-qemu2-1775204321`
- result: `PASS phase15-base-rollback-qemu`
- validation sequence:
1. boot current base
2. boot candidate base
3. boot current base again
- confirmed:
- `current_first_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd`
- `candidate_closure=/frx/store/dc40b1b7a76084e140d0457f3b7f6c5d4acc185f0d6cee0b161c9775d5fb3bec-fruix-system-fruix-freebsd`
- `rollback_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd`
- `current_base_version_label=15.0-STABLE`
- `candidate_base_version_label=15.0-STABLE-p1`
- `rollback_base_version_label=15.0-STABLE`
- `base_rollforward_and_rollback=ok`
- real XCP-ng rollback harness passes:
- `tests/system/run-phase15-base-rollback-xcpng.sh`
- workdir: `/tmp/phase15-2-xcpng-1775204839`
- result: `PASS phase15-base-rollback-xcpng`
- validation sequence:
1. boot candidate base on the approved VM/VDI
2. boot current base again on the same approved VM/VDI
- confirmed:
- `candidate_closure=/frx/store/dc40b1b7a76084e140d0457f3b7f6c5d4acc185f0d6cee0b161c9775d5fb3bec-fruix-system-fruix-freebsd`
- `rollback_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd`
- `candidate_base_version_label=15.0-STABLE-p1`
- `rollback_base_version_label=15.0-STABLE`
- `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289`
- `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743`
- `base_rollforward_and_rollback=ok`
- guest invariants stayed intact for both boots:
- `shepherd_pid=1`
- `sshd_status=running`
- `compat_prefix_shims=absent`
- `guile_module_smoke=ok`
Current assessment:
- Phase 15.2 is complete
- Fruix now supports a real upgrade-style FreeBSD base workflow at the store/deployment level:
- explicit current vs. candidate base declarations
- side-by-side native base outputs in `/frx/store`
- rollback to the earlier closure without mutating it in place
- the remaining Phase 15 work is to document the evidence-based decision on whether self-hosted base builds should be the next step, or whether host-built native base artifacts should remain the near-term path while reproducibility/source acquisition improve

View File

@@ -0,0 +1,179 @@
# Phase 15.2: side-by-side native base versions and rollback-friendly redeploy
Date: 2026-04-03
## Goal
Phase 15.2 demonstrated that Fruix can keep at least two distinct declarative FreeBSD base builds in `/frx/store` at the same time and switch between them through the normal system rebuild/image/boot flow.
For this first upgrade-story validation, both declared bases still point at the same local `/usr/src`, but they carry distinct declarative version labels:
- current base: `15.0-STABLE`
- candidate base: `15.0-STABLE-p1`
That is enough to prove the Fruix properties needed here:
- distinct content-addressed outputs
- side-by-side coexistence
- no in-place mutation of the older base closure
- rollback to the earlier closure using the normal deployment path
## New files
Added:
- `tests/system/run-phase15-base-coexistence.sh`
- `tests/system/run-phase15-base-rollback-qemu.sh`
- `tests/system/run-phase15-base-rollback-xcpng.sh`
## Validation model
### Current base declaration
```scheme
(freebsd-base
#:name "stable-default"
#:version-label "15.0-STABLE"
#:release "15.0-STABLE"
#:branch "stable/15"
...)
```
### Candidate base declaration
```scheme
(freebsd-base
#:name "stable-canary"
#:version-label "15.0-STABLE-p1"
#:release "15.0-STABLE"
#:branch "stable/15"
...)
```
Both declarations use the same validated native Phase 14 package composition:
- kernel from `freebsd-native-kernel-for`
- bootloader from `freebsd-native-bootloader-for`
- runtime from `freebsd-native-system-packages-for`
- `shepherd-pid1`
## Side-by-side build validation
Passing run:
- `PASS phase15-base-coexistence`
- workdir: `/tmp/phase15-2-coexist-1775202833`
Confirmed:
```text
current_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd
candidate_closure=/frx/store/dc40b1b7a76084e140d0457f3b7f6c5d4acc185f0d6cee0b161c9775d5fb3bec-fruix-system-fruix-freebsd
current_base_version_label=15.0-STABLE
candidate_base_version_label=15.0-STABLE-p1
side_by_side_base_versions=ok
rollback_rebuild_path=ok
```
Current native base stores:
```text
/frx/store/d9785661ea4829d51fbf545c2607a5691af2cc33c8ef3cd44de7ad5626685098-freebsd-native-kernel-15.0-STABLE
/frx/store/b448c822302ccdfb2f06da811fb224a044c51a9935bbfcd77a71a25d02f228f1-freebsd-native-bootloader-15.0-STABLE
/frx/store/ac3ba684020e70d3c76e593fd687cef8ab5e148958baabb477b7ef3d2647c5cd-freebsd-native-runtime-15.0-STABLE
```
Candidate native base stores:
```text
/frx/store/05bee8ffbe8c43242ffd97da4dc305f2921612a660cbcb48c3a3536bfac07079-freebsd-native-kernel-15.0-STABLE-p1
/frx/store/8955f1bfe89321e6e1e628c59376f2092547523f48a773974cc259963adac184-freebsd-native-bootloader-15.0-STABLE-p1
/frx/store/30314f17fd8ff4a1a3eff31c8c5048f15f67c46d1132d5b8c45fd9768742665e-freebsd-native-runtime-15.0-STABLE-p1
```
Important result:
- the older current closure stayed in `/frx/store`
- the candidate closure appeared beside it
- rebuilding the current declaration returned the exact original current closure path again
## Local QEMU rollback validation
Passing run:
- `PASS phase15-base-rollback-qemu`
- workdir: `/tmp/phase15-2-qemu2-1775204321`
Validation sequence:
1. boot current base
2. boot candidate base
3. boot current base again
Confirmed:
```text
current_first_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd
candidate_closure=/frx/store/dc40b1b7a76084e140d0457f3b7f6c5d4acc185f0d6cee0b161c9775d5fb3bec-fruix-system-fruix-freebsd
rollback_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd
current_base_version_label=15.0-STABLE
candidate_base_version_label=15.0-STABLE-p1
rollback_base_version_label=15.0-STABLE
base_rollforward_and_rollback=ok
```
This showed that the booted system could move forward to the candidate base and then return to the earlier closure without mutating it in place.
## Real XCP-ng rollback validation
Passing run:
- `PASS phase15-base-rollback-xcpng`
- workdir: `/tmp/phase15-2-xcpng-1775204839`
Validation sequence:
1. boot candidate base on the approved VM/VDI
2. boot current base again on the same approved VM/VDI
Confirmed:
```text
candidate_closure=/frx/store/dc40b1b7a76084e140d0457f3b7f6c5d4acc185f0d6cee0b161c9775d5fb3bec-fruix-system-fruix-freebsd
rollback_closure=/frx/store/9f57ecc6481e271811ceb53ac21a3b2aef4ef329f82b7d4788622315db1f0e43-fruix-system-fruix-freebsd
candidate_base_version_label=15.0-STABLE-p1
rollback_base_version_label=15.0-STABLE
vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289
vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743
base_rollforward_and_rollback=ok
```
Both boots also preserved the already-hardened guest properties:
- `shepherd_pid=1`
- `sshd_status=running`
- `compat_prefix_shims=absent`
- `guile_module_smoke=ok`
## Result
Phase 15.2 is complete.
Fruix now has a real declarative rebuild/redeploy/rollback story for the FreeBSD base at the store/model layer:
- two declared base versions can coexist side by side in `/frx/store`
- the candidate deployment does not overwrite the current one in place
- rebuilding the earlier declaration returns to the earlier closure path
- the same story works both locally under QEMU and on the approved XCP-ng VM/VDI path
## Scope note
This first upgrade-story validation still uses the same local `/usr/src` as the underlying source tree for both declarations. What changed is the declared base identity and therefore the store/model/deployment identity.
That is sufficient for this phase because the requirement was to establish the upgrade semantics:
- explicit base declaration
- side-by-side outputs
- rollback-friendly closures
The next improvement beyond Phase 15 would be to make acquiring or selecting distinct source trees/releases more reproducible and less tied to a single host checkout.