Files
fruix/docs/PLAN_4.md

18 KiB
Raw Permalink Blame History

Fruix on FreeBSD, Path D: Declarative Source Acquisition, Installation Artifacts, and the Road to Self-Hosting

This document extends docs/PLAN_3.md after the completion of Phases 1 through 15.

The project has now crossed another important threshold:

  • Fruix builds native FreeBSD base artifacts from /usr/src into /frx/store
  • the validated boot/runtime path is host-base-free at the deployed system layer
  • the FreeBSD base is now an explicit declarative Fruix input
  • side-by-side base versions can coexist in /frx/store
  • Fruix can rebuild, redeploy, and roll back between declared base versions

That means the next question is no longer whether Fruix can assemble and boot a native FreeBSD system. It can.

The next question is how to make that native base path more reproducible, more source-declarative, and more installable.

The biggest remaining impurity is now clear:

  • the native base build path still relies on the builder host's ambient /usr/src

That was the right bridge through Phases 13 to 15, but it should not be the long-term source story.

Accordingly, Plan 4 focuses on three connected goals:

  1. make FreeBSD source acquisition and source identity more declarative
  2. turn the current image-generation path into a real installation story
  3. only then move carefully toward self-hosted base builds

This preserves the Guix-inspired core while continuing to embrace FreeBSD semantics rather than trying to imitate Linux-specific workflows.

Throughout this plan, the canonical Fruix roots remain:

  • /frx/store
  • /frx/var
  • /frx/etc

The user-facing system remains Fruix, with CLI fruix, while internal upstream-derived names continue to be renamed selectively rather than mechanically.

The current real-VM validation constraints still apply unless explicitly relaxed later:

  • approved VM: 90490f2e-e8fc-4b7a-388e-5c26f0157289
  • approved A/B VDIs:
    • 0f1f90d3-48ca-4fa2-91d8-fc6339b95743
    • 7061d761-3639-4bec-87f7-2ba1af924eaa

Current State at the Start of Plan 4

Fruix on FreeBSD already has:

  • a functioning content-addressed store and derivation path under /frx/store
  • daemon-mediated builds with validated FreeBSD isolation concepts
  • a working declarative FreeBSD operating-system model
  • validated system closure, rootfs, and image generation through fruix system ...
  • real QEMU and XCP-ng boot validation
  • a host-base-free native boot/runtime composition built from:
    • freebsd-native-kernel
    • freebsd-native-bootloader
    • freebsd-native-runtime
  • a declarative freebsd-base model that records:
    • base identity
    • version label
    • branch
    • source root
    • target and kernel configuration
  • side-by-side native base versions in /frx/store
  • rollback-friendly redeploy across those declared base versions
  • a documented decision to continue using host-built native base artifacts for now rather than jumping immediately to guest self-hosting

The main remaining architectural compromise is now not the runtime/boot artifact split, but the source boundary:

  • native FreeBSD base builds still use ambient /usr/src
  • source acquisition is not yet a first-class Fruix-managed input
  • therefore reproducibility and provenance still stop short of a fully declared source story

At the same time, Fruix still lacks a real installation workflow beyond image generation and validation harnesses.


Guiding Decision for the Next Milestone

The next major milestone should be:

  • declarative FreeBSD source acquisition and source pinning first,
  • then native base builds from fetched or materialized source inputs,
  • then a real installation story,
  • and only after that, a controlled re-evaluation of self-hosted base builds.

This means the next work should optimize for:

  • explicit source identity
  • stronger provenance
  • side-by-side source revisions
  • repeatable rebuilds from fetched or materialized source trees
  • installation artifacts that are operator-usable beyond current validation harnesses

It should not optimize for:

  • jumping straight into guest self-hosting while source identity is still weak
  • building a large interactive installer before the installation primitives are clear
  • replacing the current validated host-built native-base path prematurely

Phase 16: Make FreeBSD Source Acquisition Declarative

This is the next architectural pivot after the native base/runtime split.

The goal is to move from:

  • “build from whatever /usr/src is on the host”

into:

  • “build from a declared FreeBSD source input with explicit provenance.”

Intermediate Goal 16.1: Model FreeBSD Source Inputs Explicitly

Verification Goal 16.1: Introduce a first-class Fruix model for FreeBSD source inputs.

This can be a new freebsd-source record, an extension of freebsd-base, or another explicit source object, but it should represent at least:

  • source kind:
    • local checkout snapshot
    • fetched Git checkout
    • fetched src.txz archive
  • source URL or local path
  • branch or release line
  • commit, tag, or revision when applicable
  • expected tree or archive hash
  • any intended patch queue or source transformation layer

This step should also document how that source object relates to:

  • freebsd-base
  • native kernel/world/runtime/bootloader/headers builds
  • output identity in /frx/store

Success Criteria: Fruix can describe FreeBSD source inputs as explicit declared objects rather than only relying on ambient /usr/src.

Intermediate Goal 16.2: Fetch or Materialize Source Trees Under Fruix Control

