You've already forked fruix-bootstrap
358 lines
9.5 KiB
Markdown
358 lines
9.5 KiB
Markdown
# Plan 5: split Fruix bootstrap from canonical Fruix
|
|
|
|
This plan turns the boundary from `docs/bootstrap.md` into a concrete migration sequence.
|
|
|
|
The intended end state is:
|
|
|
|
- `fruix-bootstrap` prepares a plain FreeBSD host to act as a **Fruix builder**
|
|
- `fruix` is the canonical repo/channel for:
|
|
- packages
|
|
- systems
|
|
- installers
|
|
- deployment
|
|
- node lifecycle
|
|
- a booted Fruix system no longer depends on `fruix-bootstrap`
|
|
|
|
## Primary goal
|
|
|
|
Reach the point where a plain FreeBSD machine can:
|
|
|
|
1. use `fruix-bootstrap` to become a Fruix builder
|
|
2. use that builder to evaluate a pinned `fruix` checkout or revision
|
|
3. build a Fruix artifact from `fruix`
|
|
- installer ISO
|
|
- VM image
|
|
- system closure
|
|
4. boot or install that artifact
|
|
5. continue operating using only `fruix`
|
|
|
|
## Guiding rules
|
|
|
|
1. `fruix` is the only canonical home for long-lived Fruix logic.
|
|
2. `fruix-bootstrap` may wrap `fruix`, but should not fork it.
|
|
3. If a booted Fruix node should understand it, it belongs in `fruix`.
|
|
4. Bootstrap-only foreign-host glue belongs in `fruix-bootstrap`.
|
|
5. Prefer temporary wrappers over duplicated logic.
|
|
|
|
## What should move to `fruix` first
|
|
|
|
These are the highest-priority items to live in `fruix`, because they define the product rather than the bootstrap path.
|
|
|
|
### 1. Package definitions
|
|
|
|
Move first:
|
|
|
|
- `modules/fruix/packages/...`
|
|
|
|
Why:
|
|
|
|
- package definitions are canonical Fruix content
|
|
- they are part of the future channel story
|
|
- booted Fruix systems should use these directly
|
|
|
|
### 2. FreeBSD system model and system artifact logic
|
|
|
|
Move early:
|
|
|
|
- `modules/fruix/system/freebsd/model.scm`
|
|
- `modules/fruix/system/freebsd/source.scm`
|
|
- `modules/fruix/system/freebsd/build.scm`
|
|
- `modules/fruix/system/freebsd/render.scm`
|
|
- `modules/fruix/system/freebsd/media.scm`
|
|
- `modules/fruix/system/freebsd/utils.scm`
|
|
- `modules/fruix/system/freebsd/executor.scm`
|
|
- the thin facade `modules/fruix/system/freebsd.scm`
|
|
|
|
Why:
|
|
|
|
- these define what a Fruix system is
|
|
- they define build/promotion/deploy behavior
|
|
- they must remain stable across bootstrap and post-bootstrap operation
|
|
|
|
### 3. Fruix CLI semantics
|
|
|
|
Move early:
|
|
|
|
- `scripts/fruix.scm`
|
|
- the long-lived CLI behavior it implements
|
|
|
|
Why:
|
|
|
|
- command semantics belong to Fruix, not bootstrap
|
|
- installed nodes should match the host CLI model
|
|
|
|
### 4. Installed-node lifecycle logic
|
|
|
|
Move early:
|
|
|
|
- node helper/module tree logic
|
|
- `build`
|
|
- `build-base`
|
|
- `deploy`
|
|
- `reconfigure`
|
|
- `status`
|
|
- `switch`
|
|
- `rollback`
|
|
|
|
Why:
|
|
|
|
- these are core Fruix product actions after first boot
|
|
|
|
### 5. Installer and future TUI installer
|
|
|
|
Move early and keep there:
|
|
|
|
- installer environment logic
|
|
- installer ISO logic
|
|
- future TUI installer application
|
|
|
|
Why:
|
|
|
|
- the installer is a Fruix product artifact
|
|
- Fruix should be able to rebuild its own installer
|
|
|
|
### 6. Metadata formats
|
|
|
|
Move early and treat as canonical:
|
|
|
|
- system generation metadata
|
|
- deployment metadata
|
|
- promoted native-build result metadata
|
|
- any future Fruix revision/pin metadata
|
|
|
|
Why:
|
|
|
|
- metadata is part of Fruix identity
|
|
- bootstrap should consume these formats, not redefine them
|
|
|
|
## What can temporarily remain in `fruix-bootstrap`
|
|
|
|
These items are allowed to remain here while the split is in progress.
|
|
|
|
### 1. Bootstrap wrapper entrypoints
|
|
|
|
Examples:
|
|
|
|
- shell wrappers that locate the pinned `fruix` checkout
|
|
- shell wrappers that set `GUILE_LOAD_PATH`, `GUILE_PREFIX`, etc.
|
|
- entrypoints that invoke the real Fruix CLI from the foreign host
|
|
|
|
These should become thin wrappers around `fruix`, not alternate implementations.
|
|
|
|
### 2. Foreign-host dependency bring-up
|
|
|
|
Examples:
|
|
|
|
- locating or building Guile
|
|
- locating or building Shepherd support pieces
|
|
- preparing the host environment so the Fruix CLI can run
|
|
|
|
This is bootstrap territory.
|
|
|
|
### 3. Foreign-host validation harnesses
|
|
|
|
Examples:
|
|
|
|
- tests for plain-FreeBSD -> Fruix-builder bring-up
|
|
- tests that validate local bootstrap assumptions
|
|
- docs for first-time setup on vanilla FreeBSD
|
|
|
|
These stay useful here even after most Fruix logic moves out.
|
|
|
|
### 4. Temporary compatibility glue
|
|
|
|
Examples:
|
|
|
|
- wrappers that still point from bootstrap into `../fruix`
|
|
- temporary environment shims needed while the split settles
|
|
|
|
These are acceptable if they are clearly transitional and do not redefine Fruix semantics.
|
|
|
|
## What should not remain in `fruix-bootstrap`
|
|
|
|
Do not let this repo become a second home for:
|
|
|
|
- canonical package definitions
|
|
- canonical system semantics
|
|
- deployment semantics
|
|
- installer semantics
|
|
- long-lived metadata definitions
|
|
- installed-node behavior after first boot
|
|
|
|
If bootstrap needs those capabilities, it should invoke them from `fruix`.
|
|
|
|
## Proposed migration sequence
|
|
|
|
## Milestone 1: make `fruix-bootstrap` call `fruix`
|
|
|
|
Goal:
|
|
|
|
- this repo stops being the canonical implementation and becomes a launcher/bootstrap layer
|
|
|
|
Deliverables:
|
|
|
|
- define a pinned `fruix` checkout input for bootstrap
|
|
- initially a local path such as `../fruix` is acceptable
|
|
- bootstrap wrappers invoke Fruix modules/scripts from that checkout
|
|
- package/system logic is no longer edited here as the primary source of truth
|
|
|
|
Success signal:
|
|
|
|
- running the bootstrap entrypoint clearly uses `../fruix` as the canonical Fruix source
|
|
|
|
## Milestone 2: move canonical modules into `fruix`
|
|
|
|
Goal:
|
|
|
|
- all long-lived package/system logic lives in `fruix`
|
|
|
|
Deliverables:
|
|
|
|
- `modules/fruix/packages/...` live in `fruix`
|
|
- `modules/fruix/system/...` live in `fruix`
|
|
- `scripts/fruix.scm` lives in `fruix`
|
|
- this repo only wraps/invokes those files
|
|
|
|
Success signal:
|
|
|
|
- the same Fruix code is used both:
|
|
- from a foreign host via bootstrap
|
|
- from a booted Fruix node
|
|
|
|
## Milestone 3: record a pinned Fruix identity in artifacts
|
|
|
|
Goal:
|
|
|
|
- built artifacts know which Fruix revision produced them
|
|
|
|
Deliverables:
|
|
|
|
- define minimal Fruix identity metadata, such as:
|
|
- checkout path for local development
|
|
- git commit when available
|
|
- optional dirty/clean marker
|
|
- record that identity in:
|
|
- image metadata
|
|
- installer metadata
|
|
- deployed generation metadata
|
|
- installed-node metadata
|
|
|
|
Success signal:
|
|
|
|
- a system can answer: “which Fruix revision built me?”
|
|
|
|
## Milestone 4: first self-contained Fruix install from bootstrap
|
|
|
|
Goal:
|
|
|
|
- prove that bootstrap is needed only to create the first Fruix artifact
|
|
|
|
Deliverables:
|
|
|
|
- from plain FreeBSD + bootstrap, build either:
|
|
- a Fruix installer ISO, or
|
|
- a Fruix VM image
|
|
- boot/install the resulting system
|
|
- validate that the running Fruix node can perform post-boot actions using `fruix` only:
|
|
- `fruix system build`
|
|
- `fruix system build-base`
|
|
- `fruix system reconfigure`
|
|
- `fruix system deploy`
|
|
- `fruix system rollback`
|
|
|
|
Success signal:
|
|
|
|
- no runtime dependence on the bootstrap checkout is required after first boot
|
|
|
|
## Milestone 5: build the first TUI installer in `fruix`
|
|
|
|
Goal:
|
|
|
|
- the user-facing installation experience is defined by Fruix itself
|
|
|
|
Deliverables:
|
|
|
|
- minimal text/TUI installer application in `fruix`
|
|
- built into the Fruix installer environment / installer ISO
|
|
- opinionated input surface, for example:
|
|
- target disk
|
|
- hostname
|
|
- root SSH key or password
|
|
- optional operator user
|
|
- optional profile/template selection
|
|
- generated declaration and install metadata recorded by Fruix
|
|
|
|
Success signal:
|
|
|
|
- bootstrap builds the installer, but Fruix defines the installer behavior
|
|
|
|
## First split-validation milestone
|
|
|
|
The first major proof should be this:
|
|
|
|
### Bootstrap builds Fruix, then Fruix continues alone
|
|
|
|
Concretely:
|
|
|
|
1. start from plain FreeBSD
|
|
2. use `fruix-bootstrap` to create a Fruix builder
|
|
3. point it at pinned `../fruix`
|
|
4. build a Fruix VM image or installer ISO from `fruix`
|
|
5. boot the resulting Fruix system
|
|
6. on the running Fruix system, perform at least:
|
|
- `fruix system build`
|
|
- `fruix system reconfigure`
|
|
- `fruix system rollback`
|
|
7. verify none of those steps need the bootstrap checkout
|
|
|
|
This is the first meaningful architectural victory of the split.
|
|
|
|
## Recommended immediate tasks
|
|
|
|
1. add a bootstrap configuration variable for the pinned Fruix checkout
|
|
- initially defaulting to `../fruix`
|
|
2. change bootstrap wrappers to load Fruix code from that checkout
|
|
3. stop treating this repo as the canonical edit location for Fruix modules
|
|
4. move package/system/CLI logic into `fruix`
|
|
5. add minimal Fruix revision metadata recording to built artifacts
|
|
6. then proceed to the Fruix-defined TUI installer
|
|
|
|
## Temporary practical compromises
|
|
|
|
The split does not require perfection on day one.
|
|
|
|
Temporarily acceptable:
|
|
|
|
- local-path pinning to `../fruix`
|
|
- wrapper scripts in bootstrap that export environment variables for Fruix
|
|
- some bootstrap-era host assumptions while the builder path stabilizes
|
|
|
|
Not acceptable long-term:
|
|
|
|
- duplicated package definitions in both repos
|
|
- duplicated system semantics in both repos
|
|
- booted Fruix nodes depending on bootstrap logic to keep operating
|
|
|
|
## Open questions to resolve later
|
|
|
|
These do not block the boundary itself:
|
|
|
|
- exact Fruix channel/lock file format
|
|
- exact user-facing `upgrade` policy
|
|
- binary publication/substitution design
|
|
- local `jail` executor for native base builds
|
|
|
|
Those are important, but they should be built on top of the split rather than baked into the boundary prematurely.
|
|
|
|
## Summary
|
|
|
|
The migration priority is:
|
|
|
|
1. make bootstrap a thin launcher for pinned `fruix`
|
|
2. move canonical logic into `fruix`
|
|
3. record Fruix identity in artifacts
|
|
4. prove a booted Fruix node can continue without bootstrap
|
|
5. build the TUI installer in `fruix`
|
|
|
|
If this plan is followed, `fruix-bootstrap` stays small and generic, while `fruix` becomes the real long-term system source of truth.
|