Document Fruix FreeBSD source policy

This commit is contained in:
2026-04-03 20:04:54 +02:00
parent 865012ea0c
commit 02a02e365d
4 changed files with 462 additions and 2 deletions

View File

@@ -1,5 +1,57 @@
# Progress
## 2026-04-03 — Phase 17.3 completed: the repo now records Fruix FreeBSD source policy explicitly
Completed work:
- added a repo-level source policy document:
- `docs/freebsd-source-policy.md`
- documented the current Fruix policy for:
- source kinds:
- `local-tree`
- `git`
- `src-txz`
- declared source vs effective source
- cache locations under `/frx/var/cache/fruix/freebsd-source`
- materialized source outputs under `/frx/store/*-freebsd-source-*`
- identity boundaries for:
- local-tree snapshots
- Git refs vs commits
- verified `src.txz` archives
- effective source root detection:
- `tree`
- `tree/usr/src`
- native build invalidation semantics
- closure provenance semantics
- update policy for moving refs vs pinned identities
- current patch/transformation policy
- wrote:
- `docs/reports/phase17-source-policy-freebsd.md`
Validation / evidence basis:
- policy matches the already-validated implementation from Phases 1617.2, including:
- `PASS phase16-source-materialization`
- `PASS phase16-source-driven-native-build`
- `PASS phase17-source-coexistence`
- `PASS phase17-source-revisions-qemu`
- the repo now states clearly that:
- Git refs are selectors, not stable reproducibility boundaries
- resolved Git commits are the effective Git identity boundary
- `src.txz` inputs require `sha256`
- native outputs must invalidate when materialized source identity changes, even when the visible base version label does not
Current assessment:
- Phase 17 is now fully complete
- Fruix can now:
- materialize FreeBSD sources declaratively
- keep distinct source revisions side by side in `/frx/store`
- boot systems built from those distinct source revisions
- explain the intended source caching/provenance/invalidation/update policy explicitly in the repo
- the next step is Phase 18:
- turn the current image/deployment primitives into a real installation workflow
## 2026-04-03 — Phase 17.2 completed: Fruix now boots systems from distinct declared FreeBSD source revisions
Completed work:

View File

@@ -30,6 +30,7 @@ Completed milestones include:
- **Source-driven native base builds**: native FreeBSD kernel/bootloader/runtime artifacts now consume those materialized source snapshots rather than ambient `/usr/src`, and their build metadata records both the declared source and the effective materialized source identity.
- **Side-by-side source revisions**: Fruix can now keep distinct FreeBSD source identities side by side in `/frx/store` and produce distinct native base outputs from them, even when the visible base version label is held constant.
- **Source-driven boot validation**: Fruix can now also boot systems built from distinct declared FreeBSD source revisions while preserving those source identities in image/build metadata.
- **Explicit source policy**: the repo now records how FreeBSD source objects are fetched, cached, identified, invalidated, and consumed by native base builds in `docs/freebsd-source-policy.md`.
- **Base upgrade story**: Fruix can now keep distinct declared base versions side by side in `/frx/store` and roll forward / back between them through the normal system deployment flow.
## Major pain points now behind us
@@ -44,7 +45,7 @@ Completed milestones include:
## Major pain points still ahead
- **True store-native runtime artifacts**: some historical build/install prefixes are still embedded in binaries and metadata. They are no longer required at runtime, but the local Guile/guile-extra/Shepherd build/install flow should still be moved to a genuinely store-native prefix from the start.
- **Source provenance/update policy**: Fruix now has side-by-side source-driven boots, but it still needs the repo-level policy for source caching, refresh, invalidation, and update semantics before later installation/deployment work depends on it.
- **Installation workflow**: the major remaining near-term gap is no longer source identity itself, but turning the existing build/image machinery into a first-class installation story with clearer deployment semantics.
- **Boot-path simplification**: Fruix now supports both the legacy `freebsd-init+rc.d-shepherd` path and the more Guix-like `shepherd-pid1` path. We still need to decide whether Shepherd PID 1 becomes the preferred/default architecture.
- **Reduce transitional FreeBSD glue**: more of the current bootstrap/activation/runtime setup should become cleaner and less prototype-specific over time.
- **Tooling and platform constraints**: local bhyve remains blocked by missing nested virtualization under Xen, and XO permissions still prevent creating/importing new VDIs; current validation must keep reusing the approved VM/VDI path.
@@ -52,4 +53,4 @@ Completed milestones include:
## Bottom line
Fruix has crossed the most important threshold: it is no longer just a collection of isolated FreeBSD experiments. It can now build declarative FreeBSD system artifacts, boot them on the real target VM, reach the network, serve SSH, run Shepherd as PID 1, operate from `/frx` without depending on temporary runtime-prefix shims, build native FreeBSD base artifacts into `/frx/store`, roll forward / back between declared base versions, materialize declared FreeBSD source inputs into `/frx/store`, and drive native base builds from those materialized source snapshots. The biggest remaining work is no longer “can this boot?” but “how fully can those fetched, pinned source revisions be validated side by side and turned into a real installation/deployment story?”
Fruix has crossed the most important threshold: it is no longer just a collection of isolated FreeBSD experiments. It can now build declarative FreeBSD system artifacts, boot them on the real target VM, reach the network, serve SSH, run Shepherd as PID 1, operate from `/frx` without depending on temporary runtime-prefix shims, build native FreeBSD base artifacts into `/frx/store`, roll forward / back between declared base versions, materialize declared FreeBSD source inputs into `/frx/store`, drive native base builds from those materialized source snapshots, boot systems from distinct source revisions, and explain the source provenance/invalidation rules explicitly. The biggest remaining work is no longer “can this boot?” but “how do those source-driven system artifacts become a real installation and deployment workflow?”