Verification Goal 16.2: Materialize a clean FreeBSD source tree from a declared source input using Fruix-managed fetch/materialization logic.

The first implementation may be intentionally modest, such as:

  • fetching a Git checkout at a pinned revision from https://git.FreeBSD.org/src.git
  • or downloading a src.txz archive and verifying its hash
    • for example from https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz
    • or from snapshot paths such as https://download.freebsd.org/snapshots/amd64/15.0-STABLE/src.txz
  • or snapshotting a local source tree into a content-addressed source artifact with explicit metadata

This phase should also define where downloaded or temporary source material lives, for example under:

  • /frx/var/cache/fruix/freebsd-source

The important point is that the eventual build input should no longer be “the current mutable host tree” but a materialized source snapshot with recorded identity.

Success Criteria: Fruix can fetch or materialize a pinned FreeBSD source tree with recorded provenance and a stable identity suitable for native base builds.

Intermediate Goal 16.3: Build Native Base Artifacts From the Declared Source Input

Verification Goal 16.3: Teach the native FreeBSD base build path to consume the declared source artifact rather than ambient /usr/src.

This should preserve the validated Plan-3/Plan-4 deployment story:

  • native kernel
  • native bootloader slice
  • native runtime slice
  • host-base-free validated path

The goal is not yet to change the successful boot/runtime model, only the source input boundary.

Success Criteria: Fruix builds native FreeBSD base artifacts from a declared source input, and the resulting store artifacts record that source identity explicitly.


Phase 17: Support Multiple FreeBSD Source Revisions Side by Side

Once source acquisition is explicit, Fruix should prove that it can treat source revisions the way it already treats declared base versions: as side-by-side inputs rather than in-place mutations.

Intermediate Goal 17.1: Support Side-by-Side FreeBSD Source Revisions in /frx/store

Verification Goal 17.1: Demonstrate that at least two distinct declared FreeBSD source inputs can coexist and produce distinct native base artifacts in /frx/store.

These can differ by:

  • Git revision
  • source archive hash
  • local source snapshot hash
  • or another explicit source identity boundary

The goal is to prove that the source declaration, not ambient host state, now drives the base build outputs.

Success Criteria: Fruix can hold at least two distinct FreeBSD source revisions side by side as meaningful native base inputs and outputs.

Intermediate Goal 17.2: Rebuild and Boot From Two Distinct Source Revisions

Verification Goal 17.2: Build and boot systems from at least two distinct declared source revisions using the validated native base path.

This should preserve the current validation strategy:

  • local QEMU/UEFI/TCG where useful
  • real XCP-ng validation on the approved VM and approved A/B VDI path

The booted systems do not necessarily need to differ in obvious runtime behavior; the important point is that their source identity and native base outputs differ and are tracked correctly.

Success Criteria: Fruix boots systems built from two distinct declared FreeBSD source revisions and records those revisions in system metadata.

Intermediate Goal 17.3: Clarify Source Provenance, Caching, and Update Policy

Verification Goal 17.3: Document and encode the intended policy for:

  • source caching
  • source refresh/invalidation
  • patch application if any
  • tree hashing rules
  • when a new source identity should or should not invalidate native base outputs

This step should reduce ambiguity before installation artifacts and later self-hosting experiments depend on these source objects.

Success Criteria: the repo clearly explains how FreeBSD source objects are fetched, cached, identified, invalidated, and consumed by native base builds.


Phase 18: Turn System Images Into a Real Installation Story

Fruix can already produce bootable images. The next step is to make installation itself a first-class Fruix story rather than a manual consequence of image generation.

Intermediate Goal 18.1: Define a Minimal Non-Interactive Installation Flow

Verification Goal 18.1: Introduce a minimal installation workflow that can take a Fruix system artifact and install it to a target disk or image in a repeatable way.

The first version should prefer clarity and automation over interactivity. For example, it may:

  • partition a target disk
  • create required filesystems
  • copy or materialize the selected system closure
  • install boot assets
  • stage activation/runtime metadata
  • configure root SSH key or basic operator access

This first step should be VM-friendly and serial-console-friendly.

Success Criteria: Fruix can perform a repeatable installation of a declarative system onto a target disk or image without relying on ad hoc manual assembly.

Intermediate Goal 18.2: Produce a Minimal Installer Environment

Verification Goal 18.2: Produce a small installer environment that can boot into a Fruix-managed install context and perform the installation workflow.

This environment may initially be one of:

  • a special-purpose disk image
  • a minimal recovery/install rootfs
  • a proto-installer medium with only the tools needed for partitioning, filesystem creation, and deployment

The target here is not a polished live environment. It is a reliable installer substrate.

Success Criteria: Fruix can boot a minimal installer environment and use it to install a selected Fruix system to a target disk.

Intermediate Goal 18.3: Build a Bootable Installer ISO

Verification Goal 18.3: Produce a bootable installer ISO for UEFI systems.

