190 lines
6.1 KiB
Markdown
190 lines
6.1 KiB
Markdown
# Post-Phase 20: native build result promotion into first-class Fruix store objects
|
|
|
|
Date: 2026-04-05
|
|
|
|
## Goal
|
|
|
|
Make native FreeBSD base-build results feel like real Fruix objects instead of stopping at mutable staged files under:
|
|
|
|
- `/var/lib/fruix/native-builds/...`
|
|
|
|
The desired model is:
|
|
|
|
- `/var/lib/fruix/native-builds/...` remains a staging/result area
|
|
- `/frx/store/...` remains the real immutable identity
|
|
|
|
Validated artifact identities:
|
|
|
|
- `world`
|
|
- `kernel`
|
|
- `headers`
|
|
- `bootloader`
|
|
|
|
## What changed
|
|
|
|
### Promotion metadata in guest result roots
|
|
|
|
The guest self-hosted helper now emits a promotion description file at:
|
|
|
|
- `/var/lib/fruix/native-builds/<run-id>/promotion.scm`
|
|
|
|
That metadata records at least:
|
|
|
|
- executor / executor-version
|
|
- run-id / guest-host-name
|
|
- closure path
|
|
- development profile path
|
|
- declared FreeBSD base metadata
|
|
- source store provenance
|
|
- build policy
|
|
- artifact entries for:
|
|
- `world`
|
|
- `kernel`
|
|
- `headers`
|
|
- `bootloader`
|
|
|
|
The helper also stages a promotable `world` artifact tree in addition to the already validated narrower artifacts.
|
|
|
|
### Host-side promotion API
|
|
|
|
Fruix now exports:
|
|
|
|
- `promote-native-build-result`
|
|
|
|
and the CLI now exposes:
|
|
|
|
- `fruix native-build promote RESULT_ROOT [--store DIR]`
|
|
|
|
### Promoted store object layout
|
|
|
|
Promotion now creates immutable store objects for:
|
|
|
|
- `/frx/store/...-fruix-native-world-...`
|
|
- `/frx/store/...-fruix-native-kernel-...`
|
|
- `/frx/store/...-fruix-native-headers-...`
|
|
- `/frx/store/...-fruix-native-bootloader-...`
|
|
|
|
Each promoted artifact store records:
|
|
|
|
- `.fruix-native-build-object.scm`
|
|
- `.references`
|
|
|
|
Promotion also creates a result-bundle store object:
|
|
|
|
- `/frx/store/...-fruix-native-build-result-...`
|
|
|
|
That bundle records:
|
|
|
|
- `.fruix-native-build-result.scm`
|
|
- `artifacts/world`
|
|
- `artifacts/kernel`
|
|
- `artifacts/headers`
|
|
- `artifacts/bootloader`
|
|
|
|
where the `artifacts/*` entries are symlinks to the promoted artifact stores.
|
|
|
|
### Identity policy
|
|
|
|
Artifact identity is now based on Fruix metadata plus a tree-content signature of the staged artifact tree.
|
|
|
|
That means promotion identity depends on both:
|
|
|
|
- the explicit Fruix-native build metadata
|
|
- the actual content of the promoted artifact tree
|
|
|
|
## Validation harness
|
|
|
|
Added:
|
|
|
|
- `tests/system/run-phase20-native-build-store-promotion-xcpng.sh`
|
|
|
|
This harness:
|
|
|
|
1. boots the approved real XCP-ng guest path
|
|
2. runs the validated in-guest self-hosted native build helper
|
|
3. imports the guest result root back to the host
|
|
4. runs `fruix native-build promote`
|
|
5. verifies promoted store paths, metadata, symlink structure, and representative hashes
|
|
|
|
## Validation
|
|
|
|
Passing run:
|
|
|
|
- `PASS phase20-native-build-store-promotion-xcpng`
|
|
- workdir: `/tmp/current-phase20-native-build-store-promotion-xcpng`
|
|
|
|
Approved real XCP-ng path:
|
|
|
|
- VM `90490f2e-e8fc-4b7a-388e-5c26f0157289`
|
|
- VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743`
|
|
|
|
Representative metadata:
|
|
|
|
```text
|
|
run_id=20260405T213444Z
|
|
source_store=/frx/store/12d7704362e95afc2697db63f168b878e082b372-freebsd-source-default
|
|
guest_result_root=/var/lib/fruix/native-builds/20260405T213444Z
|
|
result_store=/frx/store/c6329a0053720b05aff3274b8b1d522c909f475d-fruix-native-build-result-15.0-STABLE-guest-self-hosted
|
|
world_store=/frx/store/dfe37b36f6537a95ceea16ea62001b2ca5617eb7-fruix-native-world-15.0-STABLE-guest-self-hosted
|
|
kernel_store=/frx/store/0ab7cbceca240ab2c3b91e83e059844ea792e49e-fruix-native-kernel-15.0-STABLE-guest-self-hosted
|
|
headers_store=/frx/store/5bbeae9266687a229f1c6d176a08886c35243ff0-fruix-native-headers-15.0-STABLE-guest-self-hosted
|
|
bootloader_store=/frx/store/bd49a508bd7a3b94a2535d6774f31c993c406552-fruix-native-bootloader-15.0-STABLE-guest-self-hosted
|
|
artifact_store_count=4
|
|
sha_kernel=16950f116a52134b98e2f8e0dacc556e18fe254e4a0ac2c1741422dde281a341
|
|
sha_loader=ea417846167ece270ada611624dca622ca38bd30125b9a125cd8ebb8b3600313
|
|
sha_param=9eb140ca7d9666f3d484a4174c9acd94b45427db6292b4e17de19af2c6aa5219
|
|
promoted_kernel_sha=16950f116a52134b98e2f8e0dacc556e18fe254e4a0ac2c1741422dde281a341
|
|
promoted_loader_sha=ea417846167ece270ada611624dca622ca38bd30125b9a125cd8ebb8b3600313
|
|
promoted_param_sha=9eb140ca7d9666f3d484a4174c9acd94b45427db6292b4e17de19af2c6aa5219
|
|
native_build_store_promotion=ok
|
|
```
|
|
|
|
Validated facts:
|
|
|
|
- guest self-hosted native-build results remain available under `/var/lib/fruix/native-builds/...` as mutable staging/results
|
|
- those staged results are now sufficient to promote first-class Fruix identities on the host
|
|
- promotion creates four immutable artifact store objects plus one immutable result-bundle store object
|
|
- promoted metadata retains executor/source/build-policy/provenance information explicitly
|
|
- promoted kernel, bootloader, and headers hashes match the already validated staged artifacts
|
|
- the promoted `world` artifact is now also preserved as a first-class Fruix store object instead of remaining only as an unpromoted staged tree
|
|
|
|
## Important implementation note
|
|
|
|
The first full promotion attempt exposed an incorrect assumption in the validation surface:
|
|
|
|
- the promoted/staged `world` artifact should be checked at:
|
|
- `bin/sh`
|
|
- not at:
|
|
- `usr/bin/sh`
|
|
|
|
That path expectation was corrected in:
|
|
|
|
- helper validation
|
|
- emitted promotion metadata
|
|
- the end-to-end promotion harness
|
|
|
|
## Result
|
|
|
|
Fruix now has a validated native-build object model with a clear split:
|
|
|
|
- mutable native-build result roots under `/var/lib/fruix/native-builds/...`
|
|
- immutable promoted identities under `/frx/store/...`
|
|
|
|
That makes native FreeBSD base builds feel substantially more Fruix-native:
|
|
|
|
- build outputs have explicit immutable identities
|
|
- metadata is Fruix-native rather than implied only by ad hoc directory layout
|
|
- executor/source/provenance/build-policy remain attached to the promoted result
|
|
- the staged result area and the real store identity are now intentionally distinct
|
|
|
|
## Next direction
|
|
|
|
This suggests the next product step is not merely “more self-hosting”.
|
|
|
|
It is to generalize this result model so different execution modes can converge on the same promoted object story, for example:
|
|
|
|
- host-initiated in-guest builds
|
|
- guest self-hosted builds
|
|
- future executor variants
|
|
|
|
That would move Fruix closer to a shared executor model rather than treating each validation path as a one-off harness. |