View File

@@ -0,0 +1,330 @@
# Fruix FreeBSD Source Policy
This document records the current intended policy for how Fruix models, fetches, caches, identifies, invalidates, and consumes FreeBSD source inputs.
It reflects the behavior implemented through Plan 4 Phases 16 and 17.
## 1. Source object model
Fruix represents FreeBSD source inputs explicitly with `freebsd-source`.
Currently supported source kinds are:
- `local-tree`
- `git`
- `src-txz`
A source object records some combination of:
- `name`
- `kind`
- `url`
- `path`
- `ref`
- `commit`
- `sha256`
Fruix distinguishes between:
- the **declared source**
- what the operator asked for
- the **effective source**
- what Fruix actually resolved/materialized and built from
That distinction matters most for Git refs and local-tree snapshots.
## 2. Source identity boundaries
### `local-tree`
Declared selector:
- local filesystem path
Effective identity boundary:
- filtered source-tree hash computed from `mtree`
Current rule:
- Fruix computes source identity from:
- `mtree -c -k type,link,size,mode,sha256digest`
- comment lines are removed before hashing
This avoids unstable `mtree` comment headers such as:
- date
- user
- machine
So the effective local-tree identity is content-oriented rather than host-comment-oriented.
### `git`
Declared selectors:
- `commit`, or
- `ref`
Effective identity boundary:
- resolved commit
Current rule:
- if `commit` is present, Fruix uses it as the fetch selector
- otherwise, Fruix uses `ref`
- after fetch, Fruix records the resolved commit as the effective Git identity
Policy consequence:
- a Git **ref** is a convenience selector
- a Git **commit** is the reproducibility boundary
Therefore:
- use `ref` alone for exploratory/latest tracking when drift is acceptable
- use `commit` for reproducible builds, side-by-side comparisons, installation artifacts, and rollback-sensitive workflows
- it is valid to record both:
- `ref` for human provenance
- `commit` for stable identity
### `src-txz`
Declared selectors:
- URL
- expected `sha256`
Effective identity boundary:
- verified archive `sha256`
Policy consequence:
- `src-txz` materialization is only valid when `sha256` is declared
- archive URL alone is not enough
## 3. Cache policy
Default cache root:
- `/frx/var/cache/fruix/freebsd-source`
Current cache layout:
- Git:
- `/frx/var/cache/fruix/freebsd-source/git/<hash>.git`
- release/snapshot archives:
- `/frx/var/cache/fruix/freebsd-source/archives/<hash>-src.txz`
### Git cache behavior
Fruix keeps a bare repository cache keyed by source URL.
Current behavior:
- initialize bare repo if absent
- ensure `origin` matches the declared URL
- fetch the requested selector from `origin`
- archive the resolved commit into the materialized store object
Policy:
- the cache is a transport/proxy optimization, not the identity boundary
- the identity boundary is the resolved commit recorded in the effective source and materialization metadata
### `src-txz` cache behavior
Fruix keeps the downloaded archive under the cache root.
Current behavior:
- if a cached archive exists, hash it
- if its hash does not match the declared `sha256`, delete it
- fetch the archive if missing
- verify the downloaded archive hash
- fail if the verified hash does not match the declared `sha256`
Policy:
- the cache is reusable only when the declared hash still matches
- hash mismatch invalidates the cached archive immediately
### `local-tree`
Current behavior:
- no separate network cache
- Fruix snapshots the local tree into a materialized store object
Policy:
- the local path is only a selector to a mutable host tree
- the materialized snapshot and its filtered tree hash are the meaningful Fruix identity boundary
## 4. Materialized source store policy
Materialized FreeBSD sources are stored in:
- `/frx/store/*-freebsd-source-*`
Current manifest inputs for a materialized source object include:
- materializer version
- declared source
- effective source
- source identity tuple
- for example resolved commit, archive sha256, or local tree hash
Policy consequence:
- changing any of those identity inputs should produce a distinct source store path
- changing materialization semantics should bump the materializer version
Current materializer version:
- `freebsd-source-materializer-version = "2"`
## 5. Effective source root policy
Not every source unpacks to the same top-level directory shape.
Current behavior:
- if `tree/Makefile` exists, effective root is:
- `tree`
- else if `tree/usr/src/Makefile` exists, effective root is:
- `tree/usr/src`
This is why:
- Git exports materialize effectively at `.../tree`
- official `src.txz` archives materialize effectively at `.../tree/usr/src`
Policy:
- native builds must consume the detected effective source root, not assume `/usr/src`
- the declared transitional `source-root` may still be recorded for provenance, but it is not the effective build root once materialization is in use
## 6. Native build invalidation policy
Native FreeBSD kernel/world/runtime/bootloader outputs must be invalidated by source identity, not just by package name/version.
Current behavior:
- native package materialization rewrites the install plan to use the materialized source root
- native manifests record both:
- `declared-source`
- `materialized-source`
- package materialization caching keys on the full manifest identity rather than only package name/version
- native build common metadata includes:
- `source-root`
- `source-tree-sha256`
- kernconf hash
- target metadata
Policy consequence:
- two builds with the same visible base version label but different source identities must still produce different native output store paths
- that behavior is intentional and required
## 7. Closure provenance policy
System closures and images should preserve enough source metadata to explain exactly what source snapshot was used.
Current closure/image metadata includes:
- `metadata/freebsd-source.scm`
- `metadata/freebsd-source-materializations.scm`
- `materialized_source_store_count`
- `materialized_source_stores`
Native `.freebsd-native-build-info.scm` records:
- declared source
- materialized source store path
- materialized source root
- materialized source tree hash
- effective Git commit or archive hash when applicable
Policy:
- source provenance is part of the closure boundary, not just a transient fetch detail
## 8. Update policy
### Recommended operator policy
For reproducible and rollback-sensitive workflows:
- prefer Git sources pinned by `commit`
- prefer archive sources pinned by `sha256`
- treat `local-tree` as a development/debugging input unless the resulting materialized snapshot is itself the explicit artifact being compared
### Moving refs
A moving Git ref is expected to drift over time.
Policy:
- if only `ref` is declared, Fruix may legitimately produce a new materialized source store later
- that new materialized source identity should then invalidate native outputs
- this is expected behavior, not a cache bug
### Installed/deployed systems
For installation artifacts and generation management, the source identity should be stable enough to answer:
- what exact source revision produced this system?
- can it be rebuilt later?
- should this update be considered a new generation boundary?
That means later installation/deployment work should prefer:
- Git commit-pinned sources
- hash-pinned archives
rather than floating refs alone.
## 9. Patch/transformation policy
Fruix does not yet expose a first-class patch queue or transformation layer on top of `freebsd-source`.
Current policy until that exists:
- the declared source object should be treated as the full upstream-source identity boundary
- when a patch/transformation layer is introduced later, it must become part of the materialized source identity and manifest versioning
In other words:
- applying patches without changing source identity metadata would be wrong
## 10. Relation to Guix-inspired semantics
This policy follows the same important high-level idea as Guix:
- selectors are not enough
- resolved, content-stable identities matter
- cached transport objects are not the same as reproducible store identities
Fruix applies that idea in FreeBSD-specific form:
- `src.txz` handling
- FreeBSD source-tree effective-root detection
- mtree-based FreeBSD tree identity
- native FreeBSD base builds driven from materialized source snapshots under `/frx/store`
## 11. Practical summary
Use these rules:
- **Want reproducibility?**
- pin Git by `commit`
- pin archives by `sha256`
- **Want side-by-side comparison?**
- keep distinct source objects and let Fruix materialize them separately
- **Want native base outputs to differ only when they should?**
- rely on materialized source identity, not mutable `/usr/src`
- **Want stable deployment provenance?**
- preserve the closure metadata files and materialized source store references

