From 56d9d6a54be452c28e3ae270e283d800f9bdb05f Mon Sep 17 00:00:00 2001 From: Steffen Beyer Date: Sat, 4 Apr 2026 08:51:04 +0200 Subject: [PATCH] Archive detailed progress log --- docs/PROGRESS.md | 4274 +---------------- .../progress-log-through-phase18-2-freebsd.md | 4227 ++++++++++++++++ 2 files changed, 4303 insertions(+), 4198 deletions(-) create mode 100644 docs/reports/progress-log-through-phase18-2-freebsd.md diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 925c8bc..3eca87c 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,55 +1,65 @@ # Progress -## 2026-04-04 — Phase 18.2 completed: Fruix now boots a minimal installer environment and installs a target system from inside it +This file is now intentionally compact. -Completed work: +Detailed chronological history through Phase 18.2 has been archived at: + +- `docs/reports/progress-log-through-phase18-2-freebsd.md` + +For a broader narrative summary, see: + +- `docs/PROG_SUMMARY.md` + +## Current status + +Fruix currently has: + +- declarative system modeling on FreeBSD +- content-addressed system closures under `/frx/store` +- native FreeBSD base artifacts in `/frx/store` +- declarative FreeBSD source objects and source materialization +- source-driven native base builds from materialized source snapshots +- side-by-side source revisions and boot validation +- a host-driven non-interactive install path: + - `fruix system install` +- a bootable Fruix-managed installer environment: + - `fruix system installer` + +Validated boot modes still are: + +- `freebsd-init+rc.d-shepherd` +- `shepherd-pid1` + +The validated Phase 18 installation work currently uses: + +- `freebsd-init+rc.d-shepherd` + +## Latest completed achievement + +### 2026-04-04 — Phase 18.2 completed + +Fruix now boots a minimal installer environment and installs a target system from inside it. + +Highlights: - added in `modules/fruix/system/freebsd.scm`: - `installer-operating-system` - `operating-system-installer-image-spec` - `materialize-installer-image` -- the installer environment is now derived from the selected target operating system, while forcing the currently most stable installer boot path: - - `freebsd-init+rc.d-shepherd` -- the installer image now carries: - - its own installer-system closure - - the selected target-system closure - - the selected target-system store closure - - a staged target rootfs under: - - `/var/lib/fruix/installer/target-rootfs` - - installer plan/state files under: - - `/var/lib/fruix/installer` - - installer helper scripts: - - `/usr/local/libexec/fruix-installer-run` - - `/usr/local/etc/rc.d/fruix-installer` -- the booted installer environment now performs the install from inside the guest by: - - partitioning the selected target disk - - creating EFI + UFS filesystems - - copying the staged target rootfs - - copying only the selected target system's required store items into the target `/frx/store` - - installing the target `loader.efi` - - writing target install metadata to: - - `/var/lib/fruix/install.scm` - - recording installer state in: - - `/var/lib/fruix/installer/state` - - logging to: - - `/var/log/fruix-installer.log` -- added user-facing CLI support in `scripts/fruix.scm`: +- added CLI support in `scripts/fruix.scm`: - `fruix system installer` - - new option: - - `--install-target-device DEVICE` -- corrected the default FreeBSD virtio install target device for QEMU validation to: - - `/dev/vtbd1` - rather than the earlier incorrect Linux-flavored guess: - - `/dev/vtblk1` -- fixed `materialize-bhyve-image` so the generated UFS filesystem label now respects: - - `root-partition-label` - rather than always hardcoding: - - `fruix-root` -- added validation artifacts: - - `tests/system/phase18-installer-target-operating-system.scm.in` - - `tests/system/run-phase18-installer-environment.sh` -- wrote: - - `docs/reports/phase18-installer-environment-freebsd.md` + - `--install-target-device DEVICE` +- the installer image now carries: + - its own installer closure + - the selected target closure + - the target store closure + - a staged target rootfs payload + - in-guest installer state/log/scripts +- validated workflow: + - boot installer image in QEMU/UEFI/TCG + - reach installer over SSH + - install target system onto second disk from inside the guest + - boot the installed target successfully Validation: @@ -57,4171 +67,39 @@ Validation: - regression re-checks: - `PASS phase18-system-install` - `PASS phase17-source-revisions-qemu` -- validated a full two-disk workflow: - - booted Fruix installer image under QEMU/UEFI/TCG - - installer environment became reachable over SSH - - installer environment completed in-guest install with: - - `installer_state=done` - - installer log recorded: - - `fruix-installer:done` - - installed target disk contained: - - GPT partition table - - ESP filesystem: - - `msdosfs` - - root filesystem: - - `ufs` - - `EFI/BOOT/BOOTX64.EFI` - - `/var/lib/fruix/install.scm` -- validated source-driven provenance through the installer environment from: - - Git ref: - - `stable/15` - - pinned commit: - - `332708a606f6bf0841c1d4a74c0d067f5640fe89` - - materialized source store: - - `/frx/store/7563df2714ae7fa9bd40b83c74512ffe2cb2ad91b297915591b55c76edbb2fcb-freebsd-source-stable15-installer-target-source` -- validated boot of the installed target after in-guest installation: - - `/run/current-system` points at the installed target closure - - `/usr/local/etc/rc.d/fruix-shepherd onestatus` reports running - - `sshd` running - - activation completed successfully -Current assessment: +Report: -- Phase 18.2 is complete -- Fruix now has a minimal Fruix-managed installer environment, not just a host-driven installation primitive -- the next step is Phase 18.3: - - produce a bootable installer ISO for UEFI systems +- `docs/reports/phase18-installer-environment-freebsd.md` -## 2026-04-03 — Phase 18.1 completed: Fruix now has a minimal non-interactive installation flow +Commit: -Completed work: +- `1d00907` — `Add Fruix bootable installer environment` -- added in `modules/fruix/system/freebsd.scm`: - - `operating-system-install-spec` - - `install-operating-system` -- refactored rootfs staging with: - - `populate-rootfs-from-closure` - so image generation and installation can share the same declarative rootfs assembly logic -- the new installer now supports: - - raw image-file targets - - `/dev/...` block-device targets -- for raw image targets, Fruix now performs a repeatable install flow that: - - creates/truncates the target image - - attaches it with `mdconfig` - - creates GPT partitions - - formats an EFI partition and UFS root partition - - stages the system rootfs - - copies the selected closure and referenced `/frx/store` items into the installed root - - installs `loader.efi` to `EFI/BOOT/BOOTX64.EFI` - - writes install metadata to: - - `/var/lib/fruix/install.scm` -- added user-facing CLI support in `scripts/fruix.scm`: - - `fruix system install` - - new option: - - `--target PATH` -- install metadata emitted by the CLI now includes: - - target/target-kind/device fields - - install metadata path - - disk/root sizing - - declared/materialized FreeBSD source metadata - - closure/native/runtime store metadata -- added validation artifacts: - - `tests/system/phase18-install-operating-system.scm.in` - - `tests/system/run-phase18-system-install.sh` -- wrote: - - `docs/reports/phase18-minimal-installation-flow-freebsd.md` +## Recent major milestones -Validation: +- `1d00907` — `Add Fruix bootable installer environment` +- `2517710` — `Add non-interactive Fruix installation flow` +- `02a02e3` — `Document Fruix FreeBSD source policy` +- `865012e` — `Boot Fruix from distinct FreeBSD source revisions` +- `8150508` — `Validate side-by-side FreeBSD source revisions` +- `5cbf5b9` — `Build native bases from materialized FreeBSD sources` -- `PASS phase18-system-install` -- regression re-check: - - `PASS phase17-source-revisions-qemu` -- validated a full install to a raw target image: - - target kind: - - `raw-file` - - disk capacity: - - `12g` - - root size: - - `10g` -- validated target layout and boot artifacts: - - GPT image created - - ESP filesystem: - - `msdosfs` - - root filesystem: - - `ufs` - - `EFI/BOOT/BOOTX64.EFI` present -- validated installed-system boot through the already-validated mode: - - `freebsd-init+rc.d-shepherd` -- validated after boot: - - `sshd` running - - `/usr/local/etc/rc.d/fruix-shepherd onestatus` reports running - - activation completed successfully - - `/run/current-system` points at the installed closure under `/frx/store` -- validated source-driven installation provenance from: - - Git ref: - - `stable/15` - - pinned commit: - - `332708a606f6bf0841c1d4a74c0d067f5640fe89` - - installed materialized source store: - - `/frx/store/a892afb425235de71c9da38884e2ebdba5dafd3a1993f432fe7c446f5af2151f-freebsd-source-stable15-install-source` +## Active constraints -Operational note: - -- I tested the idea of defaulting local QEMU/TCG validation to 8 vCPUs -- result: - - under TCG, higher SMP did not help this path and regressed boot responsiveness -- current harnesses therefore keep `QEMU_SMP` configurable but retain the conservative local default of `2` - -Current assessment: - -- Phase 18.1 is complete -- Fruix can now perform a repeatable, non-interactive installation of a declarative system onto a target image or disk without relying on ad hoc manual assembly -- the next step is Phase 18.2: - - build a minimal Fruix-managed installer environment that can boot into an install context and run this workflow from within that environment - -## 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 16–17.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: - -- added boot validation harness: - - `tests/system/run-phase17-source-revisions-qemu.sh` -- the new harness renders the Phase 17 Git and `src.txz` operating-system templates and boots both systems through the validated: - - QEMU - - UEFI - - TCG - - `shepherd-pid1` - path -- validated booted source identities: - - Git source: - - ref: `stable/15` - - commit: `332708a606f6bf0841c1d4a74c0d067f5640fe89` - - `src.txz` source: - - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` - - sha256: - - `83c3e8157b6d7afcae57167fda75693bf1e5f581ca149a6ecb2d398b71bdfab0` -- confirmed image/build metadata for both boots records: - - declared source kind - - ref/commit or archive URL/sha256 - - materialized source store path - - distinct native base store sets -- wrote: - - `docs/reports/phase17-source-revision-boots-freebsd.md` - -Validation: - -- `PASS phase17-source-revisions-qemu` -- validated distinct booted closures: - - Git: - - `/frx/store/d6cbcc76f57fa9c392a80fe20e7499f7a837aab4fb96ea056e624cde95bc70c8-fruix-system-fruix-freebsd` - - `src.txz`: - - `/frx/store/02268e19930facb32e12b6ec191f2e5704d1e81033baf3637a889ad15924ff88-fruix-system-fruix-freebsd` -- validated both guests reached the validated runtime state: - - Shepherd as PID 1 - - `sshd` running -- validated distinct materialized source stores and distinct native kernel/bootloader/runtime outputs for the two boots - -Current assessment: - -- Phase 17.2 is complete -- Fruix can now both build **and boot** systems from distinct declared FreeBSD source revisions -- the next step is Phase 17.3: - - document the intended policy for source provenance, caching, invalidation, and update semantics before installation work depends on it - -## 2026-04-03 — Phase 17.1 completed: side-by-side FreeBSD source revisions now coexist in `/frx/store` - -Completed work: - -- added Phase 17 operating-system templates for distinct source identities: - - `tests/system/phase17-git-source-operating-system.scm.in` - - `tests/system/phase17-txz-source-operating-system.scm.in` -- modeled the Git side with both: - - ref: `stable/15` - - pinned commit: - - `332708a606f6bf0841c1d4a74c0d067f5640fe89` -- modeled the archive side with: - - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` - - sha256: - - `83c3e8157b6d7afcae57167fda75693bf1e5f581ca149a6ecb2d398b71bdfab0` -- added side-by-side source coexistence validation: - - `tests/system/run-phase17-source-coexistence.sh` -- the new harness builds: - - Git source build A - - `src.txz` source build - - Git source rebuild B - and verifies: - - Git rebuild stability when pinned by commit - - distinct closure paths for Git vs `src.txz` - - distinct materialized source stores - - distinct native kernel/bootloader/runtime outputs - - correct declared/materialized source metadata in closures and native build info - - continued use of the materialized source root instead of the unused declared transitional `source-root` -- wrote: - - `docs/reports/phase17-side-by-side-source-revisions-freebsd.md` - -Validation: - -- `PASS phase17-source-coexistence` -- validated side-by-side closures: - - Git closure: - - `/frx/store/d6cbcc76f57fa9c392a80fe20e7499f7a837aab4fb96ea056e624cde95bc70c8-fruix-system-fruix-freebsd` - - `src.txz` closure: - - `/frx/store/02268e19930facb32e12b6ec191f2e5704d1e81033baf3637a889ad15924ff88-fruix-system-fruix-freebsd` -- validated distinct materialized source stores: - - Git: - - `/frx/store/c9928605fa906b90a600dafeebe5005dd18ad3b8e62b7111d9d13ad60ee56490-freebsd-source-stable15-side-a` - - `src.txz`: - - `/frx/store/5eaeff5c6c55a95b6531d9cf2e1824cd4368d81c614608426bee1a5d2a664dc5-freebsd-source-release15-side-b` -- validated distinct native base outputs for the **same** version label: - - `15.0-source-side-by-side` -- validated effective source roots: - - Git: - - `.../tree` - - `src.txz`: - - `.../tree/usr/src` - -Current assessment: - -- Phase 17.1 is complete -- Fruix can now keep at least two distinct FreeBSD source revisions side by side in `/frx/store` as meaningful native base inputs/outputs -- the next step is Phase 17.2: - - boot systems built from at least two distinct declared source revisions and confirm that the booted metadata tracks those revisions - -## 2026-04-03 — Phase 16.3 completed: native FreeBSD base builds now consume materialized source inputs - -Completed work: - -- refactored native FreeBSD package materialization in `modules/fruix/system/freebsd.scm` so native packages now: - - reconstruct the declared `freebsd-source` from the package plan - - materialize that source under Fruix control - - rewrite the native build plan to use the materialized source root - - add the materialized source store path to package references -- native build manifests now include: - - `declared-source` - - `materialized-source` -- native `.freebsd-native-build-info.scm` now records: - - declared source - - materialized source store path - - materialized source root - - materialized source tree sha256 - - effective source details such as resolved Git commit / archive sha256 -- native build common manifests now reuse the materialized source tree hash when available -- package materialization caching is now keyed by manifest identity instead of only package name/version, so distinct source-driven variants do not collide in-process -- system closure materialization now keeps a dedicated source-materialization cache and records: - - `metadata/freebsd-source-materializations.scm` - - `materialized-source-store-count` - - `materialized-source-stores` -- system closure references now include the materialized source stores explicitly -- `scripts/fruix.scm` now emits for `fruix system build` and `image`: - - `freebsd_source_materializations_file` - - `materialized_source_store_count` - - `materialized_source_stores` -- added validation artifacts: - - `tests/system/phase16-git-materialized-source-operating-system.scm.in` - - `tests/system/run-phase16-source-driven-native-build.sh` -- wrote: - - `docs/reports/phase16-source-driven-native-builds-freebsd.md` - -Validation: - -- `PASS phase16-source-driven-native-build` -- `PASS phase16-source-materialization` -- `PASS phase16-declarative-source-build` -- validated a full native system build from declared Git source: - - `https://git.FreeBSD.org/src.git` - - ref: `stable/15` - - resolved commit during validation: - - `332708a606f6bf0841c1d4a74c0d067f5640fe89` -- intentionally declared an unused transitional source-root: - - `/var/empty/fruix-unused-source-root` - and confirmed native build info instead used the materialized source root under `/frx/store/*-freebsd-source-*/tree` - -Current assessment: - -- Phase 16 is now fully complete -- Fruix can: - - declare FreeBSD source inputs - - materialize them under `/frx/store` - - build native FreeBSD base artifacts from those materialized source snapshots -- the next step is Phase 17: - - build and compare side-by-side source revisions, then boot from them - -## 2026-04-03 — Phase 16.2 completed: Fruix now materializes FreeBSD source inputs under its control - -Completed work: - -- added a new exported source materializer in `modules/fruix/system/freebsd.scm`: - - `materialize-freebsd-source` -- added cache-backed materialization for source kinds: - - `local-tree` - - `git` - - `src-txz` -- added cache locations under: - - `/frx/var/cache/fruix/freebsd-source/git` - - `/frx/var/cache/fruix/freebsd-source/archives` -- materialized source outputs now live in `/frx/store` as: - - `*-freebsd-source-*` -- each materialized source now records: - - declared source - - effective/resolved source - - source store path - - effective source root - - source tree sha256 - - cache path -- added automatic effective-root detection so archive-backed sources that unpack as `usr/src/...` are still usable later: - - Git exports use `.../tree` - - `src.txz` archives use `.../tree/usr/src` -- added a new user-facing CLI path in `scripts/fruix.scm`: - - `fruix source materialize SOURCE-FILE` -- new source command options: - - `--source NAME` - - `--store DIR` - - `--cache DIR` - - `--help` -- source CLI now emits machine-readable metadata for: - - declared source fields - - materialized store path/root - - source tree hash - - cache path - - resolved Git commit - - verified archive sha256 -- tightened `src-txz` validation so materialization now requires: - - URL - - sha256 -- added validation artifacts: - - `tests/system/phase16-git-freebsd-source.scm.in` - - `tests/system/phase16-txz-freebsd-source.scm.in` - - `tests/system/run-phase16-source-materialization.sh` -- wrote: - - `docs/reports/phase16-source-materialization-freebsd.md` - -Validation: - -- `PASS phase16-source-materialization` -- `PASS phase16-declarative-source-build` -- verified Git source fetch/materialization from: - - `https://git.FreeBSD.org/src.git` - - ref: `stable/15` - - resolved commit during validation: - - `332708a606f6bf0841c1d4a74c0d067f5640fe89` -- verified canonical release archive fetch/materialization from: - - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` - - sha256: - - `83c3e8157b6d7afcae57167fda75693bf1e5f581ca149a6ecb2d398b71bdfab0` -- verified repeated materialization returns stable store paths for both the Git and `src.txz` cases - -Current assessment: - -- Phase 16.2 is complete -- Fruix can now fetch or materialize declared FreeBSD source trees into `/frx/store` with cache-backed provenance under `/frx/var/cache/fruix/freebsd-source` -- the next step is Phase 16.3: - - teach native FreeBSD kernel/world/runtime builds to consume these materialized source artifacts instead of ambient `/usr/src` - -## 2026-04-03 — Phase 16.1 completed: FreeBSD source inputs are now explicit Fruix objects - -Completed work: - -- added `docs/PLAN_4.md` to define the post-Phase-15 roadmap around: - - declarative FreeBSD source acquisition - - installation artifacts - - the controlled path toward self-hosting -- introduced a first-class `freebsd-source` record in `modules/fruix/packages/freebsd.scm` with: - - supported kinds: - - `local-tree` - - `git` - - `src-txz` - - exported accessors for: - - `name` - - `kind` - - `url` - - `path` - - `ref` - - `commit` - - `sha256` - - new `%default-freebsd-source` -- extended `freebsd-base` so it now records both: - - transitional `source-root` - - declarative `source` -- added/exported: - - `freebsd-base-source` -- threaded declared source fields into native package plans so native build outputs can record them -- in `modules/fruix/system/freebsd.scm`: - - added source validation for: - - `local-tree` - - `git` - - `src-txz` - - added `freebsd-source-spec` - - `freebsd-base-spec` now nests the declared source - - native manifests and `.freebsd-native-build-info.scm` now include: - - `declared-source` - - closures now generate: - - `metadata/freebsd-source.scm` - - `metadata/store-layout.scm` now records: - - `freebsd-source` -- in `scripts/fruix.scm`, `build` and `image` metadata now emit: - - `freebsd_source_name` - - `freebsd_source_kind` - - `freebsd_source_url` - - `freebsd_source_path` - - `freebsd_source_ref` - - `freebsd_source_commit` - - `freebsd_source_sha256` - - `freebsd_source_file` -- added validation artifacts: - - `tests/system/phase16-declarative-source-operating-system.scm.in` - - `tests/system/run-phase16-declarative-source-build.sh` - - `tests/system/validate-phase16-freebsd-source.scm` -- compared Fruix's new source model with Guix's source modeling via: - - `~/repos/guix/guix/packages.scm` - - `~/repos/guix/guix/git-download.scm` -- wrote: - - `docs/reports/phase16-declarative-source-model-freebsd.md` - -Validation: - -- `PASS phase16-declarative-source-build` -- source model probe confirmed support for: - - local-tree `/usr/src` - - Git refs such as `stable/15` at `https://git.FreeBSD.org/src.git` - - canonical `src.txz` URLs such as: - - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` - - `https://download.freebsd.org/snapshots/amd64/15.0-STABLE/src.txz` -- closure/native metadata now records the declared source explicitly while preserving the current validated `/usr/src` build path - -Current assessment: - -- Phase 16.1 is complete -- Fruix can now describe FreeBSD source inputs explicitly, but it does not fetch/materialize them yet -- the next step is Phase 16.2: - - fetch or materialize declared FreeBSD source inputs under Fruix control and use their stable identity as the next reproducibility boundary - -## 2026-04-01 — Phase 1.1 started: Guile verified on FreeBSD amd64 - -Completed work: - -- installed/confirmed `guile3-3.0.10` -- added a reusable verification harness: - - `tests/guile/run-phase1-verification.sh` - - `tests/guile/verify-phase1.scm` - - `tests/guile/modules/phase1/sample.scm` -- verified the following on `FreeBSD 15.0-STABLE` amd64: - - module loading - - deterministic output generation - - file I/O - - process handling with `primitive-fork`/`waitpid` - - loopback TCP sockets - - FFI calls into libc - - execution of Guix bootstrap-related code from `(guix build make-bootstrap)` -- wrote the results to `docs/reports/phase1-guile-freebsd.md` - -Notable findings: - -- `guile3` and `guile-3.0` are present, but there is no unversioned `guile` binary -- `system*` and `open-pipe*` currently segfault on this host (`exit 139`) -- despite that crash, the lower-level process primitives needed for further investigation do work - -Current assessment: - -- Phase 1.1 has a solid amd64 smoke-verification baseline -- Phase 1.1 is not fully complete yet because `i386` has not been checked and the subprocess crash needs investigation -- verification harness committed as `e380e88` (`Add FreeBSD Guile verification harness`) - -## 2026-04-01 — Phase 1.1 follow-up: subprocess crash isolated - -Completed work: - -- added a dedicated subprocess diagnostic harness: - - `tests/guile/run-subprocess-diagnostics.sh` - - `tests/guile/posix-spawn-freebsd-diagnostics.c` -- reproduced crashes for: - - `system*` - - `spawn` - - `open-pipe*` -- confirmed all three fail with `SIGSEGV` / `exit 139` -- confirmed native FreeBSD `posix_spawn` + `posix_spawn_file_actions_addclosefrom_np` works in a standalone C program -- confirmed FreeBSD behavior that triggers gnulib replacement logic: - - `posix_spawn_file_actions_adddup2` accepts an invalid fd in the gnulib probe - - `posix_spawn_file_actions_addopen` accepts an invalid fd in the gnulib probe - - `posix_spawnp` accepts a shebang-less executable script in the gnulib security probe -- wrote the analysis to `docs/reports/phase1-guile-subprocess-crash.md` - -Conclusion: - -- this is most likely an upstream Guile/gnulib ABI bug on FreeBSD, not a Guix-specific problem -- likely sequence: - 1. gnulib enables `REPLACE_POSIX_SPAWN=1` - 2. Guile still enables `HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP` - 3. Guile passes a gnulib replacement `posix_spawn_file_actions_t` object to native `posix_spawn_file_actions_addclosefrom_np` - 4. libc interprets gnulib struct fields as a native pointer and crashes -- evidence from the lldb core matches this hypothesis (`*fa = 0x0000000600000008`, consistent with gnulib `_allocated=8`, `_used=6`) - -Current assessment: - -- Phase 1.1 amd64 investigation is now much stronger and has a concrete root-cause hypothesis -- the next practical step is to validate a workaround or patch in Guile so subprocess helpers stop crashing -- after that, continue with Phase 1.2 (minimal native build environment / GNU Hello) - -## 2026-04-01 — Phase 1.1 follow-up: local Guile build validated the fix - -Completed work: - -- installed the additional build tooling needed for a local Guile checkout build: - - `autoconf` - - `automake` - - `libtool` - - `gettext-tools` - - `texinfo` - - `help2man` - - `gperf` - - `pkgconf` -- confirmed a FreeBSD-specific bootstrap quirk: - - Guile `autogen.sh` needs GNU `m4` - - FreeBSD base `/usr/bin/m4` is not sufficient - - `M4=gm4 ./autogen.sh` works -- built a disposable validation copy from `~/repos/guile` -- confirmed `~/repos/guile` already contains upstream commit: - - `eb828801f621d3e130b6fe88cfc4acaa69b98a03` - - `Don't use posix_spawn_file_actions_addclosefrom_np with glib posix_spawn` -- updated the local test harnesses so they can test non-system Guile builds: - - `tests/guile/run-phase1-verification.sh` - - `tests/guile/run-subprocess-diagnostics.sh` - - both now accept `GUILE_BIN` - - both now prepend the sibling `../lib` directory to `LD_LIBRARY_PATH` when a matching local `libguile-3.0.so.1` exists - - subprocess diagnostics now supports `EXPECT_GUILE_SUBPROCESS_CRASH=0` for fixed builds -- validated that the packaged Guile still reproduces the crash -- validated that the locally built Guile succeeds for: - - `system*` - - `spawn` - - `open-pipe*` -- re-ran the broader Phase 1.1 Scheme verification suite successfully against the local Guile build -- wrote the results to `docs/reports/phase1-guile-local-build-validation.md` - -Important findings: - -- the local Guile executable initially still crashed until it was forced to load its matching local `libguile-3.0.so.1` -- once `LD_LIBRARY_PATH` pointed at the local install lib directory, subprocess helpers worked correctly -- this strongly supports the earlier diagnosis and shows that the upstream Guile fix resolves the problem in practice -- the local `~/repos/bdwgc` checkout was not needed for this step; packaged `boehm-gc-threaded` was sufficient so far - -Current assessment: - -- Phase 1.1 now has both a root-cause analysis and a working validated fix path on amd64 -- no source changes were needed in `~/repos/guile` because the local checkout already contains the relevant upstream fix -- no source changes were needed in `~/repos/bdwgc` yet, but the earlier FreeBSD warning keeps it on the watch list -- the project can now move on to Phase 1.2 with a known-good local Guile fallback - -## 2026-04-01 — Phase 1.2 started: native GNU Hello build validated on FreeBSD - -Completed work: - -- added a reusable native build harness: - - `tests/native-build/run-gnu-hello.sh` -- used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for: - - GNU Hello version `2.12.3` - - expected Guix nix-base32 source hash `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd` -- verified the downloaded tarball against the translated SHA256: - - `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0` -- successfully executed the standard native build lifecycle on `FreeBSD 15.0-STABLE` amd64: - - fetch - - hash verification - - extract - - configure - - build - - staged install - - runtime execution -- confirmed the staged binary runs and prints: - - `Hello, world!` -- captured build metadata including: - - compiler and make versions - - host triplet - - configure command - - staged output path - - runtime shared-library dependencies -- wrote the results to `docs/reports/phase1-native-gnu-hello.md` - -Important findings: - -- GNU Hello built successfully with FreeBSD base `make`, not just `gmake` -- that contrasts with the earlier local Guile build, which did require GNU `gmake` -- even this minimal GNU package links against FreeBSD-userland-provided libraries such as `libiconv` and `libintl`, which is useful data for later Guix package modeling -- this step is still a native shell-driven build exercise, not yet a real Guix package build - -Current assessment: - -- Phase 1.2 now has a concrete native autotools success case on FreeBSD -- the host can perform the basic fetch/verify/configure/build/install/run cycle needed for later `gnu-build-system` adaptation work -- Guix-specific build orchestration is still missing, but the environmental baseline is stronger now - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` - -Next recommended step: - -1. extend Phase 1.2 with at least one additional representative GNU/autotools package build on FreeBSD, or -2. prototype a tiny Scheme-based `gnu-build-system`-like phase runner using the known-good local Guile path, starting from the GNU Hello flow -3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: Guix builder-side GNU Hello phase runner validated - -Completed work: - -- added a Scheme-driven GNU Hello build prototype: - - `tests/native-build/gnu-hello-guix-phase-runner.scm` - - `tests/native-build/run-gnu-hello-guix-phase-runner.sh` -- required the previously validated fixed local Guile build for this harness because it depends on subprocess-heavy Scheme operations -- used Guix modules directly from `~/repos/guix`, including: - - `(guix base32)` - - `(guix build gnu-build-system)` - - `(guix build utils)` -- fetched and hash-verified GNU Hello `2.12.3` again against the Guix package hash: - - nix-base32: `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd` - - SHA256: `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0` -- successfully executed a subset of Guix builder-side `%standard-phases` on FreeBSD: - - `set-SOURCE-DATE-EPOCH` - - `unpack` - - `configure` - - `build` - - `check` - - `install` -- installed GNU Hello into a store-like output path under the temporary work directory rather than using a `/usr/local` `DESTDIR` staging layout -- executed the resulting binary successfully and confirmed output: - - `Hello, world!` -- captured metadata including: - - host triplet - - selected phase list - - runtime dependencies - - test-suite summary -- wrote the results to `docs/reports/phase1-guix-gnu-hello-phase-runner.md` - -Important findings: - -- this is the first validation step in the repo that successfully exercised actual Guix builder-side GNU build logic on FreeBSD instead of only a shell approximation -- the harness works when driven by the fixed local Guile build, confirming that the earlier Guile subprocess-fix validation is directly useful for FreeBSD Guix build orchestration -- GNU Hello's `make check` test suite also passed in this mode: - - total: `7` - - pass: `7` - - fail: `0` -- the resulting binary's runtime dependencies differ from the earlier `/usr/local`-prefixed native shell harness; in this store-like output layout it only showed: - - `libc.so.7` - - `libsys.so.7` -- that difference is a useful clue that Guix-style output layout/build invocation can materially affect FreeBSD runtime linkage behavior - -Current assessment: - -- Phase 1.2 now has both: - - a shell-driven native GNU Hello build harness, and - - a Scheme-driven prototype that uses real Guix builder-side GNU phases -- this is still short of a true Guix package/derivation build, but it significantly narrows the gap between host validation and real `gnu-build-system` execution on FreeBSD -- the known-good local Guile path is now validated as part of a practical Guix-adjacent build workflow, not just standalone subprocess diagnostics - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` - -Next recommended step: - -1. run the Scheme-driven phase-runner pattern against at least one more small GNU/autotools package on FreeBSD, or -2. document the concrete gaps between this prototype and a real Guix package/derivation build, especially around store management and build isolation -3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: second Scheme-driven GNU package build validated with GNU which - -Completed work: - -- added a second Scheme-driven GNU package harness: - - `tests/native-build/gnu-which-guix-phase-runner.scm` - - `tests/native-build/run-gnu-which-guix-phase-runner.sh` -- again used the previously validated fixed local Guile build because this harness depends on subprocess-heavy Guix/Scheme builder logic -- used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for: - - GNU which version `2.21` - - expected Guix nix-base32 source hash `1bgafvy3ypbhhfznwjv1lxmd6mci3x1byilnnkc7gcr486wlb8pl` -- verified the downloaded tarball against the translated SHA256: - - `f4a245b94124b377d8b49646bf421f9155d36aa7614b6ebf83705d3ffc76eaad` -- successfully executed the same subset of Guix builder-side `%standard-phases` on FreeBSD as used for GNU Hello: - - `set-SOURCE-DATE-EPOCH` - - `unpack` - - `configure` - - `build` - - `check` - - `install` -- executed the resulting `which` binary successfully with a deterministic command: - - `PATH=/bin:/usr/bin ./which sh` -- confirmed output: - - `/bin/sh` -- captured metadata including: - - host triplet - - phase list - - runtime dependencies - - check-phase success status - - executed command output -- wrote the results to `docs/reports/phase1-guix-which-phase-runner.md` - -Important findings: - -- this confirms the Scheme-driven Guix builder-side phase-runner pattern is not limited to GNU Hello; a second small GNU/autotools package also succeeds on FreeBSD -- GNU which's `check` phase passed, but it did not leave behind an Automake-style `test-suite.log` or `testsuite.log` -- GNU which emitted a non-fatal `configure` warning about Guix's standard `--enable-fast-install` flag being unrecognized -- the source also emitted several clang warnings about deprecated non-prototype C declarations/definitions, but the build still completed successfully -- the resulting `which` binary again showed a minimal store-like runtime linkage profile: - - `libc.so.7` - - `libsys.so.7` -- unlike GNU Hello, the source tree did not present an obvious shipped `config.guess`, so the harness used `cc -dumpmachine` as a fallback for host-triplet metadata - -Current assessment: - -- Phase 1.2 now has two successful Scheme-driven Guix builder-side GNU package validations on FreeBSD: - - GNU Hello - - GNU which -- this increases confidence that a narrow but real subset of `gnu-build-system` builder-side execution already works on FreeBSD when paired with the fixed local Guile build -- the next uncertainty is now less about whether basic builder phases run at all, and more about where real Guix package/derivation/store integration and isolation will first require FreeBSD-specific adaptation - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` - -Next recommended step: - -1. document the concrete remaining gap between these Scheme-driven phase-runner prototypes and a true Guix package/derivation/store-daemon build on FreeBSD, especially around store management, implicit inputs, and build isolation -2. or choose a somewhat more demanding GNU package with non-trivial declared inputs to identify the first builder-side FreeBSD adaptation points -3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: documented the gap to a real Guix package build - -Completed work: - -- analyzed the concrete remaining gap between the current FreeBSD validation harnesses and a real Guix package/derivation/store-daemon build -- wrote the analysis to: - - `docs/reports/phase1-guix-build-gap-analysis.md` -- based the analysis on the current local Guix source tree, including the relevant host-side and daemon-side code paths in: - - `guix/packages.scm` - - `guix/build-system/gnu.scm` - - `guix/gexp.scm` - - `guix/store.scm` - - `guix/derivations.scm` - - `gnu/packages/commencement.scm` - - `doc/guix.texi` - - `nix/libstore/build.cc` -- compared those real Guix layers against the currently validated FreeBSD prototypes: - - shell-driven native GNU Hello harness - - Scheme-driven GNU Hello builder-phase runner - - Scheme-driven GNU which builder-phase runner - -Main conclusions recorded: - -- the current FreeBSD work has validated a narrow but real builder-side slice of Guix execution: - - Guile can run the needed Scheme code when using the fixed local build - - `(guix build gnu-build-system)` phases can build small GNU packages on FreeBSD -- however, the current prototypes still bypass several critical layers of a real Guix build: - - package -> bag lowering - - bag -> derivation lowering - - imported module closure/store materialization - - real daemon RPC and build submission - - canonical `/gnu/store` management and metadata - - build users, chroot/container or jail-style isolation - - substitute/graft/offload handling -- documented that the current phase runners rely on host tools already present on FreeBSD, whereas real `gnu-build-system` uses implicit inputs drawn from `%final-inputs` -- identified the most actionable next milestone as a derivation-generation investigation for a tiny package, to locate the first failure boundary among: - - host-side lowering - - store interaction - - derivation emission - - daemon availability - - daemon-side execution - -Current assessment: - -- Phase 1.2 now has both practical build validation and a clearer architectural map of what remains before a true Guix package build can work on FreeBSD -- the project has reduced uncertainty around builder-side GNU phase portability -- the next uncertainty is now specifically the host-side lowering/store/daemon boundary, not the builder-phase boundary - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - -Next recommended step: - -1. investigate whether a tiny package can be lowered far enough on FreeBSD to produce a real derivation, and capture the exact first failure point -2. if derivation generation proves immediately blocked, document whether the blocker is generated Guix modules/configuration, store connectivity, or daemon assumptions -3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: derivation-generation investigation identified the first real checkout blockers - -Completed work: - -- added a reproducible checkout/bootstrap/configure investigation harness: - - `tests/guix/run-derivation-generation-investigation.sh` -- used the previously validated fixed local Guile build for the investigation: - - `/tmp/guile-freebsd-validate-install/bin/guile` -- followed the operator instruction for future store setup by parameterizing the checkout attempts to use: - - store directory: `/frx/store` - - local state directory: `/frx/var` - - sysconf directory: `/frx/etc` -- created a disposable shared clone of `~/repos/guix` -- successfully ran `./bootstrap` from that disposable checkout on FreeBSD -- attempted `configure` without `--with-courage` -- attempted `configure` again with `--with-courage` -- confirmed directly that the local fixed Guile build currently cannot load: - - `(gnutls)` -- wrote the results to: - - `docs/reports/phase1-guix-derivation-generation-investigation.md` - -Important findings: - -- a stock Guix checkout currently fails configuration on FreeBSD before any derivation/store/daemon work is reached, due to the explicit unsupported-platform gate: - - ``configure: error: `x86_64-freebsd15.0' is not a supported platform.`` -- re-running `configure` with `--with-courage` gets past that gate, but then stops on a second blocker: - - `configure: error: The Guile bindings of GnuTLS are missing; please install them.` -- a direct module-load test with the same local Guile confirms the problem more concretely: - - `(use-modules (gnutls))` fails with `no code for module (gnutls)` -- this means the current effort is still blocked before reaching: - - usable `pre-inst-env` generation for Guix commands - - package -> bag lowering in a live checkout - - bag -> derivation lowering - - daemon connectivity - - actual `/frx/store` population - -Current assessment: - -- the first practical boundary between the earlier FreeBSD builder-phase prototypes and a real Guix checkout has now been located more precisely -- the project is no longer blocked by vague uncertainty at this stage; it is blocked by two concrete checkout-preparation issues: - 1. unsupported-platform configure gating - 2. missing Guile `(gnutls)` bindings -- importantly, the derivation-generation investigation has not yet reached the store/daemon boundary, so the next step must first clear the `(gnutls)` dependency issue - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` - -Next recommended step: - -1. obtain working Guile `(gnutls)` bindings compatible with the fixed local Guile build and re-run the derivation-generation investigation -2. once configuration succeeds, continue until the next failure boundary is identified among: - - `pre-inst-env` usability - - derivation emission - - daemon connectivity - - daemon-side `/frx/store` assumptions -3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: local Guile-GnuTLS built on FreeBSD; next blocker is Guile-Git - -Completed work: - -- installed the host-side C GnuTLS stack needed for Guile-GnuTLS builds: - - `gnutls` - - `libtasn1` - - `nettle` - - `p11-kit` -- added a reproducible local Guile-GnuTLS build harness: - - `tests/guix/build-local-guile-gnutls.sh` -- updated the derivation-generation investigation harness so it can consume extra Guile module prefixes through: - - `GUILE_EXTRA_PREFIX` -- used the current Guix package definition in `~/repos/guix/gnu/packages/tls.scm` as the source of truth for: - - `guile-gnutls` version `5.0.1` - - expected Guix nix-base32 source hash `0kqngyx4520gjk49l6whjd2ss994kaj9rm78lli6p3q6xry0945i` -- verified the downloaded Guile-GnuTLS tarball against the translated SHA256: - - `b190047cee068f6b22a5e8d49ca49a2425ad4593901b9ac8940f8842ba7f164f` -- built and installed a local Guile-GnuTLS validation copy against the previously validated fixed local Guile build under: - - `/tmp/guile-gnutls-freebsd-validate-install` -- validated successfully that the fixed local Guile can now load: - - `(gnutls)` -- re-ran the checkout derivation-generation investigation with: - - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - - store directory still set to `/frx/store` -- wrote the results to: - - `docs/reports/phase1-guile-gnutls-freebsd.md` - -Important findings: - -- Guile-GnuTLS does not build with FreeBSD base `make`; it requires GNU `gmake` -- a FreeBSD-specific source compatibility issue surfaced in `guile/src/core.c`: - - it includes `` unconditionally - - on this host, `alloca` is available through `` instead -- for local validation, the harness applies a small disposable-tree patch that uses `` on `__FreeBSD__` -- after that fix, the local Guile-GnuTLS build succeeded and `(use-modules (gnutls))` worked with the fixed local Guile build -- re-running the Guix checkout investigation confirms the earlier `(gnutls)` blocker is genuinely cleared -- the next configure-time blocker is now: - - `configure: error: Guile-Git is missing; please install it.` - -Current assessment: - -- the first checkout-preparation blocker after unsupported-platform gating has advanced from missing `(gnutls)` to missing `Guile-Git` -- this is meaningful progress because the project is now moving farther into the dependency chain required for a real Guix checkout on FreeBSD -- the requested experimental store path remains `/frx/store`, but the effort still has not yet reached actual store population or daemon interaction - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - -Next recommended step: - -1. obtain `Guile-Git` compatible with the fixed local Guile build and re-run the derivation-generation investigation again -2. once checkout configuration succeeds, continue until the next failure boundary is identified among: - - `pre-inst-env` usability - - derivation emission - - daemon connectivity - - daemon-side `/frx/store` assumptions -3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: local Guile-Git stack built on FreeBSD; next blocker is Guile-JSON - -Completed work: - -- added a reproducible local Guile-Git dependency-stack build harness: - - `tests/guix/build-local-guile-git.sh` -- updated the derivation-generation investigation harness to probe and record both: - - local `(gnutls)` availability - - local `(git)` / `graph-descendant?` availability -- used the current Guix package definitions in `~/repos/guix/gnu/packages/guile.scm` as the source of truth for: - - `guile-bytestructures` version `1.0.10` - - `guile-git` version `0.10.0` -- built `guile-bytestructures` from the matching upstream tag and recorded resolved commit: - - `27cadba6b69a01b38b33bb39b9766d713eb90c1b` -- built `guile-git` from the matching upstream tag and recorded resolved commit: - - `05d4a48c811f29c8db80ee6697fe658950fb503e` -- installed both into the same local dependency prefix already used for the earlier Guile-GnuTLS validation: - - `/tmp/guile-gnutls-freebsd-validate-install` -- validated successfully that the fixed local Guile can now load: - - `(bytestructures guile)` - - `(git)` -- validated specifically that the Guile-Git export required by Guix `configure.ac` is present: - - `graph-descendant?` -- confirmed the host `libgit2` dependency used for the build is: - - `1.9.2` -- re-ran the checkout derivation-generation investigation with: - - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - - store directory still set to `/frx/store` -- wrote the results to: - - `docs/reports/phase1-guile-git-freebsd.md` - -Important findings: - -- both `guile-bytestructures` and `guile-git` were built from Git source layouts, so autotools regeneration was required: - - `guile-bytestructures`: `autoreconf -vfi` - - `guile-git`: `autoreconf -vfi` via harness fallback -- unlike the earlier Guile-GnuTLS step, no additional FreeBSD-specific source patch was needed for either package in this validation pass -- the Guix checkout now gets past both previously cleared dependency gates: - - `(gnutls)` - - `Guile-Git` -- after clearing those, the next configure-time blocker is now: - - `configure: error: Guile-JSON is missing; please install it.` - -Current assessment: - -- the checkout-preparation path on FreeBSD has progressed one dependency layer deeper -- the local validation prefix under `/tmp/guile-gnutls-freebsd-validate-install` now contains at least: - - Guile-GnuTLS - - Guile bytestructures - - Guile-Git -- despite that progress, the work still has not yet reached derivation emission, daemon connectivity, or actual `/frx/store` population -- the next concrete blocker is now `Guile-JSON`, as reported directly by the real Guix checkout configure step - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - -Next recommended step: - -1. obtain `Guile-JSON` compatible with the fixed local Guile build and install it into the same local dependency prefix -2. re-run the derivation-generation investigation again to identify the next configure-time or checkout-time blocker after `Guile-JSON` -3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: local Guile-JSON built on FreeBSD; next blocker is Guile-SQLite3 - -Completed work: - -- added a reproducible local Guile-JSON build harness: - - `tests/guix/build-local-guile-json.sh` -- updated the derivation-generation investigation harness to probe and record local recent-enough `(json)` availability in addition to the earlier `(gnutls)` and `(git)` checks -- used the current Guix package definition in `~/repos/guix/gnu/packages/guile.scm` as the source of truth for: - - `guile-json` version `4.7.3` - - expected Guix nix-base32 source hash `127k2xc07w1gnyqs40z4865l8p3ra5xgpcn569dz04lxsa709fiq` -- verified the downloaded Guile-JSON tarball against the translated SHA256: - - `38ba048ed29d12f05b32c5b2fb7a51795c448b41e403a2b1b72ff0035817f388` -- built and installed a local Guile-JSON validation copy into the same local dependency prefix already used for checkout prerequisites: - - `/tmp/guile-gnutls-freebsd-validate-install` -- validated successfully that the fixed local Guile now satisfies the Guix configure-time JSON requirement by: - - loading `(json)` - - using `define-json-mapping` - - decoding a small JSON object successfully -- re-ran the checkout derivation-generation investigation with: - - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - - store directory still set to `/frx/store` -- wrote the results to: - - `docs/reports/phase1-guile-json-freebsd.md` - -Important findings: - -- unlike the earlier Guile-Git step, Guile-JSON built cleanly from the release tarball and did not require autotools regeneration in this validation pass -- unlike the earlier Guile-GnuTLS step, no FreeBSD-specific source patch was needed here -- the shared local validation prefix now contains at least: - - Guile-GnuTLS - - Guile bytestructures - - Guile-Git - - Guile-JSON -- the Guix checkout now gets past the previously cleared dependency gates for: - - `(gnutls)` - - `Guile-Git` - - `Guile-JSON` -- after clearing those, the next configure-time blocker is now: - - `configure: error: A recent Guile-SQLite3 could not be found; please install it.` - -Current assessment: - -- the checkout-preparation path on FreeBSD has progressed another dependency layer deeper -- the project still has not yet reached derivation emission, daemon connectivity, or actual `/frx/store` population -- the next concrete blocker is now recent `Guile-SQLite3`, as reported directly by the real Guix checkout configure step - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` - -Next recommended step: - -1. obtain recent `Guile-SQLite3` compatible with the fixed local Guile build and install it into the same local dependency prefix -2. re-run the derivation-generation investigation again to identify the next configure-time or checkout-time blocker after `Guile-SQLite3` -3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.2 follow-up: remaining checkout Guile prerequisites built; next blocker is `./pre-inst-env guix --version` - -Completed work: - -- installed the remaining missing host C library dependencies required for the next Guile extension stack: - - `libgcrypt` - - `libgpg-error` - - `lzlib` -- added a reproducible build harness for the remaining mandatory Guix checkout Guile modules: - - `tests/guix/build-local-guile-configure-deps.sh` -- extended the derivation-generation investigation harness to: - - probe local recent-enough availability for: - - `(sqlite3)` - - `(gcrypt hash)` - - `(zlib)` - - `(lzlib)` - - `(semver)` - - run checkout `configure` with: - - `MAKE=gmake` - - continue past successful configuration into: - - `gmake scripts/guix` - - `./pre-inst-env guix --version` -- used the current Guix package definitions as source of truth for the following additional module stack: - - `guile-sqlite3` `0.1.3` - - `guile-gcrypt` `0.5.0` - - `guile-zlib` `0.2.2` - - `guile-lzlib` `0.3.0` - - `guile-semver` `0.2.0` -- built and installed those modules into the same shared local dependency prefix already used for prior checkout prerequisites: - - `/tmp/guile-gnutls-freebsd-validate-install` -- validated successfully that the fixed local Guile can now satisfy all of the remaining configure-time Guix module checks encountered so far: - - `(sqlite3)` with `sqlite-bind-arguments` - - `(gcrypt hash)` with `hash-algorithm` lookup - - `(zlib)` with `make-zlib-input-port` - - `(lzlib)` - - `(semver)` -- re-ran the checkout derivation-generation investigation with: - - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - - store directory still set to `/frx/store` -- wrote the results to: - - `docs/reports/phase1-guix-checkout-configure-stack-freebsd.md` - -Important findings: - -- `guile-gcrypt` required an explicit configure workaround on this host: - - `--with-libgcrypt-prefix=/usr/local` - - without it, the package's `libgcrypt-config --libs` parsing produced an unusable shared-library name on FreeBSD -- the currently served upstream `guile-lzlib` `0.3.0` tarball no longer matches the Guix-recorded hash: - - expected from Guix: `a7f99c8d2a143e05ea22db2dc8b9ce6c27cae942162b45ee3015ed9027af0ff2` - - observed from current source URL: `6a2847a303a141bb95b1b5d1a4b975b4dbff9cc590eba377cc8072682e7637ec` -- for local validation, the harness fell back to the matching upstream Git tag and recorded commit: - - `474cee42116295bc0bd2acf12d4d6a766043090e` -- once the remaining Guile modules were present, checkout `configure --with-courage` stopped failing on missing modules -- however, the checkout still needed: - - `MAKE=gmake` - to complete configuration successfully on FreeBSD -- after that, `gmake scripts/guix` succeeded as well -- the next concrete blocker has moved from configuration-time prerequisites to runtime behavior of the uninstalled Guix command path: - - `./pre-inst-env guix --version` prints the version banner, then exits with: - - `Wrong type to apply: #` - -Current assessment: - -- the checkout-preparation path on FreeBSD has now progressed beyond the missing mandatory Guile module stack that previously blocked configuration -- the current local validation prefix now contains the required configure-time modules encountered so far for a real Guix checkout -- the first blocker after successful checkout configuration and `scripts/guix` generation is now a runtime Scheme failure in the uninstalled `guix` command path itself -- the work is therefore now meaningfully past “cannot configure” and into “configures, builds `scripts/guix`, but fails at `./pre-inst-env guix --version`” - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` - -Next recommended step: - -1. investigate the `leave-on-EPIPE` runtime failure now blocking `./pre-inst-env guix --version` -2. complete the remaining Phase 1.3 FreeBSD system-call mapping/documentation deliverable so Phase 1 foundations can be closed out cleanly -3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 1.3 completed: FreeBSD syscall/interface mapping documented and exercised - -Completed work: - -- added a runnable C syscall/interface mapping harness: - - `tests/system/freebsd-syscall-mapping.c` -- added a shell runner for the mapping harness: - - `tests/system/run-freebsd-syscall-mapping.sh` -- inspected current Guix/Linux-oriented source paths relevant to daemon/build isolation and host behavior, especially: - - `~/repos/guix/nix/libstore/build.cc` - - `~/repos/guix/configure.ac` -- inspected the relevant FreeBSD interfaces/documentation available on the host, including: - - `jail(2)` - - `chroot(2)` - - `closefrom(2)` / `close_range(2)` - - `mount(2)` / `nmount(2)` - - `mount_nullfs(8)` - - `cap_enter(2)` - - `cap_rights_limit(2)` - - `lutimes(2)` - - `lchown(2)` - - `posix_fallocate(2)` - - `pdfork(2)` -- ran the new syscall mapping harness successfully and captured metadata under: - - `/tmp/freebsd-syscall-mapping-metadata.txt` -- wrote the Phase 1.3 report to: - - `docs/reports/phase1-freebsd-syscall-mapping.md` - -Important findings: - -- the current FreeBSD host provides and the harness successfully exercised: - - `fork` / `waitpid` - - `posix_spawn_file_actions_addclosefrom_np` - - `close_range` - - `lutimes` - - `statvfs` - - `chroot` (root test) - - `jail(2)` (root test) - - `lchown` (root test) -- the same harness confirmed the absence of the key Linux namespace-oriented interfaces that current Guix daemon code depends on: - - `clone` - - `unshare` - - `setns` - - `pivot_root` - - `sys/prctl.h` -- FreeBSD Capsicum headers are present, which is useful context for later security design, but Capsicum is not a direct replacement for Linux namespaces or Linux capabilities -- `posix_fallocate` is present but returned `EOPNOTSUPP` on the tested filesystems, so a successful configure/link probe does not guarantee useful runtime semantics -- the mapping strongly confirms that the correct Phase 2 direction is not syscall emulation but a jail-first redesign using: - - jails - - `chroot` - - `nullfs` - - traditional build-user privilege separation - -Current assessment: - -- the Phase 1.3 deliverable is now satisfied with both: - - a technical mapping document, and - - a runnable validation harness -- the main architectural conclusion is now concrete rather than speculative: - - Linux namespace code paths in current Guix daemon/build isolation cannot be ported directly to FreeBSD - - the FreeBSD implementation must instead be designed around jails and explicit mount/layout control - -## 2026-04-01 — Phase 1 completed on the current FreeBSD amd64 porting track - -Phase 1 is now considered complete for the active amd64 FreeBSD host path. - -Why this milestone is satisfied: - -- **Phase 1.1** success criteria were met on the current host: - - Guile executes Guix bootstrap-related code - - deterministic/module/FFI/socket/process validation succeeded - - the FreeBSD subprocess crash was root-caused and a working fixed local Guile path was validated -- **Phase 1.2** success criteria were exceeded: - - native GNU Hello build success was demonstrated - - multiple Guix builder-side GNU phase validations succeeded - - a real Guix checkout now configures on FreeBSD with local dependency supplementation, builds `scripts/guix`, and reaches a concrete runtime blocker at: - - `./pre-inst-env guix --version` -- **Phase 1.3** is now completed with the syscall/interface mapping document and runnable harness - -Important scope note: - -- the original Phase 1.1 narrative mentioned `i386` as additional target coverage, but the explicit success criteria used to gate progression have been satisfied on the active amd64 FreeBSD host -- full i386 Guile validation remains useful future coverage work, but it is no longer the blocker for moving into Phase 2 design/prototyping on this machine - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` - -Next recommended step: - -1. begin Phase 2.1 by turning the new syscall mapping into a concrete FreeBSD jail-based build-isolation design/prototype -2. carry forward the current concrete runtime blocker from Phase 1.2: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` -3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear - -## 2026-04-01 — Phase 2.1 completed: jail-first build isolation design validated on FreeBSD - -Completed work: - -- added a runnable jail-based build isolation prototype: - - `tests/daemon/run-freebsd-jail-build-prototype.sh` -- wrote the Phase 2.1 design/prototype report: - - `docs/reports/phase2-freebsd-jail-build-isolation.md` -- translated the earlier Phase 1 syscall mapping into a concrete FreeBSD Guix-daemon isolation design centered on: - - thin jails - - one jail per build - - explicit `nullfs` mount plans - - networking disabled by default - - separate build-user credentials inside the jail envelope -- ran the jail prototype successfully and captured metadata under: - - `/tmp/jail-build-metadata.txt` - -Important findings: - -- a thin-jail approach is the right match for Guix's declared-input model; thick jails would overexpose ambient host state and add unnecessary duplication -- a per-build jail root assembled from explicit read-only `nullfs` mounts is a practical replacement for the Linux bind-mount + mount-namespace model in current Guix daemon code -- a basic build operation can already be executed successfully inside a FreeBSD jail with a restricted filesystem view consisting only of: - - selected read-only host toolchain paths - - a read-only declared input directory - - a writable declared output directory - - a writable `/tmp` -- a host sentinel file left outside the jail root is not visible inside the build environment, confirming the prototype is exercising real visibility restriction rather than a mere chroot-like shell wrapper -- the prototype jail ran with: - - `ip4=disable` - - `ip6=disable` - which matches the intended default for hermetic builds - -Current assessment: - -- Phase 2.1 is now satisfied on the current FreeBSD prototype track -- the main design decision is now concrete rather than speculative: - - the Guix FreeBSD daemon path should be jail-first, not Linux-namespace emulation -- the next step is to add a build-user privilege-dropping prototype inside or alongside this jail model so the design covers both containment and user-level isolation - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` - -Next recommended step: - -1. implement the Phase 2.2 privilege-dropping/build-user prototype for FreeBSD, ideally combined with the new jail execution model -2. then establish a `/frx/store`-based store-management prototype covering permissions, package readability, and garbage-collection behavior -3. continue carrying the separate Guix checkout runtime blocker: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` - -## 2026-04-01 — Phase 2.2 completed: privilege dropping and concurrent build-user isolation validated - -Completed work: - -- added a C helper implementing the core daemon-side privilege drop mechanics: - - `tests/daemon/freebsd-build-user-helper.c` -- added a harness that combines that helper with the new jail model and runs two jobs concurrently: - - `tests/daemon/run-freebsd-privilege-drop-prototype.sh` -- wrote the Phase 2.2 report: - - `docs/reports/phase2-freebsd-privilege-drop.md` -- ran the concurrent build-user prototype successfully and captured metadata under: - - `/tmp/freebsd-privdrop-metadata.txt` - -Important findings: - -- a root-launched FreeBSD helper can successfully perform the expected daemon-side transition: - - `setgroups` - - `setgid` - - `setuid` - into a dedicated build identity -- once dropped, the helper cannot regain root with `setuid(0)`: - - `Operation not permitted` -- each build job can create files in its own writable directory and those files end up owned by the dropped build UID/GID rather than by root -- two concurrent jobs using distinct numeric build identities succeeded with: - - job 1 UID/GID `35001:35001` - - job 2 UID/GID `35002:35002` -- host-side result files were observed with the matching ownership and restrictive permissions: - - `0600` -- the two jobs were deliberately held for two seconds each and the measured wall-clock elapsed time was also about two seconds, demonstrating actual concurrent execution rather than serialized execution -- two complementary denial modes were validated at the same time: - - peer build files mounted but blocked by permissions: `Permission denied` - - host path not mounted into the jail at all: `No such file or directory` -- the dropped build user also could not: - - create files in a protected root-owned directory - - `chown` its own output back to root - -Current assessment: - -- Phase 2.2 is now satisfied on the current FreeBSD prototype track -- the combined jail + build-user model now has practical validation for the most important security properties required by a future FreeBSD Guix daemon: - - root-controlled setup - - permanent drop to build credentials - - per-build writable areas - - cross-build isolation - - concurrent execution under distinct identities -- the remaining Phase 2 work is now centered on the store itself: permissions, readability, content-addressed layout, and garbage-collection behavior under `/frx/store` - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` - -Next recommended step: - -1. complete Phase 2.3 by establishing a `/frx/store`-based store prototype with: - - correct root/daemon write restrictions - - unprivileged read access - - content-addressed path naming - - garbage-collection behavior -2. if possible, use outputs or dependency relationships realistic enough to model how a future FreeBSD Guix daemon would retain referenced store items -3. continue carrying the separate Guix checkout runtime blocker: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` - -## 2026-04-01 — Phase 2.3 completed: `/frx/store` prototype validated on FreeBSD - -Completed work: - -- added a runnable `/frx/store` prototype harness: - - `tests/store/run-freebsd-store-prototype.sh` -- wrote the Phase 2.3 report: - - `docs/reports/phase2-freebsd-store-prototype.md` -- created and exercised the operator-requested `/frx` layout on-host: - - `/frx/store` - - `/frx/var` - - `/frx/etc` - - `/frx/var/fruix/gcroots` -- created a store group for the prototype path: - - `fruixbuild` -- ran the store prototype successfully and captured metadata under: - - `/tmp/freebsd-store-prototype-metadata.txt` - -Important findings: - -- the current host now has a working `/frx/store` prototype owned as: - - `root:fruixbuild` - with mode: - - `drwxrwxr-t` -- the prototype successfully created content-addressed demo store items under `/frx/store` using hash-based names -- the demo item set included: - - rooted greeting data - - a rooted app referencing that data through an absolute store path - - an unrooted orphan item intended for collection -- an unprivileged user (`nobody`) could: - - read store data - - execute the demo app from the store -- the same unprivileged user could not: - - create files directly in `/frx/store` - and the observed failure was: - - `Permission denied` -- the prototype GC logic followed rooted references successfully: - - with a GC root present, the app and its referenced data survived while the orphan item was collected - - after removing the GC root, the remaining demo items were collected as well -- the demo store returned to an empty state after the second GC pass, so the host is left with the `/frx` skeleton but without lingering prototype payloads - -Current assessment: - -- Phase 2.3 is now satisfied on the current FreeBSD prototype track -- the core store assumptions needed for a FreeBSD Guix-daemon design have practical validation now: - - `/frx/store` path viability - - root-controlled mutation - - unprivileged read access - - immutable absolute store references - - root-managed GC roots and mark/sweep retention behavior -- remaining gaps are now above this architectural layer rather than below it: - - real derivation registration - - SQLite-backed store metadata - - daemon RPC integration - - actual package lowering/build submission using these mechanisms - -## 2026-04-01 — Phase 2 completed on the current FreeBSD prototype track - -Phase 2 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 2.1** success criteria were met: - - a detailed jail-first build-isolation design was produced - - a runnable prototype successfully executed a build command in a restricted FreeBSD jail -- **Phase 2.2** success criteria were met: - - a concrete C privilege-dropping implementation was added - - build-user credential drop, inability to regain root, and concurrent cross-build isolation were demonstrated -- **Phase 2.3** success criteria were met on the prototype track: - - a working `/frx/store` equivalent was established - - content-addressed demo store items were created and consumed - - unprivileged read vs. privileged write behavior was validated - - garbage-collection behavior over rooted references was demonstrated - -Important scope note: - -- this completes the **core daemon architecture adaptation** milestone, not a full Guix-daemon port -- the separate real-checkout blocker from Phase 1 remains relevant for later integration work: - - `./pre-inst-env guix --version` still fails with `Wrong type to apply: #` -- however, that runtime issue no longer blocks the specific Phase 2 architectural deliverables because the jail, privilege, and store assumptions have now been validated independently on FreeBSD - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` -- `d65b2af` — `Prototype FreeBSD build user isolation` - -Next recommended step: - -1. begin Phase 3.1 by adapting Guix build-system expectations to the now-validated jail/privilege/store model on FreeBSD -2. carry forward the concrete real-checkout runtime blocker for later integration work: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` -3. continue using `/frx/store` rather than `/gnu/store` for FreeBSD store experiments - -## 2026-04-01 — Phase 3.1 completed: reusable FreeBSD GNU build-system adaptation validated across five packages - -Completed work: - -- added a reusable Scheme runner for FreeBSD-adapted GNU package builds: - - `tests/build-system/gnu-package-freebsd-phase-runner.scm` -- added a shell wrapper for the generic runner: - - `tests/build-system/run-gnu-package-freebsd-phase-runner.sh` -- added a five-package validation matrix: - - `tests/build-system/run-freebsd-gnu-package-matrix.sh` -- wrote the Phase 3.1 report: - - `docs/reports/phase3-freebsd-gnu-build-system.md` -- ran the matrix successfully and captured summary metadata under: - - `/tmp/freebsd-gnu-package-matrix-summary.txt` - -Important findings: - -- the build adaptation is now centralized rather than package-specific and is applied through a dedicated pre-configure FreeBSD environment phase -- the adaptation consistently uses: - - GNU `gmake` via a `make` path shim - - FreeBSD Clang via `cc`/`gcc` and `c++`/`g++` tool shims - - `CONFIG_SHELL=/bin/sh` - - `/usr/local` include/library/pkg-config search paths -- five representative GNU packages from current Guix package definitions now build successfully through the adapted runner on the current FreeBSD amd64 host: - - `hello` `2.12.3` - - `which` `2.21` - - `time` `1.9` - - `patch` `2.8` - - `nano` `8.7.1` -- the resulting binaries executed correctly with deterministic checks appropriate to each package: - - `hello` -> `Hello, world!` - - `which` -> `/bin/sh` - - `time` -> `time (GNU Time) 1.9` - - `patch` -> `GNU patch 2.8` - - `nano` -> `GNU nano, version 8.7.1` -- the matrix also validated a package with meaningful runtime dependencies: - - `nano` linked against FreeBSD/base and `/usr/local` libraries including `libintl`, `libmagic`, `libncursesw`, `libtinfow`, and `libz` -- one package-specific FreeBSD test boundary was recorded explicitly instead of being hidden: - - `time` required `RUN_TESTS=0` because the upstream `time-max-rss` test was not reliable on this host - -Current assessment: - -- Phase 3.1 is now satisfied on the current prototype track -- the main question has shifted from “can adapted GNU builder phases run on FreeBSD?” to “how should FreeBSD system components themselves be described and installed as profile-usable packages?” -- the next step is therefore Phase 3.2: define a minimal FreeBSD package set with explicit dependencies and validate profile-style installation/usability - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` -- `d65b2af` — `Prototype FreeBSD build user isolation` -- `e404e2e` — `Prototype FreeBSD store management` - -Next recommended step: - -1. complete Phase 3.2 by defining a minimal FreeBSD system package set with explicit dependency relationships and profile-style installation validation -2. carry forward the concrete real-checkout runtime blocker for later integration work: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` -3. continue using `/frx/store` rather than `/gnu/store` for future FreeBSD store experiments when the prototype work needs a persistent store root - -## 2026-04-01 — Phase 3.2 completed: FreeBSD system package-definition prototype and profile validation added - -Completed work: - -- added a Guix-style FreeBSD system package-definition prototype module: - - `modules/fruix/packages/freebsd.scm` -- added a Scheme harness to materialize those package definitions into store-like outputs and a merged profile: - - `tests/packages/freebsd-package-profile-prototype.scm` -- added a shell wrapper for that harness: - - `tests/packages/run-freebsd-package-profile-prototype.sh` -- installed the missing host shell dependency needed to satisfy the requested package set: - - `bash` -- wrote the Phase 3.2 report: - - `docs/reports/phase3-freebsd-package-definitions.md` -- ran the profile prototype successfully and captured metadata under: - - `/tmp/freebsd-package-profile-prototype-metadata.txt` - -Important findings: - -- the prototype now defines a minimal FreeBSD core package set covering the categories requested by Phase 3.2: - - kernel - - kernel headers - - libc - - userland utilities - - development tools (`clang`, `make`, autotools) - - minimum system libraries (`openssl`, `zlib`) - - shells (`sh`, `bash`) -- the current package-definition layer uses an explicit Guix-like record shape with fields for: - - name - - version - - build system - - inputs - - synopsis/description/home-page/license - - install plan -- explicit dependency relationships are now encoded and resolved recursively during materialization, including examples such as: - - `freebsd-libc` -> `freebsd-kernel-headers` - - `freebsd-userland` -> `freebsd-libc`, `freebsd-sh` - - `freebsd-clang-toolchain` -> `freebsd-libc`, `freebsd-kernel-headers`, `freebsd-sh` - - `freebsd-autotools` -> `freebsd-gmake`, `freebsd-bash`, `freebsd-libc` -- the harness successfully materialized: - - `11` core package outputs - into a store-like directory tree under the work directory -- it then merged those outputs into a development profile and validated that the profile contains working: - - `bash` - - `make` - - `autoconf` - - `cc` - - kernel image path - - kernel-header path - - core shared-library paths -- the generated profile compiled and ran a C test program successfully, with observed output: - - `hello-from-freebsd-profile` -- for executables installed under `bin/`, the prototype uses wrappers that `exec` the host tool by absolute path; this preserved correct behavior for prefix-sensitive tools such as `autoconf` - -Current assessment: - -- Phase 3.2 is now satisfied on the current prototype track -- Phase 3 as a whole is now completed on the current FreeBSD amd64 path because both: - - adapted GNU build-system execution, and - - minimal FreeBSD system package-definition/profile validation - have been demonstrated successfully -- the next remaining project milestone is now Phase 4, centered on Shepherd rather than package-building foundations - -## 2026-04-01 — Phase 3 completed on the current FreeBSD prototype track - -Phase 3 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 3.1** success criteria were met on the prototype track: - - a reusable FreeBSD adaptation layer for GNU builder phases was added - - five representative GNU packages built successfully through that adapted runner - - the resulting binaries executed correctly on the host -- **Phase 3.2** success criteria were met on the prototype track: - - a minimal FreeBSD system package-definition layer was added - - explicit dependency relationships were modeled and resolved - - the package outputs installed into a merged profile successfully - - the generated profile was validated by compiling and running a test program with the staged toolchain - -Important scope note: - -- this completes the **build-system adaptation milestone** in prototype form, not the full Guix package-lowering/daemon integration path -- the earlier concrete upstream/runtime blocker still exists for later integration work: - - `./pre-inst-env guix --version` fails with `Wrong type to apply: #` -- however, that blocker no longer prevents Phase 4 work because the core build-system and package-definition assumptions have now been validated independently - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` -- `d65b2af` — `Prototype FreeBSD build user isolation` -- `e404e2e` — `Prototype FreeBSD store management` -- `eb0d77c` — `Adapt GNU build phases for FreeBSD` - -Next recommended step: - -1. begin Phase 4.1 by validating whether Shepherd itself now builds and runs as a regular service on FreeBSD with the fixed local Guile path -2. carry forward the separate real-checkout runtime blocker for later integration work: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` -3. continue using `/frx/store` rather than `/gnu/store` for future FreeBSD integration experiments when a persistent store root is required - -## 2026-04-01 — Phase 4.1 completed: Shepherd built and validated as a regular FreeBSD service manager - -Completed work: - -- added a reproducible local Guile Fibers build harness: - - `tests/shepherd/build-local-guile-fibers.sh` -- added a reproducible local Shepherd build harness: - - `tests/shepherd/build-local-shepherd.sh` -- added a runnable multi-service Shepherd validation harness for FreeBSD: - - `tests/shepherd/run-freebsd-shepherd-service-prototype.sh` -- wrote the Phase 4.1 report: - - `docs/reports/phase4-freebsd-shepherd-service.md` -- ran the service-management prototype successfully and captured metadata under: - - `/tmp/freebsd-shepherd-service-metadata.txt` - -Important findings: - -- the current FreeBSD path now has a working local Shepherd build based on: - - local fixed Guile - - locally installed Guile Fibers `1.4.2` - - Shepherd `1.0.9` -- Shepherd build/install required one concrete FreeBSD-specific toolchain adaptation: - - `SED=/usr/local/bin/gsed` - because the install phase edits wrapper scripts using GNU `sed -i` syntax that base FreeBSD `sed` does not accept -- at runtime, Shepherd reports: - - `System lacks support for 'signalfd'; using fallback mechanism.` - but the fallback path works correctly for supervision on this host -- the prototype successfully validated all requested regular-service capabilities: - - start/stop via `herd` - - dependency handling - - status monitoring - - crash/respawn behavior - - privilege-aware execution -- the concrete service set used for validation included: - - an unprivileged heartbeat logger - - a loopback HTTP service - - a dependent file-monitor service - - a crash-once respawn test service -- observed metadata confirmed: - - `logger_running=yes` - - `web_running=yes` - - `monitor_running=yes` - - `crashy_running=yes` - - `logger_uid=65534` (`nobody`) - - `http_response=shepherd-freebsd-ok` - - `monitor_detected=detected` - - `crashy_counter=2` - -Current assessment: - -- Phase 4.1 is now satisfied on the current FreeBSD prototype track -- Shepherd is no longer just a theoretical later step; it now builds and supervises multiple services correctly on the host when paired with the fixed local Guile stack -- the next question is no longer “can Shepherd run on FreeBSD at all?” but “what is the best FreeBSD init-integration strategy for it on this prototype path?” - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` -- `d65b2af` — `Prototype FreeBSD build user isolation` -- `e404e2e` — `Prototype FreeBSD store management` -- `eb0d77c` — `Adapt GNU build phases for FreeBSD` -- `d47dc9b` — `Prototype FreeBSD package definitions` - -Next recommended step: - -1. complete Phase 4.2 by prototyping how Shepherd should be launched and stopped through FreeBSD init conventions while validating boot/shutdown dependency ordering for essential services -2. after that, bridge Shepherd to key FreeBSD service concepts such as rc.d management, loopback/network configuration, filesystem setup, and temporary user/group administration -3. continue carrying the separate real-checkout runtime blocker for later integration work: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` - -## 2026-04-01 — Phase 4.2 completed: FreeBSD rc.d init-integration prototype validated for Shepherd - -Completed work: - -- added a runnable FreeBSD init-integration prototype harness: - - `tests/shepherd/run-freebsd-shepherd-init-prototype.sh` -- wrote the Phase 4.2 report: - - `docs/reports/phase4-freebsd-shepherd-init-integration.md` -- ran the init-integration prototype successfully and captured metadata under: - - `/tmp/freebsd-shepherd-init-metadata.txt` - -Important findings: - -- a real temporary FreeBSD `rc.d` script can successfully launch the locally built Shepherd daemon through the standard: - - `service onestart` - path -- the same wrapper can stop it cleanly through: - - `service onestop` - using `herd ... stop root` under the hood -- the prototype automatically started a minimal essential-service graph at daemon launch consisting of: - - `filesystems` - - `system-log` - - `networking` - - `login` -- observed startup order matched the declared dependency chain exactly: - - `start:filesystems` - - `start:system-log` - - `start:networking` - - `start:login` -- observed shutdown order matched the expected reverse dependency order exactly: - - `stop:login` - - `stop:networking` - - `stop:system-log` - - `stop:filesystems` -- the rc.d wrapper reported the Shepherd instance as running while active: - - `rc_status=running` -- the prototype again observed the expected FreeBSD runtime note: - - `System lacks support for 'signalfd'; using fallback mechanism.` - and confirmed that it does not prevent correct boot/shutdown ordering behavior - -Current assessment: - -- Phase 4.2 is now satisfied on the current prototype track as an init-integration prototype -- the key result is that Shepherd can already be launched and stopped through native FreeBSD service-management conventions while preserving dependency-based startup and shutdown semantics -- the remaining Phase 4 work is now specifically about bridging Shepherd services to concrete FreeBSD host-management concepts rather than basic daemon launch or service ordering - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` -- `d65b2af` — `Prototype FreeBSD build user isolation` -- `e404e2e` — `Prototype FreeBSD store management` -- `eb0d77c` — `Adapt GNU build phases for FreeBSD` -- `d47dc9b` — `Prototype FreeBSD package definitions` -- `b36746f` — `Validate Shepherd services on FreeBSD` - -Next recommended step: - -1. complete Phase 4.3 by adding a small FreeBSD Shepherd bridge layer for rc.d-style services, loopback/network configuration, filesystem setup, and temporary user/group administration -2. use that bridge layer in a runnable integration harness that validates both activation and cleanup of those FreeBSD concepts -3. continue carrying the separate real-checkout runtime blocker for later integration work: - - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` - -## 2026-04-01 — Phase 4.3 completed: FreeBSD Shepherd bridge layer validated across rc.d, network, filesystem, and account management - -Completed work: - -- added a reusable FreeBSD Shepherd bridge module: - - `modules/fruix/shepherd/freebsd.scm` -- added a runnable integration harness exercising that bridge layer: - - `tests/shepherd/run-freebsd-shepherd-bridge-prototype.sh` -- wrote the Phase 4.3 report: - - `docs/reports/phase4-freebsd-shepherd-bridge.md` -- ran the bridge prototype successfully and captured metadata under: - - `/tmp/freebsd-shepherd-bridge-metadata.txt` - -Important findings: - -- the new module now exports concrete helper constructors for four FreeBSD integration categories: - - `freebsd-rc-service` - - `freebsd-loopback-alias-service` - - `freebsd-tmpfs-service` - - `freebsd-user-group-service` -- the integration harness used those helpers to manage a real chained host-side service graph under Shepherd covering: - - a temporary rc.d script in `/usr/local/etc/rc.d/` - - loopback alias configuration on `lo0` - - tmpfs mount/unmount with mode validation - - temporary user/group creation and removal via `pw` -- observed activation metadata confirmed all of those operations succeeded under Shepherd control: - - `target_running=yes` - - `rc_started=yes` - - `alias_present=yes` - - `tmpfs_mounted=yes` - - `tmpfs_mode=drwxr-x---` - - `user_present=yes` - - `group_present=yes` -- observed cleanup metadata confirmed that `stop root` also reversed all of those host-side effects successfully: - - `rc_stopped=yes` - - `alias_removed=yes` - - `tmpfs_unmounted=yes` - - `user_removed=yes` - - `group_removed=yes` -- the same expected FreeBSD runtime note remained true here as well: - - `System lacks support for 'signalfd'; using fallback mechanism.` - and again it did not prevent the prototype from working correctly - -Current assessment: - -- Phase 4.3 is now satisfied on the current prototype track -- Shepherd now has a concrete FreeBSD bridge layer in-repo rather than only ad hoc validation scripts -- with service supervision, rc.d integration, and FreeBSD host-concept bridging now all validated, Phase 4 is complete on the current FreeBSD amd64 prototype path - -## 2026-04-01 — Phase 4 completed on the current FreeBSD prototype track - -Phase 4 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 4.1** success criteria were met on the prototype track: - - Shepherd built successfully on FreeBSD with the fixed local Guile stack - - regular multi-service supervision worked - - dependency handling, status monitoring, privilege-aware execution, and respawn behavior were all validated -- **Phase 4.2** success criteria were met in init-integration prototype form: - - a real FreeBSD `rc.d` wrapper launched Shepherd successfully - - a minimal essential-service graph started automatically in correct dependency order - - orderly reverse shutdown through native FreeBSD service entry points was validated -- **Phase 4.3** success criteria were met on the prototype track: - - a reusable FreeBSD Shepherd bridge layer was added - - Shepherd services successfully bridged to rc.d service control, loopback/network configuration, filesystem mounting/permissions, and temporary user/group administration - - both activation and cleanup were validated - -Important scope note: - -- this completes the **Shepherd porting milestone** on the current prototype track, not a literal replacement of `/sbin/init` on the live host -- however, the core Shepherd questions have now been answered positively on FreeBSD: - - it builds - - it runs - - it supervises services - - it integrates with FreeBSD service-management conventions - - it can express concrete FreeBSD host-management tasks through Shepherd services -- the separate real-Guix-checkout runtime blocker still exists for later integration work: - - `./pre-inst-env guix --version` fails with `Wrong type to apply: #` - but that is now clearly outside the scope of the completed Phase 4 Shepherd milestone - -Recent commits: - -- `e380e88` — `Add FreeBSD Guile verification harness` -- `cd721b1` — `Update progress after Guile verification` -- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` -- `02f7a7f` — `Validate local Guile fix on FreeBSD` -- `4aebea4` — `Add native GNU Hello FreeBSD build harness` -- `c944cdb` — `Validate Guix builder phases on FreeBSD` -- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` -- `245a47d` — `Document gaps to real Guix FreeBSD builds` -- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` -- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` -- `15b9037` — `Build local Guile-Git on FreeBSD` -- `47d31e8` — `Build local Guile-JSON on FreeBSD` -- `d82195b` — `Advance Guix checkout on FreeBSD` -- `9bf3d30` — `Document FreeBSD syscall mapping` -- `7621798` — `Prototype FreeBSD jail build isolation` -- `d65b2af` — `Prototype FreeBSD build user isolation` -- `e404e2e` — `Prototype FreeBSD store management` -- `eb0d77c` — `Adapt GNU build phases for FreeBSD` -- `d47dc9b` — `Prototype FreeBSD package definitions` -- `b36746f` — `Validate Shepherd services on FreeBSD` -- `83715f0` — `Prototype Shepherd rc.d integration` - -Next recommended step: - -1. return to the remaining real Guix checkout/runtime blocker and investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` -2. begin the next post-Phase-4 integration milestone by connecting the now-validated daemon/build/store/Shepherd prototypes more directly to real Guix checkout behavior on FreeBSD -3. continue using `/frx/store` rather than `/gnu/store` whenever future integration experiments need a persistent store root - -## 2026-04-01 — Planning update: Fruix naming policy clarified for post-Phase-4 work - -Completed work: - -- added a new post-Phase-4 planning document: - - `docs/PLAN_2.md` -- updated that plan to clarify the naming policy for the fork going forward - -Key planning decision: - -- **Fruix** is now the intended user-facing product identity -- the user-facing CLI should become: - - `fruix` -- `/frx` remains the canonical store/state/config root on the FreeBSD path -- however, the plan explicitly avoids a blanket rename of all upstream-derived internal identifiers -- in particular: - - internal `guix` namespaces may remain temporarily where needed for compatibility and maintenance - - `gnu` names are preserved where they refer to real GNU concepts or components such as GNU packages, GNU Shepherd, or `gnu-build-system` - - new fork-specific modules and user-facing surfaces should prefer `fruix` naming - -Current assessment: - -- the naming direction is now clearer for the next integration batch -- Phase 5 and beyond should aim to: - - first make the upstream-derived checkout runnable on FreeBSD, - - then introduce a deliberate `fruix` command boundary, - - rather than destabilizing the codebase with a whole-tree `guix`/`gnu` rename too early - -## 2026-04-01 — Phase 5.1 completed: checkout runtime unblocked and first `fruix` frontend boundary established - -Completed work: - -- added a reusable phase-5 checkout setup helper: - - `tests/guix/setup-phase5-checkout.sh` -- added a checkout runtime patch queue for the upstream-derived source tree: - - `tests/guix/patches/phase5-checkout-runtime.patch` -- added a FreeBSD daemon/build patch queue needed for later phase-5 work: - - `tests/guix/patches/phase5-guix-daemon-freebsd.patch` -- added a runtime validation harness: - - `tests/guix/run-phase5-checkout-runtime.sh` -- wrote the Phase 5.1 report: - - `docs/reports/phase5-checkout-runtime-freebsd.md` -- ran the runtime harness successfully and captured metadata under: - - `/tmp/phase5-runtime-metadata.txt` - -Important findings: - -- the earlier checkout blocker - - `./pre-inst-env guix --version` - - `Wrong type to apply: #` - is now explained by top-level definition ordering in `guix/ui.scm`: - - `show-version-and-exit` called `leave-on-EPIPE` before the syntax transformer was defined later in the file - - on this FreeBSD path, that became a runtime application of a syntax-transformer object instead of a macro expansion site -- the phase-5 runtime patch fixes this by: - - making `(guix ui)` explicitly non-declarative - - rewriting `show-version-and-exit` to use direct `catch 'system-error` handling - - parameterizing `program-name` in `guix-main` - - deriving the top-level version banner name from `program-name` - - making `(guix scripts repl)` explicitly non-declarative as well -- the checkout now successfully runs the following commands on FreeBSD: - - `./pre-inst-env guix --version` - - `./pre-inst-env guix repl --help` - - `./pre-inst-env guix build --help` -- the first user-facing Fruix command boundary is now implemented in the checkout setup via: - - `scripts/fruix` - as a front-end alias next to `scripts/guix` -- observed runtime metadata confirmed: - - `first_guix_version_line=guix (GNU Guix) ...` - - `first_fruix_version_line=fruix (GNU Guix) ...` -- this matches the agreed naming policy: - - Fruix at the user-facing boundary - - stable upstream-derived internal `guix`/`gnu` names unless there is a concrete reason to rename them - -Current assessment: - -- Phase 5.1 is now satisfied on the current FreeBSD prototype track -- the key boundary has shifted from “the checkout still crashes immediately” to “the checkout runs, and can now be used as the basis for real derivation/store experiments” -- the next step is to prove that a real derivation can be emitted against `/frx/store` from the now-runnable checkout - -## 2026-04-01 — Phase 5.2 completed: real derivation generation validated against `/frx/store` - -Completed work: - -- added a runnable derivation-generation harness: - - `tests/guix/run-phase5-derivation-generation.sh` -- wrote the Phase 5.2 report: - - `docs/reports/phase5-derivation-generation-freebsd.md` -- ran the derivation-generation harness successfully and captured metadata under: - - `/tmp/phase5-derivation-metadata.txt` - -Important findings: - -- the now-runnable checkout can successfully use a real daemon/store connection on FreeBSD to lower a package through: - - `package->bag` - - `bag->derivation` -- the emitted derivation is a real `/frx/store` derivation path rather than an ad hoc placeholder or shell metadata artifact -- the validation used a deliberately minimal custom package with a custom low-level build system so that this subphase isolates the real lowering/store boundary without being dominated by still-unresolved upstream bootstrap assumptions for full native FreeBSD package graphs -- observed metadata confirmed: - - `bag_name=phase5-freebsd-lowering-0` - - `bag_host_inputs=("source")` - - `drv_path=/frx/store/...-phase5-freebsd-lowering-0.drv` - - `out_path=/frx/store/...-phase5-freebsd-lowering-0` -- this means the key architectural step is now real and no longer hypothetical: - - a package object in the checkout can be lowered to a real derivation targeting `/frx/store` on FreeBSD - -Current assessment: - -- Phase 5.2 is now satisfied on the current FreeBSD prototype track -- the next step is no longer “can we emit a derivation at all?” but “can the same daemon/store path accept and execute a derivation-backed build request successfully?” - -## 2026-04-01 — Phase 5.3 completed: minimal daemon/store RPC integration validated on FreeBSD - -Completed work: - -- added a runnable daemon/store RPC validation harness: - - `tests/guix/run-phase5-daemon-rpc.sh` -- wrote the Phase 5.3 report: - - `docs/reports/phase5-daemon-rpc-freebsd.md` -- ran the daemon/store RPC harness successfully and captured metadata under: - - `/tmp/phase5-daemon-rpc-metadata.txt` - -Important findings: - -- the patched checkout can now contact a real FreeBSD-aware daemon over a Unix socket and submit a derivation-backed build request successfully -- the resulting build path is a real `/frx/store` output rather than a simulated prototype artifact -- the successful metadata path now includes the full minimal chain needed for later system work: - - checkout command path - - daemon RPC - - derivation submission - - build execution - - store output materialization -- observed metadata confirmed: - - `drv_path=/frx/store/...-phase5-freebsd-daemon-build-0.drv` - - `out_path=/frx/store/...-phase5-freebsd-daemon-build-0` - - `payload=phase5-daemon-build-source` - - `source_path=/frx/store/...-phase5-source.txt` -- this step was exercised through the Fruix-facing checkout boundary: - - `./pre-inst-env fruix repl -- ...` - which means the user-facing transition is now connected to actual daemon/store activity, not just to help text or version banners - -Current assessment: - -- Phase 5.3 is now satisfied on the current FreeBSD prototype track -- the project now has a real but narrow end-to-end host-side execution path on FreeBSD: - - runnable checkout - - Fruix front-end boundary - - real derivation emission - - daemon/store RPC - - successful derivation-backed build into `/frx/store` - -## 2026-04-01 — Phase 5 completed on the current FreeBSD prototype track - -Phase 5 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 5.1** success criteria were met on the prototype track: - - the checkout runtime blocker around `leave-on-EPIPE` was root-caused and fixed in the patch queue - - the uninstalled checkout command path now runs on FreeBSD - - a first user-facing `fruix` command boundary was established -- **Phase 5.2** success criteria were met on the prototype track: - - a real package object was lowered through `package->bag` and `bag->derivation` - - a real derivation was emitted targeting `/frx/store` -- **Phase 5.3** success criteria were met on the prototype track: - - a real checkout command path contacted a FreeBSD-aware daemon/store path - - that path accepted and executed a derivation-backed build request - - the resulting output was materialized successfully in `/frx/store` - -Important scope note: - -- this completes the **real checkout and host runtime unblocking milestone** on the current prototype track, not full upstream-package-graph support for arbitrary native FreeBSD package builds yet -- the successful derivation/build path currently uses a deliberately minimal custom package/build-system path to isolate real daemon/store viability from still-unresolved upstream bootstrap and package-graph assumptions for native FreeBSD -- nevertheless, the core Phase 5 question has now been answered positively: - - the checkout runs - - real derivations can be emitted - - the daemon can be built far enough to serve store RPC - - and derivation-backed builds can succeed into `/frx/store` - -Next recommended step: - -1. begin Phase 6.1 by moving from the minimal custom derivation-backed package path to at least one real FreeBSD store-backed package build driven by Fruix/Guix mechanisms -2. then integrate the already validated jail/build-user model more directly into the live daemon build path -3. continue preserving the selective Fruix naming policy: - - Fruix at the product boundary - - `/frx` as the canonical store root - - stable upstream-derived internal names unless there is strong architectural value in renaming them - -## 2026-04-01 — Phase 6.1 completed: real package build validated into `/frx/store` - -Completed work: - -- added a runnable real-package harness: - - `tests/guix/run-phase6-real-package-build.sh` -- wrote the Phase 6.1 report: - - `docs/reports/phase6-real-package-build-freebsd.md` -- ran the real-package harness successfully and captured metadata under: - - `/tmp/phase6-real-package-metadata.txt` - -Important findings: - -- the checkout can now build a real package definition derived from Guix's `hello` package through: - - `./pre-inst-env fruix build -f ...` - - the FreeBSD-aware daemon - - `/frx/store` -- this moves the project beyond the deliberately minimal Phase 5 custom derivation path and into a real package-definition flow -- the current successful path still uses a prefetched local GNU Hello tarball as the package source because the built-in downloader path remains a separate unresolved FreeBSD/root-daemon issue -- observed metadata confirmed: - - `drv_path=/frx/store/...-hello-2.12.3.drv` - - `out_path=/frx/store/...-hello-2.12.3` - - `source_store_path=/frx/store/...-hello-2.12.3.tar.gz` - - `runtime_output=Hello, world!` -- a daemon-side references query confirmed that the built output preserved the declared source store item as a direct reference - -Current assessment: - -- Phase 6.1 is now satisfied on the current FreeBSD prototype track -- the next step is to move the already validated jail/build-user model into this live package-build path rather than keeping it prototype-only - -## 2026-04-01 — Phase 6.2 completed: jail/build-user isolation integrated into the real package path - -Completed work: - -- added a reusable UID/GID drop helper source: - - `tests/daemon/freebsd-drop-exec.c` -- added a runnable jail-integrated package harness: - - `tests/guix/run-phase6-jail-package-build.sh` -- wrote the Phase 6.2 report: - - `docs/reports/phase6-jail-build-integration-freebsd.md` -- ran the jail-integrated harness successfully and captured metadata under: - - `/tmp/phase6-jail-package-metadata.txt` - -Important findings: - -- a real package build derived from Guix's `hello` definition now runs through the live daemon path inside a FreeBSD jail rather than only through the earlier prototype scripts -- the actual build work inside the jail runs as dropped credentials: - - UID `35001` - - GID `35001` -- the integrated build path required one additional FreeBSD-specific adjustment beyond the earlier prototype: - - the daemon-side host `TMPDIR` path was not automatically valid inside the jail, so the jailed build environment must reset `TMPDIR=/tmp` -- observed metadata confirmed: - - `drv_path=/frx/store/...-hello-2.12.3.drv` - - `out_path=/frx/store/...-hello-2.12.3` - - `runtime_output=Hello, world!` - - `build_uid=35001` - - `build_gid=35001` - - `jail_hostname=fruix-phase6-hello-...` - - `build_mode=freebsd-jail` - - `source_store_path=/frx/store/...-hello-2.12.3.tar.gz` -- the GNU Hello test suite also passed inside the jail-integrated build path - -Current assessment: - -- Phase 6.2 is now satisfied on the current FreeBSD prototype track -- the next step is to validate a minimal user-facing profile installation flow on top of these real store outputs - -## 2026-04-01 — Phase 6.3 completed: minimal profile installation validated on real store outputs - -Completed work: - -- added a runnable real-store profile harness: - - `tests/packages/run-phase6-real-store-profile-prototype.sh` -- wrote the Phase 6.3 report: - - `docs/reports/phase6-real-store-profile-freebsd.md` -- updated the Phase 6 package-build harnesses so they can recover derivation paths even when the requested outputs are already present in `/frx/store` -- ran the real-store profile harness successfully and captured metadata under: - - `/tmp/phase6-real-store-profile-metadata.txt` - -Important findings: - -- the current FreeBSD track now has a minimal user-facing profile installation flow built on top of real Phase 6 store outputs rather than the earlier Phase 3 package/profile prototype inputs -- the validated transaction semantics are intentionally small but real: - - generation 1 is created from the Phase 6.1 host-built store item - - generation 2 is created from the Phase 6.2 jail-built store item - - the `profile` symlink switches to generation 2 - - both generations remain addressable -- observed metadata confirmed: - - `profile_target=profile-2-link` - - `generation1_store_path=/frx/store/...-hello-2.12.3` - - `generation2_store_path=/frx/store/...-hello-2.12.3` - - `current_store_path=/frx/store/...-hello-2.12.3` - - `profile_hello_output=Hello, world!` - - `clean_env_hello_output=Hello, world!` -- the upstream-derived profile layer is still not fully usable on this FreeBSD track because the current `guix profiles` / `fruix package` path still reaches the unresolved bootstrap-platform blocker: - - `dynamic linker name not known for this system "x86_64-freebsd15.0"` -- despite that blocker, the minimal Fruix-owned profile path is now validated on top of real daemon-built store items - -Current assessment: - -- Phase 6.3 is now satisfied on the current FreeBSD prototype track -- Phase 6 as a whole is now complete on the active FreeBSD amd64 prototype path - -## 2026-04-01 — Phase 6 completed on the current FreeBSD prototype track - -Phase 6 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 6.1** success criteria were met on the prototype track: - - a real package definition derived from Guix's `hello` package now builds through `fruix build` - - the output lands in `/frx/store` - - the package runs from the store and preserves a declared source reference -- **Phase 6.2** success criteria were met on the prototype track: - - a real package build now executes inside a FreeBSD jail - - the build work runs under dropped numeric build credentials - - the jailed build succeeds into `/frx/store` -- **Phase 6.3** success criteria were met on the prototype track: - - real Phase 6 store outputs can be installed into a minimal profile environment - - generation switching works in a concrete form - - package execution through the profile succeeds for the current user - -Important scope note: - -- this completes the **real FreeBSD-backed store-build milestone** on the current prototype track, not full upstream-package-graph support or full upstream profile-layer parity yet -- the current package path still relies on a prefetched local source tarball for GNU Hello because the built-in downloader/root-daemon path remains a separate FreeBSD issue -- the current profile-installation path is a Fruix-owned minimal layer over real store outputs because the upstream-derived profile code still hits the unresolved FreeBSD bootstrap-platform mapping blocker -- nevertheless, the core Phase 6 question has now been answered positively: - - real package definitions can be built into `/frx/store` - - those builds can run under integrated jail/build-user isolation - - and the resulting store items can be exposed through a minimal user-facing profile flow - -Next recommended step: - -1. begin Phase 7.1 by defining a minimal Fruix operating-system model for FreeBSD -2. carry forward the selective Fruix naming policy: - - Fruix at the product boundary - - `/frx` as the canonical store root - - stable upstream-derived internal names unless there is strong architectural value in renaming them -3. keep the two remaining Phase 6 follow-up blockers visible but scoped: - - built-in downloader/root-daemon integration for real package origins - - upstream-derived profile/bootstrap-platform support for `x86_64-freebsd15.0` - -## 2026-04-01 — Phase 7.1 completed: minimal Fruix operating-system model defined for FreeBSD - -Completed work: - -- added the first Fruix-owned FreeBSD system module: - - `modules/fruix/system/freebsd.scm` -- added the Phase 7.1 operating-system example and validation harnesses: - - `tests/system/phase7-minimal-operating-system.scm` - - `tests/system/validate-phase7-operating-system.scm` - - `tests/system/run-phase7-operating-system-model.sh` -- extended the FreeBSD package model with additional system-oriented prototype packages: - - `freebsd-bootloader` - - `freebsd-rc-scripts` - - `freebsd-runtime` - - `%freebsd-system-packages` -- wrote the Phase 7.1 report: - - `docs/reports/phase7-operating-system-model-freebsd.md` -- ran the operating-system model harness successfully and captured metadata under: - - `/tmp/phase7-os-model-metadata.txt` - -Important findings: - -- the FreeBSD track now has a concrete declarative operating-system object rather than only package/profile and service prototypes -- the model currently covers: - - host identity - - kernel and bootloader assets - - essential base packages - - users/groups - - file systems - - generated `/etc` payloads - - activation payload generation - - generated Shepherd configuration -- the selected first init strategy is now explicit in the model: - - `freebsd-init+rc.d-shepherd` -- observed metadata confirmed: - - `host_name=fruix-freebsd` - - `kernel_package=freebsd-kernel` - - `bootloader_package=freebsd-bootloader` - - `base_packages=freebsd-runtime,freebsd-userland,freebsd-libc,freebsd-rc-scripts,freebsd-sh,freebsd-bash` - - `users=root,operator` - - `groups=wheel,operator` - - `generated_files=boot/loader.conf,etc/rc.conf,etc/fstab,etc/hosts,etc/passwd,etc/group,etc/shells,etc/motd,activate,shepherd/init.scm` - - `init_mode=freebsd-init+rc.d-shepherd` - -Current assessment: - -- Phase 7.1 is now satisfied on the current FreeBSD prototype track -- the next step is to materialize this operating-system description into a reproducible system closure under `/frx/store` - -## 2026-04-01 — Phase 7.2 completed: minimal system closure generated under `/frx/store` - -Completed work: - -- added the Phase 7.2 closure materialization harnesses: - - `tests/system/materialize-phase7-system-closure.scm` - - `tests/system/run-phase7-system-closure.sh` -- refined the minimal operating-system example so the generated system profile also contains `/bin/sh` -- wrote the Phase 7.2 report: - - `docs/reports/phase7-system-closure-freebsd.md` -- ran the system-closure harness successfully and captured metadata under: - - `/tmp/phase7-system-closure-metadata.txt` - -Important findings: - -- the declarative FreeBSD Fruix operating-system object now materializes into a real system closure under `/frx/store` -- that closure contains: - - boot assets - - a merged system profile - - generated `/etc` files - - a generated activation script - - a generated Shepherd configuration - - a generated `rc.d` launcher for Shepherd -- the closure now embeds the concrete first init integration choice for the FreeBSD track: - - `freebsd-init+rc.d-shepherd` -- rerunning the same materialization produced the same closure path, which is the current prototype proof of reproducible closure generation for this phase -- observed metadata confirmed: - - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` - - `closure_rebuild_path=/frx/store/...-fruix-system-fruix-freebsd` - - `kernel_store=/frx/store/...-freebsd-kernel-15.0-STABLE` - - `bootloader_store=/frx/store/...-freebsd-bootloader-15.0-STABLE` - - `guile_store=/frx/store/...-fruix-guile-runtime-3.0` - - `guile_extra_store=/frx/store/...-fruix-guile-extra-3.0` - - `shepherd_store=/frx/store/...-fruix-shepherd-runtime-1.0.9` - - `profile_bin_sh=/frx/store/...-fruix-system-fruix-freebsd/profile/bin/sh` - - `profile_sbin_init=/frx/store/...-fruix-system-fruix-freebsd/profile/sbin/init` - - `profile_rc=/frx/store/...-fruix-system-fruix-freebsd/profile/etc/rc` - -Current assessment: - -- Phase 7.2 is now satisfied on the current FreeBSD prototype track -- the next step is to materialize and statically validate an installable root filesystem tree from this system closure - -## 2026-04-01 — Phase 7.3 completed: installable rootfs tree validated from the system closure - -Completed work: - -- added the Phase 7.3 rootfs materialization harnesses: - - `tests/system/materialize-phase7-rootfs.scm` - - `tests/system/run-phase7-rootfs.sh` -- wrote the Phase 7.3 report: - - `docs/reports/phase7-rootfs-freebsd.md` -- ran the rootfs harness successfully and captured metadata under: - - `/tmp/phase7-rootfs-metadata.txt` - -Important findings: - -- the declarative Fruix FreeBSD system can now be materialized as a root filesystem tree rather than only as a store closure directory -- the rootfs uses a Guix-like anchor: - - `/run/current-system` - so that boot assets, generated configuration, and system-profile content remain tied to the declarative system closure -- static validation confirmed: - - boot asset linkage - - generated `/etc` linkage - - activation payload presence - - Shepherd `rc.d` launch integration - - declared filesystem entries - - declared user/group provisioning in the activation path - - deterministic ready-state wiring through `/var/lib/fruix/ready` -- observed metadata confirmed: - - `rootfs=/tmp/.../rootfs` - - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` - - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` - - `activate_target=/run/current-system/activate` - - `bin_target=/run/current-system/profile/bin` - - `sbin_target=/run/current-system/profile/sbin` - - `boot_kernel_target=/run/current-system/boot/kernel` - - `boot_loader_target=/run/current-system/boot/loader` - - `boot_loader_efi_target=/run/current-system/boot/loader.efi` - - `rc_conf_target=/run/current-system/etc/rc.conf` - - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` - - `ready_marker=/var/lib/fruix/ready` - - `validation_mode=static-rootfs-check` - -Current assessment: - -- Phase 7.3 is now satisfied on the current FreeBSD prototype track -- Phase 7 as a whole is now complete on the active FreeBSD amd64 prototype path - -## 2026-04-01 — Phase 7 completed on the current FreeBSD prototype track - -Phase 7 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 7.1** success criteria were met on the prototype track: - - a minimal Fruix operating-system object now exists for FreeBSD - - it evaluates into a coherent system-closure specification -- **Phase 7.2** success criteria were met on the prototype track: - - that system model now materializes into a reproducible closure under `/frx/store` - - the closure contains boot assets, generated `/etc` files, activation payloads, and Shepherd launch integration -- **Phase 7.3** success criteria were met on the prototype track: - - the closure now materializes into a concrete rootfs tree - - the resulting rootfs passes static validation for later image-construction work - -Important scope note: - -- this completes the **declarative system-composition milestone** for the current prototype track, not a fully booted Fruix guest yet -- the current output is a validated closure plus rootfs tree; Phase 8 still needs to turn that into a reproducible bhyve-friendly disk image -- the chosen first system-init strategy remains: - - FreeBSD init + `rc.d` launching Shepherd - rather than Shepherd-as-PID-1 -- the current system model remains Fruix-owned and FreeBSD-oriented rather than attempting full upstream Guix System integration prematurely - -Next recommended step: - -1. begin Phase 8.1 by creating a reproducible disk-image build path from the generated Fruix rootfs tree -2. keep the current init decision explicit for the first boot target: - - FreeBSD init + `rc.d` + Shepherd -3. continue preserving the selective Fruix naming policy: - - Fruix at the product boundary - - `/frx` as the canonical store root - - stable upstream-derived internal names unless there is strong architectural value in renaming them - -## 2026-04-01 — Phase 8.1 completed: reproducible bhyve-compatible raw disk image generated - -Completed work: - -- added the first Phase 8 image-generation harness: - - `tests/system/run-phase8-bhyve-image.sh` -- wrote the Phase 8.1 report: - - `docs/reports/phase8-bhyve-image-freebsd.md` -- ran the image-generation harness successfully and captured metadata under: - - `/tmp/phase8-bhyve-image-metadata.txt` - -Important findings: - -- the current Fruix FreeBSD track now has a reproducible raw disk-image build path using: - - GPT - - UEFI boot - - a FAT EFI system partition - - a UFS root partition - - serial-console-friendly loader settings -- the earlier Phase 7 rootfs tree was not sufficient by itself for an installable image because it still referenced `/frx/store` content that only existed on the host; the image builder therefore had to stage the system closure and its recursively declared store references inside the image rootfs under `/frx/store` -- rebuilding the same image a second time with fixed timestamps and explicit filesystem parameters produced the same SHA256, which is the current prototype proof of reproducible image generation on this host -- observed metadata confirmed: - - `raw_sha256=08605d738021cb6fb5b87c270e1eafde57e1acb5159d3a2257aad4c560e2efc5` - - `image_size_bytes=335578624` - - `esp_fstype=msdosfs` - - `root_fstype=ufs` - - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` - - `boot_loader_target=/run/current-system/boot/loader` - - `boot_loader_conf_target=/run/current-system/boot/loader.conf` - - `rc_conf_target=/run/current-system/etc/rc.conf` - - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` - - `store_item_count=13` - - `boot_mode=uefi` - - `image_format=raw` - - `partition_scheme=gpt` - - `serial_console=comconsole` - -Current assessment: - -- Phase 8.1 is now satisfied on the current FreeBSD prototype track -- the next step is to integrate this image generation path into the declarative Fruix system-composition layer so that a single operating-system description can drive image generation end-to-end - -## 2026-04-01 — Phase 8.2 completed: image generation integrated into the declarative system layer - -Completed work: - -- extended the FreeBSD system module with integrated image-generation operations: - - `operating-system-image-spec` - - `materialize-bhyve-image` -- added the Phase 8.2 integration harnesses: - - `tests/system/materialize-phase8-system-image.scm` - - `tests/system/run-phase8-system-image.sh` -- wrote the Phase 8.2 report: - - `docs/reports/phase8-system-image-freebsd.md` -- ran the integrated system-image harness successfully and captured metadata under: - - `/tmp/phase8-system-image-metadata.txt` - -Important findings: - -- image generation is now a direct output of the Fruix FreeBSD system-definition layer rather than an external shell-only follow-up to Phase 7 -- the integrated path now stores the resulting image artifact itself under `/frx/store`, preserving the store-centered Fruix composition story even at the VM-image layer -- rerunning `materialize-bhyve-image` for the same operating-system description produced the same image store path, which is the current prototype proof that one declarative system object can drive image generation end-to-end -- observed metadata confirmed: - - `image_store_path=/frx/store/...-fruix-bhyve-image-fruix-freebsd` - - `disk_image=/frx/store/...-fruix-bhyve-image-fruix-freebsd/disk.img` - - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` - - `raw_sha256=ac57d4c694ea3cf6b1bd24be48982090a6cfcfa301d052c1f903636a46f2d56e` - - `image_size_bytes=335578624` - - `store_item_count=13` - - `esp_fstype=msdosfs` - - `root_fstype=ufs` - - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` - - `boot_loader_target=/run/current-system/boot/loader` - - `rc_conf_target=/run/current-system/etc/rc.conf` - - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` - - `image_generation_mode=declarative-system-layer` - -Current assessment: - -- Phase 8.2 is now satisfied on the current FreeBSD prototype track -- Phase 8 as a whole is now complete on the active FreeBSD amd64 prototype path - -## 2026-04-01 — Phase 8 completed on the current FreeBSD prototype track - -Phase 8 is now considered complete for the active FreeBSD amd64 prototype path. - -Why this milestone is satisfied: - -- **Phase 8.1** success criteria were met on the prototype track: - - a reproducible raw GPT+UEFI+UFS image can now be generated from the Fruix system outputs - - that image passes static boot-structure sanity checks -- **Phase 8.2** success criteria were met on the prototype track: - - the image builder is now integrated with the declarative Fruix system-definition layer - - a single operating-system description now drives image generation end-to-end - - the integrated output is itself a store-backed Fruix image artifact under `/frx/store` - -Important scope note: - -- this completes the **image-construction milestone** for the current prototype track, not the first successful bhyve boot yet -- the generated image is now ready for the next phase’s VM-launch and serial-console validation work -- the current first-boot strategy remains explicit and unchanged: - - FreeBSD init + `rc.d` + Shepherd -- the image path still reflects the current prototype system/runtime limitations, including the fact that deeper runtime closure completeness for locally copied Guile/Shepherd dependencies will be exercised more fully in Phase 9 boot validation - -Next recommended step: - -1. begin Phase 9.1 by creating a bhyve launcher and serial-console validation harness for the generated image -2. keep the current deterministic ready-state target visible: - - Shepherd startup leading to the generated `/var/lib/fruix/ready` marker path -3. continue preserving the selective Fruix naming policy: - - Fruix at the product boundary - - `/frx` as the canonical store root - - stable upstream-derived internal names unless there is strong architectural value in renaming them - -## 2026-04-02 — Phase 9 checkpoint: XCP-ng guest reached DHCP and SSH - -Completed work: - -- added a dedicated Phase 9 XCP-ng operating-system template: - - `tests/system/phase9-minimal-operating-system.scm.in` -- added an XCP-ng boot/import/validation harness: - - `tests/system/run-phase9-xcpng-boot.sh` -- extended the staged FreeBSD runtime and system-generation layers so the guest can complete enough of real boot for network access: - - `modules/fruix/packages/freebsd.scm` - - `modules/fruix/system/freebsd.scm` -- updated the integrated image-generation path for Phase 9 use cases: - - `tests/system/materialize-phase8-system-image.scm` - - `tests/system/run-phase8-system-image.sh` -- wrote the checkpoint report: - - `docs/reports/phase9-xcpng-ssh-boot-freebsd.md` - -Important findings: - -- a decisive local QEMU/TCG serial-boot pass exposed the first real early-boot blocker: - - the generated `fstab` was wrong for pseudo-filesystems, so `rc` tried to fsck `devfs` and aborted boot -- after fixing `fstab`, later serial logs exposed additional FreeBSD base runtime gaps that only appear during real boot, including missing commands, runtime directories, and base config files used by `rc`, DHCP, logging, and service startup -- the staged image now includes the minimum currently known set of FreeBSD runtime pieces needed to: - - run `rc` - - obtain DHCP - - generate SSH host keys - - start `sshd` -- public-key SSH login initially still failed because the minimal guest did not stage a complete PAM runtime/config path; for the current Phase 9 prototype track, the generated `sshd_config` now uses: - - `UsePAM no` -- the current XCP-ng validation path succeeded against the operator-approved VM and existing VDI only: +- local `bhyve` remains blocked under Xen due to lack of nested VT-x exposure +- XO self-service creation is still not usable with the current token +- real XCP-ng validation must continue to use: - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` - - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` -- the successful XCP-ng boot obtained: - - guest IP `192.168.213.62` -- successful SSH validation on the real guest confirmed: - - `hostname=fruix-freebsd` - - `sshd` is reachable with the injected root key - - networking is configured on the Xen NIC + - approved A/B VDIs: + - `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` + - `7061d761-3639-4bec-87f7-2ba1af924eaa` +- local QEMU/TCG validation keeps conservative default SMP settings; `QEMU_SMP` remains overrideable -Current assessment: +## Next step -- this checkpoint establishes the first real network-reachable Fruix boot on the active FreeBSD/XCP-ng track -- the generated image now boots far enough for DHCP and SSH, which closes the earlier uncertainty about whether the Phase 8 image could become a remotely usable guest at all -- Phase 9 is still not complete because the Fruix-specific readiness path remains blocked: - - `fruix-shepherd` does not start - - `/var/lib/fruix/ready` is still missing - - Guile still crashes in the guest with `signal 11` -- therefore the current state is: - - kernel boot: yes - - root mount: yes - - DHCP: yes - - SSH: yes - - Shepherd/ready marker: not yet +Per `docs/PLAN_4.md`, the next planned step is: -Next recommended step: +- **Phase 18.3** — produce a bootable UEFI installer ISO -1. continue the in-guest Guile crash investigation so `fruix-shepherd` can start on the booted guest -2. once Shepherd is stable, rerun `tests/system/run-phase9-xcpng-boot.sh` to validate the full ready-marker path end-to-end -3. then close Phase 9 with updated report/progress entries for: - - deterministic boot readiness - - in-guest Shepherd validation - - minimal operator usability - -## 2026-04-02 — Phase 9 completed on the active XCP-ng FreeBSD track - -Completed work: - -- resolved the in-guest Guile/Shepherd blocker that remained after the earlier DHCP+SSH checkpoint -- wrote the completion report: - - `docs/reports/phase9-xcpng-ready-boot-freebsd.md` -- extended the staged runtime again in: - - `modules/fruix/packages/freebsd.scm` - - added `/usr/sbin/daemon` - - added `/usr/share/locale/C.UTF-8/LC_CTYPE` -- completed the guest runtime integration in: - - `modules/fruix/system/freebsd.scm` - - activation now recreates compatibility symlinks for the currently locally built Guile / guile-extra / Shepherd prefixes, but points them at the real `/frx/store` items in the guest - - the rootfs now exposes `/usr/share/locale` - - the generated Shepherd config no longer relies on missing `mkdir-p` or unsupported `call-with-output-file #:append` behavior - - the Shepherd rc script now exports `LANG=C.UTF-8` / `LC_ALL=C.UTF-8` - - the Shepherd rc script now exports explicit Guile system/site path variables - - Shepherd is now started through FreeBSD `daemon(8)` so it remains alive after rc/session teardown -- corrected the XCP-ng harness in: - - `tests/system/run-phase9-xcpng-boot.sh` - - it now uses a distinct SSH private key file for login instead of incorrectly trying to authenticate with the public key file - -Important findings: - -- the original guest Guile failure had multiple layers: - - missing UTF-8 locale data in the image - - baked-in temporary install-prefix references inside the copied Guile / guile-extra / Shepherd artifacts - - and Shepherd process lifetime issues caused by a fragile shell-background startup path -- reproducing the problem in a host-side chroot into the generated image root partition made the final debugging loop much tighter than repeated full VM imports alone -- after locale staging and compatibility-prefix recreation, Guile and Shepherd became runnable in the guest, but Shepherd still exited too early on the real boot path until it was launched via `daemon(8)` -- after those fixes, the full ready-marker path became reliable enough for end-to-end XCP-ng validation - -Final validation: - -- `tests/system/run-phase9-xcpng-boot.sh` now passes end-to-end against: - - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` - - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` -- passing run workdir: - - `/tmp/phase9-xcpng-pass-1775113189` -- passing real-guest metadata confirmed: - - `ready_marker=ready` - - `shepherd_status=running` - - `sshd_status=running` - - `run_current_system_target=/frx/store/0fe459ea22156510e64cea794b7a001151b59625bd5f12a488d6851e1c6d2198-fruix-system-fruix-freebsd` - - `operator_home_listing=/home/operator` - - `logger_log=fruix-shepherd-started` - -Current assessment: - -- Phase 9 is now complete for the active FreeBSD prototype track, using the XCP-ng replacement path adopted for this environment -- the generated Fruix image now reaches all currently required first-boot milestones on the real VM: - - kernel boot: yes - - root mount: yes - - DHCP: yes - - SSH: yes - - Shepherd: yes - - ready marker: yes - - minimal operator usability: yes -- this establishes the first real Fruix-on-FreeBSD VM that: - - boots from the declaratively generated image, - - reaches the generated ready state, - - keeps Shepherd running, - - and remains inspectable over SSH as a minimally usable system - -Next recommended step: - -1. begin the next post-Phase-9 cleanup/native-integration pass from `docs/PLAN_2.md` Optional Phase 10 -2. prioritize replacing the current compatibility shims for locally built Guile / Shepherd prefixes with a more native store-path-aware Fruix runtime arrangement -3. clean up remaining non-fatal boot noise observed during Phase 9, such as: - - login-class warnings around `daemon` - - the `gpart: Unknown command: show` rc noise - - residual syslog/cron/runtime polish issues where they still matter - -## 2026-04-02 — Phase 10.1: added a real `fruix system` command - -Completed work: - -- started Optional Phase 10 with the first user-facing Fruix system-management command surface -- wrote the subphase report: - - `docs/reports/phase10-fruix-system-command-freebsd.md` -- added a real CLI wrapper: - - `bin/fruix` -- added the corresponding Guile entry point: - - `scripts/fruix.scm` -- added a dedicated validation harness: - - `tests/system/run-phase10-fruix-system-command.sh` - -What the new command does: - -- exposes declarative FreeBSD system artifact generation through a Fruix CLI instead of only phase-specific harness scripts -- currently supports: - - `fruix system build OS-FILE` - - `fruix system image OS-FILE` - - `fruix system rootfs OS-FILE ROOTFS-DIR` -- currently supports options: - - `--system NAME` - - `--store DIR` - - `--disk-capacity SIZE` - - `--rootfs DIR` - - `--help` -- loads an operating-system object from a Scheme file, validates it, and dispatches to: - - `materialize-operating-system` - - `materialize-rootfs` - - `materialize-bhyve-image` -- emits machine-readable `key=value` metadata for the produced artifacts - -Important findings: - -- the project already had the core declarative system machinery by the end of Phase 9; the missing piece here was a direct Fruix operator interface to that machinery -- a small dedicated wrapper in this repo is currently the most practical way to expose that functionality without waiting for deeper upstream command-framework integration -- keeping the command aligned with the already validated local FreeBSD Guile / Fibers / Shepherd toolchain avoids introducing a second, divergent runtime path - -Validation: - -- `tests/system/run-phase10-fruix-system-command.sh` passes -- passing run workdir: - - `/tmp/phase10-fruix-cmd-1775117490` -- the test validated that: - - `fruix system build` materializes a closure under `/frx/store/*-fruix-system-fruix-freebsd` - - the produced closure contains the activation path - - `fruix system image` materializes a disk image under `/frx/store/*-fruix-bhyve-image-fruix-freebsd/disk.img` - - the command returns expected metadata fields for both actions - -Current assessment: - -- Fruix now has a real user-facing system command in this repo, which is a concrete step from “prototype scripts” toward “OS tooling” -- this does not replace all earlier harnesses yet, but it establishes `fruix system` as the new canonical interface for system closure/rootfs/image materialization work -- system/image creation still typically requires `sudo` because the command writes into `/frx/store` and uses privileged image-building operations - -Next recommended step: - -1. continue Phase 10 by making more of the existing system workflows call `bin/fruix` directly instead of bespoke phase scripts -2. reduce the current runtime compatibility shims for locally built Guile / Shepherd prefixes and move toward a more native store-path-aware Fruix runtime arrangement -3. consider adding the next operator-facing subcommand on top of the now-working image path, such as a `vm`/deploy-oriented flow for the active XCP-ng workflow - -## 2026-04-02 — Phase 10 completed: canonical system workflows now use `fruix system` - -Completed work: - -- completed the current Optional Phase 10 track by making the existing FreeBSD system workflows use the real Fruix CLI as their canonical frontend -- wrote the completion report: - - `docs/reports/phase10-canonical-system-workflows-freebsd.md` -- extended the `fruix system build` metadata in: - - `scripts/fruix.scm` - - added: - - `ready_marker` - - `base_package_store_count` - - `base_package_stores` -- refactored the main static system harnesses to call `bin/fruix` instead of invoking internal Scheme materializer runners directly: - - `tests/system/run-phase7-system-closure.sh` - - `tests/system/run-phase7-rootfs.sh` - - `tests/system/run-phase8-system-image.sh` - -What changed in practice: - -- the closure path is now validated through: - - `fruix system build` -- the rootfs path is now validated through: - - `fruix system rootfs` -- the image path is now validated through: - - `fruix system image` -- the real XCP-ng boot path now benefits from this automatically because: - - `tests/system/run-phase9-xcpng-boot.sh` - still calls the Phase 8 harness, and that harness now builds its image through `bin/fruix` - -Validation: - -- `tests/system/run-phase7-system-closure.sh` passes - - workdir: `/tmp/phase10-canon-closure2-1775119728` -- `tests/system/run-phase7-rootfs.sh` passes - - workdir: `/tmp/phase10-canon-rootfs3-1775120391` -- `tests/system/run-phase8-system-image.sh` passes - - workdir: `/tmp/phase10-canon-image-1775120548` -- full real XCP-ng regression still passes after the frontend refactor: - - `tests/system/run-phase9-xcpng-boot.sh` - - workdir: `/tmp/phase10-canon-xcpng-1775120869` - -Important findings: - -- the Phase 9 booted system path was already real, but the remaining transitional layer was the tooling/frontend boundary rather than the system internals -- adding `bin/fruix` in Phase 10.1 was necessary but not sufficient on its own; the existing validation and deployment workflows also had to adopt it, or the project would still effectively be driven by bespoke phase scripts -- after this refactor, the command path is now exercised by: - - static closure validation - - static rootfs validation - - static image validation - - and the real XCP-ng boot/import/SSH/ready-marker path - -Current assessment: - -- Optional Phase 10 is now complete for the current FreeBSD prototype track -- Fruix now has: - - a user-facing command surface in `bin/fruix` - - real `system build`, `system rootfs`, and `system image` actions - - canonical validation/deployment workflows that use that command instead of directly entering the materializers - - and a command-driven image path that remains validated on the real XCP-ng VM -- this means the project now has not just declarative OS internals, but also a real Fruix operator/tooling layer around those internals - -Next recommended step: - -1. begin the next post-Phase-10 cleanup/polish pass outside the plan milestones -2. prioritize replacing the current Guile / Shepherd compatibility-prefix shims with a more native store-path-aware runtime arrangement -3. consider adding richer deploy/vm-oriented `fruix` commands beyond the now-canonical `system build/rootfs/image` path - -## 2026-04-02 — Post-Phase-10: local Shepherd-as-PID-1 prototype booted on FreeBSD - -Completed work: - -- began the next post-Phase-10 runtime-integration pass by exploring a Shepherd-as-PID-1 boot mode for Fruix on FreeBSD -- compared the approach with Guix's root Shepherd design in: - - `~/repos/guix/gnu/services/shepherd.scm` -- wrote the subphase report: - - `docs/reports/postphase10-shepherd-pid1-qemu-freebsd.md` -- extended the declarative FreeBSD operating-system model in: - - `modules/fruix/system/freebsd.scm` - - added an `init-mode` field with: - - `freebsd-init+rc.d-shepherd` - - `shepherd-pid1` - - generated loader configuration now sets: - - `init_exec="/run/current-system/boot/fruix-pid1"` - when `init-mode` is `shepherd-pid1` - - generated systems in PID 1 mode now include: - - `boot/fruix-pid1` - - the generated activation script now treats `cap_mkdb` / `pwd_mkdb` as best-effort so immutable store-backed config files do not abort this early boot path -- added a dedicated Shepherd-PID-1 operating-system template: - - `tests/system/phase11-shepherd-pid1-operating-system.scm.in` -- added a dedicated local QEMU/UEFI validation harness: - - `tests/system/run-phase11-shepherd-pid1-qemu.sh` - -Important findings: - -- FreeBSD's `init(8)` already has a suitable handoff mechanism for this experiment via: - - `init_exec` -- compared with Guix, the current Fruix implementation is still much more imperative, but it now follows the same broad direction: - - boot into Shepherd directly as PID 1 rather than merely starting Shepherd late from rc.d -- the first PID 1 attempt failed because the generated Shepherd config imported a repo-side module: - - `(fruix shepherd freebsd)` - that was not present inside the guest runtime; the fix was to inline the small helper procedures needed by the generated config itself -- the early PID 1 path also exposed that store-backed `/etc/login.conf` and `/etc/master.passwd` updates must be best-effort rather than fatal on this bootstrap path -- for the current locally built runtime artifacts, the compatibility-prefix shims are still needed; this subphase did not eliminate them yet, but it did remove the larger `rc.d` boot-manager dependency from the local prototype path - -Validation: - -- `tests/system/run-phase11-shepherd-pid1-qemu.sh` now passes -- passing run workdir: - - `/tmp/pid1-qemu6-1775128407` -- validated local guest state included: - - `ready_marker=ready` - - `shepherd_pid=1` - - `shepherd_socket=present` - - `shepherd_status=running` - - `sshd_status=running` - - `boot_backend=qemu-uefi-tcg` - - `init_mode=shepherd-pid1` - -Current assessment: - -- Fruix now has a working local FreeBSD prototype where Shepherd itself is PID 1 -- this is not yet the new mainline boot path, but it proves that the project can move beyond the earlier `freebsd-init+rc.d-shepherd` bridge architecture -- the PID 1 process image appears as Guile because Shepherd is launched as a Guile script, but the decisive validation point is that: - - `/var/run/shepherd.pid` contains `1` -- this subphase was validated locally under QEMU/TCG + UEFI; the next meaningful test is the real XCP-ng VM - -Next recommended step: - -1. try the `shepherd-pid1` image on the real XCP-ng VM -2. if it boots there too, decide whether to keep `shepherd-pid1` as an experimental selectable boot mode or advance it further toward the main Fruix boot path -3. continue reducing the remaining Guile / Shepherd compatibility-prefix shims now that the broader `rc.d` boot-manager dependency has been locally bypassed - -## 2026-04-02 — Post-Phase-10: Shepherd-as-PID-1 boot also passed on the real XCP-ng VM - -Completed work: - -- took the locally validated `shepherd-pid1` boot mode and tested it on the real XCP-ng deployment path -- wrote the follow-up report: - - `docs/reports/postphase10-shepherd-pid1-xcpng-freebsd.md` -- expanded the Shepherd-PID-1 operating-system template so the generated guest remains compatible with both local virtio and the real Xen NIC path: - - `tests/system/phase11-shepherd-pid1-operating-system.scm.in` - - now includes: - - `ifconfig_xn0=SYNCDHCP` - - `ifconfig_em0=SYNCDHCP` - - `ifconfig_vtnet0=SYNCDHCP` -- added a dedicated real-VM Shepherd-PID-1 deployment/validation harness: - - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - -Validation: - -- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` now passes on the operator-approved VM and existing VDI: - - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` - - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` -- passing run workdir: - - `/tmp/pid1-xcpng-1775129768` -- passing real-guest metadata confirmed: - - `ready_marker=ready` - - `run_current_system_target=/frx/store/2940c952e9d35e47f98fe62f296be2b6ab4fceb3eee8248d6a7823decd42a305-fruix-system-fruix-freebsd` - - `pid1_command=[guile]` - - `shepherd_pid=1` - - `shepherd_socket=present` - - `shepherd_status=running` - - `sshd_status=running` - - `init_mode=shepherd-pid1` - -Important findings: - -- the local QEMU PID 1 prototype was not a simulator-only artifact; the same general boot design also works on the real XCP-ng/Xen guest -- as expected for a Guile-script entry point, the PID 1 process image shows up as Guile, but the meaningful architectural check is that: - - `/var/run/shepherd.pid` contains `1` -- this means Fruix has now validated two distinct real-VM boot architectures on FreeBSD: - - `freebsd-init+rc.d-shepherd` - - `shepherd-pid1` -- however, this still does not remove the current Guile / Shepherd compatibility-prefix shims; those remain a separate runtime-artifact issue rather than an init-manager issue - -Current assessment: - -- Shepherd-as-PID-1 is now no longer merely a local prototype; it is validated on the real XCP-ng VM as well -- this significantly strengthens the path toward a more Guix-like Fruix system architecture on FreeBSD -- the main remaining native-runtime gap is now the baked-prefix / compatibility-shim problem, not whether Fruix can boot with Shepherd as PID 1 - -Next recommended step: - -1. focus directly on eliminating the remaining Guile / Shepherd compatibility-prefix shims from the guest runtime -2. preserve `shepherd-pid1` as an experimental selectable boot mode while that cleanup proceeds -3. once the runtime-prefix issue is reduced, reassess whether `shepherd-pid1` should replace the older `freebsd-init+rc.d-shepherd` path as the preferred Fruix boot architecture - -## 2026-04-02 — Post-Phase-10: removed runtime dependence on `/tmp` Guile / Shepherd compatibility-prefix shims - -Completed work: - -- removed the generated guest's runtime dependence on the old `/tmp` compatibility-prefix symlinks for Guile, guile-extra, and Shepherd -- wrote the subphase report: - - `docs/reports/postphase10-runtime-prefix-shims-freebsd.md` -- updated the prefix materializer in: - - `modules/fruix/system/freebsd.scm` - - bumped the prefix-materializer revision - - added deterministic post-copy sanitation for staged runtime prefixes -- removed activation-time recreation of these guest-side shims from the generated activation path: - - `/tmp/guile-freebsd-validate-install` - - `/tmp/guile-gnutls-freebsd-validate-install` - - `/tmp/shepherd-freebsd-validate-install` -- sanitized the staged guile-extra runtime so it no longer depends on those old prefixes for key module loading: - - patched `fibers/config.scm` to use `GUILE_EXTENSIONS_PATH` - - patched `gnutls.scm` to fall back to `GUILE_EXTENSIONS_PATH` - - removed stale compiled cache files that would otherwise retain the old prefix behavior: - - `fibers/config.go` - - `gnutls.go` -- sanitized the staged Shepherd runtime so it no longer depends on the old temporary prefix for `shepherd config`: - - patched `share/guile/site/3.0/shepherd/config.scm` - - removed stale compiled cache file: - - `shepherd/config.go` -- extended the real XCP-ng validation harnesses so they now explicitly check for: - - absence of the `/tmp` compatibility-prefix trees - - successful Guile module loading from the store-backed runtime -- updated: - - `tests/system/run-phase9-xcpng-boot.sh` - - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - -Validation: - -- `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with: - - workdir: `/tmp/noshim-phase9-smoke-1775143001` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `ready_marker=ready` - - `shepherd_status=running` - - `sshd_status=running` -- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with: - - workdir: `/tmp/noshim-phase11-smoke-1775142712` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `ready_marker=ready` - - `shepherd_pid=1` - - `shepherd_status=running` - - `sshd_status=running` -- a direct manual guest probe also confirmed that all three `/tmp` compatibility-prefix paths are absent while Guile can still load: - - `(fibers config)` - - `(gnutls)` - - `(shepherd config)` - -Important findings: - -- the remaining native-runtime problem was narrower than the earlier boot-manager issue: - - boot was already solved - - PID 1 was already solved - - the next real dependency to remove was the guest's reliance on temporary compatibility aliases -- deleting the stale compiled cache files for the affected modules was important; otherwise Guile could continue using prefix-baked compiled forms even after the source modules were patched -- this subphase removes runtime dependence on the old `/tmp` compatibility shims, but it does not yet guarantee that every embedded historical prefix string has disappeared from every binary or metadata artifact - -Current assessment: - -- Fruix now boots and runs from a store-backed Guile / Shepherd runtime arrangement on FreeBSD without needing guest-side `/tmp` compatibility-prefix symlinks -- this now holds for both validated real-VM boot modes: - - `freebsd-init+rc.d-shepherd` - - `shepherd-pid1` -- the main remaining cleanup is deeper and lower-level: - - move the local Guile / guile-extra / Shepherd build/install flow itself closer to a truly store-native prefix so the remaining baked strings disappear from the artifacts rather than merely becoming runtime-irrelevant - -Next recommended step: - -1. keep `shepherd-pid1` available as the stronger experimental boot architecture -2. start pushing the local Guile / guile-extra / Shepherd build/install process itself toward a truly store-native prefix layout -3. clean up the remaining historical prefix strings still present in binaries, libtool metadata, and pkg-config metadata where they still matter for developer/operator workflows - -## 2026-04-02 — Phase 12.1: deployment provenance and diagnostic metadata improved - -Completed work: - -- wrote the next-stage plan document: - - `docs/PLAN_3.md` -- added a concise progress snapshot: - - `docs/PROG_SUMMARY.md` -- wrote the Phase 12.1 report: - - `docs/reports/phase12-provenance-diagnostics-freebsd.md` -- updated `modules/fruix/system/freebsd.scm` so generated system closures now carry explicit provenance files: - - `metadata/host-base-provenance.scm` - - `metadata/store-layout.scm` -- those closure metadata files now record at least: - - host `freebsd-version -kru` - - host `uname -a` - - `/usr/src` path - - `/usr/src` git revision/branch when available - - `newvers.sh` SHA256 as a fallback source-tree identifier - - exact host-staged FreeBSD base store paths - - exact Fruix runtime store paths - - selected init mode -- extended `scripts/fruix.scm` so `fruix system build` and `fruix system image` now emit explicit provenance/layout metadata including: - - `host_base_store_count` - - `host_base_stores` - - `fruix_runtime_store_count` - - `fruix_runtime_stores` - - `host_base_provenance_file` - - `store_layout_file` - - `host_freebsd_version` - - `host_uname` - - `usr_src_git_revision` - - `usr_src_git_branch` - - `usr_src_newvers_sha256` -- tightened the local closure/image validation harnesses so they now assert that this provenance metadata exists: - - `tests/system/run-phase7-system-closure.sh` - - `tests/system/run-phase8-system-image.sh` -- expanded the VM-oriented harnesses to collect more guest-side diagnostic tails where available: - - `tests/system/run-phase9-xcpng-boot.sh` - - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - - `tests/system/run-phase11-shepherd-pid1-qemu.sh` - - now include additional capture for: - - `shepherd-bootstrap.out` - - `shepherd.log` - - recent `dmesg` -- stabilized local reproducibility checks by forcing: - - `GUILE_AUTO_COMPILE=0` - in the host-side closure/image harnesses when invoking `fruix` under `sudo env` - -Validation: - -- `tests/system/run-phase7-system-closure.sh` passes with the new provenance checks: - - workdir: `/tmp/phase12-1b-closure-1775157039` - - confirmed: - - `host_base_store_count=8` - - `fruix_runtime_store_count=3` - - `host_base_provenance_file=/frx/store/.../metadata/host-base-provenance.scm` - - `store_layout_file=/frx/store/.../metadata/store-layout.scm` - - `host_freebsd_version=15.0-STABLE` -- `tests/system/run-phase8-system-image.sh` passes with the new provenance checks: - - workdir: `/tmp/phase12-1b-image-1775157039` - - confirmed: - - `host_base_store_count=8` - - `fruix_runtime_store_count=3` - - `host_base_provenance_file=/frx/store/.../metadata/host-base-provenance.scm` - - `store_layout_file=/frx/store/.../metadata/store-layout.scm` - - `host_uname=FreeBSD fruixdev 15.0-STABLE ...` -- syntax-checked successfully: - - `tests/system/run-phase9-xcpng-boot.sh` - - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - - `tests/system/run-phase11-shepherd-pid1-qemu.sh` - -Important findings: - -- the current host-staged FreeBSD base pipeline is still transitional, but it is now much more inspectable and self-describing -- one-shot reproducibility failures immediately after source edits were partly a host-side auto-compilation artifact; forcing `GUILE_AUTO_COMPILE=0` in the validation harnesses makes the closure/image checks more stable -- the project can now identify much more directly: - - which closure/image inputs came from the host-staged FreeBSD base - - which came from Fruix-built Guile/Shepherd runtime artifacts - - what `/usr/src` identity was available at build time - -Current assessment: - -- Fruix now has a better-documented and easier-to-debug working pipeline for the current host-staged FreeBSD base model -- this is the right amount of hardening before beginning native FreeBSD base-build work; it improves traceability without pretending the current host-copy model is final - -Next recommended step: - -1. continue with Phase 12.2 and tighten the guest-side runtime/operator diagnostics -2. remove or reduce the most distracting remaining boot/runtime rough edges where the fixes are small and local -3. keep the deployment path stable so Phase 13 can start from a sharper baseline - -## 2026-04-02 — Phase 12.2: guest runtime diagnostics tightened and `/etc` handling improved - -Completed work: - -- wrote the Phase 12.2 report: - - `docs/reports/phase12-runtime-diagnostics-freebsd.md` -- updated `modules/fruix/system/freebsd.scm` so selected database-backed `/etc` files are now materialized as regular files in the guest rootfs instead of symlinks: - - `/etc/passwd` - - `/etc/master.passwd` - - `/etc/group` - - `/etc/login.conf` -- the generated activation script now refreshes those files from `/run/current-system/etc` before rebuilding FreeBSD databases -- activation now writes a guest-visible log: - - `/var/log/fruix-activate.log` - - with markers including: - - `fruix-activate:start` - - `fruix-activate:cap_mkdb=ok` - - `fruix-activate:pwd_mkdb=ok` - - `fruix-activate:done` - - exit status marker via shell trap -- tightened closure permissions slightly by making: - - `etc/master.passwd` - mode `0600` -- upgraded validation harnesses so they now assert the improved runtime behavior directly: - - `tests/system/run-phase8-system-image.sh` - - now checks that image `/etc/login.conf` is a regular file - - now checks that image `/etc/master.passwd` is a regular file - - `tests/system/run-phase9-xcpng-boot.sh` - - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - - `tests/system/run-phase11-shepherd-pid1-qemu.sh` - - now check for: - - `login_conf_kind=regular` - - `login_conf_db=present` - - `pwd_dbs=present` - - activation log completion marker -- fixed a small follow-up bug in the activation log path: - - initial implementation used `touch`, which is not staged in the minimal guest - - switched to shell redirection instead: - - `: >> "$logfile"` - -Validation: - -- `tests/system/run-phase8-system-image.sh` passes locally with the new image-layout checks: - - workdir: `/tmp/phase12-2-image-1775159011` - - confirmed: - - `login_conf_kind=regular` - - `master_passwd_kind=regular` -- `tests/system/run-phase11-shepherd-pid1-qemu.sh` passes locally again with the new activation/runtime checks: - - workdir: `/tmp/phase12-2b-qemu-1775161367` - - confirmed: - - `activate_log=fruix-activate:start ... fruix-activate:done ...` - - `login_conf_kind=regular` - - `login_conf_db=present` - - `pwd_dbs=present` - - `shepherd_pid=1` - - `sshd_status=running` -- `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with the new checks: - - workdir: `/tmp/phase12-2b-phase9-1775161731` - - confirmed: - - `activate_log=fruix-activate:start ... fruix-activate:done ...` - - `login_conf_kind=regular` - - `login_conf_db=present` - - `pwd_dbs=present` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `shepherd_status=running` - - `sshd_status=running` -- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with the new checks: - - workdir: `/tmp/phase12-2b-phase11-1775162210` - - confirmed: - - `activate_log=fruix-activate:start ... fruix-activate:done ...` - - `login_conf_kind=regular` - - `login_conf_db=present` - - `pwd_dbs=present` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `shepherd_pid=1` - - `sshd_status=running` - -Important findings: - -- the old symlink-based handling for login/password database inputs was a real mismatch with FreeBSD expectations; making those files regular in the guest was a better fit than leaving them store-backed symlinks -- adding a direct activation log materially improves post-boot diagnosis and avoids guessing whether activation actually completed -- the first attempt exposed a missing-userland dependency (`touch`) quickly; because the new diagnostics were explicit, the follow-up fix was immediate and local -- both validated boot paths still hold after this change: - - `freebsd-init+rc.d-shepherd` - - `shepherd-pid1` - -Current assessment: - -- the current Fruix guest remains intentionally minimal, but its runtime behavior is now less prototype-noisy and easier to inspect as a basic FreeBSD-like system -- this is exactly the kind of targeted hardening that makes the existing system a better launch point for native FreeBSD base-build work - -Next recommended step: - -1. complete Phase 12.3 by making the host-staged FreeBSD base boundary explicit in the package/model layer and docs -2. document the first intended replacement order for native world/kernel work -3. then begin Phase 13 with a clearer transitional boundary - -## 2026-04-02 — Phase 12.3: made the host-staged FreeBSD base boundary explicit - -Completed work: - -- wrote the Phase 12.3 report: - - `docs/reports/phase12-host-staged-base-boundary-freebsd.md` -- refined `modules/fruix/packages/freebsd.scm` so the transitional host-copy base boundary is now explicit in the package/model layer -- added and exported named transitional package sets: - - `%freebsd-host-staged-all-packages` - - `%freebsd-host-staged-core-packages` - - `%freebsd-host-staged-development-profile-packages` - - `%freebsd-host-staged-system-packages` -- added and exported: - - `freebsd-host-staged-package?` - - `%freebsd-host-staged-replacement-order` -- preserved compatibility aliases so existing callers still work: - - `%freebsd-core-packages` - - `%freebsd-development-profile-packages` - - `%freebsd-system-packages` -- encoded the intended first replacement order for native base-build work directly in the package layer: - 1. `freebsd-kernel`, `freebsd-bootloader` - 2. `freebsd-runtime`, `freebsd-libc`, `freebsd-userland`, `freebsd-rc-scripts` - 3. `freebsd-networking`, `freebsd-openssh` - 4. `freebsd-kernel-headers`, `freebsd-clang-toolchain` - 5. `freebsd-gmake`, `freebsd-autotools`, `freebsd-openssl`, `freebsd-zlib`, `freebsd-sh`, `freebsd-bash` -- updated `modules/fruix/system/freebsd.scm` so the generated closure metadata now carries this boundary information too: - - `metadata/store-layout.scm` now includes: - - `host-base-stores` - - `fruix-runtime-stores` - - `host-base-replacement-order` - - `init-mode` - -Validation: - -- confirmed package-layer behavior directly with Guile: - - `(freebsd-host-staged-package? freebsd-runtime)` => `#t` - - `%freebsd-host-staged-replacement-order` prints the expected staged replacement order -- `tests/system/run-phase7-system-closure.sh` still passes after the package-layer clarification: - - workdir: `/tmp/phase12-3-closure-1775162784` -- inspected generated closure metadata file: - - `/frx/store/25ae9bb85da60b8c77971325e0e11d5390a064132a35e1bab0866cabb802a606-fruix-system-fruix-freebsd/metadata/store-layout.scm` - - confirmed it now includes: - - `host-base-stores` - - `fruix-runtime-stores` - - `host-base-replacement-order` - -Important findings: - -- the current host-staged FreeBSD base model is no longer just an implicit fact of the implementation; it is now named and documented as a transitional boundary -- preserving compatibility aliases means the current working system model does not need a broad rename/refactor just to make that boundary explicit -- encoding the replacement order directly in the package/model layer gives Phase 13 a clearer starting point for native `world`/`kernel` work - -Current assessment: - -- Phase 12 is now complete -- the current Fruix pipeline is better documented, easier to diagnose, less noisy at runtime, and clearer about what remains transitional in the FreeBSD base layer -- this is a good stopping point before beginning native FreeBSD base-build artifacts in `/frx/store` - -Next recommended step: - -1. begin Phase 13.1 by modeling FreeBSD `world` and `kernel` as Fruix-managed build artifacts rather than host-copy packages -2. use `/usr/src` as the initial source of truth on the builder side -3. target the first bootable replacement for the current host-staged kernel and core runtime path - -## 2026-04-02 — Phase 13.1: modeled native FreeBSD world/kernel artifacts - -Completed work: - -- wrote the Phase 13.1 report: - - `docs/reports/phase13-native-base-model-freebsd.md` -- added native FreeBSD base package objects in `modules/fruix/packages/freebsd.scm`: - - `freebsd-native-kernel` - - `freebsd-native-world` -- added and exported: - - `freebsd-native-build-package?` -- encoded the first native build parameters directly in those package definitions, including: - - `source-root=/usr/src` - - `target=amd64` - - `target-arch=amd64` - - `kernconf=GENERIC` - - make flags: - - `__MAKE_CONF=/dev/null` - - `SRCCONF=/dev/null` - - `SRC_ENV_CONF=/dev/null` - - `MK_DEBUG_FILES=no` - - `MK_TESTS=no` -- the first native world artifact now also carries an explicit runtime-oriented prune list: - - `usr/share/doc` - - `usr/share/examples` - - `usr/share/info` - - `usr/share/man` - - `usr/tests` -- extended `modules/fruix/system/freebsd.scm` so `materialize-freebsd-package` now understands: - - `copy-build-system` - - `freebsd-world-build-system` - - `freebsd-kernel-build-system` -- added native-build identity/materialization helpers for: - - `/usr/src` source-tree identity - - `KERNCONF` path hashing - - build-root identity - - buildworld/buildkernel stamp handling - - staged installworld/installkernel materialization - - native build metadata files in store outputs -- chose an `mtree`-based `/usr/src` identity for the first native output model using: - - `type` - - `link` - - `size` - - `mode` - - `sha256digest` -- updated closure/image metadata modeling so the system can now distinguish: - - `host_base_stores` - - `native_base_stores` - - `fruix_runtime_stores` -- updated profile/tree merging to skip private dotfile metadata from store outputs so native-build metadata does not leak into the merged runtime tree - -Validation: - -- confirmed the updated package/system modules still load after the native build-model additions -- confirmed the new native package objects are present and classified as expected: - - `freebsd-native-kernel` reports build-system `freebsd-kernel-build-system` - - `freebsd-native-build-package? freebsd-native-world` returns `#t` -- re-ran the existing host-copy regression check successfully: - - `tests/system/run-phase7-system-closure.sh` - - workdir: `/tmp/phase13-1-closure-1775164392` - - result: `PASS phase7-system-closure` - -Important findings: - -- Fruix now has a real model for FreeBSD base artifacts built from `/usr/src`; the project is no longer limited to describing the FreeBSD base only as host-copy packages -- the first native identity story is explicit: - - `/usr/src` contributes through an `mtree`-based tree digest - - `KERNCONF` contributes through its resolved path hash - - selected make/build parameters are part of the manifest too -- the repo can now describe a mixed system more honestly by separating: - - transitional host-staged base stores - - native base stores - - Fruix runtime stores - -Current assessment: - -- Phase 13.1 is complete -- the next step is no longer architectural guesswork; it is concrete execution of the newly added native package/materialization path - -Next recommended step: - -1. build the first concrete `freebsd-native-kernel` and `freebsd-native-world` outputs from `/usr/src` -2. inspect/document their staged contents in `/frx/store` -3. then wire a bootable system closure/image around those native outputs - -## 2026-04-03 — Phase 13.2: first native FreeBSD world/kernel outputs built from `/usr/src` - -Completed work: - -- wrote the Phase 13.2 report: - - `docs/reports/phase13-native-world-kernel-build-freebsd.md` -- exercised the new native build path for real and produced the first concrete store outputs from `/usr/src`: - - native kernel output under `/frx/store` - - native world output under `/frx/store` -- added a dedicated Phase 13.2 template/harness: - - `tests/system/phase13-native-base-pid1-operating-system.scm.in` - - `tests/system/run-phase13-native-base-build.sh` -- fixed the first real native-build failure: - - `MAKEOBJDIRPREFIX` cannot be passed as a make command-line variable for this FreeBSD build path - - changed the native builder to invoke make as: - - `env MAKEOBJDIRPREFIX=... make ...` -- fixed a subtle output-identity bug in the first `/usr/src` hash implementation: - - the initial `mtree`-based source hash accidentally included unstable header comments such as date/user/machine lines - - now strips `# ...` header lines before hashing - - this stabilized the source-tree identity and stopped the native output/build-root identity from drifting on each run -- verified that native world and kernel now share the same: - - `source-tree-sha256` - - `build-root` -- the first native world split remains intentionally runtime-oriented and prunes at least: - - `usr/share/doc` - - `usr/share/examples` - - `usr/share/info` - - `usr/share/man` - - `usr/tests` - -Concrete validated outputs: - -- native kernel store path: - - `/frx/store/93f35ddcb9a03f63f83c9e8ae29788685d339789da664f881822b4a1914f5ff6-freebsd-native-kernel-15.0-STABLE` -- native world store path: - - `/frx/store/3f6f7f8c06ed8dad4cae21a1e8ac8ba4823bdb7cf54328c9bbcccaeb858beb77-freebsd-native-world-15.0-STABLE` -- shared native build root: - - `/var/tmp/fruix-freebsd-native-build-c59b1b8128b305d9bad9cf3d654771c941c4e8b6a2732f6bc959df96d1d32f58` - -Validated native-world contents include at least: - -- `/bin/sh` -- `/sbin/init` -- `/etc/rc` -- `/usr/sbin/sshd` -- `/sbin/dhclient` -- `/usr/bin/cap_mkdb` -- `/usr/sbin/pwd_mkdb` -- `/usr/share/locale/C.UTF-8/LC_CTYPE` - -Validated pruned paths are absent from the world output: - -- `/usr/share/man` -- `/usr/tests` - -Validation: - -- real native-base `fruix system build` succeeded with an operating-system using: - - `freebsd-native-kernel` - - `freebsd-native-world` - - host-staged `freebsd-bootloader` - - `shepherd-pid1` -- `tests/system/run-phase13-native-base-build.sh` passes: - - workdir: `/tmp/phase13-2-build-1775173551` - - result: `PASS phase13-native-base-build` -- the harness confirmed: - - closure rebuild path reproducibility - - native kernel/world store paths exist - - native build info files exist - - world/kernel source-tree hashes match - - world/kernel build roots match - - native build logs exist - - `native-base-stores` is present in closure metadata - - host/native store boundary now looks as expected for this mixed system: - - `host_base_store_count=1` - - `native_base_store_count=2` - -Important findings: - -- the native build path is now real, not just modeled -- the first mixed Phase-13 system boundary is explicit and sensible: - - host-staged bootloader only - - native kernel + native world - - Fruix runtime stores unchanged -- the `mtree` preamble bug would have made native output identity drift across runs; fixing it was essential before treating these as reproducible store artifacts -- the shared build-root result is important: the kernel/world pair now reuses the same `/usr/src` build state instead of acting like two unrelated builds - -Current assessment: - -- Phase 13.2 is complete -- Fruix can now build and stage native FreeBSD base artifacts from `/usr/src` in `/frx/store` -- the next step is to boot a system using those native outputs rather than stopping at build-time inspection - -Next recommended step: - -1. wire the image/boot path to use the native kernel/world outputs end-to-end -2. validate locally with QEMU/UEFI -3. validate on the approved XCP-ng VM and VDI path - -## 2026-04-03 — Phase 13.3: booted Fruix from native FreeBSD kernel/world outputs - -Completed work: - -- wrote the Phase 13.3 report: - - `docs/reports/phase13-native-base-boot-freebsd.md` -- completed the first end-to-end boot path using native `/usr/src`-built FreeBSD base artifacts in `/frx/store` -- fixed the first native-image sizing problem: - - the old fixed `root-size=256m` was too small once the image carried a native world - - added explicit root filesystem sizing support to the CLI/image path: - - `scripts/fruix.scm` now accepts `--root-size SIZE` - - image metadata now records `root_size` - - `tests/system/run-phase8-system-image.sh` now accepts: - - `ROOT_SIZE` - and records: - - `root_size` - - `native_base_store_count` - - `native_base_stores` -- fixed a follow-up image metadata bug: - - `materialize-bhyve-image` now returns: - - `native-base-stores` - - this removed the `length #f` failure in the native image path -- generalized the local PID1 QEMU harness a bit further: - - `tests/system/run-phase11-shepherd-pid1-qemu.sh` now accepts `OS_TEMPLATE` -- added dedicated Phase 13.3 native-base boot wrappers: - - `tests/system/run-phase13-native-base-qemu.sh` - - `tests/system/run-phase13-native-base-xcpng.sh` -- these wrappers reuse the validated PID1 boot path but additionally require the image metadata to prove the booted system is really using the intended Phase-13 base split: - - native kernel present - - native world present - - host base reduced to bootloader only - -Working native-base boot configuration: - -- local QEMU: - - `ROOT_SIZE=6g` - - `DISK_CAPACITY=8g` -- real XCP-ng: - - `ROOT_SIZE=6g` - - disk capacity kept matched to the fixed 30 GiB VDI as before - -Validation: - -- local QEMU/UEFI/TCG boot passes through the new wrapper: - - `tests/system/run-phase13-native-base-qemu.sh` - - workdir: `/tmp/phase13-3-qemu3-1775174863` - - result: `PASS phase13-native-base-qemu` - - confirmed: - - `disk_capacity=8g` - - `root_size=6g` - - `native_base_store_count=2` - - `host_base_store_count=1` - - `shepherd_pid=1` - - `sshd_status=running` - - `native_base_boot=ok` -- real XCP-ng boot passes through the new wrapper: - - `tests/system/run-phase13-native-base-xcpng.sh` - - workdir: `/tmp/phase13-3-xcpng-1775175086` - - result: `PASS phase13-native-base-xcpng` - - confirmed: - - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` - - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - - `guest_ip=192.168.213.62` - - `root_size=6g` - - `native_base_store_count=2` - - `host_base_store_count=1` - - `shepherd_pid=1` - - `sshd_status=running` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `native_base_boot=ok` -- validated native-base closure/image composition now boots with: - - native kernel store: - - `/frx/store/93f35ddcb9a03f63f83c9e8ae29788685d339789da664f881822b4a1914f5ff6-freebsd-native-kernel-15.0-STABLE` - - native world store: - - `/frx/store/3f6f7f8c06ed8dad4cae21a1e8ac8ba4823bdb7cf54328c9bbcccaeb858beb77-freebsd-native-world-15.0-STABLE` - - remaining host base store: - - `/frx/store/8ffcfe0356fea815726b610514a1280a11266851c2acb870047d559795569f0e-freebsd-bootloader-15.0-STABLE` - -Important findings: - -- the native world is large enough that the older 256 MiB rootfs assumption is no longer realistic; explicit image sizing is now part of the practical Phase-13 path -- after the native-base transition, the remaining transitional boundary is now much narrower and explicit: - - host-staged bootloader/boot assets - - native kernel - - native core world runtime -- the real XCP-ng upload path still works with the larger native-world image, but the dynamic VHD is naturally much bigger now (~4.42 GiB) - -Current assessment: - -- Phase 13 is complete -- Fruix now builds FreeBSD kernel/world artifacts from `/usr/src` into `/frx/store` and successfully boots a declarative system from those native outputs -- this is the main architectural pivot Plan 3 called for before Phase 14 - -Next recommended step: - -1. begin Phase 14 by replacing the remaining host-copy boot assets first -2. keep shrinking the host-staged base boundary around the now-working native world/kernel path -3. revisit cleaner runtime vs. development splits after the boot asset transition - -## 2026-04-03 — Phase 14.1: removed host-copied boot assets from the validated native boot path - -Completed work: - -- wrote the Phase 14.1 report: - - `docs/reports/phase14-native-boot-assets-freebsd.md` -- added a dedicated Phase 14.1 native-boot PID1 template: - - `tests/system/phase14-native-boot-pid1-operating-system.scm.in` -- added dedicated Phase 14.1 validation wrappers: - - `tests/system/run-phase14-native-boot-qemu.sh` - - `tests/system/run-phase14-native-boot-xcpng.sh` -- validated a cleaner native boot path by sourcing boot assets from the existing native world output instead of the host-staged `freebsd-bootloader` package: - - `#:kernel freebsd-native-kernel` - - `#:bootloader freebsd-native-world` - - `#:base-packages (list freebsd-native-world)` -- hardened the reusable local PID1 QEMU harness so it no longer boots the raw store image directly read/write from `/frx/store`: - - `tests/system/run-phase11-shepherd-pid1-qemu.sh` now copies the generated raw image to: - - `boot-disk.img` - in the workdir before launching QEMU - - this prevents repeated local boots from mutating the supposed store artifact and causing dirty-filesystem follow-up failures - -Validation: - -- local QEMU/UEFI/TCG native-boot wrapper passes: - - `tests/system/run-phase14-native-boot-qemu.sh` - - workdir: `/tmp/phase14-1-qemu2-1775188371` - - result: `PASS phase14-native-boot-qemu` - - confirmed: - - `native_base_store_count=2` - - `host_base_store_count=0` - - `shepherd_pid=1` - - `sshd_status=running` - - `native_boot_assets=freebsd-native-world` - - `native_base_boot=ok` -- real XCP-ng native-boot wrapper passes: - - `tests/system/run-phase14-native-boot-xcpng.sh` - - workdir: `/tmp/phase14-1-xcpng-1775188701` - - result: `PASS phase14-native-boot-xcpng` - - confirmed: - - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` - - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - - `guest_ip=192.168.213.62` - - `native_base_store_count=2` - - `host_base_store_count=0` - - `shepherd_pid=1` - - `sshd_status=running` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `native_boot_assets=freebsd-native-world` - - `native_base_boot=ok` - -Current assessment: - -- Phase 14.1 is complete -- the validated native boot path no longer depends on host-copied `/boot/...` material -- the current Phase-14.1 native boundary is now fully host-base-free for the validated path: - - native kernel - - native world supplying boot assets - - native world supplying runtime - -Next recommended step: - -1. introduce a clearer native runtime slice so runtime is no longer modeled by reusing the broader native world output for both boot and runtime -2. validate that explicit native runtime slice on QEMU and XCP-ng -3. then revisit headers/toolchain/development package boundaries - -## 2026-04-03 — Phase 14.2: validated an explicit native FreeBSD runtime slice - -Completed work: - -- wrote the Phase 14.2 report: - - `docs/reports/phase14-native-runtime-freebsd.md` -- added a new native package in `modules/fruix/packages/freebsd.scm`: - - `freebsd-native-runtime` -- this runtime slice is built from `/usr/src` through the native world path and now prunes at least: - - `boot` - - `usr/include` - - `usr/share/doc` - - `usr/share/examples` - - `usr/share/info` - - `usr/share/man` - - `usr/share/mk` - - `usr/tests` -- added a dedicated Phase 14.2 operating-system template: - - `tests/system/phase14-native-runtime-pid1-operating-system.scm.in` -- added dedicated validation wrappers: - - `tests/system/run-phase14-native-runtime-qemu.sh` - - `tests/system/run-phase14-native-runtime-xcpng.sh` -- the validated Phase 14.2 model now uses: - - `#:kernel freebsd-native-kernel` - - `#:bootloader freebsd-native-world` - - `#:base-packages (list freebsd-native-runtime)` -- this makes the system composition more explicit: - - native world provides boot assets - - native runtime provides the guest runtime slice - - host base stores remain absent from the validated path - -Important finding: - -- this Phase 14.2 layout still duplicates some content because boot assets still come from the broader native world output while runtime comes from the separate native runtime slice -- that made the earlier Phase 13 image sizes too small -- the working values are now: - - local QEMU: - - `DISK_CAPACITY=12g` - - `ROOT_SIZE=10g` - - real XCP-ng: - - `ROOT_SIZE=10g` - - disk capacity still matched to the fixed 30 GiB VDI -- the new Phase 14.2 wrappers now use those larger defaults - -Validation: - -- local QEMU/UEFI/TCG runtime wrapper passes: - - `tests/system/run-phase14-native-runtime-qemu.sh` - - workdir: `/tmp/phase14-2-qemu2-1775189802` - - result: `PASS phase14-native-runtime-qemu` - - confirmed: - - `disk_capacity=12g` - - `root_size=10g` - - `runtime_store=/frx/store/684a82aeed2c9a353e3a09d2cbf5358274d758005e0bfa9b1025d101bc166f79-freebsd-native-runtime-15.0-STABLE` - - `native_base_store_count=3` - - `host_base_store_count=0` - - `shepherd_pid=1` - - `sshd_status=running` - - `native_runtime_ready=ok` -- real XCP-ng runtime wrapper passes: - - `tests/system/run-phase14-native-runtime-xcpng.sh` - - workdir: `/tmp/phase14-2-xcpng-1775190184` - - result: `PASS phase14-native-runtime-xcpng` - - confirmed: - - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` - - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - - `guest_ip=192.168.213.62` - - `root_size=10g` - - `runtime_store=/frx/store/684a82aeed2c9a353e3a09d2cbf5358274d758005e0bfa9b1025d101bc166f79-freebsd-native-runtime-15.0-STABLE` - - `native_base_store_count=3` - - `host_base_store_count=0` - - `shepherd_pid=1` - - `sshd_status=running` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `native_runtime_ready=ok` -- the wrappers also assert the runtime-split boundary directly: - - runtime store contains required boot-to-ready files such as: - - `/bin/sh` - - `/sbin/init` - - `/etc/rc` - - `/usr/sbin/sshd` - - `/sbin/dhclient` - - `/usr/bin/ssh-keygen` - - `/usr/share/locale/C.UTF-8/LC_CTYPE` - - runtime store no longer contains: - - `/boot` - - `/usr/include` - -Current assessment: - -- Phase 14.2 is complete -- the validated Fruix guest now reaches ready state using an explicit native runtime artifact rather than reusing the broad native world output for both boot and runtime roles -- the validated path remains host-base-free: - - native kernel - - native world as the temporary boot-source artifact - - native runtime as the guest runtime artifact - -Next recommended step: - -1. define cleaner runtime vs. development boundaries in code/package sets -2. introduce a narrower native boot asset package so the broader native world output is no longer needed as the temporary boot-source store -3. revalidate the full host-base-free path after that split - -## 2026-04-03 — Phase 14.3: split native FreeBSD boot, runtime, and development artifacts - -Completed work: - -- wrote the Phase 14.3 report: - - `docs/reports/phase14-native-splits-freebsd.md` -- added new native packages in `modules/fruix/packages/freebsd.scm`: - - `freebsd-native-bootloader` - - `freebsd-native-headers` -- refined `freebsd-native-runtime` into a narrower runtime slice by pruning more obviously non-runtime content, including at least: - - `boot` - - `rescue` - - `usr/include` - - `usr/lib/debug` - - `usr/lib32` - - `usr/obj` - - `usr/src` - - `usr/share/doc` - - `usr/share/examples` - - `usr/share/info` - - `usr/share/man` - - `usr/share/mk` - - `usr/tests` -- extended the native world-derived build path in `modules/fruix/system/freebsd.scm` with support for: - - `keep-paths` -- native build manifests/output metadata now record both: - - `keep-paths` - - `prune-paths` -- added explicit native package-set boundaries: - - `%freebsd-native-system-packages` - - `%freebsd-native-development-profile-packages` -- the final validated Phase 14 system template now uses: - - `#:kernel freebsd-native-kernel` - - `#:bootloader freebsd-native-bootloader` - - `#:base-packages %freebsd-native-system-packages` -- this removes the need for the broad `freebsd-native-world` artifact from the final validated system closure - -New validation files: - -- `tests/system/phase14-native-split-pid1-operating-system.scm.in` -- `tests/system/run-phase14-native-split-qemu.sh` -- `tests/system/run-phase14-native-split-xcpng.sh` -- `tests/system/run-phase14-native-development-split.sh` - -Validation: - -- development/runtime split harness passes: - - `tests/system/run-phase14-native-development-split.sh` - - workdir: `/tmp/phase14-3-dev5-1775191195` - - result: `PASS phase14-native-development-split` - - confirmed: - - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` - - `headers_store=/frx/store/aab09122d37962e6d479c17172ce4b8ea85e5ff33c98aa76424ada2fa1a82617-freebsd-native-headers-15.0-STABLE` - - `native_system_packages=freebsd-native-runtime` - - `native_development_packages=freebsd-native-runtime,freebsd-native-headers,freebsd-clang-toolchain,freebsd-gmake,freebsd-autotools,freebsd-openssl,freebsd-zlib,freebsd-sh,freebsd-bash` - - `runtime_vs_development_split=ok` - - the harness also confirmed: - - bootloader slice contains the expected boot assets only - - headers slice contains headers/mk files - - headers slice does not contain `/boot` or runtime binaries -- final split-system local QEMU validation passes: - - `tests/system/run-phase14-native-split-qemu.sh` - - workdir: `/tmp/phase14-3-qemu-1775191337` - - result: `PASS phase14-native-split-qemu` - - confirmed: - - `disk_capacity=8g` - - `root_size=6g` - - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` - - `runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE` - - `native_base_store_count=3` - - `host_base_store_count=0` - - `shepherd_pid=1` - - `sshd_status=running` - - `native_split_boot=ok` -- final split-system real XCP-ng validation passes: - - `tests/system/run-phase14-native-split-xcpng.sh` - - workdir: `/tmp/phase14-3-xcpng-1775191743` - - result: `PASS phase14-native-split-xcpng` - - confirmed: - - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` - - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - - `guest_ip=192.168.213.62` - - `root_size=6g` - - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` - - `runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE` - - `native_base_store_count=3` - - `host_base_store_count=0` - - `shepherd_pid=1` - - `sshd_status=running` - - `compat_prefix_shims=absent` - - `guile_module_smoke=ok` - - `native_split_boot=ok` - -Important findings: - -- after replacing the temporary broad-world boot source with the narrower native bootloader slice and tightening the runtime slice, the validated image became much smaller again -- the real XCP-ng dynamic VHD upload for the final split path was: - - `1560725504` bytes (~1.45 GiB) -- that is far better than the temporary broad-world + runtime duplication in Phase 14.2 -- the final validated Phase 14 closure no longer needs the broad `freebsd-native-world` artifact in its native base store set - -Current assessment: - -- Phase 14 is complete -- Fruix now has a validated, host-base-free FreeBSD system path composed from native artifacts in `/frx/store`: - - `freebsd-native-kernel` - - `freebsd-native-bootloader` - - `freebsd-native-runtime` -- the runtime vs. development boundary is also clearer now through: - - `freebsd-native-headers` - - `%freebsd-native-development-profile-packages` -- this completes the Plan-3 Phase-14 goal of incrementally replacing the host-copy FreeBSD base layer for the validated boot/runtime path - -Next recommended step: - -1. begin Phase 15 by making the FreeBSD base version a declarative Fruix input -2. demonstrate side-by-side native base versions in `/frx/store` -3. validate rebuild/redeploy/rollback across those base versions - -## 2026-04-03 — Phase 15.1: made the FreeBSD base a declarative Fruix input - -Completed work: - -- wrote the Phase 15.1 report: - - `docs/reports/phase15-declarative-base-freebsd.md` -- added a new declarative base record in `modules/fruix/packages/freebsd.scm`: - - `freebsd-base` - - `freebsd-base?` - - `%default-freebsd-base` -- the declarative base now records at least: - - `name` - - `version-label` - - `release` - - `branch` - - `source-root` - - `target` - - `target-arch` - - `kernconf` - - `make-flags` -- native FreeBSD package constructors are now parameterized by a declared base: - - `freebsd-native-kernel-for` - - `freebsd-native-world-for` - - `freebsd-native-runtime-for` - - `freebsd-native-bootloader-for` - - `freebsd-native-headers-for` - - `freebsd-native-system-packages-for` - - `freebsd-native-development-profile-packages-for` -- existing exported native package variables remain available as the `%default-freebsd-base` instances: - - `freebsd-native-kernel` - - `freebsd-native-world` - - `freebsd-native-runtime` - - `freebsd-native-bootloader` - - `freebsd-native-headers` -- added a new operating-system field in `modules/fruix/system/freebsd.scm`: - - `#:freebsd-base` - - exported accessor: `operating-system-freebsd-base` -- the declared base is now recorded in system/image metadata through: - - `operating-system-closure-spec` - - `operating-system-image-spec` - - `metadata/freebsd-base.scm` - - `metadata/store-layout.scm` -- native build manifests and `.freebsd-native-build-info.scm` now record: - - `declared-base` -- `scripts/fruix.scm` now emits declared base metadata for `build` and `image`: - - `freebsd_base_name` - - `freebsd_base_version_label` - - `freebsd_base_release` - - `freebsd_base_branch` - - `freebsd_base_source_root` - - `freebsd_base_target` - - `freebsd_base_target_arch` - - `freebsd_base_kernconf` - - `freebsd_base_file` - -New validation files: - -- `tests/system/phase15-declarative-base-pid1-operating-system.scm.in` -- `tests/system/run-phase15-declarative-base-build.sh` - -Validation: - -- declarative-base build harness passes: - - `tests/system/run-phase15-declarative-base-build.sh` - - workdir: `/tmp/phase15-1-build-1775202535` - - result: `PASS phase15-declarative-base-build` - - confirmed: - - `kernel_store=/frx/store/8fcef04c7e507e86ea5e92f251fe3c6ac1aa3bcf4809fa77ddd8b92854bfcde0-freebsd-native-kernel-15.0-STABLE-declarative` - - `bootloader_store=/frx/store/7a0ba431e487dc35a8f6318108da16a37c8426c43e77e7a7f91404ba1d980eef-freebsd-native-bootloader-15.0-STABLE-declarative` - - `runtime_store=/frx/store/17c24ad20ddcb136c39352b68e758deae0b480258ba0128a5546f696a7eba0a6-freebsd-native-runtime-15.0-STABLE-declarative` - - `native_base_store_count=3` - - `host_base_store_count=0` - - `freebsd_base_name=stable-default` - - `freebsd_base_version_label=15.0-STABLE-declarative` - - `freebsd_base_release=15.0-STABLE` - - `freebsd_base_branch=stable/15` - - `freebsd_base_source_root=/usr/src` - - `freebsd_base_kernconf=GENERIC` - - `declarative_base_input=ok` - - the harness also confirmed: - - `metadata/freebsd-base.scm` exists - - `parameters.scm` records the declared base - - `metadata/store-layout.scm` records the declared base - - native build info files record the declared base version/branch - -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 - -## 2026-04-03 — Phase 15.3: decided not to pursue self-hosted base builds yet - -Completed work: - -- wrote the Phase 15.3 report: - - `docs/reports/phase15-self-hosting-decision-freebsd.md` -- updated the high-level summary: - - `docs/PROG_SUMMARY.md` -- recorded an evidence-based decision about the next architecture step after Phases 13–15 - -Decision: - -- do **not** pursue self-hosted FreeBSD base builds as the next immediate milestone -- keep the near-term path on: - 1. host-built native FreeBSD base artifacts from `/usr/src` - 2. storage in `/frx/store` - 3. stronger declarative source-tree/version selection and provenance - 4. tighter reproducibility around source inputs and build parameters -- only revisit guest self-hosting after those pieces are stronger - -Evidence used for the decision: - -- Fruix already builds native FreeBSD base artifacts from `/usr/src` into `/frx/store` -- Fruix already validates a host-base-free boot/runtime path composed from: - - `freebsd-native-kernel` - - `freebsd-native-bootloader` - - `freebsd-native-runtime` -- that path already boots on: - - local QEMU/UEFI/TCG - - the approved real XCP-ng VM/VDI path -- the FreeBSD base is now an explicit declarative input through `freebsd-base` -- Fruix now supports side-by-side declared base versions and rollback-friendly redeploy -- the most important remaining reproducibility gap is now source-tree selection/acquisition, not host-copy boot/runtime assembly -- environment constraints still argue for caution before a self-hosting pivot: - - local bhyve remains blocked under Xen due to missing nested VT-x exposure - - real validation still reuses a single approved XCP-ng VM/VDI pair - - XCP-ng storage permissions still prevent creating fresh VDIs on demand - -Current assessment: - -- Phase 15.3 is complete -- Phase 15 is fully complete -- Fruix now has: - - a host-base-free native FreeBSD boot/runtime path in `/frx/store` - - an explicit declarative FreeBSD base model - - side-by-side base-version coexistence in `/frx/store` - - rollback-friendly redeploy across declared base versions - - a documented decision to continue with host-built native base artifacts for now rather than jumping immediately to guest self-hosting - -Next recommended step: - -1. focus the next phase on making FreeBSD source-tree selection/acquisition more declarative and reproducible -2. keep improving provenance and source-input identity around the now-working native base path -3. revisit self-hosted base builds only after the source/reproducibility boundary is substantially stronger +That should build on the now-validated installer environment rather than replacing it. diff --git a/docs/reports/progress-log-through-phase18-2-freebsd.md b/docs/reports/progress-log-through-phase18-2-freebsd.md new file mode 100644 index 0000000..925c8bc --- /dev/null +++ b/docs/reports/progress-log-through-phase18-2-freebsd.md @@ -0,0 +1,4227 @@ +# Progress + +## 2026-04-04 — Phase 18.2 completed: Fruix now boots a minimal installer environment and installs a target system from inside it + +Completed work: + +- added in `modules/fruix/system/freebsd.scm`: + - `installer-operating-system` + - `operating-system-installer-image-spec` + - `materialize-installer-image` +- the installer environment is now derived from the selected target operating system, while forcing the currently most stable installer boot path: + - `freebsd-init+rc.d-shepherd` +- the installer image now carries: + - its own installer-system closure + - the selected target-system closure + - the selected target-system store closure + - a staged target rootfs under: + - `/var/lib/fruix/installer/target-rootfs` + - installer plan/state files under: + - `/var/lib/fruix/installer` + - installer helper scripts: + - `/usr/local/libexec/fruix-installer-run` + - `/usr/local/etc/rc.d/fruix-installer` +- the booted installer environment now performs the install from inside the guest by: + - partitioning the selected target disk + - creating EFI + UFS filesystems + - copying the staged target rootfs + - copying only the selected target system's required store items into the target `/frx/store` + - installing the target `loader.efi` + - writing target install metadata to: + - `/var/lib/fruix/install.scm` + - recording installer state in: + - `/var/lib/fruix/installer/state` + - logging to: + - `/var/log/fruix-installer.log` +- added user-facing CLI support in `scripts/fruix.scm`: + - `fruix system installer` + - new option: + - `--install-target-device DEVICE` +- corrected the default FreeBSD virtio install target device for QEMU validation to: + - `/dev/vtbd1` + rather than the earlier incorrect Linux-flavored guess: + - `/dev/vtblk1` +- fixed `materialize-bhyve-image` so the generated UFS filesystem label now respects: + - `root-partition-label` + rather than always hardcoding: + - `fruix-root` +- added validation artifacts: + - `tests/system/phase18-installer-target-operating-system.scm.in` + - `tests/system/run-phase18-installer-environment.sh` +- wrote: + - `docs/reports/phase18-installer-environment-freebsd.md` + +Validation: + +- `PASS phase18-installer-environment` +- regression re-checks: + - `PASS phase18-system-install` + - `PASS phase17-source-revisions-qemu` +- validated a full two-disk workflow: + - booted Fruix installer image under QEMU/UEFI/TCG + - installer environment became reachable over SSH + - installer environment completed in-guest install with: + - `installer_state=done` + - installer log recorded: + - `fruix-installer:done` + - installed target disk contained: + - GPT partition table + - ESP filesystem: + - `msdosfs` + - root filesystem: + - `ufs` + - `EFI/BOOT/BOOTX64.EFI` + - `/var/lib/fruix/install.scm` +- validated source-driven provenance through the installer environment from: + - Git ref: + - `stable/15` + - pinned commit: + - `332708a606f6bf0841c1d4a74c0d067f5640fe89` + - materialized source store: + - `/frx/store/7563df2714ae7fa9bd40b83c74512ffe2cb2ad91b297915591b55c76edbb2fcb-freebsd-source-stable15-installer-target-source` +- validated boot of the installed target after in-guest installation: + - `/run/current-system` points at the installed target closure + - `/usr/local/etc/rc.d/fruix-shepherd onestatus` reports running + - `sshd` running + - activation completed successfully + +Current assessment: + +- Phase 18.2 is complete +- Fruix now has a minimal Fruix-managed installer environment, not just a host-driven installation primitive +- the next step is Phase 18.3: + - produce a bootable installer ISO for UEFI systems + +## 2026-04-03 — Phase 18.1 completed: Fruix now has a minimal non-interactive installation flow + +Completed work: + +- added in `modules/fruix/system/freebsd.scm`: + - `operating-system-install-spec` + - `install-operating-system` +- refactored rootfs staging with: + - `populate-rootfs-from-closure` + so image generation and installation can share the same declarative rootfs assembly logic +- the new installer now supports: + - raw image-file targets + - `/dev/...` block-device targets +- for raw image targets, Fruix now performs a repeatable install flow that: + - creates/truncates the target image + - attaches it with `mdconfig` + - creates GPT partitions + - formats an EFI partition and UFS root partition + - stages the system rootfs + - copies the selected closure and referenced `/frx/store` items into the installed root + - installs `loader.efi` to `EFI/BOOT/BOOTX64.EFI` + - writes install metadata to: + - `/var/lib/fruix/install.scm` +- added user-facing CLI support in `scripts/fruix.scm`: + - `fruix system install` + - new option: + - `--target PATH` +- install metadata emitted by the CLI now includes: + - target/target-kind/device fields + - install metadata path + - disk/root sizing + - declared/materialized FreeBSD source metadata + - closure/native/runtime store metadata +- added validation artifacts: + - `tests/system/phase18-install-operating-system.scm.in` + - `tests/system/run-phase18-system-install.sh` +- wrote: + - `docs/reports/phase18-minimal-installation-flow-freebsd.md` + +Validation: + +- `PASS phase18-system-install` +- regression re-check: + - `PASS phase17-source-revisions-qemu` +- validated a full install to a raw target image: + - target kind: + - `raw-file` + - disk capacity: + - `12g` + - root size: + - `10g` +- validated target layout and boot artifacts: + - GPT image created + - ESP filesystem: + - `msdosfs` + - root filesystem: + - `ufs` + - `EFI/BOOT/BOOTX64.EFI` present +- validated installed-system boot through the already-validated mode: + - `freebsd-init+rc.d-shepherd` +- validated after boot: + - `sshd` running + - `/usr/local/etc/rc.d/fruix-shepherd onestatus` reports running + - activation completed successfully + - `/run/current-system` points at the installed closure under `/frx/store` +- validated source-driven installation provenance from: + - Git ref: + - `stable/15` + - pinned commit: + - `332708a606f6bf0841c1d4a74c0d067f5640fe89` + - installed materialized source store: + - `/frx/store/a892afb425235de71c9da38884e2ebdba5dafd3a1993f432fe7c446f5af2151f-freebsd-source-stable15-install-source` + +Operational note: + +- I tested the idea of defaulting local QEMU/TCG validation to 8 vCPUs +- result: + - under TCG, higher SMP did not help this path and regressed boot responsiveness +- current harnesses therefore keep `QEMU_SMP` configurable but retain the conservative local default of `2` + +Current assessment: + +- Phase 18.1 is complete +- Fruix can now perform a repeatable, non-interactive installation of a declarative system onto a target image or disk without relying on ad hoc manual assembly +- the next step is Phase 18.2: + - build a minimal Fruix-managed installer environment that can boot into an install context and run this workflow from within that environment + +## 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 16–17.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: + +- added boot validation harness: + - `tests/system/run-phase17-source-revisions-qemu.sh` +- the new harness renders the Phase 17 Git and `src.txz` operating-system templates and boots both systems through the validated: + - QEMU + - UEFI + - TCG + - `shepherd-pid1` + path +- validated booted source identities: + - Git source: + - ref: `stable/15` + - commit: `332708a606f6bf0841c1d4a74c0d067f5640fe89` + - `src.txz` source: + - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` + - sha256: + - `83c3e8157b6d7afcae57167fda75693bf1e5f581ca149a6ecb2d398b71bdfab0` +- confirmed image/build metadata for both boots records: + - declared source kind + - ref/commit or archive URL/sha256 + - materialized source store path + - distinct native base store sets +- wrote: + - `docs/reports/phase17-source-revision-boots-freebsd.md` + +Validation: + +- `PASS phase17-source-revisions-qemu` +- validated distinct booted closures: + - Git: + - `/frx/store/d6cbcc76f57fa9c392a80fe20e7499f7a837aab4fb96ea056e624cde95bc70c8-fruix-system-fruix-freebsd` + - `src.txz`: + - `/frx/store/02268e19930facb32e12b6ec191f2e5704d1e81033baf3637a889ad15924ff88-fruix-system-fruix-freebsd` +- validated both guests reached the validated runtime state: + - Shepherd as PID 1 + - `sshd` running +- validated distinct materialized source stores and distinct native kernel/bootloader/runtime outputs for the two boots + +Current assessment: + +- Phase 17.2 is complete +- Fruix can now both build **and boot** systems from distinct declared FreeBSD source revisions +- the next step is Phase 17.3: + - document the intended policy for source provenance, caching, invalidation, and update semantics before installation work depends on it + +## 2026-04-03 — Phase 17.1 completed: side-by-side FreeBSD source revisions now coexist in `/frx/store` + +Completed work: + +- added Phase 17 operating-system templates for distinct source identities: + - `tests/system/phase17-git-source-operating-system.scm.in` + - `tests/system/phase17-txz-source-operating-system.scm.in` +- modeled the Git side with both: + - ref: `stable/15` + - pinned commit: + - `332708a606f6bf0841c1d4a74c0d067f5640fe89` +- modeled the archive side with: + - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` + - sha256: + - `83c3e8157b6d7afcae57167fda75693bf1e5f581ca149a6ecb2d398b71bdfab0` +- added side-by-side source coexistence validation: + - `tests/system/run-phase17-source-coexistence.sh` +- the new harness builds: + - Git source build A + - `src.txz` source build + - Git source rebuild B + and verifies: + - Git rebuild stability when pinned by commit + - distinct closure paths for Git vs `src.txz` + - distinct materialized source stores + - distinct native kernel/bootloader/runtime outputs + - correct declared/materialized source metadata in closures and native build info + - continued use of the materialized source root instead of the unused declared transitional `source-root` +- wrote: + - `docs/reports/phase17-side-by-side-source-revisions-freebsd.md` + +Validation: + +- `PASS phase17-source-coexistence` +- validated side-by-side closures: + - Git closure: + - `/frx/store/d6cbcc76f57fa9c392a80fe20e7499f7a837aab4fb96ea056e624cde95bc70c8-fruix-system-fruix-freebsd` + - `src.txz` closure: + - `/frx/store/02268e19930facb32e12b6ec191f2e5704d1e81033baf3637a889ad15924ff88-fruix-system-fruix-freebsd` +- validated distinct materialized source stores: + - Git: + - `/frx/store/c9928605fa906b90a600dafeebe5005dd18ad3b8e62b7111d9d13ad60ee56490-freebsd-source-stable15-side-a` + - `src.txz`: + - `/frx/store/5eaeff5c6c55a95b6531d9cf2e1824cd4368d81c614608426bee1a5d2a664dc5-freebsd-source-release15-side-b` +- validated distinct native base outputs for the **same** version label: + - `15.0-source-side-by-side` +- validated effective source roots: + - Git: + - `.../tree` + - `src.txz`: + - `.../tree/usr/src` + +Current assessment: + +- Phase 17.1 is complete +- Fruix can now keep at least two distinct FreeBSD source revisions side by side in `/frx/store` as meaningful native base inputs/outputs +- the next step is Phase 17.2: + - boot systems built from at least two distinct declared source revisions and confirm that the booted metadata tracks those revisions + +## 2026-04-03 — Phase 16.3 completed: native FreeBSD base builds now consume materialized source inputs + +Completed work: + +- refactored native FreeBSD package materialization in `modules/fruix/system/freebsd.scm` so native packages now: + - reconstruct the declared `freebsd-source` from the package plan + - materialize that source under Fruix control + - rewrite the native build plan to use the materialized source root + - add the materialized source store path to package references +- native build manifests now include: + - `declared-source` + - `materialized-source` +- native `.freebsd-native-build-info.scm` now records: + - declared source + - materialized source store path + - materialized source root + - materialized source tree sha256 + - effective source details such as resolved Git commit / archive sha256 +- native build common manifests now reuse the materialized source tree hash when available +- package materialization caching is now keyed by manifest identity instead of only package name/version, so distinct source-driven variants do not collide in-process +- system closure materialization now keeps a dedicated source-materialization cache and records: + - `metadata/freebsd-source-materializations.scm` + - `materialized-source-store-count` + - `materialized-source-stores` +- system closure references now include the materialized source stores explicitly +- `scripts/fruix.scm` now emits for `fruix system build` and `image`: + - `freebsd_source_materializations_file` + - `materialized_source_store_count` + - `materialized_source_stores` +- added validation artifacts: + - `tests/system/phase16-git-materialized-source-operating-system.scm.in` + - `tests/system/run-phase16-source-driven-native-build.sh` +- wrote: + - `docs/reports/phase16-source-driven-native-builds-freebsd.md` + +Validation: + +- `PASS phase16-source-driven-native-build` +- `PASS phase16-source-materialization` +- `PASS phase16-declarative-source-build` +- validated a full native system build from declared Git source: + - `https://git.FreeBSD.org/src.git` + - ref: `stable/15` + - resolved commit during validation: + - `332708a606f6bf0841c1d4a74c0d067f5640fe89` +- intentionally declared an unused transitional source-root: + - `/var/empty/fruix-unused-source-root` + and confirmed native build info instead used the materialized source root under `/frx/store/*-freebsd-source-*/tree` + +Current assessment: + +- Phase 16 is now fully complete +- Fruix can: + - declare FreeBSD source inputs + - materialize them under `/frx/store` + - build native FreeBSD base artifacts from those materialized source snapshots +- the next step is Phase 17: + - build and compare side-by-side source revisions, then boot from them + +## 2026-04-03 — Phase 16.2 completed: Fruix now materializes FreeBSD source inputs under its control + +Completed work: + +- added a new exported source materializer in `modules/fruix/system/freebsd.scm`: + - `materialize-freebsd-source` +- added cache-backed materialization for source kinds: + - `local-tree` + - `git` + - `src-txz` +- added cache locations under: + - `/frx/var/cache/fruix/freebsd-source/git` + - `/frx/var/cache/fruix/freebsd-source/archives` +- materialized source outputs now live in `/frx/store` as: + - `*-freebsd-source-*` +- each materialized source now records: + - declared source + - effective/resolved source + - source store path + - effective source root + - source tree sha256 + - cache path +- added automatic effective-root detection so archive-backed sources that unpack as `usr/src/...` are still usable later: + - Git exports use `.../tree` + - `src.txz` archives use `.../tree/usr/src` +- added a new user-facing CLI path in `scripts/fruix.scm`: + - `fruix source materialize SOURCE-FILE` +- new source command options: + - `--source NAME` + - `--store DIR` + - `--cache DIR` + - `--help` +- source CLI now emits machine-readable metadata for: + - declared source fields + - materialized store path/root + - source tree hash + - cache path + - resolved Git commit + - verified archive sha256 +- tightened `src-txz` validation so materialization now requires: + - URL + - sha256 +- added validation artifacts: + - `tests/system/phase16-git-freebsd-source.scm.in` + - `tests/system/phase16-txz-freebsd-source.scm.in` + - `tests/system/run-phase16-source-materialization.sh` +- wrote: + - `docs/reports/phase16-source-materialization-freebsd.md` + +Validation: + +- `PASS phase16-source-materialization` +- `PASS phase16-declarative-source-build` +- verified Git source fetch/materialization from: + - `https://git.FreeBSD.org/src.git` + - ref: `stable/15` + - resolved commit during validation: + - `332708a606f6bf0841c1d4a74c0d067f5640fe89` +- verified canonical release archive fetch/materialization from: + - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` + - sha256: + - `83c3e8157b6d7afcae57167fda75693bf1e5f581ca149a6ecb2d398b71bdfab0` +- verified repeated materialization returns stable store paths for both the Git and `src.txz` cases + +Current assessment: + +- Phase 16.2 is complete +- Fruix can now fetch or materialize declared FreeBSD source trees into `/frx/store` with cache-backed provenance under `/frx/var/cache/fruix/freebsd-source` +- the next step is Phase 16.3: + - teach native FreeBSD kernel/world/runtime builds to consume these materialized source artifacts instead of ambient `/usr/src` + +## 2026-04-03 — Phase 16.1 completed: FreeBSD source inputs are now explicit Fruix objects + +Completed work: + +- added `docs/PLAN_4.md` to define the post-Phase-15 roadmap around: + - declarative FreeBSD source acquisition + - installation artifacts + - the controlled path toward self-hosting +- introduced a first-class `freebsd-source` record in `modules/fruix/packages/freebsd.scm` with: + - supported kinds: + - `local-tree` + - `git` + - `src-txz` + - exported accessors for: + - `name` + - `kind` + - `url` + - `path` + - `ref` + - `commit` + - `sha256` + - new `%default-freebsd-source` +- extended `freebsd-base` so it now records both: + - transitional `source-root` + - declarative `source` +- added/exported: + - `freebsd-base-source` +- threaded declared source fields into native package plans so native build outputs can record them +- in `modules/fruix/system/freebsd.scm`: + - added source validation for: + - `local-tree` + - `git` + - `src-txz` + - added `freebsd-source-spec` + - `freebsd-base-spec` now nests the declared source + - native manifests and `.freebsd-native-build-info.scm` now include: + - `declared-source` + - closures now generate: + - `metadata/freebsd-source.scm` + - `metadata/store-layout.scm` now records: + - `freebsd-source` +- in `scripts/fruix.scm`, `build` and `image` metadata now emit: + - `freebsd_source_name` + - `freebsd_source_kind` + - `freebsd_source_url` + - `freebsd_source_path` + - `freebsd_source_ref` + - `freebsd_source_commit` + - `freebsd_source_sha256` + - `freebsd_source_file` +- added validation artifacts: + - `tests/system/phase16-declarative-source-operating-system.scm.in` + - `tests/system/run-phase16-declarative-source-build.sh` + - `tests/system/validate-phase16-freebsd-source.scm` +- compared Fruix's new source model with Guix's source modeling via: + - `~/repos/guix/guix/packages.scm` + - `~/repos/guix/guix/git-download.scm` +- wrote: + - `docs/reports/phase16-declarative-source-model-freebsd.md` + +Validation: + +- `PASS phase16-declarative-source-build` +- source model probe confirmed support for: + - local-tree `/usr/src` + - Git refs such as `stable/15` at `https://git.FreeBSD.org/src.git` + - canonical `src.txz` URLs such as: + - `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz` + - `https://download.freebsd.org/snapshots/amd64/15.0-STABLE/src.txz` +- closure/native metadata now records the declared source explicitly while preserving the current validated `/usr/src` build path + +Current assessment: + +- Phase 16.1 is complete +- Fruix can now describe FreeBSD source inputs explicitly, but it does not fetch/materialize them yet +- the next step is Phase 16.2: + - fetch or materialize declared FreeBSD source inputs under Fruix control and use their stable identity as the next reproducibility boundary + +## 2026-04-01 — Phase 1.1 started: Guile verified on FreeBSD amd64 + +Completed work: + +- installed/confirmed `guile3-3.0.10` +- added a reusable verification harness: + - `tests/guile/run-phase1-verification.sh` + - `tests/guile/verify-phase1.scm` + - `tests/guile/modules/phase1/sample.scm` +- verified the following on `FreeBSD 15.0-STABLE` amd64: + - module loading + - deterministic output generation + - file I/O + - process handling with `primitive-fork`/`waitpid` + - loopback TCP sockets + - FFI calls into libc + - execution of Guix bootstrap-related code from `(guix build make-bootstrap)` +- wrote the results to `docs/reports/phase1-guile-freebsd.md` + +Notable findings: + +- `guile3` and `guile-3.0` are present, but there is no unversioned `guile` binary +- `system*` and `open-pipe*` currently segfault on this host (`exit 139`) +- despite that crash, the lower-level process primitives needed for further investigation do work + +Current assessment: + +- Phase 1.1 has a solid amd64 smoke-verification baseline +- Phase 1.1 is not fully complete yet because `i386` has not been checked and the subprocess crash needs investigation +- verification harness committed as `e380e88` (`Add FreeBSD Guile verification harness`) + +## 2026-04-01 — Phase 1.1 follow-up: subprocess crash isolated + +Completed work: + +- added a dedicated subprocess diagnostic harness: + - `tests/guile/run-subprocess-diagnostics.sh` + - `tests/guile/posix-spawn-freebsd-diagnostics.c` +- reproduced crashes for: + - `system*` + - `spawn` + - `open-pipe*` +- confirmed all three fail with `SIGSEGV` / `exit 139` +- confirmed native FreeBSD `posix_spawn` + `posix_spawn_file_actions_addclosefrom_np` works in a standalone C program +- confirmed FreeBSD behavior that triggers gnulib replacement logic: + - `posix_spawn_file_actions_adddup2` accepts an invalid fd in the gnulib probe + - `posix_spawn_file_actions_addopen` accepts an invalid fd in the gnulib probe + - `posix_spawnp` accepts a shebang-less executable script in the gnulib security probe +- wrote the analysis to `docs/reports/phase1-guile-subprocess-crash.md` + +Conclusion: + +- this is most likely an upstream Guile/gnulib ABI bug on FreeBSD, not a Guix-specific problem +- likely sequence: + 1. gnulib enables `REPLACE_POSIX_SPAWN=1` + 2. Guile still enables `HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP` + 3. Guile passes a gnulib replacement `posix_spawn_file_actions_t` object to native `posix_spawn_file_actions_addclosefrom_np` + 4. libc interprets gnulib struct fields as a native pointer and crashes +- evidence from the lldb core matches this hypothesis (`*fa = 0x0000000600000008`, consistent with gnulib `_allocated=8`, `_used=6`) + +Current assessment: + +- Phase 1.1 amd64 investigation is now much stronger and has a concrete root-cause hypothesis +- the next practical step is to validate a workaround or patch in Guile so subprocess helpers stop crashing +- after that, continue with Phase 1.2 (minimal native build environment / GNU Hello) + +## 2026-04-01 — Phase 1.1 follow-up: local Guile build validated the fix + +Completed work: + +- installed the additional build tooling needed for a local Guile checkout build: + - `autoconf` + - `automake` + - `libtool` + - `gettext-tools` + - `texinfo` + - `help2man` + - `gperf` + - `pkgconf` +- confirmed a FreeBSD-specific bootstrap quirk: + - Guile `autogen.sh` needs GNU `m4` + - FreeBSD base `/usr/bin/m4` is not sufficient + - `M4=gm4 ./autogen.sh` works +- built a disposable validation copy from `~/repos/guile` +- confirmed `~/repos/guile` already contains upstream commit: + - `eb828801f621d3e130b6fe88cfc4acaa69b98a03` + - `Don't use posix_spawn_file_actions_addclosefrom_np with glib posix_spawn` +- updated the local test harnesses so they can test non-system Guile builds: + - `tests/guile/run-phase1-verification.sh` + - `tests/guile/run-subprocess-diagnostics.sh` + - both now accept `GUILE_BIN` + - both now prepend the sibling `../lib` directory to `LD_LIBRARY_PATH` when a matching local `libguile-3.0.so.1` exists + - subprocess diagnostics now supports `EXPECT_GUILE_SUBPROCESS_CRASH=0` for fixed builds +- validated that the packaged Guile still reproduces the crash +- validated that the locally built Guile succeeds for: + - `system*` + - `spawn` + - `open-pipe*` +- re-ran the broader Phase 1.1 Scheme verification suite successfully against the local Guile build +- wrote the results to `docs/reports/phase1-guile-local-build-validation.md` + +Important findings: + +- the local Guile executable initially still crashed until it was forced to load its matching local `libguile-3.0.so.1` +- once `LD_LIBRARY_PATH` pointed at the local install lib directory, subprocess helpers worked correctly +- this strongly supports the earlier diagnosis and shows that the upstream Guile fix resolves the problem in practice +- the local `~/repos/bdwgc` checkout was not needed for this step; packaged `boehm-gc-threaded` was sufficient so far + +Current assessment: + +- Phase 1.1 now has both a root-cause analysis and a working validated fix path on amd64 +- no source changes were needed in `~/repos/guile` because the local checkout already contains the relevant upstream fix +- no source changes were needed in `~/repos/bdwgc` yet, but the earlier FreeBSD warning keeps it on the watch list +- the project can now move on to Phase 1.2 with a known-good local Guile fallback + +## 2026-04-01 — Phase 1.2 started: native GNU Hello build validated on FreeBSD + +Completed work: + +- added a reusable native build harness: + - `tests/native-build/run-gnu-hello.sh` +- used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for: + - GNU Hello version `2.12.3` + - expected Guix nix-base32 source hash `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd` +- verified the downloaded tarball against the translated SHA256: + - `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0` +- successfully executed the standard native build lifecycle on `FreeBSD 15.0-STABLE` amd64: + - fetch + - hash verification + - extract + - configure + - build + - staged install + - runtime execution +- confirmed the staged binary runs and prints: + - `Hello, world!` +- captured build metadata including: + - compiler and make versions + - host triplet + - configure command + - staged output path + - runtime shared-library dependencies +- wrote the results to `docs/reports/phase1-native-gnu-hello.md` + +Important findings: + +- GNU Hello built successfully with FreeBSD base `make`, not just `gmake` +- that contrasts with the earlier local Guile build, which did require GNU `gmake` +- even this minimal GNU package links against FreeBSD-userland-provided libraries such as `libiconv` and `libintl`, which is useful data for later Guix package modeling +- this step is still a native shell-driven build exercise, not yet a real Guix package build + +Current assessment: + +- Phase 1.2 now has a concrete native autotools success case on FreeBSD +- the host can perform the basic fetch/verify/configure/build/install/run cycle needed for later `gnu-build-system` adaptation work +- Guix-specific build orchestration is still missing, but the environmental baseline is stronger now + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` + +Next recommended step: + +1. extend Phase 1.2 with at least one additional representative GNU/autotools package build on FreeBSD, or +2. prototype a tiny Scheme-based `gnu-build-system`-like phase runner using the known-good local Guile path, starting from the GNU Hello flow +3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: Guix builder-side GNU Hello phase runner validated + +Completed work: + +- added a Scheme-driven GNU Hello build prototype: + - `tests/native-build/gnu-hello-guix-phase-runner.scm` + - `tests/native-build/run-gnu-hello-guix-phase-runner.sh` +- required the previously validated fixed local Guile build for this harness because it depends on subprocess-heavy Scheme operations +- used Guix modules directly from `~/repos/guix`, including: + - `(guix base32)` + - `(guix build gnu-build-system)` + - `(guix build utils)` +- fetched and hash-verified GNU Hello `2.12.3` again against the Guix package hash: + - nix-base32: `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd` + - SHA256: `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0` +- successfully executed a subset of Guix builder-side `%standard-phases` on FreeBSD: + - `set-SOURCE-DATE-EPOCH` + - `unpack` + - `configure` + - `build` + - `check` + - `install` +- installed GNU Hello into a store-like output path under the temporary work directory rather than using a `/usr/local` `DESTDIR` staging layout +- executed the resulting binary successfully and confirmed output: + - `Hello, world!` +- captured metadata including: + - host triplet + - selected phase list + - runtime dependencies + - test-suite summary +- wrote the results to `docs/reports/phase1-guix-gnu-hello-phase-runner.md` + +Important findings: + +- this is the first validation step in the repo that successfully exercised actual Guix builder-side GNU build logic on FreeBSD instead of only a shell approximation +- the harness works when driven by the fixed local Guile build, confirming that the earlier Guile subprocess-fix validation is directly useful for FreeBSD Guix build orchestration +- GNU Hello's `make check` test suite also passed in this mode: + - total: `7` + - pass: `7` + - fail: `0` +- the resulting binary's runtime dependencies differ from the earlier `/usr/local`-prefixed native shell harness; in this store-like output layout it only showed: + - `libc.so.7` + - `libsys.so.7` +- that difference is a useful clue that Guix-style output layout/build invocation can materially affect FreeBSD runtime linkage behavior + +Current assessment: + +- Phase 1.2 now has both: + - a shell-driven native GNU Hello build harness, and + - a Scheme-driven prototype that uses real Guix builder-side GNU phases +- this is still short of a true Guix package/derivation build, but it significantly narrows the gap between host validation and real `gnu-build-system` execution on FreeBSD +- the known-good local Guile path is now validated as part of a practical Guix-adjacent build workflow, not just standalone subprocess diagnostics + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` + +Next recommended step: + +1. run the Scheme-driven phase-runner pattern against at least one more small GNU/autotools package on FreeBSD, or +2. document the concrete gaps between this prototype and a real Guix package/derivation build, especially around store management and build isolation +3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: second Scheme-driven GNU package build validated with GNU which + +Completed work: + +- added a second Scheme-driven GNU package harness: + - `tests/native-build/gnu-which-guix-phase-runner.scm` + - `tests/native-build/run-gnu-which-guix-phase-runner.sh` +- again used the previously validated fixed local Guile build because this harness depends on subprocess-heavy Guix/Scheme builder logic +- used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for: + - GNU which version `2.21` + - expected Guix nix-base32 source hash `1bgafvy3ypbhhfznwjv1lxmd6mci3x1byilnnkc7gcr486wlb8pl` +- verified the downloaded tarball against the translated SHA256: + - `f4a245b94124b377d8b49646bf421f9155d36aa7614b6ebf83705d3ffc76eaad` +- successfully executed the same subset of Guix builder-side `%standard-phases` on FreeBSD as used for GNU Hello: + - `set-SOURCE-DATE-EPOCH` + - `unpack` + - `configure` + - `build` + - `check` + - `install` +- executed the resulting `which` binary successfully with a deterministic command: + - `PATH=/bin:/usr/bin ./which sh` +- confirmed output: + - `/bin/sh` +- captured metadata including: + - host triplet + - phase list + - runtime dependencies + - check-phase success status + - executed command output +- wrote the results to `docs/reports/phase1-guix-which-phase-runner.md` + +Important findings: + +- this confirms the Scheme-driven Guix builder-side phase-runner pattern is not limited to GNU Hello; a second small GNU/autotools package also succeeds on FreeBSD +- GNU which's `check` phase passed, but it did not leave behind an Automake-style `test-suite.log` or `testsuite.log` +- GNU which emitted a non-fatal `configure` warning about Guix's standard `--enable-fast-install` flag being unrecognized +- the source also emitted several clang warnings about deprecated non-prototype C declarations/definitions, but the build still completed successfully +- the resulting `which` binary again showed a minimal store-like runtime linkage profile: + - `libc.so.7` + - `libsys.so.7` +- unlike GNU Hello, the source tree did not present an obvious shipped `config.guess`, so the harness used `cc -dumpmachine` as a fallback for host-triplet metadata + +Current assessment: + +- Phase 1.2 now has two successful Scheme-driven Guix builder-side GNU package validations on FreeBSD: + - GNU Hello + - GNU which +- this increases confidence that a narrow but real subset of `gnu-build-system` builder-side execution already works on FreeBSD when paired with the fixed local Guile build +- the next uncertainty is now less about whether basic builder phases run at all, and more about where real Guix package/derivation/store integration and isolation will first require FreeBSD-specific adaptation + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` + +Next recommended step: + +1. document the concrete remaining gap between these Scheme-driven phase-runner prototypes and a true Guix package/derivation/store-daemon build on FreeBSD, especially around store management, implicit inputs, and build isolation +2. or choose a somewhat more demanding GNU package with non-trivial declared inputs to identify the first builder-side FreeBSD adaptation points +3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: documented the gap to a real Guix package build + +Completed work: + +- analyzed the concrete remaining gap between the current FreeBSD validation harnesses and a real Guix package/derivation/store-daemon build +- wrote the analysis to: + - `docs/reports/phase1-guix-build-gap-analysis.md` +- based the analysis on the current local Guix source tree, including the relevant host-side and daemon-side code paths in: + - `guix/packages.scm` + - `guix/build-system/gnu.scm` + - `guix/gexp.scm` + - `guix/store.scm` + - `guix/derivations.scm` + - `gnu/packages/commencement.scm` + - `doc/guix.texi` + - `nix/libstore/build.cc` +- compared those real Guix layers against the currently validated FreeBSD prototypes: + - shell-driven native GNU Hello harness + - Scheme-driven GNU Hello builder-phase runner + - Scheme-driven GNU which builder-phase runner + +Main conclusions recorded: + +- the current FreeBSD work has validated a narrow but real builder-side slice of Guix execution: + - Guile can run the needed Scheme code when using the fixed local build + - `(guix build gnu-build-system)` phases can build small GNU packages on FreeBSD +- however, the current prototypes still bypass several critical layers of a real Guix build: + - package -> bag lowering + - bag -> derivation lowering + - imported module closure/store materialization + - real daemon RPC and build submission + - canonical `/gnu/store` management and metadata + - build users, chroot/container or jail-style isolation + - substitute/graft/offload handling +- documented that the current phase runners rely on host tools already present on FreeBSD, whereas real `gnu-build-system` uses implicit inputs drawn from `%final-inputs` +- identified the most actionable next milestone as a derivation-generation investigation for a tiny package, to locate the first failure boundary among: + - host-side lowering + - store interaction + - derivation emission + - daemon availability + - daemon-side execution + +Current assessment: + +- Phase 1.2 now has both practical build validation and a clearer architectural map of what remains before a true Guix package build can work on FreeBSD +- the project has reduced uncertainty around builder-side GNU phase portability +- the next uncertainty is now specifically the host-side lowering/store/daemon boundary, not the builder-phase boundary + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` + +Next recommended step: + +1. investigate whether a tiny package can be lowered far enough on FreeBSD to produce a real derivation, and capture the exact first failure point +2. if derivation generation proves immediately blocked, document whether the blocker is generated Guix modules/configuration, store connectivity, or daemon assumptions +3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: derivation-generation investigation identified the first real checkout blockers + +Completed work: + +- added a reproducible checkout/bootstrap/configure investigation harness: + - `tests/guix/run-derivation-generation-investigation.sh` +- used the previously validated fixed local Guile build for the investigation: + - `/tmp/guile-freebsd-validate-install/bin/guile` +- followed the operator instruction for future store setup by parameterizing the checkout attempts to use: + - store directory: `/frx/store` + - local state directory: `/frx/var` + - sysconf directory: `/frx/etc` +- created a disposable shared clone of `~/repos/guix` +- successfully ran `./bootstrap` from that disposable checkout on FreeBSD +- attempted `configure` without `--with-courage` +- attempted `configure` again with `--with-courage` +- confirmed directly that the local fixed Guile build currently cannot load: + - `(gnutls)` +- wrote the results to: + - `docs/reports/phase1-guix-derivation-generation-investigation.md` + +Important findings: + +- a stock Guix checkout currently fails configuration on FreeBSD before any derivation/store/daemon work is reached, due to the explicit unsupported-platform gate: + - ``configure: error: `x86_64-freebsd15.0' is not a supported platform.`` +- re-running `configure` with `--with-courage` gets past that gate, but then stops on a second blocker: + - `configure: error: The Guile bindings of GnuTLS are missing; please install them.` +- a direct module-load test with the same local Guile confirms the problem more concretely: + - `(use-modules (gnutls))` fails with `no code for module (gnutls)` +- this means the current effort is still blocked before reaching: + - usable `pre-inst-env` generation for Guix commands + - package -> bag lowering in a live checkout + - bag -> derivation lowering + - daemon connectivity + - actual `/frx/store` population + +Current assessment: + +- the first practical boundary between the earlier FreeBSD builder-phase prototypes and a real Guix checkout has now been located more precisely +- the project is no longer blocked by vague uncertainty at this stage; it is blocked by two concrete checkout-preparation issues: + 1. unsupported-platform configure gating + 2. missing Guile `(gnutls)` bindings +- importantly, the derivation-generation investigation has not yet reached the store/daemon boundary, so the next step must first clear the `(gnutls)` dependency issue + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` + +Next recommended step: + +1. obtain working Guile `(gnutls)` bindings compatible with the fixed local Guile build and re-run the derivation-generation investigation +2. once configuration succeeds, continue until the next failure boundary is identified among: + - `pre-inst-env` usability + - derivation emission + - daemon connectivity + - daemon-side `/frx/store` assumptions +3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: local Guile-GnuTLS built on FreeBSD; next blocker is Guile-Git + +Completed work: + +- installed the host-side C GnuTLS stack needed for Guile-GnuTLS builds: + - `gnutls` + - `libtasn1` + - `nettle` + - `p11-kit` +- added a reproducible local Guile-GnuTLS build harness: + - `tests/guix/build-local-guile-gnutls.sh` +- updated the derivation-generation investigation harness so it can consume extra Guile module prefixes through: + - `GUILE_EXTRA_PREFIX` +- used the current Guix package definition in `~/repos/guix/gnu/packages/tls.scm` as the source of truth for: + - `guile-gnutls` version `5.0.1` + - expected Guix nix-base32 source hash `0kqngyx4520gjk49l6whjd2ss994kaj9rm78lli6p3q6xry0945i` +- verified the downloaded Guile-GnuTLS tarball against the translated SHA256: + - `b190047cee068f6b22a5e8d49ca49a2425ad4593901b9ac8940f8842ba7f164f` +- built and installed a local Guile-GnuTLS validation copy against the previously validated fixed local Guile build under: + - `/tmp/guile-gnutls-freebsd-validate-install` +- validated successfully that the fixed local Guile can now load: + - `(gnutls)` +- re-ran the checkout derivation-generation investigation with: + - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` + - store directory still set to `/frx/store` +- wrote the results to: + - `docs/reports/phase1-guile-gnutls-freebsd.md` + +Important findings: + +- Guile-GnuTLS does not build with FreeBSD base `make`; it requires GNU `gmake` +- a FreeBSD-specific source compatibility issue surfaced in `guile/src/core.c`: + - it includes `` unconditionally + - on this host, `alloca` is available through `` instead +- for local validation, the harness applies a small disposable-tree patch that uses `` on `__FreeBSD__` +- after that fix, the local Guile-GnuTLS build succeeded and `(use-modules (gnutls))` worked with the fixed local Guile build +- re-running the Guix checkout investigation confirms the earlier `(gnutls)` blocker is genuinely cleared +- the next configure-time blocker is now: + - `configure: error: Guile-Git is missing; please install it.` + +Current assessment: + +- the first checkout-preparation blocker after unsupported-platform gating has advanced from missing `(gnutls)` to missing `Guile-Git` +- this is meaningful progress because the project is now moving farther into the dependency chain required for a real Guix checkout on FreeBSD +- the requested experimental store path remains `/frx/store`, but the effort still has not yet reached actual store population or daemon interaction + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` + +Next recommended step: + +1. obtain `Guile-Git` compatible with the fixed local Guile build and re-run the derivation-generation investigation again +2. once checkout configuration succeeds, continue until the next failure boundary is identified among: + - `pre-inst-env` usability + - derivation emission + - daemon connectivity + - daemon-side `/frx/store` assumptions +3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: local Guile-Git stack built on FreeBSD; next blocker is Guile-JSON + +Completed work: + +- added a reproducible local Guile-Git dependency-stack build harness: + - `tests/guix/build-local-guile-git.sh` +- updated the derivation-generation investigation harness to probe and record both: + - local `(gnutls)` availability + - local `(git)` / `graph-descendant?` availability +- used the current Guix package definitions in `~/repos/guix/gnu/packages/guile.scm` as the source of truth for: + - `guile-bytestructures` version `1.0.10` + - `guile-git` version `0.10.0` +- built `guile-bytestructures` from the matching upstream tag and recorded resolved commit: + - `27cadba6b69a01b38b33bb39b9766d713eb90c1b` +- built `guile-git` from the matching upstream tag and recorded resolved commit: + - `05d4a48c811f29c8db80ee6697fe658950fb503e` +- installed both into the same local dependency prefix already used for the earlier Guile-GnuTLS validation: + - `/tmp/guile-gnutls-freebsd-validate-install` +- validated successfully that the fixed local Guile can now load: + - `(bytestructures guile)` + - `(git)` +- validated specifically that the Guile-Git export required by Guix `configure.ac` is present: + - `graph-descendant?` +- confirmed the host `libgit2` dependency used for the build is: + - `1.9.2` +- re-ran the checkout derivation-generation investigation with: + - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` + - store directory still set to `/frx/store` +- wrote the results to: + - `docs/reports/phase1-guile-git-freebsd.md` + +Important findings: + +- both `guile-bytestructures` and `guile-git` were built from Git source layouts, so autotools regeneration was required: + - `guile-bytestructures`: `autoreconf -vfi` + - `guile-git`: `autoreconf -vfi` via harness fallback +- unlike the earlier Guile-GnuTLS step, no additional FreeBSD-specific source patch was needed for either package in this validation pass +- the Guix checkout now gets past both previously cleared dependency gates: + - `(gnutls)` + - `Guile-Git` +- after clearing those, the next configure-time blocker is now: + - `configure: error: Guile-JSON is missing; please install it.` + +Current assessment: + +- the checkout-preparation path on FreeBSD has progressed one dependency layer deeper +- the local validation prefix under `/tmp/guile-gnutls-freebsd-validate-install` now contains at least: + - Guile-GnuTLS + - Guile bytestructures + - Guile-Git +- despite that progress, the work still has not yet reached derivation emission, daemon connectivity, or actual `/frx/store` population +- the next concrete blocker is now `Guile-JSON`, as reported directly by the real Guix checkout configure step + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` + +Next recommended step: + +1. obtain `Guile-JSON` compatible with the fixed local Guile build and install it into the same local dependency prefix +2. re-run the derivation-generation investigation again to identify the next configure-time or checkout-time blocker after `Guile-JSON` +3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: local Guile-JSON built on FreeBSD; next blocker is Guile-SQLite3 + +Completed work: + +- added a reproducible local Guile-JSON build harness: + - `tests/guix/build-local-guile-json.sh` +- updated the derivation-generation investigation harness to probe and record local recent-enough `(json)` availability in addition to the earlier `(gnutls)` and `(git)` checks +- used the current Guix package definition in `~/repos/guix/gnu/packages/guile.scm` as the source of truth for: + - `guile-json` version `4.7.3` + - expected Guix nix-base32 source hash `127k2xc07w1gnyqs40z4865l8p3ra5xgpcn569dz04lxsa709fiq` +- verified the downloaded Guile-JSON tarball against the translated SHA256: + - `38ba048ed29d12f05b32c5b2fb7a51795c448b41e403a2b1b72ff0035817f388` +- built and installed a local Guile-JSON validation copy into the same local dependency prefix already used for checkout prerequisites: + - `/tmp/guile-gnutls-freebsd-validate-install` +- validated successfully that the fixed local Guile now satisfies the Guix configure-time JSON requirement by: + - loading `(json)` + - using `define-json-mapping` + - decoding a small JSON object successfully +- re-ran the checkout derivation-generation investigation with: + - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` + - store directory still set to `/frx/store` +- wrote the results to: + - `docs/reports/phase1-guile-json-freebsd.md` + +Important findings: + +- unlike the earlier Guile-Git step, Guile-JSON built cleanly from the release tarball and did not require autotools regeneration in this validation pass +- unlike the earlier Guile-GnuTLS step, no FreeBSD-specific source patch was needed here +- the shared local validation prefix now contains at least: + - Guile-GnuTLS + - Guile bytestructures + - Guile-Git + - Guile-JSON +- the Guix checkout now gets past the previously cleared dependency gates for: + - `(gnutls)` + - `Guile-Git` + - `Guile-JSON` +- after clearing those, the next configure-time blocker is now: + - `configure: error: A recent Guile-SQLite3 could not be found; please install it.` + +Current assessment: + +- the checkout-preparation path on FreeBSD has progressed another dependency layer deeper +- the project still has not yet reached derivation emission, daemon connectivity, or actual `/frx/store` population +- the next concrete blocker is now recent `Guile-SQLite3`, as reported directly by the real Guix checkout configure step + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` + +Next recommended step: + +1. obtain recent `Guile-SQLite3` compatible with the fixed local Guile build and install it into the same local dependency prefix +2. re-run the derivation-generation investigation again to identify the next configure-time or checkout-time blocker after `Guile-SQLite3` +3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.2 follow-up: remaining checkout Guile prerequisites built; next blocker is `./pre-inst-env guix --version` + +Completed work: + +- installed the remaining missing host C library dependencies required for the next Guile extension stack: + - `libgcrypt` + - `libgpg-error` + - `lzlib` +- added a reproducible build harness for the remaining mandatory Guix checkout Guile modules: + - `tests/guix/build-local-guile-configure-deps.sh` +- extended the derivation-generation investigation harness to: + - probe local recent-enough availability for: + - `(sqlite3)` + - `(gcrypt hash)` + - `(zlib)` + - `(lzlib)` + - `(semver)` + - run checkout `configure` with: + - `MAKE=gmake` + - continue past successful configuration into: + - `gmake scripts/guix` + - `./pre-inst-env guix --version` +- used the current Guix package definitions as source of truth for the following additional module stack: + - `guile-sqlite3` `0.1.3` + - `guile-gcrypt` `0.5.0` + - `guile-zlib` `0.2.2` + - `guile-lzlib` `0.3.0` + - `guile-semver` `0.2.0` +- built and installed those modules into the same shared local dependency prefix already used for prior checkout prerequisites: + - `/tmp/guile-gnutls-freebsd-validate-install` +- validated successfully that the fixed local Guile can now satisfy all of the remaining configure-time Guix module checks encountered so far: + - `(sqlite3)` with `sqlite-bind-arguments` + - `(gcrypt hash)` with `hash-algorithm` lookup + - `(zlib)` with `make-zlib-input-port` + - `(lzlib)` + - `(semver)` +- re-ran the checkout derivation-generation investigation with: + - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` + - store directory still set to `/frx/store` +- wrote the results to: + - `docs/reports/phase1-guix-checkout-configure-stack-freebsd.md` + +Important findings: + +- `guile-gcrypt` required an explicit configure workaround on this host: + - `--with-libgcrypt-prefix=/usr/local` + - without it, the package's `libgcrypt-config --libs` parsing produced an unusable shared-library name on FreeBSD +- the currently served upstream `guile-lzlib` `0.3.0` tarball no longer matches the Guix-recorded hash: + - expected from Guix: `a7f99c8d2a143e05ea22db2dc8b9ce6c27cae942162b45ee3015ed9027af0ff2` + - observed from current source URL: `6a2847a303a141bb95b1b5d1a4b975b4dbff9cc590eba377cc8072682e7637ec` +- for local validation, the harness fell back to the matching upstream Git tag and recorded commit: + - `474cee42116295bc0bd2acf12d4d6a766043090e` +- once the remaining Guile modules were present, checkout `configure --with-courage` stopped failing on missing modules +- however, the checkout still needed: + - `MAKE=gmake` + to complete configuration successfully on FreeBSD +- after that, `gmake scripts/guix` succeeded as well +- the next concrete blocker has moved from configuration-time prerequisites to runtime behavior of the uninstalled Guix command path: + - `./pre-inst-env guix --version` prints the version banner, then exits with: + - `Wrong type to apply: #` + +Current assessment: + +- the checkout-preparation path on FreeBSD has now progressed beyond the missing mandatory Guile module stack that previously blocked configuration +- the current local validation prefix now contains the required configure-time modules encountered so far for a real Guix checkout +- the first blocker after successful checkout configuration and `scripts/guix` generation is now a runtime Scheme failure in the uninstalled `guix` command path itself +- the work is therefore now meaningfully past “cannot configure” and into “configures, builds `scripts/guix`, but fails at `./pre-inst-env guix --version`” + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` + +Next recommended step: + +1. investigate the `leave-on-EPIPE` runtime failure now blocking `./pre-inst-env guix --version` +2. complete the remaining Phase 1.3 FreeBSD system-call mapping/documentation deliverable so Phase 1 foundations can be closed out cleanly +3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 1.3 completed: FreeBSD syscall/interface mapping documented and exercised + +Completed work: + +- added a runnable C syscall/interface mapping harness: + - `tests/system/freebsd-syscall-mapping.c` +- added a shell runner for the mapping harness: + - `tests/system/run-freebsd-syscall-mapping.sh` +- inspected current Guix/Linux-oriented source paths relevant to daemon/build isolation and host behavior, especially: + - `~/repos/guix/nix/libstore/build.cc` + - `~/repos/guix/configure.ac` +- inspected the relevant FreeBSD interfaces/documentation available on the host, including: + - `jail(2)` + - `chroot(2)` + - `closefrom(2)` / `close_range(2)` + - `mount(2)` / `nmount(2)` + - `mount_nullfs(8)` + - `cap_enter(2)` + - `cap_rights_limit(2)` + - `lutimes(2)` + - `lchown(2)` + - `posix_fallocate(2)` + - `pdfork(2)` +- ran the new syscall mapping harness successfully and captured metadata under: + - `/tmp/freebsd-syscall-mapping-metadata.txt` +- wrote the Phase 1.3 report to: + - `docs/reports/phase1-freebsd-syscall-mapping.md` + +Important findings: + +- the current FreeBSD host provides and the harness successfully exercised: + - `fork` / `waitpid` + - `posix_spawn_file_actions_addclosefrom_np` + - `close_range` + - `lutimes` + - `statvfs` + - `chroot` (root test) + - `jail(2)` (root test) + - `lchown` (root test) +- the same harness confirmed the absence of the key Linux namespace-oriented interfaces that current Guix daemon code depends on: + - `clone` + - `unshare` + - `setns` + - `pivot_root` + - `sys/prctl.h` +- FreeBSD Capsicum headers are present, which is useful context for later security design, but Capsicum is not a direct replacement for Linux namespaces or Linux capabilities +- `posix_fallocate` is present but returned `EOPNOTSUPP` on the tested filesystems, so a successful configure/link probe does not guarantee useful runtime semantics +- the mapping strongly confirms that the correct Phase 2 direction is not syscall emulation but a jail-first redesign using: + - jails + - `chroot` + - `nullfs` + - traditional build-user privilege separation + +Current assessment: + +- the Phase 1.3 deliverable is now satisfied with both: + - a technical mapping document, and + - a runnable validation harness +- the main architectural conclusion is now concrete rather than speculative: + - Linux namespace code paths in current Guix daemon/build isolation cannot be ported directly to FreeBSD + - the FreeBSD implementation must instead be designed around jails and explicit mount/layout control + +## 2026-04-01 — Phase 1 completed on the current FreeBSD amd64 porting track + +Phase 1 is now considered complete for the active amd64 FreeBSD host path. + +Why this milestone is satisfied: + +- **Phase 1.1** success criteria were met on the current host: + - Guile executes Guix bootstrap-related code + - deterministic/module/FFI/socket/process validation succeeded + - the FreeBSD subprocess crash was root-caused and a working fixed local Guile path was validated +- **Phase 1.2** success criteria were exceeded: + - native GNU Hello build success was demonstrated + - multiple Guix builder-side GNU phase validations succeeded + - a real Guix checkout now configures on FreeBSD with local dependency supplementation, builds `scripts/guix`, and reaches a concrete runtime blocker at: + - `./pre-inst-env guix --version` +- **Phase 1.3** is now completed with the syscall/interface mapping document and runnable harness + +Important scope note: + +- the original Phase 1.1 narrative mentioned `i386` as additional target coverage, but the explicit success criteria used to gate progression have been satisfied on the active amd64 FreeBSD host +- full i386 Guile validation remains useful future coverage work, but it is no longer the blocker for moving into Phase 2 design/prototyping on this machine + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` + +Next recommended step: + +1. begin Phase 2.1 by turning the new syscall mapping into a concrete FreeBSD jail-based build-isolation design/prototype +2. carry forward the current concrete runtime blocker from Phase 1.2: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` +3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear + +## 2026-04-01 — Phase 2.1 completed: jail-first build isolation design validated on FreeBSD + +Completed work: + +- added a runnable jail-based build isolation prototype: + - `tests/daemon/run-freebsd-jail-build-prototype.sh` +- wrote the Phase 2.1 design/prototype report: + - `docs/reports/phase2-freebsd-jail-build-isolation.md` +- translated the earlier Phase 1 syscall mapping into a concrete FreeBSD Guix-daemon isolation design centered on: + - thin jails + - one jail per build + - explicit `nullfs` mount plans + - networking disabled by default + - separate build-user credentials inside the jail envelope +- ran the jail prototype successfully and captured metadata under: + - `/tmp/jail-build-metadata.txt` + +Important findings: + +- a thin-jail approach is the right match for Guix's declared-input model; thick jails would overexpose ambient host state and add unnecessary duplication +- a per-build jail root assembled from explicit read-only `nullfs` mounts is a practical replacement for the Linux bind-mount + mount-namespace model in current Guix daemon code +- a basic build operation can already be executed successfully inside a FreeBSD jail with a restricted filesystem view consisting only of: + - selected read-only host toolchain paths + - a read-only declared input directory + - a writable declared output directory + - a writable `/tmp` +- a host sentinel file left outside the jail root is not visible inside the build environment, confirming the prototype is exercising real visibility restriction rather than a mere chroot-like shell wrapper +- the prototype jail ran with: + - `ip4=disable` + - `ip6=disable` + which matches the intended default for hermetic builds + +Current assessment: + +- Phase 2.1 is now satisfied on the current FreeBSD prototype track +- the main design decision is now concrete rather than speculative: + - the Guix FreeBSD daemon path should be jail-first, not Linux-namespace emulation +- the next step is to add a build-user privilege-dropping prototype inside or alongside this jail model so the design covers both containment and user-level isolation + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` + +Next recommended step: + +1. implement the Phase 2.2 privilege-dropping/build-user prototype for FreeBSD, ideally combined with the new jail execution model +2. then establish a `/frx/store`-based store-management prototype covering permissions, package readability, and garbage-collection behavior +3. continue carrying the separate Guix checkout runtime blocker: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` + +## 2026-04-01 — Phase 2.2 completed: privilege dropping and concurrent build-user isolation validated + +Completed work: + +- added a C helper implementing the core daemon-side privilege drop mechanics: + - `tests/daemon/freebsd-build-user-helper.c` +- added a harness that combines that helper with the new jail model and runs two jobs concurrently: + - `tests/daemon/run-freebsd-privilege-drop-prototype.sh` +- wrote the Phase 2.2 report: + - `docs/reports/phase2-freebsd-privilege-drop.md` +- ran the concurrent build-user prototype successfully and captured metadata under: + - `/tmp/freebsd-privdrop-metadata.txt` + +Important findings: + +- a root-launched FreeBSD helper can successfully perform the expected daemon-side transition: + - `setgroups` + - `setgid` + - `setuid` + into a dedicated build identity +- once dropped, the helper cannot regain root with `setuid(0)`: + - `Operation not permitted` +- each build job can create files in its own writable directory and those files end up owned by the dropped build UID/GID rather than by root +- two concurrent jobs using distinct numeric build identities succeeded with: + - job 1 UID/GID `35001:35001` + - job 2 UID/GID `35002:35002` +- host-side result files were observed with the matching ownership and restrictive permissions: + - `0600` +- the two jobs were deliberately held for two seconds each and the measured wall-clock elapsed time was also about two seconds, demonstrating actual concurrent execution rather than serialized execution +- two complementary denial modes were validated at the same time: + - peer build files mounted but blocked by permissions: `Permission denied` + - host path not mounted into the jail at all: `No such file or directory` +- the dropped build user also could not: + - create files in a protected root-owned directory + - `chown` its own output back to root + +Current assessment: + +- Phase 2.2 is now satisfied on the current FreeBSD prototype track +- the combined jail + build-user model now has practical validation for the most important security properties required by a future FreeBSD Guix daemon: + - root-controlled setup + - permanent drop to build credentials + - per-build writable areas + - cross-build isolation + - concurrent execution under distinct identities +- the remaining Phase 2 work is now centered on the store itself: permissions, readability, content-addressed layout, and garbage-collection behavior under `/frx/store` + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` + +Next recommended step: + +1. complete Phase 2.3 by establishing a `/frx/store`-based store prototype with: + - correct root/daemon write restrictions + - unprivileged read access + - content-addressed path naming + - garbage-collection behavior +2. if possible, use outputs or dependency relationships realistic enough to model how a future FreeBSD Guix daemon would retain referenced store items +3. continue carrying the separate Guix checkout runtime blocker: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` + +## 2026-04-01 — Phase 2.3 completed: `/frx/store` prototype validated on FreeBSD + +Completed work: + +- added a runnable `/frx/store` prototype harness: + - `tests/store/run-freebsd-store-prototype.sh` +- wrote the Phase 2.3 report: + - `docs/reports/phase2-freebsd-store-prototype.md` +- created and exercised the operator-requested `/frx` layout on-host: + - `/frx/store` + - `/frx/var` + - `/frx/etc` + - `/frx/var/fruix/gcroots` +- created a store group for the prototype path: + - `fruixbuild` +- ran the store prototype successfully and captured metadata under: + - `/tmp/freebsd-store-prototype-metadata.txt` + +Important findings: + +- the current host now has a working `/frx/store` prototype owned as: + - `root:fruixbuild` + with mode: + - `drwxrwxr-t` +- the prototype successfully created content-addressed demo store items under `/frx/store` using hash-based names +- the demo item set included: + - rooted greeting data + - a rooted app referencing that data through an absolute store path + - an unrooted orphan item intended for collection +- an unprivileged user (`nobody`) could: + - read store data + - execute the demo app from the store +- the same unprivileged user could not: + - create files directly in `/frx/store` + and the observed failure was: + - `Permission denied` +- the prototype GC logic followed rooted references successfully: + - with a GC root present, the app and its referenced data survived while the orphan item was collected + - after removing the GC root, the remaining demo items were collected as well +- the demo store returned to an empty state after the second GC pass, so the host is left with the `/frx` skeleton but without lingering prototype payloads + +Current assessment: + +- Phase 2.3 is now satisfied on the current FreeBSD prototype track +- the core store assumptions needed for a FreeBSD Guix-daemon design have practical validation now: + - `/frx/store` path viability + - root-controlled mutation + - unprivileged read access + - immutable absolute store references + - root-managed GC roots and mark/sweep retention behavior +- remaining gaps are now above this architectural layer rather than below it: + - real derivation registration + - SQLite-backed store metadata + - daemon RPC integration + - actual package lowering/build submission using these mechanisms + +## 2026-04-01 — Phase 2 completed on the current FreeBSD prototype track + +Phase 2 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 2.1** success criteria were met: + - a detailed jail-first build-isolation design was produced + - a runnable prototype successfully executed a build command in a restricted FreeBSD jail +- **Phase 2.2** success criteria were met: + - a concrete C privilege-dropping implementation was added + - build-user credential drop, inability to regain root, and concurrent cross-build isolation were demonstrated +- **Phase 2.3** success criteria were met on the prototype track: + - a working `/frx/store` equivalent was established + - content-addressed demo store items were created and consumed + - unprivileged read vs. privileged write behavior was validated + - garbage-collection behavior over rooted references was demonstrated + +Important scope note: + +- this completes the **core daemon architecture adaptation** milestone, not a full Guix-daemon port +- the separate real-checkout blocker from Phase 1 remains relevant for later integration work: + - `./pre-inst-env guix --version` still fails with `Wrong type to apply: #` +- however, that runtime issue no longer blocks the specific Phase 2 architectural deliverables because the jail, privilege, and store assumptions have now been validated independently on FreeBSD + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` +- `d65b2af` — `Prototype FreeBSD build user isolation` + +Next recommended step: + +1. begin Phase 3.1 by adapting Guix build-system expectations to the now-validated jail/privilege/store model on FreeBSD +2. carry forward the concrete real-checkout runtime blocker for later integration work: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` +3. continue using `/frx/store` rather than `/gnu/store` for FreeBSD store experiments + +## 2026-04-01 — Phase 3.1 completed: reusable FreeBSD GNU build-system adaptation validated across five packages + +Completed work: + +- added a reusable Scheme runner for FreeBSD-adapted GNU package builds: + - `tests/build-system/gnu-package-freebsd-phase-runner.scm` +- added a shell wrapper for the generic runner: + - `tests/build-system/run-gnu-package-freebsd-phase-runner.sh` +- added a five-package validation matrix: + - `tests/build-system/run-freebsd-gnu-package-matrix.sh` +- wrote the Phase 3.1 report: + - `docs/reports/phase3-freebsd-gnu-build-system.md` +- ran the matrix successfully and captured summary metadata under: + - `/tmp/freebsd-gnu-package-matrix-summary.txt` + +Important findings: + +- the build adaptation is now centralized rather than package-specific and is applied through a dedicated pre-configure FreeBSD environment phase +- the adaptation consistently uses: + - GNU `gmake` via a `make` path shim + - FreeBSD Clang via `cc`/`gcc` and `c++`/`g++` tool shims + - `CONFIG_SHELL=/bin/sh` + - `/usr/local` include/library/pkg-config search paths +- five representative GNU packages from current Guix package definitions now build successfully through the adapted runner on the current FreeBSD amd64 host: + - `hello` `2.12.3` + - `which` `2.21` + - `time` `1.9` + - `patch` `2.8` + - `nano` `8.7.1` +- the resulting binaries executed correctly with deterministic checks appropriate to each package: + - `hello` -> `Hello, world!` + - `which` -> `/bin/sh` + - `time` -> `time (GNU Time) 1.9` + - `patch` -> `GNU patch 2.8` + - `nano` -> `GNU nano, version 8.7.1` +- the matrix also validated a package with meaningful runtime dependencies: + - `nano` linked against FreeBSD/base and `/usr/local` libraries including `libintl`, `libmagic`, `libncursesw`, `libtinfow`, and `libz` +- one package-specific FreeBSD test boundary was recorded explicitly instead of being hidden: + - `time` required `RUN_TESTS=0` because the upstream `time-max-rss` test was not reliable on this host + +Current assessment: + +- Phase 3.1 is now satisfied on the current prototype track +- the main question has shifted from “can adapted GNU builder phases run on FreeBSD?” to “how should FreeBSD system components themselves be described and installed as profile-usable packages?” +- the next step is therefore Phase 3.2: define a minimal FreeBSD package set with explicit dependencies and validate profile-style installation/usability + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` +- `d65b2af` — `Prototype FreeBSD build user isolation` +- `e404e2e` — `Prototype FreeBSD store management` + +Next recommended step: + +1. complete Phase 3.2 by defining a minimal FreeBSD system package set with explicit dependency relationships and profile-style installation validation +2. carry forward the concrete real-checkout runtime blocker for later integration work: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` +3. continue using `/frx/store` rather than `/gnu/store` for future FreeBSD store experiments when the prototype work needs a persistent store root + +## 2026-04-01 — Phase 3.2 completed: FreeBSD system package-definition prototype and profile validation added + +Completed work: + +- added a Guix-style FreeBSD system package-definition prototype module: + - `modules/fruix/packages/freebsd.scm` +- added a Scheme harness to materialize those package definitions into store-like outputs and a merged profile: + - `tests/packages/freebsd-package-profile-prototype.scm` +- added a shell wrapper for that harness: + - `tests/packages/run-freebsd-package-profile-prototype.sh` +- installed the missing host shell dependency needed to satisfy the requested package set: + - `bash` +- wrote the Phase 3.2 report: + - `docs/reports/phase3-freebsd-package-definitions.md` +- ran the profile prototype successfully and captured metadata under: + - `/tmp/freebsd-package-profile-prototype-metadata.txt` + +Important findings: + +- the prototype now defines a minimal FreeBSD core package set covering the categories requested by Phase 3.2: + - kernel + - kernel headers + - libc + - userland utilities + - development tools (`clang`, `make`, autotools) + - minimum system libraries (`openssl`, `zlib`) + - shells (`sh`, `bash`) +- the current package-definition layer uses an explicit Guix-like record shape with fields for: + - name + - version + - build system + - inputs + - synopsis/description/home-page/license + - install plan +- explicit dependency relationships are now encoded and resolved recursively during materialization, including examples such as: + - `freebsd-libc` -> `freebsd-kernel-headers` + - `freebsd-userland` -> `freebsd-libc`, `freebsd-sh` + - `freebsd-clang-toolchain` -> `freebsd-libc`, `freebsd-kernel-headers`, `freebsd-sh` + - `freebsd-autotools` -> `freebsd-gmake`, `freebsd-bash`, `freebsd-libc` +- the harness successfully materialized: + - `11` core package outputs + into a store-like directory tree under the work directory +- it then merged those outputs into a development profile and validated that the profile contains working: + - `bash` + - `make` + - `autoconf` + - `cc` + - kernel image path + - kernel-header path + - core shared-library paths +- the generated profile compiled and ran a C test program successfully, with observed output: + - `hello-from-freebsd-profile` +- for executables installed under `bin/`, the prototype uses wrappers that `exec` the host tool by absolute path; this preserved correct behavior for prefix-sensitive tools such as `autoconf` + +Current assessment: + +- Phase 3.2 is now satisfied on the current prototype track +- Phase 3 as a whole is now completed on the current FreeBSD amd64 path because both: + - adapted GNU build-system execution, and + - minimal FreeBSD system package-definition/profile validation + have been demonstrated successfully +- the next remaining project milestone is now Phase 4, centered on Shepherd rather than package-building foundations + +## 2026-04-01 — Phase 3 completed on the current FreeBSD prototype track + +Phase 3 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 3.1** success criteria were met on the prototype track: + - a reusable FreeBSD adaptation layer for GNU builder phases was added + - five representative GNU packages built successfully through that adapted runner + - the resulting binaries executed correctly on the host +- **Phase 3.2** success criteria were met on the prototype track: + - a minimal FreeBSD system package-definition layer was added + - explicit dependency relationships were modeled and resolved + - the package outputs installed into a merged profile successfully + - the generated profile was validated by compiling and running a test program with the staged toolchain + +Important scope note: + +- this completes the **build-system adaptation milestone** in prototype form, not the full Guix package-lowering/daemon integration path +- the earlier concrete upstream/runtime blocker still exists for later integration work: + - `./pre-inst-env guix --version` fails with `Wrong type to apply: #` +- however, that blocker no longer prevents Phase 4 work because the core build-system and package-definition assumptions have now been validated independently + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` +- `d65b2af` — `Prototype FreeBSD build user isolation` +- `e404e2e` — `Prototype FreeBSD store management` +- `eb0d77c` — `Adapt GNU build phases for FreeBSD` + +Next recommended step: + +1. begin Phase 4.1 by validating whether Shepherd itself now builds and runs as a regular service on FreeBSD with the fixed local Guile path +2. carry forward the separate real-checkout runtime blocker for later integration work: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` +3. continue using `/frx/store` rather than `/gnu/store` for future FreeBSD integration experiments when a persistent store root is required + +## 2026-04-01 — Phase 4.1 completed: Shepherd built and validated as a regular FreeBSD service manager + +Completed work: + +- added a reproducible local Guile Fibers build harness: + - `tests/shepherd/build-local-guile-fibers.sh` +- added a reproducible local Shepherd build harness: + - `tests/shepherd/build-local-shepherd.sh` +- added a runnable multi-service Shepherd validation harness for FreeBSD: + - `tests/shepherd/run-freebsd-shepherd-service-prototype.sh` +- wrote the Phase 4.1 report: + - `docs/reports/phase4-freebsd-shepherd-service.md` +- ran the service-management prototype successfully and captured metadata under: + - `/tmp/freebsd-shepherd-service-metadata.txt` + +Important findings: + +- the current FreeBSD path now has a working local Shepherd build based on: + - local fixed Guile + - locally installed Guile Fibers `1.4.2` + - Shepherd `1.0.9` +- Shepherd build/install required one concrete FreeBSD-specific toolchain adaptation: + - `SED=/usr/local/bin/gsed` + because the install phase edits wrapper scripts using GNU `sed -i` syntax that base FreeBSD `sed` does not accept +- at runtime, Shepherd reports: + - `System lacks support for 'signalfd'; using fallback mechanism.` + but the fallback path works correctly for supervision on this host +- the prototype successfully validated all requested regular-service capabilities: + - start/stop via `herd` + - dependency handling + - status monitoring + - crash/respawn behavior + - privilege-aware execution +- the concrete service set used for validation included: + - an unprivileged heartbeat logger + - a loopback HTTP service + - a dependent file-monitor service + - a crash-once respawn test service +- observed metadata confirmed: + - `logger_running=yes` + - `web_running=yes` + - `monitor_running=yes` + - `crashy_running=yes` + - `logger_uid=65534` (`nobody`) + - `http_response=shepherd-freebsd-ok` + - `monitor_detected=detected` + - `crashy_counter=2` + +Current assessment: + +- Phase 4.1 is now satisfied on the current FreeBSD prototype track +- Shepherd is no longer just a theoretical later step; it now builds and supervises multiple services correctly on the host when paired with the fixed local Guile stack +- the next question is no longer “can Shepherd run on FreeBSD at all?” but “what is the best FreeBSD init-integration strategy for it on this prototype path?” + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` +- `d65b2af` — `Prototype FreeBSD build user isolation` +- `e404e2e` — `Prototype FreeBSD store management` +- `eb0d77c` — `Adapt GNU build phases for FreeBSD` +- `d47dc9b` — `Prototype FreeBSD package definitions` + +Next recommended step: + +1. complete Phase 4.2 by prototyping how Shepherd should be launched and stopped through FreeBSD init conventions while validating boot/shutdown dependency ordering for essential services +2. after that, bridge Shepherd to key FreeBSD service concepts such as rc.d management, loopback/network configuration, filesystem setup, and temporary user/group administration +3. continue carrying the separate real-checkout runtime blocker for later integration work: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` + +## 2026-04-01 — Phase 4.2 completed: FreeBSD rc.d init-integration prototype validated for Shepherd + +Completed work: + +- added a runnable FreeBSD init-integration prototype harness: + - `tests/shepherd/run-freebsd-shepherd-init-prototype.sh` +- wrote the Phase 4.2 report: + - `docs/reports/phase4-freebsd-shepherd-init-integration.md` +- ran the init-integration prototype successfully and captured metadata under: + - `/tmp/freebsd-shepherd-init-metadata.txt` + +Important findings: + +- a real temporary FreeBSD `rc.d` script can successfully launch the locally built Shepherd daemon through the standard: + - `service onestart` + path +- the same wrapper can stop it cleanly through: + - `service onestop` + using `herd ... stop root` under the hood +- the prototype automatically started a minimal essential-service graph at daemon launch consisting of: + - `filesystems` + - `system-log` + - `networking` + - `login` +- observed startup order matched the declared dependency chain exactly: + - `start:filesystems` + - `start:system-log` + - `start:networking` + - `start:login` +- observed shutdown order matched the expected reverse dependency order exactly: + - `stop:login` + - `stop:networking` + - `stop:system-log` + - `stop:filesystems` +- the rc.d wrapper reported the Shepherd instance as running while active: + - `rc_status=running` +- the prototype again observed the expected FreeBSD runtime note: + - `System lacks support for 'signalfd'; using fallback mechanism.` + and confirmed that it does not prevent correct boot/shutdown ordering behavior + +Current assessment: + +- Phase 4.2 is now satisfied on the current prototype track as an init-integration prototype +- the key result is that Shepherd can already be launched and stopped through native FreeBSD service-management conventions while preserving dependency-based startup and shutdown semantics +- the remaining Phase 4 work is now specifically about bridging Shepherd services to concrete FreeBSD host-management concepts rather than basic daemon launch or service ordering + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` +- `d65b2af` — `Prototype FreeBSD build user isolation` +- `e404e2e` — `Prototype FreeBSD store management` +- `eb0d77c` — `Adapt GNU build phases for FreeBSD` +- `d47dc9b` — `Prototype FreeBSD package definitions` +- `b36746f` — `Validate Shepherd services on FreeBSD` + +Next recommended step: + +1. complete Phase 4.3 by adding a small FreeBSD Shepherd bridge layer for rc.d-style services, loopback/network configuration, filesystem setup, and temporary user/group administration +2. use that bridge layer in a runnable integration harness that validates both activation and cleanup of those FreeBSD concepts +3. continue carrying the separate real-checkout runtime blocker for later integration work: + - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` + +## 2026-04-01 — Phase 4.3 completed: FreeBSD Shepherd bridge layer validated across rc.d, network, filesystem, and account management + +Completed work: + +- added a reusable FreeBSD Shepherd bridge module: + - `modules/fruix/shepherd/freebsd.scm` +- added a runnable integration harness exercising that bridge layer: + - `tests/shepherd/run-freebsd-shepherd-bridge-prototype.sh` +- wrote the Phase 4.3 report: + - `docs/reports/phase4-freebsd-shepherd-bridge.md` +- ran the bridge prototype successfully and captured metadata under: + - `/tmp/freebsd-shepherd-bridge-metadata.txt` + +Important findings: + +- the new module now exports concrete helper constructors for four FreeBSD integration categories: + - `freebsd-rc-service` + - `freebsd-loopback-alias-service` + - `freebsd-tmpfs-service` + - `freebsd-user-group-service` +- the integration harness used those helpers to manage a real chained host-side service graph under Shepherd covering: + - a temporary rc.d script in `/usr/local/etc/rc.d/` + - loopback alias configuration on `lo0` + - tmpfs mount/unmount with mode validation + - temporary user/group creation and removal via `pw` +- observed activation metadata confirmed all of those operations succeeded under Shepherd control: + - `target_running=yes` + - `rc_started=yes` + - `alias_present=yes` + - `tmpfs_mounted=yes` + - `tmpfs_mode=drwxr-x---` + - `user_present=yes` + - `group_present=yes` +- observed cleanup metadata confirmed that `stop root` also reversed all of those host-side effects successfully: + - `rc_stopped=yes` + - `alias_removed=yes` + - `tmpfs_unmounted=yes` + - `user_removed=yes` + - `group_removed=yes` +- the same expected FreeBSD runtime note remained true here as well: + - `System lacks support for 'signalfd'; using fallback mechanism.` + and again it did not prevent the prototype from working correctly + +Current assessment: + +- Phase 4.3 is now satisfied on the current prototype track +- Shepherd now has a concrete FreeBSD bridge layer in-repo rather than only ad hoc validation scripts +- with service supervision, rc.d integration, and FreeBSD host-concept bridging now all validated, Phase 4 is complete on the current FreeBSD amd64 prototype path + +## 2026-04-01 — Phase 4 completed on the current FreeBSD prototype track + +Phase 4 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 4.1** success criteria were met on the prototype track: + - Shepherd built successfully on FreeBSD with the fixed local Guile stack + - regular multi-service supervision worked + - dependency handling, status monitoring, privilege-aware execution, and respawn behavior were all validated +- **Phase 4.2** success criteria were met in init-integration prototype form: + - a real FreeBSD `rc.d` wrapper launched Shepherd successfully + - a minimal essential-service graph started automatically in correct dependency order + - orderly reverse shutdown through native FreeBSD service entry points was validated +- **Phase 4.3** success criteria were met on the prototype track: + - a reusable FreeBSD Shepherd bridge layer was added + - Shepherd services successfully bridged to rc.d service control, loopback/network configuration, filesystem mounting/permissions, and temporary user/group administration + - both activation and cleanup were validated + +Important scope note: + +- this completes the **Shepherd porting milestone** on the current prototype track, not a literal replacement of `/sbin/init` on the live host +- however, the core Shepherd questions have now been answered positively on FreeBSD: + - it builds + - it runs + - it supervises services + - it integrates with FreeBSD service-management conventions + - it can express concrete FreeBSD host-management tasks through Shepherd services +- the separate real-Guix-checkout runtime blocker still exists for later integration work: + - `./pre-inst-env guix --version` fails with `Wrong type to apply: #` + but that is now clearly outside the scope of the completed Phase 4 Shepherd milestone + +Recent commits: + +- `e380e88` — `Add FreeBSD Guile verification harness` +- `cd721b1` — `Update progress after Guile verification` +- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` +- `02f7a7f` — `Validate local Guile fix on FreeBSD` +- `4aebea4` — `Add native GNU Hello FreeBSD build harness` +- `c944cdb` — `Validate Guix builder phases on FreeBSD` +- `0a2e48e` — `Validate GNU which builder phases on FreeBSD` +- `245a47d` — `Document gaps to real Guix FreeBSD builds` +- `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` +- `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` +- `15b9037` — `Build local Guile-Git on FreeBSD` +- `47d31e8` — `Build local Guile-JSON on FreeBSD` +- `d82195b` — `Advance Guix checkout on FreeBSD` +- `9bf3d30` — `Document FreeBSD syscall mapping` +- `7621798` — `Prototype FreeBSD jail build isolation` +- `d65b2af` — `Prototype FreeBSD build user isolation` +- `e404e2e` — `Prototype FreeBSD store management` +- `eb0d77c` — `Adapt GNU build phases for FreeBSD` +- `d47dc9b` — `Prototype FreeBSD package definitions` +- `b36746f` — `Validate Shepherd services on FreeBSD` +- `83715f0` — `Prototype Shepherd rc.d integration` + +Next recommended step: + +1. return to the remaining real Guix checkout/runtime blocker and investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` +2. begin the next post-Phase-4 integration milestone by connecting the now-validated daemon/build/store/Shepherd prototypes more directly to real Guix checkout behavior on FreeBSD +3. continue using `/frx/store` rather than `/gnu/store` whenever future integration experiments need a persistent store root + +## 2026-04-01 — Planning update: Fruix naming policy clarified for post-Phase-4 work + +Completed work: + +- added a new post-Phase-4 planning document: + - `docs/PLAN_2.md` +- updated that plan to clarify the naming policy for the fork going forward + +Key planning decision: + +- **Fruix** is now the intended user-facing product identity +- the user-facing CLI should become: + - `fruix` +- `/frx` remains the canonical store/state/config root on the FreeBSD path +- however, the plan explicitly avoids a blanket rename of all upstream-derived internal identifiers +- in particular: + - internal `guix` namespaces may remain temporarily where needed for compatibility and maintenance + - `gnu` names are preserved where they refer to real GNU concepts or components such as GNU packages, GNU Shepherd, or `gnu-build-system` + - new fork-specific modules and user-facing surfaces should prefer `fruix` naming + +Current assessment: + +- the naming direction is now clearer for the next integration batch +- Phase 5 and beyond should aim to: + - first make the upstream-derived checkout runnable on FreeBSD, + - then introduce a deliberate `fruix` command boundary, + - rather than destabilizing the codebase with a whole-tree `guix`/`gnu` rename too early + +## 2026-04-01 — Phase 5.1 completed: checkout runtime unblocked and first `fruix` frontend boundary established + +Completed work: + +- added a reusable phase-5 checkout setup helper: + - `tests/guix/setup-phase5-checkout.sh` +- added a checkout runtime patch queue for the upstream-derived source tree: + - `tests/guix/patches/phase5-checkout-runtime.patch` +- added a FreeBSD daemon/build patch queue needed for later phase-5 work: + - `tests/guix/patches/phase5-guix-daemon-freebsd.patch` +- added a runtime validation harness: + - `tests/guix/run-phase5-checkout-runtime.sh` +- wrote the Phase 5.1 report: + - `docs/reports/phase5-checkout-runtime-freebsd.md` +- ran the runtime harness successfully and captured metadata under: + - `/tmp/phase5-runtime-metadata.txt` + +Important findings: + +- the earlier checkout blocker + - `./pre-inst-env guix --version` + - `Wrong type to apply: #` + is now explained by top-level definition ordering in `guix/ui.scm`: + - `show-version-and-exit` called `leave-on-EPIPE` before the syntax transformer was defined later in the file + - on this FreeBSD path, that became a runtime application of a syntax-transformer object instead of a macro expansion site +- the phase-5 runtime patch fixes this by: + - making `(guix ui)` explicitly non-declarative + - rewriting `show-version-and-exit` to use direct `catch 'system-error` handling + - parameterizing `program-name` in `guix-main` + - deriving the top-level version banner name from `program-name` + - making `(guix scripts repl)` explicitly non-declarative as well +- the checkout now successfully runs the following commands on FreeBSD: + - `./pre-inst-env guix --version` + - `./pre-inst-env guix repl --help` + - `./pre-inst-env guix build --help` +- the first user-facing Fruix command boundary is now implemented in the checkout setup via: + - `scripts/fruix` + as a front-end alias next to `scripts/guix` +- observed runtime metadata confirmed: + - `first_guix_version_line=guix (GNU Guix) ...` + - `first_fruix_version_line=fruix (GNU Guix) ...` +- this matches the agreed naming policy: + - Fruix at the user-facing boundary + - stable upstream-derived internal `guix`/`gnu` names unless there is a concrete reason to rename them + +Current assessment: + +- Phase 5.1 is now satisfied on the current FreeBSD prototype track +- the key boundary has shifted from “the checkout still crashes immediately” to “the checkout runs, and can now be used as the basis for real derivation/store experiments” +- the next step is to prove that a real derivation can be emitted against `/frx/store` from the now-runnable checkout + +## 2026-04-01 — Phase 5.2 completed: real derivation generation validated against `/frx/store` + +Completed work: + +- added a runnable derivation-generation harness: + - `tests/guix/run-phase5-derivation-generation.sh` +- wrote the Phase 5.2 report: + - `docs/reports/phase5-derivation-generation-freebsd.md` +- ran the derivation-generation harness successfully and captured metadata under: + - `/tmp/phase5-derivation-metadata.txt` + +Important findings: + +- the now-runnable checkout can successfully use a real daemon/store connection on FreeBSD to lower a package through: + - `package->bag` + - `bag->derivation` +- the emitted derivation is a real `/frx/store` derivation path rather than an ad hoc placeholder or shell metadata artifact +- the validation used a deliberately minimal custom package with a custom low-level build system so that this subphase isolates the real lowering/store boundary without being dominated by still-unresolved upstream bootstrap assumptions for full native FreeBSD package graphs +- observed metadata confirmed: + - `bag_name=phase5-freebsd-lowering-0` + - `bag_host_inputs=("source")` + - `drv_path=/frx/store/...-phase5-freebsd-lowering-0.drv` + - `out_path=/frx/store/...-phase5-freebsd-lowering-0` +- this means the key architectural step is now real and no longer hypothetical: + - a package object in the checkout can be lowered to a real derivation targeting `/frx/store` on FreeBSD + +Current assessment: + +- Phase 5.2 is now satisfied on the current FreeBSD prototype track +- the next step is no longer “can we emit a derivation at all?” but “can the same daemon/store path accept and execute a derivation-backed build request successfully?” + +## 2026-04-01 — Phase 5.3 completed: minimal daemon/store RPC integration validated on FreeBSD + +Completed work: + +- added a runnable daemon/store RPC validation harness: + - `tests/guix/run-phase5-daemon-rpc.sh` +- wrote the Phase 5.3 report: + - `docs/reports/phase5-daemon-rpc-freebsd.md` +- ran the daemon/store RPC harness successfully and captured metadata under: + - `/tmp/phase5-daemon-rpc-metadata.txt` + +Important findings: + +- the patched checkout can now contact a real FreeBSD-aware daemon over a Unix socket and submit a derivation-backed build request successfully +- the resulting build path is a real `/frx/store` output rather than a simulated prototype artifact +- the successful metadata path now includes the full minimal chain needed for later system work: + - checkout command path + - daemon RPC + - derivation submission + - build execution + - store output materialization +- observed metadata confirmed: + - `drv_path=/frx/store/...-phase5-freebsd-daemon-build-0.drv` + - `out_path=/frx/store/...-phase5-freebsd-daemon-build-0` + - `payload=phase5-daemon-build-source` + - `source_path=/frx/store/...-phase5-source.txt` +- this step was exercised through the Fruix-facing checkout boundary: + - `./pre-inst-env fruix repl -- ...` + which means the user-facing transition is now connected to actual daemon/store activity, not just to help text or version banners + +Current assessment: + +- Phase 5.3 is now satisfied on the current FreeBSD prototype track +- the project now has a real but narrow end-to-end host-side execution path on FreeBSD: + - runnable checkout + - Fruix front-end boundary + - real derivation emission + - daemon/store RPC + - successful derivation-backed build into `/frx/store` + +## 2026-04-01 — Phase 5 completed on the current FreeBSD prototype track + +Phase 5 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 5.1** success criteria were met on the prototype track: + - the checkout runtime blocker around `leave-on-EPIPE` was root-caused and fixed in the patch queue + - the uninstalled checkout command path now runs on FreeBSD + - a first user-facing `fruix` command boundary was established +- **Phase 5.2** success criteria were met on the prototype track: + - a real package object was lowered through `package->bag` and `bag->derivation` + - a real derivation was emitted targeting `/frx/store` +- **Phase 5.3** success criteria were met on the prototype track: + - a real checkout command path contacted a FreeBSD-aware daemon/store path + - that path accepted and executed a derivation-backed build request + - the resulting output was materialized successfully in `/frx/store` + +Important scope note: + +- this completes the **real checkout and host runtime unblocking milestone** on the current prototype track, not full upstream-package-graph support for arbitrary native FreeBSD package builds yet +- the successful derivation/build path currently uses a deliberately minimal custom package/build-system path to isolate real daemon/store viability from still-unresolved upstream bootstrap and package-graph assumptions for native FreeBSD +- nevertheless, the core Phase 5 question has now been answered positively: + - the checkout runs + - real derivations can be emitted + - the daemon can be built far enough to serve store RPC + - and derivation-backed builds can succeed into `/frx/store` + +Next recommended step: + +1. begin Phase 6.1 by moving from the minimal custom derivation-backed package path to at least one real FreeBSD store-backed package build driven by Fruix/Guix mechanisms +2. then integrate the already validated jail/build-user model more directly into the live daemon build path +3. continue preserving the selective Fruix naming policy: + - Fruix at the product boundary + - `/frx` as the canonical store root + - stable upstream-derived internal names unless there is strong architectural value in renaming them + +## 2026-04-01 — Phase 6.1 completed: real package build validated into `/frx/store` + +Completed work: + +- added a runnable real-package harness: + - `tests/guix/run-phase6-real-package-build.sh` +- wrote the Phase 6.1 report: + - `docs/reports/phase6-real-package-build-freebsd.md` +- ran the real-package harness successfully and captured metadata under: + - `/tmp/phase6-real-package-metadata.txt` + +Important findings: + +- the checkout can now build a real package definition derived from Guix's `hello` package through: + - `./pre-inst-env fruix build -f ...` + - the FreeBSD-aware daemon + - `/frx/store` +- this moves the project beyond the deliberately minimal Phase 5 custom derivation path and into a real package-definition flow +- the current successful path still uses a prefetched local GNU Hello tarball as the package source because the built-in downloader path remains a separate unresolved FreeBSD/root-daemon issue +- observed metadata confirmed: + - `drv_path=/frx/store/...-hello-2.12.3.drv` + - `out_path=/frx/store/...-hello-2.12.3` + - `source_store_path=/frx/store/...-hello-2.12.3.tar.gz` + - `runtime_output=Hello, world!` +- a daemon-side references query confirmed that the built output preserved the declared source store item as a direct reference + +Current assessment: + +- Phase 6.1 is now satisfied on the current FreeBSD prototype track +- the next step is to move the already validated jail/build-user model into this live package-build path rather than keeping it prototype-only + +## 2026-04-01 — Phase 6.2 completed: jail/build-user isolation integrated into the real package path + +Completed work: + +- added a reusable UID/GID drop helper source: + - `tests/daemon/freebsd-drop-exec.c` +- added a runnable jail-integrated package harness: + - `tests/guix/run-phase6-jail-package-build.sh` +- wrote the Phase 6.2 report: + - `docs/reports/phase6-jail-build-integration-freebsd.md` +- ran the jail-integrated harness successfully and captured metadata under: + - `/tmp/phase6-jail-package-metadata.txt` + +Important findings: + +- a real package build derived from Guix's `hello` definition now runs through the live daemon path inside a FreeBSD jail rather than only through the earlier prototype scripts +- the actual build work inside the jail runs as dropped credentials: + - UID `35001` + - GID `35001` +- the integrated build path required one additional FreeBSD-specific adjustment beyond the earlier prototype: + - the daemon-side host `TMPDIR` path was not automatically valid inside the jail, so the jailed build environment must reset `TMPDIR=/tmp` +- observed metadata confirmed: + - `drv_path=/frx/store/...-hello-2.12.3.drv` + - `out_path=/frx/store/...-hello-2.12.3` + - `runtime_output=Hello, world!` + - `build_uid=35001` + - `build_gid=35001` + - `jail_hostname=fruix-phase6-hello-...` + - `build_mode=freebsd-jail` + - `source_store_path=/frx/store/...-hello-2.12.3.tar.gz` +- the GNU Hello test suite also passed inside the jail-integrated build path + +Current assessment: + +- Phase 6.2 is now satisfied on the current FreeBSD prototype track +- the next step is to validate a minimal user-facing profile installation flow on top of these real store outputs + +## 2026-04-01 — Phase 6.3 completed: minimal profile installation validated on real store outputs + +Completed work: + +- added a runnable real-store profile harness: + - `tests/packages/run-phase6-real-store-profile-prototype.sh` +- wrote the Phase 6.3 report: + - `docs/reports/phase6-real-store-profile-freebsd.md` +- updated the Phase 6 package-build harnesses so they can recover derivation paths even when the requested outputs are already present in `/frx/store` +- ran the real-store profile harness successfully and captured metadata under: + - `/tmp/phase6-real-store-profile-metadata.txt` + +Important findings: + +- the current FreeBSD track now has a minimal user-facing profile installation flow built on top of real Phase 6 store outputs rather than the earlier Phase 3 package/profile prototype inputs +- the validated transaction semantics are intentionally small but real: + - generation 1 is created from the Phase 6.1 host-built store item + - generation 2 is created from the Phase 6.2 jail-built store item + - the `profile` symlink switches to generation 2 + - both generations remain addressable +- observed metadata confirmed: + - `profile_target=profile-2-link` + - `generation1_store_path=/frx/store/...-hello-2.12.3` + - `generation2_store_path=/frx/store/...-hello-2.12.3` + - `current_store_path=/frx/store/...-hello-2.12.3` + - `profile_hello_output=Hello, world!` + - `clean_env_hello_output=Hello, world!` +- the upstream-derived profile layer is still not fully usable on this FreeBSD track because the current `guix profiles` / `fruix package` path still reaches the unresolved bootstrap-platform blocker: + - `dynamic linker name not known for this system "x86_64-freebsd15.0"` +- despite that blocker, the minimal Fruix-owned profile path is now validated on top of real daemon-built store items + +Current assessment: + +- Phase 6.3 is now satisfied on the current FreeBSD prototype track +- Phase 6 as a whole is now complete on the active FreeBSD amd64 prototype path + +## 2026-04-01 — Phase 6 completed on the current FreeBSD prototype track + +Phase 6 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 6.1** success criteria were met on the prototype track: + - a real package definition derived from Guix's `hello` package now builds through `fruix build` + - the output lands in `/frx/store` + - the package runs from the store and preserves a declared source reference +- **Phase 6.2** success criteria were met on the prototype track: + - a real package build now executes inside a FreeBSD jail + - the build work runs under dropped numeric build credentials + - the jailed build succeeds into `/frx/store` +- **Phase 6.3** success criteria were met on the prototype track: + - real Phase 6 store outputs can be installed into a minimal profile environment + - generation switching works in a concrete form + - package execution through the profile succeeds for the current user + +Important scope note: + +- this completes the **real FreeBSD-backed store-build milestone** on the current prototype track, not full upstream-package-graph support or full upstream profile-layer parity yet +- the current package path still relies on a prefetched local source tarball for GNU Hello because the built-in downloader/root-daemon path remains a separate FreeBSD issue +- the current profile-installation path is a Fruix-owned minimal layer over real store outputs because the upstream-derived profile code still hits the unresolved FreeBSD bootstrap-platform mapping blocker +- nevertheless, the core Phase 6 question has now been answered positively: + - real package definitions can be built into `/frx/store` + - those builds can run under integrated jail/build-user isolation + - and the resulting store items can be exposed through a minimal user-facing profile flow + +Next recommended step: + +1. begin Phase 7.1 by defining a minimal Fruix operating-system model for FreeBSD +2. carry forward the selective Fruix naming policy: + - Fruix at the product boundary + - `/frx` as the canonical store root + - stable upstream-derived internal names unless there is strong architectural value in renaming them +3. keep the two remaining Phase 6 follow-up blockers visible but scoped: + - built-in downloader/root-daemon integration for real package origins + - upstream-derived profile/bootstrap-platform support for `x86_64-freebsd15.0` + +## 2026-04-01 — Phase 7.1 completed: minimal Fruix operating-system model defined for FreeBSD + +Completed work: + +- added the first Fruix-owned FreeBSD system module: + - `modules/fruix/system/freebsd.scm` +- added the Phase 7.1 operating-system example and validation harnesses: + - `tests/system/phase7-minimal-operating-system.scm` + - `tests/system/validate-phase7-operating-system.scm` + - `tests/system/run-phase7-operating-system-model.sh` +- extended the FreeBSD package model with additional system-oriented prototype packages: + - `freebsd-bootloader` + - `freebsd-rc-scripts` + - `freebsd-runtime` + - `%freebsd-system-packages` +- wrote the Phase 7.1 report: + - `docs/reports/phase7-operating-system-model-freebsd.md` +- ran the operating-system model harness successfully and captured metadata under: + - `/tmp/phase7-os-model-metadata.txt` + +Important findings: + +- the FreeBSD track now has a concrete declarative operating-system object rather than only package/profile and service prototypes +- the model currently covers: + - host identity + - kernel and bootloader assets + - essential base packages + - users/groups + - file systems + - generated `/etc` payloads + - activation payload generation + - generated Shepherd configuration +- the selected first init strategy is now explicit in the model: + - `freebsd-init+rc.d-shepherd` +- observed metadata confirmed: + - `host_name=fruix-freebsd` + - `kernel_package=freebsd-kernel` + - `bootloader_package=freebsd-bootloader` + - `base_packages=freebsd-runtime,freebsd-userland,freebsd-libc,freebsd-rc-scripts,freebsd-sh,freebsd-bash` + - `users=root,operator` + - `groups=wheel,operator` + - `generated_files=boot/loader.conf,etc/rc.conf,etc/fstab,etc/hosts,etc/passwd,etc/group,etc/shells,etc/motd,activate,shepherd/init.scm` + - `init_mode=freebsd-init+rc.d-shepherd` + +Current assessment: + +- Phase 7.1 is now satisfied on the current FreeBSD prototype track +- the next step is to materialize this operating-system description into a reproducible system closure under `/frx/store` + +## 2026-04-01 — Phase 7.2 completed: minimal system closure generated under `/frx/store` + +Completed work: + +- added the Phase 7.2 closure materialization harnesses: + - `tests/system/materialize-phase7-system-closure.scm` + - `tests/system/run-phase7-system-closure.sh` +- refined the minimal operating-system example so the generated system profile also contains `/bin/sh` +- wrote the Phase 7.2 report: + - `docs/reports/phase7-system-closure-freebsd.md` +- ran the system-closure harness successfully and captured metadata under: + - `/tmp/phase7-system-closure-metadata.txt` + +Important findings: + +- the declarative FreeBSD Fruix operating-system object now materializes into a real system closure under `/frx/store` +- that closure contains: + - boot assets + - a merged system profile + - generated `/etc` files + - a generated activation script + - a generated Shepherd configuration + - a generated `rc.d` launcher for Shepherd +- the closure now embeds the concrete first init integration choice for the FreeBSD track: + - `freebsd-init+rc.d-shepherd` +- rerunning the same materialization produced the same closure path, which is the current prototype proof of reproducible closure generation for this phase +- observed metadata confirmed: + - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` + - `closure_rebuild_path=/frx/store/...-fruix-system-fruix-freebsd` + - `kernel_store=/frx/store/...-freebsd-kernel-15.0-STABLE` + - `bootloader_store=/frx/store/...-freebsd-bootloader-15.0-STABLE` + - `guile_store=/frx/store/...-fruix-guile-runtime-3.0` + - `guile_extra_store=/frx/store/...-fruix-guile-extra-3.0` + - `shepherd_store=/frx/store/...-fruix-shepherd-runtime-1.0.9` + - `profile_bin_sh=/frx/store/...-fruix-system-fruix-freebsd/profile/bin/sh` + - `profile_sbin_init=/frx/store/...-fruix-system-fruix-freebsd/profile/sbin/init` + - `profile_rc=/frx/store/...-fruix-system-fruix-freebsd/profile/etc/rc` + +Current assessment: + +- Phase 7.2 is now satisfied on the current FreeBSD prototype track +- the next step is to materialize and statically validate an installable root filesystem tree from this system closure + +## 2026-04-01 — Phase 7.3 completed: installable rootfs tree validated from the system closure + +Completed work: + +- added the Phase 7.3 rootfs materialization harnesses: + - `tests/system/materialize-phase7-rootfs.scm` + - `tests/system/run-phase7-rootfs.sh` +- wrote the Phase 7.3 report: + - `docs/reports/phase7-rootfs-freebsd.md` +- ran the rootfs harness successfully and captured metadata under: + - `/tmp/phase7-rootfs-metadata.txt` + +Important findings: + +- the declarative Fruix FreeBSD system can now be materialized as a root filesystem tree rather than only as a store closure directory +- the rootfs uses a Guix-like anchor: + - `/run/current-system` + so that boot assets, generated configuration, and system-profile content remain tied to the declarative system closure +- static validation confirmed: + - boot asset linkage + - generated `/etc` linkage + - activation payload presence + - Shepherd `rc.d` launch integration + - declared filesystem entries + - declared user/group provisioning in the activation path + - deterministic ready-state wiring through `/var/lib/fruix/ready` +- observed metadata confirmed: + - `rootfs=/tmp/.../rootfs` + - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` + - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` + - `activate_target=/run/current-system/activate` + - `bin_target=/run/current-system/profile/bin` + - `sbin_target=/run/current-system/profile/sbin` + - `boot_kernel_target=/run/current-system/boot/kernel` + - `boot_loader_target=/run/current-system/boot/loader` + - `boot_loader_efi_target=/run/current-system/boot/loader.efi` + - `rc_conf_target=/run/current-system/etc/rc.conf` + - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` + - `ready_marker=/var/lib/fruix/ready` + - `validation_mode=static-rootfs-check` + +Current assessment: + +- Phase 7.3 is now satisfied on the current FreeBSD prototype track +- Phase 7 as a whole is now complete on the active FreeBSD amd64 prototype path + +## 2026-04-01 — Phase 7 completed on the current FreeBSD prototype track + +Phase 7 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 7.1** success criteria were met on the prototype track: + - a minimal Fruix operating-system object now exists for FreeBSD + - it evaluates into a coherent system-closure specification +- **Phase 7.2** success criteria were met on the prototype track: + - that system model now materializes into a reproducible closure under `/frx/store` + - the closure contains boot assets, generated `/etc` files, activation payloads, and Shepherd launch integration +- **Phase 7.3** success criteria were met on the prototype track: + - the closure now materializes into a concrete rootfs tree + - the resulting rootfs passes static validation for later image-construction work + +Important scope note: + +- this completes the **declarative system-composition milestone** for the current prototype track, not a fully booted Fruix guest yet +- the current output is a validated closure plus rootfs tree; Phase 8 still needs to turn that into a reproducible bhyve-friendly disk image +- the chosen first system-init strategy remains: + - FreeBSD init + `rc.d` launching Shepherd + rather than Shepherd-as-PID-1 +- the current system model remains Fruix-owned and FreeBSD-oriented rather than attempting full upstream Guix System integration prematurely + +Next recommended step: + +1. begin Phase 8.1 by creating a reproducible disk-image build path from the generated Fruix rootfs tree +2. keep the current init decision explicit for the first boot target: + - FreeBSD init + `rc.d` + Shepherd +3. continue preserving the selective Fruix naming policy: + - Fruix at the product boundary + - `/frx` as the canonical store root + - stable upstream-derived internal names unless there is strong architectural value in renaming them + +## 2026-04-01 — Phase 8.1 completed: reproducible bhyve-compatible raw disk image generated + +Completed work: + +- added the first Phase 8 image-generation harness: + - `tests/system/run-phase8-bhyve-image.sh` +- wrote the Phase 8.1 report: + - `docs/reports/phase8-bhyve-image-freebsd.md` +- ran the image-generation harness successfully and captured metadata under: + - `/tmp/phase8-bhyve-image-metadata.txt` + +Important findings: + +- the current Fruix FreeBSD track now has a reproducible raw disk-image build path using: + - GPT + - UEFI boot + - a FAT EFI system partition + - a UFS root partition + - serial-console-friendly loader settings +- the earlier Phase 7 rootfs tree was not sufficient by itself for an installable image because it still referenced `/frx/store` content that only existed on the host; the image builder therefore had to stage the system closure and its recursively declared store references inside the image rootfs under `/frx/store` +- rebuilding the same image a second time with fixed timestamps and explicit filesystem parameters produced the same SHA256, which is the current prototype proof of reproducible image generation on this host +- observed metadata confirmed: + - `raw_sha256=08605d738021cb6fb5b87c270e1eafde57e1acb5159d3a2257aad4c560e2efc5` + - `image_size_bytes=335578624` + - `esp_fstype=msdosfs` + - `root_fstype=ufs` + - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` + - `boot_loader_target=/run/current-system/boot/loader` + - `boot_loader_conf_target=/run/current-system/boot/loader.conf` + - `rc_conf_target=/run/current-system/etc/rc.conf` + - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` + - `store_item_count=13` + - `boot_mode=uefi` + - `image_format=raw` + - `partition_scheme=gpt` + - `serial_console=comconsole` + +Current assessment: + +- Phase 8.1 is now satisfied on the current FreeBSD prototype track +- the next step is to integrate this image generation path into the declarative Fruix system-composition layer so that a single operating-system description can drive image generation end-to-end + +## 2026-04-01 — Phase 8.2 completed: image generation integrated into the declarative system layer + +Completed work: + +- extended the FreeBSD system module with integrated image-generation operations: + - `operating-system-image-spec` + - `materialize-bhyve-image` +- added the Phase 8.2 integration harnesses: + - `tests/system/materialize-phase8-system-image.scm` + - `tests/system/run-phase8-system-image.sh` +- wrote the Phase 8.2 report: + - `docs/reports/phase8-system-image-freebsd.md` +- ran the integrated system-image harness successfully and captured metadata under: + - `/tmp/phase8-system-image-metadata.txt` + +Important findings: + +- image generation is now a direct output of the Fruix FreeBSD system-definition layer rather than an external shell-only follow-up to Phase 7 +- the integrated path now stores the resulting image artifact itself under `/frx/store`, preserving the store-centered Fruix composition story even at the VM-image layer +- rerunning `materialize-bhyve-image` for the same operating-system description produced the same image store path, which is the current prototype proof that one declarative system object can drive image generation end-to-end +- observed metadata confirmed: + - `image_store_path=/frx/store/...-fruix-bhyve-image-fruix-freebsd` + - `disk_image=/frx/store/...-fruix-bhyve-image-fruix-freebsd/disk.img` + - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` + - `raw_sha256=ac57d4c694ea3cf6b1bd24be48982090a6cfcfa301d052c1f903636a46f2d56e` + - `image_size_bytes=335578624` + - `store_item_count=13` + - `esp_fstype=msdosfs` + - `root_fstype=ufs` + - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` + - `boot_loader_target=/run/current-system/boot/loader` + - `rc_conf_target=/run/current-system/etc/rc.conf` + - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` + - `image_generation_mode=declarative-system-layer` + +Current assessment: + +- Phase 8.2 is now satisfied on the current FreeBSD prototype track +- Phase 8 as a whole is now complete on the active FreeBSD amd64 prototype path + +## 2026-04-01 — Phase 8 completed on the current FreeBSD prototype track + +Phase 8 is now considered complete for the active FreeBSD amd64 prototype path. + +Why this milestone is satisfied: + +- **Phase 8.1** success criteria were met on the prototype track: + - a reproducible raw GPT+UEFI+UFS image can now be generated from the Fruix system outputs + - that image passes static boot-structure sanity checks +- **Phase 8.2** success criteria were met on the prototype track: + - the image builder is now integrated with the declarative Fruix system-definition layer + - a single operating-system description now drives image generation end-to-end + - the integrated output is itself a store-backed Fruix image artifact under `/frx/store` + +Important scope note: + +- this completes the **image-construction milestone** for the current prototype track, not the first successful bhyve boot yet +- the generated image is now ready for the next phase’s VM-launch and serial-console validation work +- the current first-boot strategy remains explicit and unchanged: + - FreeBSD init + `rc.d` + Shepherd +- the image path still reflects the current prototype system/runtime limitations, including the fact that deeper runtime closure completeness for locally copied Guile/Shepherd dependencies will be exercised more fully in Phase 9 boot validation + +Next recommended step: + +1. begin Phase 9.1 by creating a bhyve launcher and serial-console validation harness for the generated image +2. keep the current deterministic ready-state target visible: + - Shepherd startup leading to the generated `/var/lib/fruix/ready` marker path +3. continue preserving the selective Fruix naming policy: + - Fruix at the product boundary + - `/frx` as the canonical store root + - stable upstream-derived internal names unless there is strong architectural value in renaming them + +## 2026-04-02 — Phase 9 checkpoint: XCP-ng guest reached DHCP and SSH + +Completed work: + +- added a dedicated Phase 9 XCP-ng operating-system template: + - `tests/system/phase9-minimal-operating-system.scm.in` +- added an XCP-ng boot/import/validation harness: + - `tests/system/run-phase9-xcpng-boot.sh` +- extended the staged FreeBSD runtime and system-generation layers so the guest can complete enough of real boot for network access: + - `modules/fruix/packages/freebsd.scm` + - `modules/fruix/system/freebsd.scm` +- updated the integrated image-generation path for Phase 9 use cases: + - `tests/system/materialize-phase8-system-image.scm` + - `tests/system/run-phase8-system-image.sh` +- wrote the checkpoint report: + - `docs/reports/phase9-xcpng-ssh-boot-freebsd.md` + +Important findings: + +- a decisive local QEMU/TCG serial-boot pass exposed the first real early-boot blocker: + - the generated `fstab` was wrong for pseudo-filesystems, so `rc` tried to fsck `devfs` and aborted boot +- after fixing `fstab`, later serial logs exposed additional FreeBSD base runtime gaps that only appear during real boot, including missing commands, runtime directories, and base config files used by `rc`, DHCP, logging, and service startup +- the staged image now includes the minimum currently known set of FreeBSD runtime pieces needed to: + - run `rc` + - obtain DHCP + - generate SSH host keys + - start `sshd` +- public-key SSH login initially still failed because the minimal guest did not stage a complete PAM runtime/config path; for the current Phase 9 prototype track, the generated `sshd_config` now uses: + - `UsePAM no` +- the current XCP-ng validation path succeeded against the operator-approved VM and existing VDI only: + - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` + - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` +- the successful XCP-ng boot obtained: + - guest IP `192.168.213.62` +- successful SSH validation on the real guest confirmed: + - `hostname=fruix-freebsd` + - `sshd` is reachable with the injected root key + - networking is configured on the Xen NIC + +Current assessment: + +- this checkpoint establishes the first real network-reachable Fruix boot on the active FreeBSD/XCP-ng track +- the generated image now boots far enough for DHCP and SSH, which closes the earlier uncertainty about whether the Phase 8 image could become a remotely usable guest at all +- Phase 9 is still not complete because the Fruix-specific readiness path remains blocked: + - `fruix-shepherd` does not start + - `/var/lib/fruix/ready` is still missing + - Guile still crashes in the guest with `signal 11` +- therefore the current state is: + - kernel boot: yes + - root mount: yes + - DHCP: yes + - SSH: yes + - Shepherd/ready marker: not yet + +Next recommended step: + +1. continue the in-guest Guile crash investigation so `fruix-shepherd` can start on the booted guest +2. once Shepherd is stable, rerun `tests/system/run-phase9-xcpng-boot.sh` to validate the full ready-marker path end-to-end +3. then close Phase 9 with updated report/progress entries for: + - deterministic boot readiness + - in-guest Shepherd validation + - minimal operator usability + +## 2026-04-02 — Phase 9 completed on the active XCP-ng FreeBSD track + +Completed work: + +- resolved the in-guest Guile/Shepherd blocker that remained after the earlier DHCP+SSH checkpoint +- wrote the completion report: + - `docs/reports/phase9-xcpng-ready-boot-freebsd.md` +- extended the staged runtime again in: + - `modules/fruix/packages/freebsd.scm` + - added `/usr/sbin/daemon` + - added `/usr/share/locale/C.UTF-8/LC_CTYPE` +- completed the guest runtime integration in: + - `modules/fruix/system/freebsd.scm` + - activation now recreates compatibility symlinks for the currently locally built Guile / guile-extra / Shepherd prefixes, but points them at the real `/frx/store` items in the guest + - the rootfs now exposes `/usr/share/locale` + - the generated Shepherd config no longer relies on missing `mkdir-p` or unsupported `call-with-output-file #:append` behavior + - the Shepherd rc script now exports `LANG=C.UTF-8` / `LC_ALL=C.UTF-8` + - the Shepherd rc script now exports explicit Guile system/site path variables + - Shepherd is now started through FreeBSD `daemon(8)` so it remains alive after rc/session teardown +- corrected the XCP-ng harness in: + - `tests/system/run-phase9-xcpng-boot.sh` + - it now uses a distinct SSH private key file for login instead of incorrectly trying to authenticate with the public key file + +Important findings: + +- the original guest Guile failure had multiple layers: + - missing UTF-8 locale data in the image + - baked-in temporary install-prefix references inside the copied Guile / guile-extra / Shepherd artifacts + - and Shepherd process lifetime issues caused by a fragile shell-background startup path +- reproducing the problem in a host-side chroot into the generated image root partition made the final debugging loop much tighter than repeated full VM imports alone +- after locale staging and compatibility-prefix recreation, Guile and Shepherd became runnable in the guest, but Shepherd still exited too early on the real boot path until it was launched via `daemon(8)` +- after those fixes, the full ready-marker path became reliable enough for end-to-end XCP-ng validation + +Final validation: + +- `tests/system/run-phase9-xcpng-boot.sh` now passes end-to-end against: + - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` + - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` +- passing run workdir: + - `/tmp/phase9-xcpng-pass-1775113189` +- passing real-guest metadata confirmed: + - `ready_marker=ready` + - `shepherd_status=running` + - `sshd_status=running` + - `run_current_system_target=/frx/store/0fe459ea22156510e64cea794b7a001151b59625bd5f12a488d6851e1c6d2198-fruix-system-fruix-freebsd` + - `operator_home_listing=/home/operator` + - `logger_log=fruix-shepherd-started` + +Current assessment: + +- Phase 9 is now complete for the active FreeBSD prototype track, using the XCP-ng replacement path adopted for this environment +- the generated Fruix image now reaches all currently required first-boot milestones on the real VM: + - kernel boot: yes + - root mount: yes + - DHCP: yes + - SSH: yes + - Shepherd: yes + - ready marker: yes + - minimal operator usability: yes +- this establishes the first real Fruix-on-FreeBSD VM that: + - boots from the declaratively generated image, + - reaches the generated ready state, + - keeps Shepherd running, + - and remains inspectable over SSH as a minimally usable system + +Next recommended step: + +1. begin the next post-Phase-9 cleanup/native-integration pass from `docs/PLAN_2.md` Optional Phase 10 +2. prioritize replacing the current compatibility shims for locally built Guile / Shepherd prefixes with a more native store-path-aware Fruix runtime arrangement +3. clean up remaining non-fatal boot noise observed during Phase 9, such as: + - login-class warnings around `daemon` + - the `gpart: Unknown command: show` rc noise + - residual syslog/cron/runtime polish issues where they still matter + +## 2026-04-02 — Phase 10.1: added a real `fruix system` command + +Completed work: + +- started Optional Phase 10 with the first user-facing Fruix system-management command surface +- wrote the subphase report: + - `docs/reports/phase10-fruix-system-command-freebsd.md` +- added a real CLI wrapper: + - `bin/fruix` +- added the corresponding Guile entry point: + - `scripts/fruix.scm` +- added a dedicated validation harness: + - `tests/system/run-phase10-fruix-system-command.sh` + +What the new command does: + +- exposes declarative FreeBSD system artifact generation through a Fruix CLI instead of only phase-specific harness scripts +- currently supports: + - `fruix system build OS-FILE` + - `fruix system image OS-FILE` + - `fruix system rootfs OS-FILE ROOTFS-DIR` +- currently supports options: + - `--system NAME` + - `--store DIR` + - `--disk-capacity SIZE` + - `--rootfs DIR` + - `--help` +- loads an operating-system object from a Scheme file, validates it, and dispatches to: + - `materialize-operating-system` + - `materialize-rootfs` + - `materialize-bhyve-image` +- emits machine-readable `key=value` metadata for the produced artifacts + +Important findings: + +- the project already had the core declarative system machinery by the end of Phase 9; the missing piece here was a direct Fruix operator interface to that machinery +- a small dedicated wrapper in this repo is currently the most practical way to expose that functionality without waiting for deeper upstream command-framework integration +- keeping the command aligned with the already validated local FreeBSD Guile / Fibers / Shepherd toolchain avoids introducing a second, divergent runtime path + +Validation: + +- `tests/system/run-phase10-fruix-system-command.sh` passes +- passing run workdir: + - `/tmp/phase10-fruix-cmd-1775117490` +- the test validated that: + - `fruix system build` materializes a closure under `/frx/store/*-fruix-system-fruix-freebsd` + - the produced closure contains the activation path + - `fruix system image` materializes a disk image under `/frx/store/*-fruix-bhyve-image-fruix-freebsd/disk.img` + - the command returns expected metadata fields for both actions + +Current assessment: + +- Fruix now has a real user-facing system command in this repo, which is a concrete step from “prototype scripts” toward “OS tooling” +- this does not replace all earlier harnesses yet, but it establishes `fruix system` as the new canonical interface for system closure/rootfs/image materialization work +- system/image creation still typically requires `sudo` because the command writes into `/frx/store` and uses privileged image-building operations + +Next recommended step: + +1. continue Phase 10 by making more of the existing system workflows call `bin/fruix` directly instead of bespoke phase scripts +2. reduce the current runtime compatibility shims for locally built Guile / Shepherd prefixes and move toward a more native store-path-aware Fruix runtime arrangement +3. consider adding the next operator-facing subcommand on top of the now-working image path, such as a `vm`/deploy-oriented flow for the active XCP-ng workflow + +## 2026-04-02 — Phase 10 completed: canonical system workflows now use `fruix system` + +Completed work: + +- completed the current Optional Phase 10 track by making the existing FreeBSD system workflows use the real Fruix CLI as their canonical frontend +- wrote the completion report: + - `docs/reports/phase10-canonical-system-workflows-freebsd.md` +- extended the `fruix system build` metadata in: + - `scripts/fruix.scm` + - added: + - `ready_marker` + - `base_package_store_count` + - `base_package_stores` +- refactored the main static system harnesses to call `bin/fruix` instead of invoking internal Scheme materializer runners directly: + - `tests/system/run-phase7-system-closure.sh` + - `tests/system/run-phase7-rootfs.sh` + - `tests/system/run-phase8-system-image.sh` + +What changed in practice: + +- the closure path is now validated through: + - `fruix system build` +- the rootfs path is now validated through: + - `fruix system rootfs` +- the image path is now validated through: + - `fruix system image` +- the real XCP-ng boot path now benefits from this automatically because: + - `tests/system/run-phase9-xcpng-boot.sh` + still calls the Phase 8 harness, and that harness now builds its image through `bin/fruix` + +Validation: + +- `tests/system/run-phase7-system-closure.sh` passes + - workdir: `/tmp/phase10-canon-closure2-1775119728` +- `tests/system/run-phase7-rootfs.sh` passes + - workdir: `/tmp/phase10-canon-rootfs3-1775120391` +- `tests/system/run-phase8-system-image.sh` passes + - workdir: `/tmp/phase10-canon-image-1775120548` +- full real XCP-ng regression still passes after the frontend refactor: + - `tests/system/run-phase9-xcpng-boot.sh` + - workdir: `/tmp/phase10-canon-xcpng-1775120869` + +Important findings: + +- the Phase 9 booted system path was already real, but the remaining transitional layer was the tooling/frontend boundary rather than the system internals +- adding `bin/fruix` in Phase 10.1 was necessary but not sufficient on its own; the existing validation and deployment workflows also had to adopt it, or the project would still effectively be driven by bespoke phase scripts +- after this refactor, the command path is now exercised by: + - static closure validation + - static rootfs validation + - static image validation + - and the real XCP-ng boot/import/SSH/ready-marker path + +Current assessment: + +- Optional Phase 10 is now complete for the current FreeBSD prototype track +- Fruix now has: + - a user-facing command surface in `bin/fruix` + - real `system build`, `system rootfs`, and `system image` actions + - canonical validation/deployment workflows that use that command instead of directly entering the materializers + - and a command-driven image path that remains validated on the real XCP-ng VM +- this means the project now has not just declarative OS internals, but also a real Fruix operator/tooling layer around those internals + +Next recommended step: + +1. begin the next post-Phase-10 cleanup/polish pass outside the plan milestones +2. prioritize replacing the current Guile / Shepherd compatibility-prefix shims with a more native store-path-aware runtime arrangement +3. consider adding richer deploy/vm-oriented `fruix` commands beyond the now-canonical `system build/rootfs/image` path + +## 2026-04-02 — Post-Phase-10: local Shepherd-as-PID-1 prototype booted on FreeBSD + +Completed work: + +- began the next post-Phase-10 runtime-integration pass by exploring a Shepherd-as-PID-1 boot mode for Fruix on FreeBSD +- compared the approach with Guix's root Shepherd design in: + - `~/repos/guix/gnu/services/shepherd.scm` +- wrote the subphase report: + - `docs/reports/postphase10-shepherd-pid1-qemu-freebsd.md` +- extended the declarative FreeBSD operating-system model in: + - `modules/fruix/system/freebsd.scm` + - added an `init-mode` field with: + - `freebsd-init+rc.d-shepherd` + - `shepherd-pid1` + - generated loader configuration now sets: + - `init_exec="/run/current-system/boot/fruix-pid1"` + when `init-mode` is `shepherd-pid1` + - generated systems in PID 1 mode now include: + - `boot/fruix-pid1` + - the generated activation script now treats `cap_mkdb` / `pwd_mkdb` as best-effort so immutable store-backed config files do not abort this early boot path +- added a dedicated Shepherd-PID-1 operating-system template: + - `tests/system/phase11-shepherd-pid1-operating-system.scm.in` +- added a dedicated local QEMU/UEFI validation harness: + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` + +Important findings: + +- FreeBSD's `init(8)` already has a suitable handoff mechanism for this experiment via: + - `init_exec` +- compared with Guix, the current Fruix implementation is still much more imperative, but it now follows the same broad direction: + - boot into Shepherd directly as PID 1 rather than merely starting Shepherd late from rc.d +- the first PID 1 attempt failed because the generated Shepherd config imported a repo-side module: + - `(fruix shepherd freebsd)` + that was not present inside the guest runtime; the fix was to inline the small helper procedures needed by the generated config itself +- the early PID 1 path also exposed that store-backed `/etc/login.conf` and `/etc/master.passwd` updates must be best-effort rather than fatal on this bootstrap path +- for the current locally built runtime artifacts, the compatibility-prefix shims are still needed; this subphase did not eliminate them yet, but it did remove the larger `rc.d` boot-manager dependency from the local prototype path + +Validation: + +- `tests/system/run-phase11-shepherd-pid1-qemu.sh` now passes +- passing run workdir: + - `/tmp/pid1-qemu6-1775128407` +- validated local guest state included: + - `ready_marker=ready` + - `shepherd_pid=1` + - `shepherd_socket=present` + - `shepherd_status=running` + - `sshd_status=running` + - `boot_backend=qemu-uefi-tcg` + - `init_mode=shepherd-pid1` + +Current assessment: + +- Fruix now has a working local FreeBSD prototype where Shepherd itself is PID 1 +- this is not yet the new mainline boot path, but it proves that the project can move beyond the earlier `freebsd-init+rc.d-shepherd` bridge architecture +- the PID 1 process image appears as Guile because Shepherd is launched as a Guile script, but the decisive validation point is that: + - `/var/run/shepherd.pid` contains `1` +- this subphase was validated locally under QEMU/TCG + UEFI; the next meaningful test is the real XCP-ng VM + +Next recommended step: + +1. try the `shepherd-pid1` image on the real XCP-ng VM +2. if it boots there too, decide whether to keep `shepherd-pid1` as an experimental selectable boot mode or advance it further toward the main Fruix boot path +3. continue reducing the remaining Guile / Shepherd compatibility-prefix shims now that the broader `rc.d` boot-manager dependency has been locally bypassed + +## 2026-04-02 — Post-Phase-10: Shepherd-as-PID-1 boot also passed on the real XCP-ng VM + +Completed work: + +- took the locally validated `shepherd-pid1` boot mode and tested it on the real XCP-ng deployment path +- wrote the follow-up report: + - `docs/reports/postphase10-shepherd-pid1-xcpng-freebsd.md` +- expanded the Shepherd-PID-1 operating-system template so the generated guest remains compatible with both local virtio and the real Xen NIC path: + - `tests/system/phase11-shepherd-pid1-operating-system.scm.in` + - now includes: + - `ifconfig_xn0=SYNCDHCP` + - `ifconfig_em0=SYNCDHCP` + - `ifconfig_vtnet0=SYNCDHCP` +- added a dedicated real-VM Shepherd-PID-1 deployment/validation harness: + - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` + +Validation: + +- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` now passes on the operator-approved VM and existing VDI: + - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` + - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` +- passing run workdir: + - `/tmp/pid1-xcpng-1775129768` +- passing real-guest metadata confirmed: + - `ready_marker=ready` + - `run_current_system_target=/frx/store/2940c952e9d35e47f98fe62f296be2b6ab4fceb3eee8248d6a7823decd42a305-fruix-system-fruix-freebsd` + - `pid1_command=[guile]` + - `shepherd_pid=1` + - `shepherd_socket=present` + - `shepherd_status=running` + - `sshd_status=running` + - `init_mode=shepherd-pid1` + +Important findings: + +- the local QEMU PID 1 prototype was not a simulator-only artifact; the same general boot design also works on the real XCP-ng/Xen guest +- as expected for a Guile-script entry point, the PID 1 process image shows up as Guile, but the meaningful architectural check is that: + - `/var/run/shepherd.pid` contains `1` +- this means Fruix has now validated two distinct real-VM boot architectures on FreeBSD: + - `freebsd-init+rc.d-shepherd` + - `shepherd-pid1` +- however, this still does not remove the current Guile / Shepherd compatibility-prefix shims; those remain a separate runtime-artifact issue rather than an init-manager issue + +Current assessment: + +- Shepherd-as-PID-1 is now no longer merely a local prototype; it is validated on the real XCP-ng VM as well +- this significantly strengthens the path toward a more Guix-like Fruix system architecture on FreeBSD +- the main remaining native-runtime gap is now the baked-prefix / compatibility-shim problem, not whether Fruix can boot with Shepherd as PID 1 + +Next recommended step: + +1. focus directly on eliminating the remaining Guile / Shepherd compatibility-prefix shims from the guest runtime +2. preserve `shepherd-pid1` as an experimental selectable boot mode while that cleanup proceeds +3. once the runtime-prefix issue is reduced, reassess whether `shepherd-pid1` should replace the older `freebsd-init+rc.d-shepherd` path as the preferred Fruix boot architecture + +## 2026-04-02 — Post-Phase-10: removed runtime dependence on `/tmp` Guile / Shepherd compatibility-prefix shims + +Completed work: + +- removed the generated guest's runtime dependence on the old `/tmp` compatibility-prefix symlinks for Guile, guile-extra, and Shepherd +- wrote the subphase report: + - `docs/reports/postphase10-runtime-prefix-shims-freebsd.md` +- updated the prefix materializer in: + - `modules/fruix/system/freebsd.scm` + - bumped the prefix-materializer revision + - added deterministic post-copy sanitation for staged runtime prefixes +- removed activation-time recreation of these guest-side shims from the generated activation path: + - `/tmp/guile-freebsd-validate-install` + - `/tmp/guile-gnutls-freebsd-validate-install` + - `/tmp/shepherd-freebsd-validate-install` +- sanitized the staged guile-extra runtime so it no longer depends on those old prefixes for key module loading: + - patched `fibers/config.scm` to use `GUILE_EXTENSIONS_PATH` + - patched `gnutls.scm` to fall back to `GUILE_EXTENSIONS_PATH` + - removed stale compiled cache files that would otherwise retain the old prefix behavior: + - `fibers/config.go` + - `gnutls.go` +- sanitized the staged Shepherd runtime so it no longer depends on the old temporary prefix for `shepherd config`: + - patched `share/guile/site/3.0/shepherd/config.scm` + - removed stale compiled cache file: + - `shepherd/config.go` +- extended the real XCP-ng validation harnesses so they now explicitly check for: + - absence of the `/tmp` compatibility-prefix trees + - successful Guile module loading from the store-backed runtime +- updated: + - `tests/system/run-phase9-xcpng-boot.sh` + - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` + +Validation: + +- `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with: + - workdir: `/tmp/noshim-phase9-smoke-1775143001` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `ready_marker=ready` + - `shepherd_status=running` + - `sshd_status=running` +- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with: + - workdir: `/tmp/noshim-phase11-smoke-1775142712` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `ready_marker=ready` + - `shepherd_pid=1` + - `shepherd_status=running` + - `sshd_status=running` +- a direct manual guest probe also confirmed that all three `/tmp` compatibility-prefix paths are absent while Guile can still load: + - `(fibers config)` + - `(gnutls)` + - `(shepherd config)` + +Important findings: + +- the remaining native-runtime problem was narrower than the earlier boot-manager issue: + - boot was already solved + - PID 1 was already solved + - the next real dependency to remove was the guest's reliance on temporary compatibility aliases +- deleting the stale compiled cache files for the affected modules was important; otherwise Guile could continue using prefix-baked compiled forms even after the source modules were patched +- this subphase removes runtime dependence on the old `/tmp` compatibility shims, but it does not yet guarantee that every embedded historical prefix string has disappeared from every binary or metadata artifact + +Current assessment: + +- Fruix now boots and runs from a store-backed Guile / Shepherd runtime arrangement on FreeBSD without needing guest-side `/tmp` compatibility-prefix symlinks +- this now holds for both validated real-VM boot modes: + - `freebsd-init+rc.d-shepherd` + - `shepherd-pid1` +- the main remaining cleanup is deeper and lower-level: + - move the local Guile / guile-extra / Shepherd build/install flow itself closer to a truly store-native prefix so the remaining baked strings disappear from the artifacts rather than merely becoming runtime-irrelevant + +Next recommended step: + +1. keep `shepherd-pid1` available as the stronger experimental boot architecture +2. start pushing the local Guile / guile-extra / Shepherd build/install process itself toward a truly store-native prefix layout +3. clean up the remaining historical prefix strings still present in binaries, libtool metadata, and pkg-config metadata where they still matter for developer/operator workflows + +## 2026-04-02 — Phase 12.1: deployment provenance and diagnostic metadata improved + +Completed work: + +- wrote the next-stage plan document: + - `docs/PLAN_3.md` +- added a concise progress snapshot: + - `docs/PROG_SUMMARY.md` +- wrote the Phase 12.1 report: + - `docs/reports/phase12-provenance-diagnostics-freebsd.md` +- updated `modules/fruix/system/freebsd.scm` so generated system closures now carry explicit provenance files: + - `metadata/host-base-provenance.scm` + - `metadata/store-layout.scm` +- those closure metadata files now record at least: + - host `freebsd-version -kru` + - host `uname -a` + - `/usr/src` path + - `/usr/src` git revision/branch when available + - `newvers.sh` SHA256 as a fallback source-tree identifier + - exact host-staged FreeBSD base store paths + - exact Fruix runtime store paths + - selected init mode +- extended `scripts/fruix.scm` so `fruix system build` and `fruix system image` now emit explicit provenance/layout metadata including: + - `host_base_store_count` + - `host_base_stores` + - `fruix_runtime_store_count` + - `fruix_runtime_stores` + - `host_base_provenance_file` + - `store_layout_file` + - `host_freebsd_version` + - `host_uname` + - `usr_src_git_revision` + - `usr_src_git_branch` + - `usr_src_newvers_sha256` +- tightened the local closure/image validation harnesses so they now assert that this provenance metadata exists: + - `tests/system/run-phase7-system-closure.sh` + - `tests/system/run-phase8-system-image.sh` +- expanded the VM-oriented harnesses to collect more guest-side diagnostic tails where available: + - `tests/system/run-phase9-xcpng-boot.sh` + - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` + - now include additional capture for: + - `shepherd-bootstrap.out` + - `shepherd.log` + - recent `dmesg` +- stabilized local reproducibility checks by forcing: + - `GUILE_AUTO_COMPILE=0` + in the host-side closure/image harnesses when invoking `fruix` under `sudo env` + +Validation: + +- `tests/system/run-phase7-system-closure.sh` passes with the new provenance checks: + - workdir: `/tmp/phase12-1b-closure-1775157039` + - confirmed: + - `host_base_store_count=8` + - `fruix_runtime_store_count=3` + - `host_base_provenance_file=/frx/store/.../metadata/host-base-provenance.scm` + - `store_layout_file=/frx/store/.../metadata/store-layout.scm` + - `host_freebsd_version=15.0-STABLE` +- `tests/system/run-phase8-system-image.sh` passes with the new provenance checks: + - workdir: `/tmp/phase12-1b-image-1775157039` + - confirmed: + - `host_base_store_count=8` + - `fruix_runtime_store_count=3` + - `host_base_provenance_file=/frx/store/.../metadata/host-base-provenance.scm` + - `store_layout_file=/frx/store/.../metadata/store-layout.scm` + - `host_uname=FreeBSD fruixdev 15.0-STABLE ...` +- syntax-checked successfully: + - `tests/system/run-phase9-xcpng-boot.sh` + - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` + +Important findings: + +- the current host-staged FreeBSD base pipeline is still transitional, but it is now much more inspectable and self-describing +- one-shot reproducibility failures immediately after source edits were partly a host-side auto-compilation artifact; forcing `GUILE_AUTO_COMPILE=0` in the validation harnesses makes the closure/image checks more stable +- the project can now identify much more directly: + - which closure/image inputs came from the host-staged FreeBSD base + - which came from Fruix-built Guile/Shepherd runtime artifacts + - what `/usr/src` identity was available at build time + +Current assessment: + +- Fruix now has a better-documented and easier-to-debug working pipeline for the current host-staged FreeBSD base model +- this is the right amount of hardening before beginning native FreeBSD base-build work; it improves traceability without pretending the current host-copy model is final + +Next recommended step: + +1. continue with Phase 12.2 and tighten the guest-side runtime/operator diagnostics +2. remove or reduce the most distracting remaining boot/runtime rough edges where the fixes are small and local +3. keep the deployment path stable so Phase 13 can start from a sharper baseline + +## 2026-04-02 — Phase 12.2: guest runtime diagnostics tightened and `/etc` handling improved + +Completed work: + +- wrote the Phase 12.2 report: + - `docs/reports/phase12-runtime-diagnostics-freebsd.md` +- updated `modules/fruix/system/freebsd.scm` so selected database-backed `/etc` files are now materialized as regular files in the guest rootfs instead of symlinks: + - `/etc/passwd` + - `/etc/master.passwd` + - `/etc/group` + - `/etc/login.conf` +- the generated activation script now refreshes those files from `/run/current-system/etc` before rebuilding FreeBSD databases +- activation now writes a guest-visible log: + - `/var/log/fruix-activate.log` + - with markers including: + - `fruix-activate:start` + - `fruix-activate:cap_mkdb=ok` + - `fruix-activate:pwd_mkdb=ok` + - `fruix-activate:done` + - exit status marker via shell trap +- tightened closure permissions slightly by making: + - `etc/master.passwd` + mode `0600` +- upgraded validation harnesses so they now assert the improved runtime behavior directly: + - `tests/system/run-phase8-system-image.sh` + - now checks that image `/etc/login.conf` is a regular file + - now checks that image `/etc/master.passwd` is a regular file + - `tests/system/run-phase9-xcpng-boot.sh` + - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` + - now check for: + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - activation log completion marker +- fixed a small follow-up bug in the activation log path: + - initial implementation used `touch`, which is not staged in the minimal guest + - switched to shell redirection instead: + - `: >> "$logfile"` + +Validation: + +- `tests/system/run-phase8-system-image.sh` passes locally with the new image-layout checks: + - workdir: `/tmp/phase12-2-image-1775159011` + - confirmed: + - `login_conf_kind=regular` + - `master_passwd_kind=regular` +- `tests/system/run-phase11-shepherd-pid1-qemu.sh` passes locally again with the new activation/runtime checks: + - workdir: `/tmp/phase12-2b-qemu-1775161367` + - confirmed: + - `activate_log=fruix-activate:start ... fruix-activate:done ...` + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - `shepherd_pid=1` + - `sshd_status=running` +- `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with the new checks: + - workdir: `/tmp/phase12-2b-phase9-1775161731` + - confirmed: + - `activate_log=fruix-activate:start ... fruix-activate:done ...` + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `shepherd_status=running` + - `sshd_status=running` +- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with the new checks: + - workdir: `/tmp/phase12-2b-phase11-1775162210` + - confirmed: + - `activate_log=fruix-activate:start ... fruix-activate:done ...` + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `shepherd_pid=1` + - `sshd_status=running` + +Important findings: + +- the old symlink-based handling for login/password database inputs was a real mismatch with FreeBSD expectations; making those files regular in the guest was a better fit than leaving them store-backed symlinks +- adding a direct activation log materially improves post-boot diagnosis and avoids guessing whether activation actually completed +- the first attempt exposed a missing-userland dependency (`touch`) quickly; because the new diagnostics were explicit, the follow-up fix was immediate and local +- both validated boot paths still hold after this change: + - `freebsd-init+rc.d-shepherd` + - `shepherd-pid1` + +Current assessment: + +- the current Fruix guest remains intentionally minimal, but its runtime behavior is now less prototype-noisy and easier to inspect as a basic FreeBSD-like system +- this is exactly the kind of targeted hardening that makes the existing system a better launch point for native FreeBSD base-build work + +Next recommended step: + +1. complete Phase 12.3 by making the host-staged FreeBSD base boundary explicit in the package/model layer and docs +2. document the first intended replacement order for native world/kernel work +3. then begin Phase 13 with a clearer transitional boundary + +## 2026-04-02 — Phase 12.3: made the host-staged FreeBSD base boundary explicit + +Completed work: + +- wrote the Phase 12.3 report: + - `docs/reports/phase12-host-staged-base-boundary-freebsd.md` +- refined `modules/fruix/packages/freebsd.scm` so the transitional host-copy base boundary is now explicit in the package/model layer +- added and exported named transitional package sets: + - `%freebsd-host-staged-all-packages` + - `%freebsd-host-staged-core-packages` + - `%freebsd-host-staged-development-profile-packages` + - `%freebsd-host-staged-system-packages` +- added and exported: + - `freebsd-host-staged-package?` + - `%freebsd-host-staged-replacement-order` +- preserved compatibility aliases so existing callers still work: + - `%freebsd-core-packages` + - `%freebsd-development-profile-packages` + - `%freebsd-system-packages` +- encoded the intended first replacement order for native base-build work directly in the package layer: + 1. `freebsd-kernel`, `freebsd-bootloader` + 2. `freebsd-runtime`, `freebsd-libc`, `freebsd-userland`, `freebsd-rc-scripts` + 3. `freebsd-networking`, `freebsd-openssh` + 4. `freebsd-kernel-headers`, `freebsd-clang-toolchain` + 5. `freebsd-gmake`, `freebsd-autotools`, `freebsd-openssl`, `freebsd-zlib`, `freebsd-sh`, `freebsd-bash` +- updated `modules/fruix/system/freebsd.scm` so the generated closure metadata now carries this boundary information too: + - `metadata/store-layout.scm` now includes: + - `host-base-stores` + - `fruix-runtime-stores` + - `host-base-replacement-order` + - `init-mode` + +Validation: + +- confirmed package-layer behavior directly with Guile: + - `(freebsd-host-staged-package? freebsd-runtime)` => `#t` + - `%freebsd-host-staged-replacement-order` prints the expected staged replacement order +- `tests/system/run-phase7-system-closure.sh` still passes after the package-layer clarification: + - workdir: `/tmp/phase12-3-closure-1775162784` +- inspected generated closure metadata file: + - `/frx/store/25ae9bb85da60b8c77971325e0e11d5390a064132a35e1bab0866cabb802a606-fruix-system-fruix-freebsd/metadata/store-layout.scm` + - confirmed it now includes: + - `host-base-stores` + - `fruix-runtime-stores` + - `host-base-replacement-order` + +Important findings: + +- the current host-staged FreeBSD base model is no longer just an implicit fact of the implementation; it is now named and documented as a transitional boundary +- preserving compatibility aliases means the current working system model does not need a broad rename/refactor just to make that boundary explicit +- encoding the replacement order directly in the package/model layer gives Phase 13 a clearer starting point for native `world`/`kernel` work + +Current assessment: + +- Phase 12 is now complete +- the current Fruix pipeline is better documented, easier to diagnose, less noisy at runtime, and clearer about what remains transitional in the FreeBSD base layer +- this is a good stopping point before beginning native FreeBSD base-build artifacts in `/frx/store` + +Next recommended step: + +1. begin Phase 13.1 by modeling FreeBSD `world` and `kernel` as Fruix-managed build artifacts rather than host-copy packages +2. use `/usr/src` as the initial source of truth on the builder side +3. target the first bootable replacement for the current host-staged kernel and core runtime path + +## 2026-04-02 — Phase 13.1: modeled native FreeBSD world/kernel artifacts + +Completed work: + +- wrote the Phase 13.1 report: + - `docs/reports/phase13-native-base-model-freebsd.md` +- added native FreeBSD base package objects in `modules/fruix/packages/freebsd.scm`: + - `freebsd-native-kernel` + - `freebsd-native-world` +- added and exported: + - `freebsd-native-build-package?` +- encoded the first native build parameters directly in those package definitions, including: + - `source-root=/usr/src` + - `target=amd64` + - `target-arch=amd64` + - `kernconf=GENERIC` + - make flags: + - `__MAKE_CONF=/dev/null` + - `SRCCONF=/dev/null` + - `SRC_ENV_CONF=/dev/null` + - `MK_DEBUG_FILES=no` + - `MK_TESTS=no` +- the first native world artifact now also carries an explicit runtime-oriented prune list: + - `usr/share/doc` + - `usr/share/examples` + - `usr/share/info` + - `usr/share/man` + - `usr/tests` +- extended `modules/fruix/system/freebsd.scm` so `materialize-freebsd-package` now understands: + - `copy-build-system` + - `freebsd-world-build-system` + - `freebsd-kernel-build-system` +- added native-build identity/materialization helpers for: + - `/usr/src` source-tree identity + - `KERNCONF` path hashing + - build-root identity + - buildworld/buildkernel stamp handling + - staged installworld/installkernel materialization + - native build metadata files in store outputs +- chose an `mtree`-based `/usr/src` identity for the first native output model using: + - `type` + - `link` + - `size` + - `mode` + - `sha256digest` +- updated closure/image metadata modeling so the system can now distinguish: + - `host_base_stores` + - `native_base_stores` + - `fruix_runtime_stores` +- updated profile/tree merging to skip private dotfile metadata from store outputs so native-build metadata does not leak into the merged runtime tree + +Validation: + +- confirmed the updated package/system modules still load after the native build-model additions +- confirmed the new native package objects are present and classified as expected: + - `freebsd-native-kernel` reports build-system `freebsd-kernel-build-system` + - `freebsd-native-build-package? freebsd-native-world` returns `#t` +- re-ran the existing host-copy regression check successfully: + - `tests/system/run-phase7-system-closure.sh` + - workdir: `/tmp/phase13-1-closure-1775164392` + - result: `PASS phase7-system-closure` + +Important findings: + +- Fruix now has a real model for FreeBSD base artifacts built from `/usr/src`; the project is no longer limited to describing the FreeBSD base only as host-copy packages +- the first native identity story is explicit: + - `/usr/src` contributes through an `mtree`-based tree digest + - `KERNCONF` contributes through its resolved path hash + - selected make/build parameters are part of the manifest too +- the repo can now describe a mixed system more honestly by separating: + - transitional host-staged base stores + - native base stores + - Fruix runtime stores + +Current assessment: + +- Phase 13.1 is complete +- the next step is no longer architectural guesswork; it is concrete execution of the newly added native package/materialization path + +Next recommended step: + +1. build the first concrete `freebsd-native-kernel` and `freebsd-native-world` outputs from `/usr/src` +2. inspect/document their staged contents in `/frx/store` +3. then wire a bootable system closure/image around those native outputs + +## 2026-04-03 — Phase 13.2: first native FreeBSD world/kernel outputs built from `/usr/src` + +Completed work: + +- wrote the Phase 13.2 report: + - `docs/reports/phase13-native-world-kernel-build-freebsd.md` +- exercised the new native build path for real and produced the first concrete store outputs from `/usr/src`: + - native kernel output under `/frx/store` + - native world output under `/frx/store` +- added a dedicated Phase 13.2 template/harness: + - `tests/system/phase13-native-base-pid1-operating-system.scm.in` + - `tests/system/run-phase13-native-base-build.sh` +- fixed the first real native-build failure: + - `MAKEOBJDIRPREFIX` cannot be passed as a make command-line variable for this FreeBSD build path + - changed the native builder to invoke make as: + - `env MAKEOBJDIRPREFIX=... make ...` +- fixed a subtle output-identity bug in the first `/usr/src` hash implementation: + - the initial `mtree`-based source hash accidentally included unstable header comments such as date/user/machine lines + - now strips `# ...` header lines before hashing + - this stabilized the source-tree identity and stopped the native output/build-root identity from drifting on each run +- verified that native world and kernel now share the same: + - `source-tree-sha256` + - `build-root` +- the first native world split remains intentionally runtime-oriented and prunes at least: + - `usr/share/doc` + - `usr/share/examples` + - `usr/share/info` + - `usr/share/man` + - `usr/tests` + +Concrete validated outputs: + +- native kernel store path: + - `/frx/store/93f35ddcb9a03f63f83c9e8ae29788685d339789da664f881822b4a1914f5ff6-freebsd-native-kernel-15.0-STABLE` +- native world store path: + - `/frx/store/3f6f7f8c06ed8dad4cae21a1e8ac8ba4823bdb7cf54328c9bbcccaeb858beb77-freebsd-native-world-15.0-STABLE` +- shared native build root: + - `/var/tmp/fruix-freebsd-native-build-c59b1b8128b305d9bad9cf3d654771c941c4e8b6a2732f6bc959df96d1d32f58` + +Validated native-world contents include at least: + +- `/bin/sh` +- `/sbin/init` +- `/etc/rc` +- `/usr/sbin/sshd` +- `/sbin/dhclient` +- `/usr/bin/cap_mkdb` +- `/usr/sbin/pwd_mkdb` +- `/usr/share/locale/C.UTF-8/LC_CTYPE` + +Validated pruned paths are absent from the world output: + +- `/usr/share/man` +- `/usr/tests` + +Validation: + +- real native-base `fruix system build` succeeded with an operating-system using: + - `freebsd-native-kernel` + - `freebsd-native-world` + - host-staged `freebsd-bootloader` + - `shepherd-pid1` +- `tests/system/run-phase13-native-base-build.sh` passes: + - workdir: `/tmp/phase13-2-build-1775173551` + - result: `PASS phase13-native-base-build` +- the harness confirmed: + - closure rebuild path reproducibility + - native kernel/world store paths exist + - native build info files exist + - world/kernel source-tree hashes match + - world/kernel build roots match + - native build logs exist + - `native-base-stores` is present in closure metadata + - host/native store boundary now looks as expected for this mixed system: + - `host_base_store_count=1` + - `native_base_store_count=2` + +Important findings: + +- the native build path is now real, not just modeled +- the first mixed Phase-13 system boundary is explicit and sensible: + - host-staged bootloader only + - native kernel + native world + - Fruix runtime stores unchanged +- the `mtree` preamble bug would have made native output identity drift across runs; fixing it was essential before treating these as reproducible store artifacts +- the shared build-root result is important: the kernel/world pair now reuses the same `/usr/src` build state instead of acting like two unrelated builds + +Current assessment: + +- Phase 13.2 is complete +- Fruix can now build and stage native FreeBSD base artifacts from `/usr/src` in `/frx/store` +- the next step is to boot a system using those native outputs rather than stopping at build-time inspection + +Next recommended step: + +1. wire the image/boot path to use the native kernel/world outputs end-to-end +2. validate locally with QEMU/UEFI +3. validate on the approved XCP-ng VM and VDI path + +## 2026-04-03 — Phase 13.3: booted Fruix from native FreeBSD kernel/world outputs + +Completed work: + +- wrote the Phase 13.3 report: + - `docs/reports/phase13-native-base-boot-freebsd.md` +- completed the first end-to-end boot path using native `/usr/src`-built FreeBSD base artifacts in `/frx/store` +- fixed the first native-image sizing problem: + - the old fixed `root-size=256m` was too small once the image carried a native world + - added explicit root filesystem sizing support to the CLI/image path: + - `scripts/fruix.scm` now accepts `--root-size SIZE` + - image metadata now records `root_size` + - `tests/system/run-phase8-system-image.sh` now accepts: + - `ROOT_SIZE` + and records: + - `root_size` + - `native_base_store_count` + - `native_base_stores` +- fixed a follow-up image metadata bug: + - `materialize-bhyve-image` now returns: + - `native-base-stores` + - this removed the `length #f` failure in the native image path +- generalized the local PID1 QEMU harness a bit further: + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` now accepts `OS_TEMPLATE` +- added dedicated Phase 13.3 native-base boot wrappers: + - `tests/system/run-phase13-native-base-qemu.sh` + - `tests/system/run-phase13-native-base-xcpng.sh` +- these wrappers reuse the validated PID1 boot path but additionally require the image metadata to prove the booted system is really using the intended Phase-13 base split: + - native kernel present + - native world present + - host base reduced to bootloader only + +Working native-base boot configuration: + +- local QEMU: + - `ROOT_SIZE=6g` + - `DISK_CAPACITY=8g` +- real XCP-ng: + - `ROOT_SIZE=6g` + - disk capacity kept matched to the fixed 30 GiB VDI as before + +Validation: + +- local QEMU/UEFI/TCG boot passes through the new wrapper: + - `tests/system/run-phase13-native-base-qemu.sh` + - workdir: `/tmp/phase13-3-qemu3-1775174863` + - result: `PASS phase13-native-base-qemu` + - confirmed: + - `disk_capacity=8g` + - `root_size=6g` + - `native_base_store_count=2` + - `host_base_store_count=1` + - `shepherd_pid=1` + - `sshd_status=running` + - `native_base_boot=ok` +- real XCP-ng boot passes through the new wrapper: + - `tests/system/run-phase13-native-base-xcpng.sh` + - workdir: `/tmp/phase13-3-xcpng-1775175086` + - result: `PASS phase13-native-base-xcpng` + - confirmed: + - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` + - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` + - `guest_ip=192.168.213.62` + - `root_size=6g` + - `native_base_store_count=2` + - `host_base_store_count=1` + - `shepherd_pid=1` + - `sshd_status=running` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `native_base_boot=ok` +- validated native-base closure/image composition now boots with: + - native kernel store: + - `/frx/store/93f35ddcb9a03f63f83c9e8ae29788685d339789da664f881822b4a1914f5ff6-freebsd-native-kernel-15.0-STABLE` + - native world store: + - `/frx/store/3f6f7f8c06ed8dad4cae21a1e8ac8ba4823bdb7cf54328c9bbcccaeb858beb77-freebsd-native-world-15.0-STABLE` + - remaining host base store: + - `/frx/store/8ffcfe0356fea815726b610514a1280a11266851c2acb870047d559795569f0e-freebsd-bootloader-15.0-STABLE` + +Important findings: + +- the native world is large enough that the older 256 MiB rootfs assumption is no longer realistic; explicit image sizing is now part of the practical Phase-13 path +- after the native-base transition, the remaining transitional boundary is now much narrower and explicit: + - host-staged bootloader/boot assets + - native kernel + - native core world runtime +- the real XCP-ng upload path still works with the larger native-world image, but the dynamic VHD is naturally much bigger now (~4.42 GiB) + +Current assessment: + +- Phase 13 is complete +- Fruix now builds FreeBSD kernel/world artifacts from `/usr/src` into `/frx/store` and successfully boots a declarative system from those native outputs +- this is the main architectural pivot Plan 3 called for before Phase 14 + +Next recommended step: + +1. begin Phase 14 by replacing the remaining host-copy boot assets first +2. keep shrinking the host-staged base boundary around the now-working native world/kernel path +3. revisit cleaner runtime vs. development splits after the boot asset transition + +## 2026-04-03 — Phase 14.1: removed host-copied boot assets from the validated native boot path + +Completed work: + +- wrote the Phase 14.1 report: + - `docs/reports/phase14-native-boot-assets-freebsd.md` +- added a dedicated Phase 14.1 native-boot PID1 template: + - `tests/system/phase14-native-boot-pid1-operating-system.scm.in` +- added dedicated Phase 14.1 validation wrappers: + - `tests/system/run-phase14-native-boot-qemu.sh` + - `tests/system/run-phase14-native-boot-xcpng.sh` +- validated a cleaner native boot path by sourcing boot assets from the existing native world output instead of the host-staged `freebsd-bootloader` package: + - `#:kernel freebsd-native-kernel` + - `#:bootloader freebsd-native-world` + - `#:base-packages (list freebsd-native-world)` +- hardened the reusable local PID1 QEMU harness so it no longer boots the raw store image directly read/write from `/frx/store`: + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` now copies the generated raw image to: + - `boot-disk.img` + in the workdir before launching QEMU + - this prevents repeated local boots from mutating the supposed store artifact and causing dirty-filesystem follow-up failures + +Validation: + +- local QEMU/UEFI/TCG native-boot wrapper passes: + - `tests/system/run-phase14-native-boot-qemu.sh` + - workdir: `/tmp/phase14-1-qemu2-1775188371` + - result: `PASS phase14-native-boot-qemu` + - confirmed: + - `native_base_store_count=2` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `native_boot_assets=freebsd-native-world` + - `native_base_boot=ok` +- real XCP-ng native-boot wrapper passes: + - `tests/system/run-phase14-native-boot-xcpng.sh` + - workdir: `/tmp/phase14-1-xcpng-1775188701` + - result: `PASS phase14-native-boot-xcpng` + - confirmed: + - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` + - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` + - `guest_ip=192.168.213.62` + - `native_base_store_count=2` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `native_boot_assets=freebsd-native-world` + - `native_base_boot=ok` + +Current assessment: + +- Phase 14.1 is complete +- the validated native boot path no longer depends on host-copied `/boot/...` material +- the current Phase-14.1 native boundary is now fully host-base-free for the validated path: + - native kernel + - native world supplying boot assets + - native world supplying runtime + +Next recommended step: + +1. introduce a clearer native runtime slice so runtime is no longer modeled by reusing the broader native world output for both boot and runtime +2. validate that explicit native runtime slice on QEMU and XCP-ng +3. then revisit headers/toolchain/development package boundaries + +## 2026-04-03 — Phase 14.2: validated an explicit native FreeBSD runtime slice + +Completed work: + +- wrote the Phase 14.2 report: + - `docs/reports/phase14-native-runtime-freebsd.md` +- added a new native package in `modules/fruix/packages/freebsd.scm`: + - `freebsd-native-runtime` +- this runtime slice is built from `/usr/src` through the native world path and now prunes at least: + - `boot` + - `usr/include` + - `usr/share/doc` + - `usr/share/examples` + - `usr/share/info` + - `usr/share/man` + - `usr/share/mk` + - `usr/tests` +- added a dedicated Phase 14.2 operating-system template: + - `tests/system/phase14-native-runtime-pid1-operating-system.scm.in` +- added dedicated validation wrappers: + - `tests/system/run-phase14-native-runtime-qemu.sh` + - `tests/system/run-phase14-native-runtime-xcpng.sh` +- the validated Phase 14.2 model now uses: + - `#:kernel freebsd-native-kernel` + - `#:bootloader freebsd-native-world` + - `#:base-packages (list freebsd-native-runtime)` +- this makes the system composition more explicit: + - native world provides boot assets + - native runtime provides the guest runtime slice + - host base stores remain absent from the validated path + +Important finding: + +- this Phase 14.2 layout still duplicates some content because boot assets still come from the broader native world output while runtime comes from the separate native runtime slice +- that made the earlier Phase 13 image sizes too small +- the working values are now: + - local QEMU: + - `DISK_CAPACITY=12g` + - `ROOT_SIZE=10g` + - real XCP-ng: + - `ROOT_SIZE=10g` + - disk capacity still matched to the fixed 30 GiB VDI +- the new Phase 14.2 wrappers now use those larger defaults + +Validation: + +- local QEMU/UEFI/TCG runtime wrapper passes: + - `tests/system/run-phase14-native-runtime-qemu.sh` + - workdir: `/tmp/phase14-2-qemu2-1775189802` + - result: `PASS phase14-native-runtime-qemu` + - confirmed: + - `disk_capacity=12g` + - `root_size=10g` + - `runtime_store=/frx/store/684a82aeed2c9a353e3a09d2cbf5358274d758005e0bfa9b1025d101bc166f79-freebsd-native-runtime-15.0-STABLE` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `native_runtime_ready=ok` +- real XCP-ng runtime wrapper passes: + - `tests/system/run-phase14-native-runtime-xcpng.sh` + - workdir: `/tmp/phase14-2-xcpng-1775190184` + - result: `PASS phase14-native-runtime-xcpng` + - confirmed: + - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` + - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` + - `guest_ip=192.168.213.62` + - `root_size=10g` + - `runtime_store=/frx/store/684a82aeed2c9a353e3a09d2cbf5358274d758005e0bfa9b1025d101bc166f79-freebsd-native-runtime-15.0-STABLE` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `native_runtime_ready=ok` +- the wrappers also assert the runtime-split boundary directly: + - runtime store contains required boot-to-ready files such as: + - `/bin/sh` + - `/sbin/init` + - `/etc/rc` + - `/usr/sbin/sshd` + - `/sbin/dhclient` + - `/usr/bin/ssh-keygen` + - `/usr/share/locale/C.UTF-8/LC_CTYPE` + - runtime store no longer contains: + - `/boot` + - `/usr/include` + +Current assessment: + +- Phase 14.2 is complete +- the validated Fruix guest now reaches ready state using an explicit native runtime artifact rather than reusing the broad native world output for both boot and runtime roles +- the validated path remains host-base-free: + - native kernel + - native world as the temporary boot-source artifact + - native runtime as the guest runtime artifact + +Next recommended step: + +1. define cleaner runtime vs. development boundaries in code/package sets +2. introduce a narrower native boot asset package so the broader native world output is no longer needed as the temporary boot-source store +3. revalidate the full host-base-free path after that split + +## 2026-04-03 — Phase 14.3: split native FreeBSD boot, runtime, and development artifacts + +Completed work: + +- wrote the Phase 14.3 report: + - `docs/reports/phase14-native-splits-freebsd.md` +- added new native packages in `modules/fruix/packages/freebsd.scm`: + - `freebsd-native-bootloader` + - `freebsd-native-headers` +- refined `freebsd-native-runtime` into a narrower runtime slice by pruning more obviously non-runtime content, including at least: + - `boot` + - `rescue` + - `usr/include` + - `usr/lib/debug` + - `usr/lib32` + - `usr/obj` + - `usr/src` + - `usr/share/doc` + - `usr/share/examples` + - `usr/share/info` + - `usr/share/man` + - `usr/share/mk` + - `usr/tests` +- extended the native world-derived build path in `modules/fruix/system/freebsd.scm` with support for: + - `keep-paths` +- native build manifests/output metadata now record both: + - `keep-paths` + - `prune-paths` +- added explicit native package-set boundaries: + - `%freebsd-native-system-packages` + - `%freebsd-native-development-profile-packages` +- the final validated Phase 14 system template now uses: + - `#:kernel freebsd-native-kernel` + - `#:bootloader freebsd-native-bootloader` + - `#:base-packages %freebsd-native-system-packages` +- this removes the need for the broad `freebsd-native-world` artifact from the final validated system closure + +New validation files: + +- `tests/system/phase14-native-split-pid1-operating-system.scm.in` +- `tests/system/run-phase14-native-split-qemu.sh` +- `tests/system/run-phase14-native-split-xcpng.sh` +- `tests/system/run-phase14-native-development-split.sh` + +Validation: + +- development/runtime split harness passes: + - `tests/system/run-phase14-native-development-split.sh` + - workdir: `/tmp/phase14-3-dev5-1775191195` + - result: `PASS phase14-native-development-split` + - confirmed: + - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` + - `headers_store=/frx/store/aab09122d37962e6d479c17172ce4b8ea85e5ff33c98aa76424ada2fa1a82617-freebsd-native-headers-15.0-STABLE` + - `native_system_packages=freebsd-native-runtime` + - `native_development_packages=freebsd-native-runtime,freebsd-native-headers,freebsd-clang-toolchain,freebsd-gmake,freebsd-autotools,freebsd-openssl,freebsd-zlib,freebsd-sh,freebsd-bash` + - `runtime_vs_development_split=ok` + - the harness also confirmed: + - bootloader slice contains the expected boot assets only + - headers slice contains headers/mk files + - headers slice does not contain `/boot` or runtime binaries +- final split-system local QEMU validation passes: + - `tests/system/run-phase14-native-split-qemu.sh` + - workdir: `/tmp/phase14-3-qemu-1775191337` + - result: `PASS phase14-native-split-qemu` + - confirmed: + - `disk_capacity=8g` + - `root_size=6g` + - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` + - `runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `native_split_boot=ok` +- final split-system real XCP-ng validation passes: + - `tests/system/run-phase14-native-split-xcpng.sh` + - workdir: `/tmp/phase14-3-xcpng-1775191743` + - result: `PASS phase14-native-split-xcpng` + - confirmed: + - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` + - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` + - `guest_ip=192.168.213.62` + - `root_size=6g` + - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` + - `runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `native_split_boot=ok` + +Important findings: + +- after replacing the temporary broad-world boot source with the narrower native bootloader slice and tightening the runtime slice, the validated image became much smaller again +- the real XCP-ng dynamic VHD upload for the final split path was: + - `1560725504` bytes (~1.45 GiB) +- that is far better than the temporary broad-world + runtime duplication in Phase 14.2 +- the final validated Phase 14 closure no longer needs the broad `freebsd-native-world` artifact in its native base store set + +Current assessment: + +- Phase 14 is complete +- Fruix now has a validated, host-base-free FreeBSD system path composed from native artifacts in `/frx/store`: + - `freebsd-native-kernel` + - `freebsd-native-bootloader` + - `freebsd-native-runtime` +- the runtime vs. development boundary is also clearer now through: + - `freebsd-native-headers` + - `%freebsd-native-development-profile-packages` +- this completes the Plan-3 Phase-14 goal of incrementally replacing the host-copy FreeBSD base layer for the validated boot/runtime path + +Next recommended step: + +1. begin Phase 15 by making the FreeBSD base version a declarative Fruix input +2. demonstrate side-by-side native base versions in `/frx/store` +3. validate rebuild/redeploy/rollback across those base versions + +## 2026-04-03 — Phase 15.1: made the FreeBSD base a declarative Fruix input + +Completed work: + +- wrote the Phase 15.1 report: + - `docs/reports/phase15-declarative-base-freebsd.md` +- added a new declarative base record in `modules/fruix/packages/freebsd.scm`: + - `freebsd-base` + - `freebsd-base?` + - `%default-freebsd-base` +- the declarative base now records at least: + - `name` + - `version-label` + - `release` + - `branch` + - `source-root` + - `target` + - `target-arch` + - `kernconf` + - `make-flags` +- native FreeBSD package constructors are now parameterized by a declared base: + - `freebsd-native-kernel-for` + - `freebsd-native-world-for` + - `freebsd-native-runtime-for` + - `freebsd-native-bootloader-for` + - `freebsd-native-headers-for` + - `freebsd-native-system-packages-for` + - `freebsd-native-development-profile-packages-for` +- existing exported native package variables remain available as the `%default-freebsd-base` instances: + - `freebsd-native-kernel` + - `freebsd-native-world` + - `freebsd-native-runtime` + - `freebsd-native-bootloader` + - `freebsd-native-headers` +- added a new operating-system field in `modules/fruix/system/freebsd.scm`: + - `#:freebsd-base` + - exported accessor: `operating-system-freebsd-base` +- the declared base is now recorded in system/image metadata through: + - `operating-system-closure-spec` + - `operating-system-image-spec` + - `metadata/freebsd-base.scm` + - `metadata/store-layout.scm` +- native build manifests and `.freebsd-native-build-info.scm` now record: + - `declared-base` +- `scripts/fruix.scm` now emits declared base metadata for `build` and `image`: + - `freebsd_base_name` + - `freebsd_base_version_label` + - `freebsd_base_release` + - `freebsd_base_branch` + - `freebsd_base_source_root` + - `freebsd_base_target` + - `freebsd_base_target_arch` + - `freebsd_base_kernconf` + - `freebsd_base_file` + +New validation files: + +- `tests/system/phase15-declarative-base-pid1-operating-system.scm.in` +- `tests/system/run-phase15-declarative-base-build.sh` + +Validation: + +- declarative-base build harness passes: + - `tests/system/run-phase15-declarative-base-build.sh` + - workdir: `/tmp/phase15-1-build-1775202535` + - result: `PASS phase15-declarative-base-build` + - confirmed: + - `kernel_store=/frx/store/8fcef04c7e507e86ea5e92f251fe3c6ac1aa3bcf4809fa77ddd8b92854bfcde0-freebsd-native-kernel-15.0-STABLE-declarative` + - `bootloader_store=/frx/store/7a0ba431e487dc35a8f6318108da16a37c8426c43e77e7a7f91404ba1d980eef-freebsd-native-bootloader-15.0-STABLE-declarative` + - `runtime_store=/frx/store/17c24ad20ddcb136c39352b68e758deae0b480258ba0128a5546f696a7eba0a6-freebsd-native-runtime-15.0-STABLE-declarative` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `freebsd_base_name=stable-default` + - `freebsd_base_version_label=15.0-STABLE-declarative` + - `freebsd_base_release=15.0-STABLE` + - `freebsd_base_branch=stable/15` + - `freebsd_base_source_root=/usr/src` + - `freebsd_base_kernconf=GENERIC` + - `declarative_base_input=ok` + - the harness also confirmed: + - `metadata/freebsd-base.scm` exists + - `parameters.scm` records the declared base + - `metadata/store-layout.scm` records the declared base + - native build info files record the declared base version/branch + +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 + +## 2026-04-03 — Phase 15.3: decided not to pursue self-hosted base builds yet + +Completed work: + +- wrote the Phase 15.3 report: + - `docs/reports/phase15-self-hosting-decision-freebsd.md` +- updated the high-level summary: + - `docs/PROG_SUMMARY.md` +- recorded an evidence-based decision about the next architecture step after Phases 13–15 + +Decision: + +- do **not** pursue self-hosted FreeBSD base builds as the next immediate milestone +- keep the near-term path on: + 1. host-built native FreeBSD base artifacts from `/usr/src` + 2. storage in `/frx/store` + 3. stronger declarative source-tree/version selection and provenance + 4. tighter reproducibility around source inputs and build parameters +- only revisit guest self-hosting after those pieces are stronger + +Evidence used for the decision: + +- Fruix already builds native FreeBSD base artifacts from `/usr/src` into `/frx/store` +- Fruix already validates a host-base-free boot/runtime path composed from: + - `freebsd-native-kernel` + - `freebsd-native-bootloader` + - `freebsd-native-runtime` +- that path already boots on: + - local QEMU/UEFI/TCG + - the approved real XCP-ng VM/VDI path +- the FreeBSD base is now an explicit declarative input through `freebsd-base` +- Fruix now supports side-by-side declared base versions and rollback-friendly redeploy +- the most important remaining reproducibility gap is now source-tree selection/acquisition, not host-copy boot/runtime assembly +- environment constraints still argue for caution before a self-hosting pivot: + - local bhyve remains blocked under Xen due to missing nested VT-x exposure + - real validation still reuses a single approved XCP-ng VM/VDI pair + - XCP-ng storage permissions still prevent creating fresh VDIs on demand + +Current assessment: + +- Phase 15.3 is complete +- Phase 15 is fully complete +- Fruix now has: + - a host-base-free native FreeBSD boot/runtime path in `/frx/store` + - an explicit declarative FreeBSD base model + - side-by-side base-version coexistence in `/frx/store` + - rollback-friendly redeploy across declared base versions + - a documented decision to continue with host-built native base artifacts for now rather than jumping immediately to guest self-hosting + +Next recommended step: + +1. focus the next phase on making FreeBSD source-tree selection/acquisition more declarative and reproducible +2. keep improving provenance and source-input identity around the now-working native base path +3. revisit self-hosted base builds only after the source/reproducibility boundary is substantially stronger