Commit Graph

3 Commits (2a87996cbb7e4abcd4b31086cda122670034e17e)

Author SHA1 Message Date
Amir Alexander Abdelbaki 919ce94d52 Output images to iso-out/, and note why arm64 audio is one image for all rooms
Renames the image output directory from build-output/ to iso-out/ (config
default, .gitignore, docs).

Also documents the asymmetry that showed up when building a household with
several endpoints: kiosks and amd64 audio endpoints get one image per array
entry, because their hostname is baked in at build time; the arm64 audio image
is generic and built once no matter how many arm64 rooms are listed, because Pi
Imager sets hostname and Wi-Fi per unit at flash time. That is project-plan
Phase 15.5's existing decision, now reflected in what build-all actually does
rather than only in prose.

Verified with a stubbed full run of a six-endpoint household: one build-all
invocation produced nine distinctly-named images with no overwrites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 13:28:08 +02:00
Amir Alexander Abdelbaki bbeabde97e Give every config array entry its own image, and build arm64 audio once
Follow-up to the tools/ build system: the kiosk and amd64 audio-endpoint
builders left their ISO in the live-build tree under live-build's fixed
filename, and never moved it to build-output/. Configure two thin clients and
build-all would build both into the same path — the second silently overwriting
the first, leaving one ISO carrying the second room's hostname and no sign the
first was ever produced.

core_publish_image() now moves each finished image to
build-output/smarthome-<hostname>-<pairid>.iso, so one array entry produces one
artifact. Verified: two thin clients now yield two distinct ISOs, and the
per-type builders still refuse with the real list when the hostname is omitted
or wrong.

The arm64 audio endpoint is the deliberate exception and is now handled as one:
Pi Imager sets hostname/Wi-Fi per unit at flash time, so a single generic .img
serves every room and build-all builds it once regardless of how many arm64
entries are listed. amd64 has no equivalent for a generic x86 ISO, so it bakes
the hostname in and does need one per room (project-plan Phase 15.5).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 13:25:38 +02:00
Amir Alexander Abdelbaki ea82ee70ad Add tools/ and CoreSystemConfig.json — one source of truth for every build
Installation was six scripts each carrying its own copy of the container host's
IP, three that had to agree on IDENTITY_TOKEN, and every service URL typed by
hand with a port in it. Any one could be wrong, and the symptom was always the
same and always late: an image that boots fine and then can't reach something,
found after a 40-minute build and a reboot.

Two properties fix that class of bug:

- Nothing is written twice. No script in tools/ contains an IP, port or token.
- Anything derivable is derived. You give the subnet prefix once and one last
  octet per host; every address and service URL is computed from those.

THE TWINNED PAIR. container_host.ip_last_octet 12 and llm_host 13 mean the
container host's OLLAMA_HOST *is* http://<prefix>.13:11434 — computed in the
same build, not typed into two files and kept in sync. Move the LLM host to .21
and the container host's Ollama URL follows; change the subnet and both halves
move along with every kiosk's URLs. Neither image can be built pointing at an
address the other isn't using. Both carry the same SMARTHOME_PAIR_ID (a hash of
the config's meaning, not its bytes) so two USB sticks can be checked against
each other later.

validate-config.py runs before every build and refuses to start on an error, so
a mistake costs seconds not an hour. It catches duplicate ports (including the
music_assistant/pantry_vision 8095 clash that Compose can't see because MA runs
network_mode:host — open decision #31), both hosts on one address, duplicate
hostnames across kiosks and audio endpoints, placeholder tokens (checked before
the length check, so padding "changeme" to 32 chars doesn't pass), a private key
pasted where the public one goes, and a kiosk pointed at a disabled service.

build-all.sh is the normal entry point — the images are a set that has to agree
with itself, so building one is the exception. It builds the core pair, every
kiosk, and every audio endpoint including both architectures (amd64 live-build
ISO and arm64 rpi-image-gen img are different toolchains, not one image).

The two new host ISOs install unattended with everything burnt in, including
service env files generated from derived values — which permanently removes the
class of bug that had chores.env shipping IDENTITY_URL=http://127.0.0.1:8097.
setup-container-host.sh and setup-llm-host.sh now read every config value as
${VAR:-default} so the images configure them without editing.

That also makes every ISO a credential: Wi-Fi PSK, tokens, MQTT and HA
credentials are readable by anyone holding the stick. .gitignore covers the
filled-in CoreSystemConfig.json and build-output/.

Tested: 43 config validation/derivation checks and 44 builder checks against the
real code paths with only `lb` stubbed — every generated env file, preseed,
network config, first-boot unit and build stamp is verified, including that a
port collision refuses the build before writing anything. No ISO has been built;
`lb build` needs live-build, root and a long fetch. tools/README.md says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 13:22:25 +02:00