The first ISO can be intentionally narrow in scope. It should be enough to:

  • boot under QEMU and, where practical, on the validated virtualization path
  • expose the install workflow
  • install a target Fruix system
  • leave the machine bootable into the installed system

A polished graphical or highly interactive installer is not required here.

Success Criteria: Fruix can build a bootable installer ISO that installs a declarative Fruix-on-FreeBSD system.


Phase 19: Strengthen System Deployment and Generation Management

The current deployment model already has the important Guix-like semantic properties at the closure/store layer. This phase is about making that story more operator-facing and less harness-specific.

Intermediate Goal 19.1: Define a First-Class Fruix Deployment Workflow

Verification Goal 19.1: Define and document the canonical user-facing deployment workflow for system rebuild, image generation, installation, and rollback.

This may introduce or refine user-facing commands such as:

  • fruix system build
  • fruix system image
  • future deployment/install/switch subcommands if justified

The key goal is clarity: operators should have an obvious Fruix way to move between generations and deployments.

Success Criteria: the repo documents a coherent user-facing deployment workflow for system build, install, roll-forward, and rollback.

Intermediate Goal 19.2: Model System Generations More Explicitly

Verification Goal 19.2: Make the system-generation story more explicit in metadata and deployment roots.

This should include deciding how Fruix wants to represent:

  • current system generation
  • previous system generation
  • rollback target
  • GC roots associated with installed systems

This does not have to copy Guix System mechanically, but it should preserve the same important properties.

Success Criteria: Fruix has a clearer model for installed system generations and rollback roots rather than relying mainly on test-harness knowledge.

Intermediate Goal 19.3: Validate Installed-System Rollback as an Operator Workflow

Verification Goal 19.3: Validate rollback through the intended installed-system workflow, not only through build/image test harnesses.

This step should prove that the installation and generation model work together coherently.

Success Criteria: an installed Fruix system can move between generations using the intended operator-facing deployment model.


Phase 20: Controlled Steps Toward Self-Hosted Base Builds

Only after source identity and installation/deployment boundaries are stronger should Fruix seriously revisit self-hosted base builds.

Intermediate Goal 20.1: Validate a Fruix-Managed Development Environment for Native Base Work

Verification Goal 20.1: Ensure that a Fruix-managed system can expose the development/runtime/toolchain environment needed for deeper FreeBSD-native build work.

This should build on the cleaner runtime/development split already established in Phase 14.

The goal is not yet full self-hosting; it is to prove that the system can host the tools and profiles needed for that work in a controlled way.

Success Criteria: a Fruix-managed system can expose a usable development environment for native FreeBSD build tasks.

Intermediate Goal 20.2: Run Host-Initiated Native Base Builds Inside a Fruix-Managed Environment

Verification Goal 20.2: As an intermediate step, perform native base builds inside a Fruix-managed environment or jail while still using the host as the outer orchestrator.

This narrows the remaining gap without immediately demanding full guest self-hosting.

Success Criteria: Fruix can build native FreeBSD base artifacts from inside a Fruix-managed build environment, with the host still orchestrating the outer loop.

Intermediate Goal 20.3: Reassess and Potentially Prototype Guest Self-Hosted Base Builds

Verification Goal 20.3: Revisit guest self-hosting only after the earlier source/install/deployment goals are complete enough to make that experiment meaningful.

At that point, the question should be answered with real evidence:

  • what exactly self-hosting would improve
  • what it would cost in complexity
  • how it would fit with the source/deployment model already established

Success Criteria: the project either:

  • validates a first controlled guest self-hosted base build, or
  • records a clear evidence-based decision to continue preferring host-orchestrated native builds.

Strategic Notes

Why this order?

This sequence is intended to preserve the most important win from Plan 3 and Phase 15:

  • Fruix already has a native, store-based, rollback-friendly FreeBSD base path

The next improvement should therefore be to make the source input as explicit as the deployment output already is.

After that, Fruix can turn its successful image-generation path into a real installation story. Only then will self-hosting be judged in the right context.

Why not jump straight to self-hosting?

Because at the end of Phase 15, the biggest remaining weakness is not “where the build runs”, but “how explicitly the source is declared and acquired”.

If self-hosting were attempted immediately, it would mix together:

  • source acquisition problems
  • toolchain/profile maturity problems
  • build-environment questions
  • deployment/installation questions
  • and virtualization/operator constraints

That would make debugging and design less clear.

Why add installation work before self-hosting?

Because Fruix should become more usable as a system even if self-hosting remains a later milestone.

A real installation story would:

  • make the current system model more operator-meaningful
  • improve validation of generation/deployment semantics
  • prepare the project for broader VM and eventually hardware use
  • make later self-hosting experiments easier to stage and reproduce

What success will mean

Success under this plan means the project moves from:

  • “Fruix builds native FreeBSD base artifacts from the hosts current /usr/src and boots them successfully”

into:

  • “Fruix acquires FreeBSD sources declaratively, builds native base artifacts from pinned source inputs, installs systems through a real Fruix workflow, and approaches self-hosting from a much cleaner architectural position.”