Files

240 lines
7.1 KiB
Markdown

# Fruix bootstrap boundary
This document defines the architectural boundary between:
- `fruix`
- `fruix-bootstrap`
The goal is to keep Fruix itself small, self-hosting, and canonical, while isolating the foreign-host bring-up logic required to get the first Fruix-capable environment running on plain FreeBSD.
## Short version
- `fruix` is the canonical source of Fruix package, system, installer, deployment, and node-management logic.
- `fruix-bootstrap` is a thin foreign-host layer that turns a plain FreeBSD installation into a **Fruix builder**.
- A booted Fruix system must be able to continue operating from `fruix` alone, without depending on `fruix-bootstrap`.
## Core concept: the Fruix builder
`fruix-bootstrap` should not be thought of as a permanent alternate Fruix implementation or a long-lived compatibility layer.
Its job is to create a **Fruix builder**: an environment capable of evaluating and materializing a pinned `fruix` revision on a non-Fruix FreeBSD host.
A Fruix builder should be able to:
- run the Fruix CLI and evaluator
- load a pinned `fruix` checkout or channel revision
- materialize Fruix package outputs
- build Fruix system closures
- build Fruix installer ISOs and VM images
- install or deploy the first Fruix system
That builder may run:
- on a plain FreeBSD machine
- in CI
- in a jail
- on a later Fruix node
The important point is that the builder is generic. It is a build/evaluation environment for Fruix, not a second product identity.
## Ownership boundary
### `fruix` owns
Anything that should still matter after first Fruix boot belongs in `fruix`.
This includes:
- package definitions
- system definitions
- source objects and source provenance logic
- native-build and promotion logic
- executor model
- system artifact materializers:
- closures
- root filesystems
- disk images
- installers
- installer ISOs
- installed-node management logic:
- build
- build-base
- deploy
- reconfigure
- switch
- rollback
- later upgrade
- installer application / TUI logic
- publication/substitution logic when added later
- metadata formats that define Fruix identity and lifecycle
Rule of thumb:
> If a booted Fruix node should conceptually understand it, it belongs in `fruix`.
### `fruix-bootstrap` owns
Anything only required to turn plain FreeBSD into a Fruix-capable builder belongs in `fruix-bootstrap`.
This includes:
- host environment checks
- locating or building bootstrap tool dependencies
- foreign-host setup glue
- wrapper entrypoints for invoking a pinned `fruix` revision
- initial bootstrap documentation
- tests for the path from vanilla FreeBSD to first Fruix-capable builder or first Fruix artifact
Rule of thumb:
> If it is only needed before Fruix exists as Fruix, it belongs in `fruix-bootstrap`.
## Dependency direction
The dependency direction must remain one-way.
Allowed:
- `fruix-bootstrap` depends on a pinned `fruix` revision
- `fruix-bootstrap` invokes `fruix` to build packages, systems, installers, and images
Not allowed:
- `fruix` depending on `fruix-bootstrap`
- a booted Fruix node needing `fruix-bootstrap` in order to keep building or upgrading itself
This keeps `fruix` canonical and prevents the bootstrap repo from becoming a second source of truth.
## Canonical source of truth
`fruix` is the only canonical home for Fruix product logic.
In particular, these should not be duplicated long-term in `fruix-bootstrap`:
- canonical package definitions
- canonical system logic
- installer workflow semantics
- deployment semantics
- long-lived metadata definitions
- installed-node lifecycle behavior
`fruix-bootstrap` may temporarily wrap or seed those capabilities, but it should consume them from `fruix`, not fork them.
## Pinning
`fruix-bootstrap` should operate on a clear Fruix identity, not an ambient checkout with unclear provenance.
Initially, that identity can be simple:
- a local checkout path
- a git commit
- a tag
- a branch plus locked commit
Later, this can become a proper Fruix channel lock/update model.
Whatever form is used, the important property is:
> the first Fruix artifact is built from a known `fruix` identity.
That identity should eventually be recorded in:
- installer metadata
- image metadata
- deployed generation metadata
- installed-node metadata
## Product flow
The intended lifecycle is:
1. start from plain FreeBSD
2. use `fruix-bootstrap` to create a Fruix builder
3. point that builder at a pinned `fruix` revision
4. materialize artifacts from `fruix`, such as:
- package outputs
- system closures
- installer ISOs
- VM images
- installed systems
5. boot or install the resulting Fruix system
6. from that point onward, use `fruix` alone to move the system forward
In short:
```text
plain FreeBSD
-> fruix-bootstrap
-> Fruix builder
-> pinned fruix revision
-> build/install/deploy Fruix artifacts
-> booted Fruix node
-> future lifecycle managed by fruix
```
## Installer implication
The installer UI and workflow belong to `fruix`, not `fruix-bootstrap`.
Why:
- the installer is part of the Fruix product surface
- Fruix should be able to build its own installer artifacts
- installed systems should be traceable to a pinned Fruix revision
- later Fruix nodes should be able to rebuild the installer without returning to bootstrap-only logic
So the split should be:
- `fruix-bootstrap`: makes it possible to build the installer
- `fruix`: defines the installer artifact and the TUI installer behavior
## Success criteria
The boundary is working when all of the following are true:
1. a plain FreeBSD host can become a Fruix builder using `fruix-bootstrap`
2. that builder can build a Fruix installer ISO or VM image from a pinned `fruix` revision
3. the resulting Fruix system boots without requiring `fruix-bootstrap`
4. the booted Fruix system can keep using `fruix` for:
- build
- build-base
- reconfigure
- deploy
- rollback
- later upgrade
5. package and system evolution happens in `fruix`, not in duplicated bootstrap logic
## Non-goals
This split does not mean:
- `fruix-bootstrap` becomes a permanent parallel Fruix distribution
- booted Fruix nodes should keep consulting bootstrap state
- bootstrap should own package or system semantics long-term
It also does not require all historical bootstrap leakage to disappear immediately. Some transitional host assumptions may remain for a while, but they should be treated as technical debt against this boundary.
## Working rule for future refactors
When deciding where code belongs, ask:
> Should a booted Fruix node still care about this?
- If yes, it belongs in `fruix`.
- If no, and it only exists to bring up Fruix from foreign FreeBSD, it belongs in `fruix-bootstrap`.
## Current direction
Near-term work should follow this boundary:
- keep bootstrap generic and thin
- move as much canonical logic as possible into `fruix`
- make the first user-facing installer a Fruix-defined product artifact
- ensure installed nodes record and operate from a pinned Fruix identity
That gives Fruix a clean product story:
- bootstrap creates a Fruix builder
- Fruix builds Fruix
- Fruix systems move forward using Fruix