View File

@@ -0,0 +1,77 @@
# Phase 17.3: clarify FreeBSD source provenance, caching, and update policy
Date: 2026-04-03
## Goal
Phase 17.3 turns the source behavior implemented in Phases 16 through 17.2 into an explicit repo-level policy.
The main question was no longer whether Fruix *can* fetch and boot from declared FreeBSD sources. It can.
The question here is:
- how should operators think about source selectors versus stable source identity?
- what exactly lives in cache versus store?
- when should native outputs be invalidated?
- what is the intended policy for moving Git refs, pinned commits, and archive hashes?
## Added documentation
Added:
- `docs/freebsd-source-policy.md`
This document explains:
- supported source kinds:
- `local-tree`
- `git`
- `src-txz`
- declared source vs effective source
- cache locations under:
- `/frx/var/cache/fruix/freebsd-source`
- materialized source outputs under:
- `/frx/store/*-freebsd-source-*`
- effective identity rules for:
- local-tree snapshots
- Git refs/commits
- verified `src.txz` archives
- effective source root detection rules:
- `tree`
- `tree/usr/src`
- native build invalidation policy
- closure provenance policy
- update policy for moving refs vs pinned commits
- the current no-hidden-patch-layer rule
## Key policy conclusions
The repo now states clearly that:
- Git refs are selectors, not stable reproducibility boundaries
- resolved Git commits are the effective Git identity boundary
- `src.txz` URLs are not enough by themselves; `sha256` is required
- local trees are mutable selectors; the materialized snapshot and filtered tree hash are the meaningful Fruix identity
- native FreeBSD base outputs must invalidate when the materialized source identity changes, even if the visible base version label does not
- cache objects are transport optimizations, not the final identity boundary
## Relation to validated behavior
The new policy document matches the validated Phase 17 behavior:
- Phase 17.1 proved that distinct source identities can coexist side by side and produce different native outputs for the same visible base version label
- Phase 17.2 proved that systems built from those distinct source identities can boot successfully through the validated native path
## Result
Phase 17.3 is complete.
The repo now clearly explains how FreeBSD source objects are:
- fetched
- cached
- identified
- invalidated
- and consumed by native FreeBSD base builds
That completes Phase 17 and leaves Fruix in a better position to begin the installation/deployment work in Phase 18.