The dev->main merge left the channel block in flake.nix pointing at
radiantwave-dev, so prod ISOs built from main shipped the dev app (which
versions itself by short git hash) and the updater polled the dev Attic
manifest. Restore the channel block to main values, re-pin flake.lock to
the latest radiantwave main revision, and expose channelName so the prod
build workflows can fail fast if main ever resolves to the dev channel.
Consolidates 8 closures to only 4 by using a git branch selector that sets
the values for -dev variants of each closure.
Reference the 'Verifying KioskConfig builds are in the right branch' note
in Obsidian for more reference.
All variants now follow the same update procedure as the dev flakes;
prod variants pull the RadiantWave binary, Attic repo, and manifest
from the radiantwave channel instead of radiantwave-dev.
RemainAfterExit=true kept the oneshot 'active' forever, which broke the
timer's OnUnitActiveSec re-arming: the timer fired once (NEXT emptied,
Trigger n/a) and never polled again. Remove it so the service returns to
dead and the 2-min cadence keeps firing.
nix-store -r was fetching the closure without --add-root, so the swapped-in
app pointer wasn't a GC root and the running closure could be collected.
Pin it with --add-root .current-root, and root the already-current closure
on the no-op path too.
nix copy --from <attic> only pulls from that single store, so nixpkgs
deps (e.g. sqlite) that Attic skips and leaves on cache.nixos.org were
missing -> 'path is not valid'. Realize the closure through the machine's
substituters so the app comes from the dev Attic and its upstream deps
resolve from cache.nixos.org, without building from source.
Add a radiantwave-updater NixOS module that polls a manifest on the
fileserver and swaps the app pointer /var/lib/radiantwave/current to new
closures fetched from the dev Attic cache. Closures are fetched with
'nix copy --from', never built from source; the swap is atomic via
mv -T.
Enable it on the -dev variants only for now: the login shell launches
from /var/lib/radiantwave/current/bin/radiantwave when enabled, and from
the immutable system path otherwise, so prod behavior is unchanged. The
pointer is seeded on first boot to the baseline copy already baked into
the closure (no duplication).
HDMI-A-1 refers to the HDMI port closest to the power cable.
In all models, we end up connecting HDMI to port 2.
HDMI-A-1 was likely taking over, becuase it suddenly had a valid
EDID assigned, indicating 'a monitor is connected here'
The RadiantWave app can now apply pending updates by restarting its own
TTY session (plain systemctl, no sudo): getty re-autologins kiosk and
the login shell relaunches cage + app from the new generation.
Also drop the cleanRadiantFiles activation script.
The case bracket expression [\ space\'\"] listed the letters s,p,a,c,e
as a character set instead of matching whitespace, rejecting every normal
path. Use the POSIX [[:space:]] class.
The inline find -exec broke through the double shell hop (the remote
shell consumed the ; separator). The script pipes its payload to remote
bash via stdin, tolerates zero matches, and fails loudly on missing
directories or failed moves.
- Wire -dev variants to the radiantwave-dev input (?ref=dev); prod keeps main
- Fix android-dev upgradeFlakeRef (was upgrading into production config)
- Parameterize one installer module (zero-touch-installer.nix); replace the
four near-duplicate ISO configs; mkIso pairs each ISO with its closure +
disk layout, fixing commercial-dev/android-dev ISO eval errors
- Add missing packages outputs (commercial-dev, android-dev, rpi, rpi-dev)
- Set networking.hostName + system.configurationRevision per variant
- Remove gitea access token and dead netrc/JWT config (repos are public)
- Drop flake.lock update step from CI (lock updates are manual)
- Refresh AGENTS.md: variants/ISO tables, facter report procedure, gotchas