Skip to main content

max / alloy

Give astra a role contract, and document the preflight astra plays the aarch64 half of fw13's build-host roles, so it wants the same statement of what has to exist on the other side of its dials. Its recipe is the one the preflight already found broken. docs/IMAGE.md gains the preflight and, in the same section, what it cannot see: non-package /var content, packages from repos the probe does not configure, COPR packages absent from a bare base, and runtime interactions. A clean run should not be read as more than it is.
Author: Max Johnson <me@maxj.phd> · 2026-09-04 20:21 UTC
Signed with PGP, not checked
Commit: 35a55cd35b61db1f82b394d5d7eca5aa778d538d
Parent: b99edf8
2 files changed, +87 insertions, -0 deletions
@@ -285,6 +285,55 @@
285 285 `PROFILE=server` and `ARCH=aarch64`; fw12 sets no dials at all and carries only
286 286 identity and answers, below.
287 287
288 + ## Preflight
289 +
290 + `build/preflight.sh <host>` answers, before any mint, what a mint would otherwise
291 + answer slowly. Run it whenever a recipe or the package set changes:
292 +
293 + ```sh
294 + build/preflight.sh fw13 # everything
295 + build/preflight.sh fw13 --fast # the instant checks only, no probe
296 + ```
297 +
298 + Four checks:
299 +
300 + | check | how | catches |
301 + |---|---|---|
302 + | `dials` | mirrors the Containerfile's own validator | a recipe that cannot pass step 20 |
303 + | `requires` | `command -v`, `pkg-config`, `find` inside a probe image | a role's capability the mint does not deliver |
304 + | `var-payload` | `bootc container lint` on that probe | undeclared `/var` content, which fails at step 101 of 103 |
305 + | `guards` | grep, on the host | a known workaround being dropped |
306 +
307 + `build/hosts/<name>.requires` is the second half of a recipe. The `.env` says
308 + which dials to set; the `.requires` says what has to exist on the other side.
309 + That distinction is the one four thrown-away mints on 2026-09-04 turned on: every
310 + dial was set correctly and the image still could not build a Tauri app or restore
311 + a production dump, because nothing anywhere said fw13 had to be able to do either.
312 +
313 + The last two checks run against a **probe image** -- this mint's package set plus
314 + the tmpfiles files it would ship -- rather than against a prediction. Predicting
315 + was tried first and was wrong twice in the same way: `var-payload` derived bootc's
316 + rule from the symptom and flagged paths the real build accepts, and `requires`
317 + compared a capability's provider against the packages the Containerfile names, so
318 + `bin:git` failed because `/usr/bin/git` comes from `git-core`. Building the
319 + smallest image that can be asked directly removes both. It is a build, which is
320 + what the script exists to avoid, but it is one dnf transaction rather than 103
321 + steps, and it is right rather than close.
322 +
323 + **What the preflight cannot see**, stated so a clean run is not read as more than
324 + it is:
325 +
326 + - `/var` content that arrives from something other than a package. The
327 + Containerfile copies `etc/` and `usr/` and runs its own steps.
328 + - Packages the real build takes from a repo the probe does not configure.
329 + Tailscale is the measured case: a bare base resolves the name to a different
330 + build with a different payload, so it is excluded and reported rather than
331 + installed.
332 + - COPR and Terra packages, which do not resolve in a bare base at all.
333 + - Runtime interactions. linuxdeploy bundling a binutils that cannot read Fedora
334 + 43's `.relr.dyn` sections is the example, and no static check finds it. What
335 + `guards` catches is that workaround being *lost*, which is how it was.
336 +
288 337 ## The answer sheet
289 338
290 339 A recipe can also answer the questions `alloy install` would otherwise ask. The
@@ -1,0 +1,38 @@
1 + # What astra's ROLE needs, as opposed to which dials its mint sets.
2 + #
3 + # See build/hosts/fw13.requires for why this file exists at all: the recipes say
4 + # what goes in, this says what has to come out, and on 2026-09-04 every dial was
5 + # correct while the image still could not build a Tauri app or restore a prod
6 + # dump. Checked by build/preflight.sh.
7 + #
8 + # astra is the aarch64 half of the same two roles fw13 plays, plus the evidence
9 + # tier. It is a server profile, so nothing here may assume a graphical session.
10 +
11 + # --- Bento's arm64 builder: the tree's crates, and the Tauri apps
12 + bin:cargo
13 + bin:rustc
14 + bin:gcc
15 + bin:git
16 + pkgconfig:webkit2gtk-4.1
17 + pkgconfig:gtk+-3.0
18 + pkgconfig:libsoup-3.0
19 + pkgconfig:librsvg-2.0
20 + pkgconfig:openssl
21 +
22 + # --- the frontends Sando's code_smoke gate compiles
23 + bin:node
24 + bin:npm
25 +
26 + # --- PoM's runner and Sando's gates restore production dumps here too.
27 + # The extensions are not optional: a restore stops at the first CREATE EXTENSION
28 + # it cannot satisfy, which is what cost rehearsal 3 a build on 2026-09-04.
29 + bin:psql
30 + bin:postgres
31 + bin:initdb
32 + file:*/pgcrypto.control
33 + file:*/pg_trgm.control
34 +
35 + # --- the fleet control plane. ops-exec spawns rsync by name, so a machine
36 + # without it cannot collect a build from another host or hand a release over.
37 + bin:rsync
38 + bin:ssh