Skip to main content

max / alloy

Give the fw13 runbook an update path, which it did not have Phase 2 minted with `build/build-iso.sh --host fw13` and nothing in the file mentioned bootc upgrade, dev-push or a registry. Followed as written it cuts the machine to an install whose origin is `quay.io/alloy/alloy:43`, which install/image.rs calls a deliberate dead end, and whose update timer stays disabled because `updates_scheduled()` reads the same absent kernel parameter. So the first problem found on the far side costs a `bootc switch` typed at the machine, or a second medium. Phase 2 now bakes `--update-target fw13:5000/alloy:local`: the tag dev-push publishes, not the channel that does not exist, under the host name so one medium also serves fw12. It says the flag arms the auto-apply timer as a side effect and masks it, since a build host four things depend on should not stage an image because a timer fired into a registry that is usually down. Phase 5 carries the loop itself, and names the two things unproven here: the registry has never run on the target machine (alloy eca827e8), and it is a podman container that does not survive the reboot it is needed after.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01WFBzMprSmNCfvdj2cGZyka
Author: Max Johnson <me@maxj.phd> · 2026-09-05 14:56 UTC
Signed with PGP, not checked
Commit: 3c1557449aeacea602ccfe10a3cc4a5fc85df6e5
Parent: d4e3075
1 file changed, +35 insertions, -1 deletion
@@ -76,11 +76,24 @@
76 76
77 77 The image build takes over an hour and can only run on an x86_64 host, which today means fw13 itself. Build and mint before the machine goes down, not during.
78 78
79 - - `build/build-iso.sh --host fw13`, on `main`, and record the commit it was minted from. A boot test against a stale image answers a question nobody asked.
79 + - `build/build-iso.sh --host fw13 --update-target fw13:5000/alloy:local`, on `main`, and record the commit it was minted from. A boot test against a stale image answers a question nobody asked. The update target is not optional here; see below.
80 80 - Write it with `build/write-device.sh`. **Standing drive rule: the SanDisk is the install-media and scratch drive, the Samsung T9 is never a write target.**
81 81 - Treat whatever is already on the SanDisk as unknown until it is plugged in and read.
82 82 - The `rust-stage` witchbroom cell is live on astra and guards the failure class that bites here: a `SHOP_REV` bump silently adding a system build dependency and taking the image build with it.
83 83
84 + ### Bake an update target, or the machine cannot be fixed without a second install
85 +
86 + Without `--update-target` the installer writes `quay.io/alloy/alloy:43` into the deployment origin, and `crates/alloy/src/install/image.rs` calls that address a deliberate dead end rather than a plan: nothing is published there and nothing is going to be. It is written anyway because omitting `--target-imgref` makes bootc record the live medium's own mount path, which fails at reference parsing instead of degrading to "no update found".
87 +
88 + So a machine minted without the flag has no update path on the far side of Phase 4, at the point where it is newest and most likely to need one, and recovering costs a `bootc switch` typed at the machine.
89 +
90 + - The tag is `local` and not `43` because `local` is what `build/dev-push.sh` publishes. `43` names a channel that does not exist. An untagged reference is refused at build time and again at install time, because the containers stack reads a missing tag as `latest` and IMAGE.md makes a Fedora major bump a deliberate act.
91 + - The host name rather than `127.0.0.1`, so one medium serves fw12 pulling from fw13 as well as fw13 pulling from itself.
92 +
93 + **The same flag enables `bootc-fetch-apply-updates.timer`.** `updates_scheduled()` reads the same kernel parameter, on the reasoning that a medium naming a target is exactly what a development build is. bootc's cadence is an hour after boot and every eight after that, and it stages what it finds for the next boot. On a machine that four other things depend on, an image arriving because a timer fired is not something anyone asked for, and the registry it would reach is a podman container that is usually down. Mask it after the install and drive updates by hand:
94 +
95 + sudo systemctl mask --now bootc-fetch-apply-updates.timer
96 +
84 97 ## Phase 3: the no-write boot test
85 98
86 99 One reboot, nothing written. Boot the medium, stop at the disk selection screen, answer three questions, power off.
@@ -107,6 +120,27 @@
107 120
108 121 Until step 5, fw13 is a machine that boots Alloy. After it, fw13 is the x86_64 build host again (infra `28cd7d0c`).
109 122
123 + ### Fixing Alloy itself, without minting a second medium
124 +
125 + This is what the Phase 2 update target buys, and it is the loop for every "did that config land" question. An ISO is the wrong artifact for that: measured on fw13, a config-only change is fifteen seconds of `podman build` followed by an ISO assembly costing sixteen times as much, producing installer media nobody is going to install from.
126 +
127 + Once, because the dev registry speaks plain HTTP:
128 +
129 + printf '[[registry]]\nlocation = "fw13:5000"\ninsecure = true\n' \
130 + | sudo tee /etc/containers/registries.conf.d/99-alloy-dev.conf
131 +
132 + `build/dev-push.sh` also prints a `bootc switch`. It is not needed when the medium baked the same reference, so read `bootc status` before typing it. Then every fix is:
133 +
134 + podman build ... # or build/build-iso.sh --skip-source
135 + build/dev-push.sh
136 + sudo bootc upgrade && sudo systemctl reboot
137 +
138 + and a bad one is `sudo bootc rollback && sudo systemctl reboot`. Same A/B staged switch and same rollback the installer uses, with the image coming off a registry on this box rather than one on the internet.
139 +
140 + **Two things about this are unproven on fw13 specifically, and the second is a trap.** dev-push has only ever been used with the registry on a different machine from the target, and here it is both; that is alloy `eca827e8`. And the registry is a podman container that does not come back on its own after a reboot, so it has to be running at the moment `bootc upgrade` does, which is why the timer is masked in Phase 2 rather than left to fire into a closed port.
141 +
142 + Nothing here needs astra, mbp or any other machine. fw13 builds its own updates and serves them to itself.
143 +
110 144 Then the machine gets daily-driven, which is where the rest of the reading happens: s2idle drain on AMD, multi-output reconcile with the laptop panel plus the BenQ, fprintd enroll on the Goodix part, and the dark-mode L stops on this panel as a second reading against the FW12's. The migration also pays Alloy back here: fw13 on Pop runs systemd 255 and `run0` needs 256, which is why alloy `3587c247` sat on needing a host.
111 145
112 146 ## What is not recoverable