velxio/backend/app/services/boot_images/manifest.json

101 lines
4.6 KiB
JSON
Raw Normal View History

feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
{
"_comment": "Source of truth for QEMU boot files. Adding a new board kind means appending an entry under image_sets; the BootImageProvider picks it up via load_manifest() with no Python edits. SHA256s are verified after download; mismatches raise IntegrityError and the cache slot is not populated. See docs/BOOT_IMAGES.md for the architecture.",
"version": 1,
"image_sets": {
feat(pi3): switch from raspi3b to virt + virtio (Phase 1) raspi3b pl011 RX is broken in QEMU 10 + kernel 6.12 — see project/pi-emulation/decisions.md for the full debugging trail. This commit lands Phase 1 of the rebuild: switch the QEMU machine to virt + cortex-a53, boot the velxio kernel/initramfs/rootfs over virtio-blk-pci, and expose the user shell on /dev/hvc0 via virtio-serial-pci + virtconsole. End-to-end smoke verified: boot → agetty autologin → bash prompt → echo round-trip returns the typed token. Tested inside the prod container with QEMU 10.0.8 and our cloud-derived kernel 6.12.88. What changed: backend/app/services/qemu_manager.py PI3_IMAGE_SET -> raspberry-pi-3-virt PI3_KERNEL_NAME / PI3_INITRAMFS_NAME / PI3_ROOTFS_NAME new QEMU cmd rewritten end-to-end: -M virt -cpu cortex-a53 -smp 4 -m 1G -kernel <velxio-kernel-arm64> -initrd <velxio-initramfs-arm64.cpio.gz> -drive ... -device virtio-blk-pci (NOT virtio-blk-device — mmio variant left /dev/vda unregistered) -nic none -display none -monitor none -serial none -chardev socket... -device virtio-serial-pci -device virtconsole (user console -> /dev/hvc0) -chardev socket... -device virtserialport,name=velxio-protocol (Phase 2 channel -> /dev/vport0p2) No -dtb (virt generates its own), no -append init=... (kernel runs our initramfs which then switch_root to rootfs and exec's its /sbin/init — Alpine OpenRC). backend/app/services/boot_images/manifest.json New image set raspberry-pi-3-virt with three assets uploaded via the existing license-endpoint pipeline. Old raspberry-pi-3 entry flagged deprecated:true and kept for one release for rollback. test/pi3_console_boot/test_pi3_console_boot.py Updated QEMU argv to match qemu_manager exactly. Markers now look for the Velxio Pi Simulator MOTD + 'login on hvc0' (autologin proof). Round-trip echo still required to pass.
2026-05-18 10:36:02 +07:00
"raspberry-pi-3-virt": {
"description": "Raspberry Pi 3 simulator on QEMU -M virt + cortex-a53. Velxio-built minimal ARM64 kernel + initramfs + Alpine-based rootfs. Replaces the broken raspi3b path (pl011 RX bug in QEMU 10 + kernel 6.12 \u2014 see project/pi-emulation/decisions.md for the full trail). Used by app.services.qemu_manager.",
feat(pi3): switch from raspi3b to virt + virtio (Phase 1) raspi3b pl011 RX is broken in QEMU 10 + kernel 6.12 — see project/pi-emulation/decisions.md for the full debugging trail. This commit lands Phase 1 of the rebuild: switch the QEMU machine to virt + cortex-a53, boot the velxio kernel/initramfs/rootfs over virtio-blk-pci, and expose the user shell on /dev/hvc0 via virtio-serial-pci + virtconsole. End-to-end smoke verified: boot → agetty autologin → bash prompt → echo round-trip returns the typed token. Tested inside the prod container with QEMU 10.0.8 and our cloud-derived kernel 6.12.88. What changed: backend/app/services/qemu_manager.py PI3_IMAGE_SET -> raspberry-pi-3-virt PI3_KERNEL_NAME / PI3_INITRAMFS_NAME / PI3_ROOTFS_NAME new QEMU cmd rewritten end-to-end: -M virt -cpu cortex-a53 -smp 4 -m 1G -kernel <velxio-kernel-arm64> -initrd <velxio-initramfs-arm64.cpio.gz> -drive ... -device virtio-blk-pci (NOT virtio-blk-device — mmio variant left /dev/vda unregistered) -nic none -display none -monitor none -serial none -chardev socket... -device virtio-serial-pci -device virtconsole (user console -> /dev/hvc0) -chardev socket... -device virtserialport,name=velxio-protocol (Phase 2 channel -> /dev/vport0p2) No -dtb (virt generates its own), no -append init=... (kernel runs our initramfs which then switch_root to rootfs and exec's its /sbin/init — Alpine OpenRC). backend/app/services/boot_images/manifest.json New image set raspberry-pi-3-virt with three assets uploaded via the existing license-endpoint pipeline. Old raspberry-pi-3 entry flagged deprecated:true and kept for one release for rollback. test/pi3_console_boot/test_pi3_console_boot.py Updated QEMU argv to match qemu_manager exactly. Markers now look for the Velxio Pi Simulator MOTD + 'login on hvc0' (autologin proof). Round-trip echo still required to pass.
2026-05-18 10:36:02 +07:00
"images": [
{
"name": "velxio-kernel-arm64",
"asset_id": "velxio-kernel-arm64",
"sha256": "76652d46bee27fe46f92c21adf9e67964356774ff4f6abe4f009344aacd3acd9",
"size_bytes": 30697408,
"version": "2026.05+v6.12.88-deb13-cloud"
},
{
"name": "velxio-initramfs-arm64.cpio.gz",
"asset_id": "velxio-initramfs-arm64",
"sha256": "9a1ecd1c83a65207562b8395fcc57cc9218f16cf240dd4b5cf84e13ef0b34efe",
"size_bytes": 1032327,
"version": "2026.05"
},
{
"name": "velxio-pi-rootfs-arm64.ext4",
"asset_id": "velxio-pi-rootfs-arm64-zst",
"sha256": "d6d4a2747d18055493a621f28bf2552e94dc2a11b1586d64b0eeb3847c7e06be",
feat(pi3): switch from raspi3b to virt + virtio (Phase 1) raspi3b pl011 RX is broken in QEMU 10 + kernel 6.12 — see project/pi-emulation/decisions.md for the full debugging trail. This commit lands Phase 1 of the rebuild: switch the QEMU machine to virt + cortex-a53, boot the velxio kernel/initramfs/rootfs over virtio-blk-pci, and expose the user shell on /dev/hvc0 via virtio-serial-pci + virtconsole. End-to-end smoke verified: boot → agetty autologin → bash prompt → echo round-trip returns the typed token. Tested inside the prod container with QEMU 10.0.8 and our cloud-derived kernel 6.12.88. What changed: backend/app/services/qemu_manager.py PI3_IMAGE_SET -> raspberry-pi-3-virt PI3_KERNEL_NAME / PI3_INITRAMFS_NAME / PI3_ROOTFS_NAME new QEMU cmd rewritten end-to-end: -M virt -cpu cortex-a53 -smp 4 -m 1G -kernel <velxio-kernel-arm64> -initrd <velxio-initramfs-arm64.cpio.gz> -drive ... -device virtio-blk-pci (NOT virtio-blk-device — mmio variant left /dev/vda unregistered) -nic none -display none -monitor none -serial none -chardev socket... -device virtio-serial-pci -device virtconsole (user console -> /dev/hvc0) -chardev socket... -device virtserialport,name=velxio-protocol (Phase 2 channel -> /dev/vport0p2) No -dtb (virt generates its own), no -append init=... (kernel runs our initramfs which then switch_root to rootfs and exec's its /sbin/init — Alpine OpenRC). backend/app/services/boot_images/manifest.json New image set raspberry-pi-3-virt with three assets uploaded via the existing license-endpoint pipeline. Old raspberry-pi-3 entry flagged deprecated:true and kept for one release for rollback. test/pi3_console_boot/test_pi3_console_boot.py Updated QEMU argv to match qemu_manager exactly. Markers now look for the Velxio Pi Simulator MOTD + 'login on hvc0' (autologin proof). Round-trip echo still required to pass.
2026-05-18 10:36:02 +07:00
"size_bytes": 629145600,
"version": "2026.05+phase2-shims-final",
feat(pi3): switch from raspi3b to virt + virtio (Phase 1) raspi3b pl011 RX is broken in QEMU 10 + kernel 6.12 — see project/pi-emulation/decisions.md for the full debugging trail. This commit lands Phase 1 of the rebuild: switch the QEMU machine to virt + cortex-a53, boot the velxio kernel/initramfs/rootfs over virtio-blk-pci, and expose the user shell on /dev/hvc0 via virtio-serial-pci + virtconsole. End-to-end smoke verified: boot → agetty autologin → bash prompt → echo round-trip returns the typed token. Tested inside the prod container with QEMU 10.0.8 and our cloud-derived kernel 6.12.88. What changed: backend/app/services/qemu_manager.py PI3_IMAGE_SET -> raspberry-pi-3-virt PI3_KERNEL_NAME / PI3_INITRAMFS_NAME / PI3_ROOTFS_NAME new QEMU cmd rewritten end-to-end: -M virt -cpu cortex-a53 -smp 4 -m 1G -kernel <velxio-kernel-arm64> -initrd <velxio-initramfs-arm64.cpio.gz> -drive ... -device virtio-blk-pci (NOT virtio-blk-device — mmio variant left /dev/vda unregistered) -nic none -display none -monitor none -serial none -chardev socket... -device virtio-serial-pci -device virtconsole (user console -> /dev/hvc0) -chardev socket... -device virtserialport,name=velxio-protocol (Phase 2 channel -> /dev/vport0p2) No -dtb (virt generates its own), no -append init=... (kernel runs our initramfs which then switch_root to rootfs and exec's its /sbin/init — Alpine OpenRC). backend/app/services/boot_images/manifest.json New image set raspberry-pi-3-virt with three assets uploaded via the existing license-endpoint pipeline. Old raspberry-pi-3 entry flagged deprecated:true and kept for one release for rollback. test/pi3_console_boot/test_pi3_console_boot.py Updated QEMU argv to match qemu_manager exactly. Markers now look for the Velxio Pi Simulator MOTD + 'login on hvc0' (autologin proof). Round-trip echo still required to pass.
2026-05-18 10:36:02 +07:00
"compressed": {
"encoding": "zstd",
"sha256": "debd1c339dc8a6e0c72494a14f032d69f3579f4f55929ca45446f030415602ca",
"size_bytes": 24733697
feat(pi3): switch from raspi3b to virt + virtio (Phase 1) raspi3b pl011 RX is broken in QEMU 10 + kernel 6.12 — see project/pi-emulation/decisions.md for the full debugging trail. This commit lands Phase 1 of the rebuild: switch the QEMU machine to virt + cortex-a53, boot the velxio kernel/initramfs/rootfs over virtio-blk-pci, and expose the user shell on /dev/hvc0 via virtio-serial-pci + virtconsole. End-to-end smoke verified: boot → agetty autologin → bash prompt → echo round-trip returns the typed token. Tested inside the prod container with QEMU 10.0.8 and our cloud-derived kernel 6.12.88. What changed: backend/app/services/qemu_manager.py PI3_IMAGE_SET -> raspberry-pi-3-virt PI3_KERNEL_NAME / PI3_INITRAMFS_NAME / PI3_ROOTFS_NAME new QEMU cmd rewritten end-to-end: -M virt -cpu cortex-a53 -smp 4 -m 1G -kernel <velxio-kernel-arm64> -initrd <velxio-initramfs-arm64.cpio.gz> -drive ... -device virtio-blk-pci (NOT virtio-blk-device — mmio variant left /dev/vda unregistered) -nic none -display none -monitor none -serial none -chardev socket... -device virtio-serial-pci -device virtconsole (user console -> /dev/hvc0) -chardev socket... -device virtserialport,name=velxio-protocol (Phase 2 channel -> /dev/vport0p2) No -dtb (virt generates its own), no -append init=... (kernel runs our initramfs which then switch_root to rootfs and exec's its /sbin/init — Alpine OpenRC). backend/app/services/boot_images/manifest.json New image set raspberry-pi-3-virt with three assets uploaded via the existing license-endpoint pipeline. Old raspberry-pi-3 entry flagged deprecated:true and kept for one release for rollback. test/pi3_console_boot/test_pi3_console_boot.py Updated QEMU argv to match qemu_manager exactly. Markers now look for the Velxio Pi Simulator MOTD + 'login on hvc0' (autologin proof). Round-trip echo still required to pass.
2026-05-18 10:36:02 +07:00
}
}
]
},
feat(pi): Phase 3.3 — Pi Zero / Pi 1 / Pi 2 armhf simulators Closes the deferred Phase 3.3. Root-causes the Pi 2 "Attempted to kill init" panic as `mount /dev/vda` failing with EINVAL — Debian armmp does not have ext4 builtin (only fuseblk in /proc/filesystems). - qemu_manager: PI_CONFIGS gains raspberry-pi-zero / -1 / -2 entries. All three use the armmp armhf kernel + Cortex-A7 CPU + the mmio virtio transport (arm-32 virt PCI fails -75 due to missing reg DT property). Pi Zero / Pi 1 get the small 1-core / 512 MB profile; Pi 2 gets 4-core / 1 GB. QEMU command builder branches on cfg.bus for virtio-blk-pci vs virtio-blk-device (and serial likewise). - manifest.json: new `raspberry-pi-armhf` image_set wiring three assets (kernel + initramfs + zstd rootfs). - Frontend BoardKind gains the three new kinds + an isPiBoardKind() helper. Replaces the eight scattered `=== 'raspberry-pi-3' || === 'raspberry-pi-4' || === 'raspberry-pi-5'` branches in useSimulatorStore, Interconnect, loadExample, boardProtocols. ComponentRegistry gets three new picker entries. - board-kinds-coverage test: ACCEPTED_UNCOVERED gains the new kinds (backend boards have no canvas examples). The matching armhf build-pi-kernel.sh / build-pi-rootfs.sh changes live in velxio-prod's scripts/ (private overlay) — the upstream kernel build script only knows about arm64; armhf is built in the private repo because the assets ship through the license endpoint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 04:23:48 +07:00
"raspberry-pi-armhf": {
"description": "Raspberry Pi Zero / 1 / 2 simulator on QEMU -M virt + cortex-a7. Velxio-built armhf kernel (Debian armmp) + initramfs (bundled ext4 + jbd2 + mbcache + crc16 + crc32c_generic + virtio_blk + virtio_mmio) + Alpine-based armhf rootfs. arm-32 virt PCI is broken (missing reg DT prop) so the QEMU command uses the mmio virtio transport; Pi Zero / Pi 1 share this image set with Pi 2 because the real ARMv6 silicon they have isn't supported by any QEMU-virt-capable upstream kernel.",
"images": [
{
"name": "velxio-kernel-armhf",
"asset_id": "velxio-kernel-armhf",
"sha256": "9d7377c33b9a5631e99ab109c8d3d9d89f99331b53eb8cc755cd76e775c9d0d5",
"size_bytes": 6033920,
"version": "2026.05+v6.12.88-armmp+ext4mods"
},
{
"name": "velxio-initramfs-armhf.cpio.gz",
"asset_id": "velxio-initramfs-armhf",
"sha256": "611eb3d219cb5d71a534d417dea564ed6eadbd2d1b40e33d28bb4a5a5f5829f5",
"size_bytes": 1390924,
"version": "2026.05+ext4mods"
},
{
"name": "velxio-pi-rootfs-armhf.ext4",
"asset_id": "velxio-pi-rootfs-armhf-zst",
"sha256": "5f2eafc0e76acc9ecc79da42313c1ffaacd577f42df5a58934d97ea167fab4ee",
"size_bytes": 629145600,
"version": "2026.05+phase2-shims-armhf",
"compressed": {
"encoding": "zstd",
"sha256": "ce9037b371aa1e847f2ce16bf6b0067c4ef51d48b66fe4c2d79941cbdff37b30",
"size_bytes": 23322299
}
}
]
},
feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
"raspberry-pi-3": {
"description": "[DEPRECATED \u2014 kept for one release to ease rollback] Original raspi3b setup. Replaced by 'raspberry-pi-3-virt' (see above). qemu_manager.py no longer references this entry; do not add new clients here.",
feat(pi3): switch from raspi3b to virt + virtio (Phase 1) raspi3b pl011 RX is broken in QEMU 10 + kernel 6.12 — see project/pi-emulation/decisions.md for the full debugging trail. This commit lands Phase 1 of the rebuild: switch the QEMU machine to virt + cortex-a53, boot the velxio kernel/initramfs/rootfs over virtio-blk-pci, and expose the user shell on /dev/hvc0 via virtio-serial-pci + virtconsole. End-to-end smoke verified: boot → agetty autologin → bash prompt → echo round-trip returns the typed token. Tested inside the prod container with QEMU 10.0.8 and our cloud-derived kernel 6.12.88. What changed: backend/app/services/qemu_manager.py PI3_IMAGE_SET -> raspberry-pi-3-virt PI3_KERNEL_NAME / PI3_INITRAMFS_NAME / PI3_ROOTFS_NAME new QEMU cmd rewritten end-to-end: -M virt -cpu cortex-a53 -smp 4 -m 1G -kernel <velxio-kernel-arm64> -initrd <velxio-initramfs-arm64.cpio.gz> -drive ... -device virtio-blk-pci (NOT virtio-blk-device — mmio variant left /dev/vda unregistered) -nic none -display none -monitor none -serial none -chardev socket... -device virtio-serial-pci -device virtconsole (user console -> /dev/hvc0) -chardev socket... -device virtserialport,name=velxio-protocol (Phase 2 channel -> /dev/vport0p2) No -dtb (virt generates its own), no -append init=... (kernel runs our initramfs which then switch_root to rootfs and exec's its /sbin/init — Alpine OpenRC). backend/app/services/boot_images/manifest.json New image set raspberry-pi-3-virt with three assets uploaded via the existing license-endpoint pipeline. Old raspberry-pi-3 entry flagged deprecated:true and kept for one release for rollback. test/pi3_console_boot/test_pi3_console_boot.py Updated QEMU argv to match qemu_manager exactly. Markers now look for the Velxio Pi Simulator MOTD + 'login on hvc0' (autologin proof). Round-trip echo still required to pass.
2026-05-18 10:36:02 +07:00
"deprecated": true,
feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
"images": [
{
"name": "kernel8.img",
"asset_id": "kernel8-pi3",
"sha256": "2f87328ab8d36c266ac0545e59a7eed53841e146a75e0010929d3dafd0209310",
"size_bytes": 24367616,
"version": "2026-03-11+raw"
feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
},
{
"name": "bcm2710-rpi-3-b.dtb",
"asset_id": "dtb-bcm2710-rpi-3-b",
"sha256": "496fa7723583a0374b5b2e2be997301368d70b411a47bc74a394291c3636ad13",
"size_bytes": 34687,
"version": "2026-04-21"
},
{
"name": "raspios-trixie-armhf.img",
"asset_id": "raspios-trixie-armhf-zst",
"sha256": "1c5d05449be589fcdbc3283364462d40dd5efbc685e2bd5169fd857a311ff5b0",
feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
"size_bytes": 5729419264,
"version": "2026-04-21+ttyAMA1",
feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
"compressed": {
"encoding": "zstd",
"sha256": "2f5e62277cba51bc66f4a2d76666eae34e8ef5a1fbba4169b9f2824830afe115",
"size_bytes": 1488004697
feat(sim): boot_images module + Pi 3 emulation restored Pi 3 simulation had been broken since at least April 2026 (51 fail-events / 24h per docs/PI3_EMULATION_BROKEN.md). Two distinct defects compounded: 1. qemu_manager.py hard-coded paths for kernel8.img, a device-tree blob (under a DOS 8.3 short name!), and a 5.4 GiB Raspberry Pi OS SD image — none of which shipped in the repo or were pulled at image build. 2. qemu-system-arm + qemu-utils were missing from the Docker image entirely, so even with the boot files in place QEMU couldn't launch. Add both to Dockerfile.standalone (~200 MB). The architecture fix is a new `app.services.boot_images` module: * Manifest-driven (boot_images/manifest.json, versioned in repo, declares SHA256 + size for each file, supports an optional `compressed.{encoding,sha256,size_bytes}` block for assets shipped as .zst). * `BootImageProvider` materialises files lazily, atomically (temp + rename), verifies SHA256 pre- AND post-decompression, caches under /var/cache/velxio/boot-images, serialises concurrent get() calls per image set via asyncio.Lock. * `AssetDownloader` Protocol with two impls: - `LicenseGatedDownloader` — same flow ESP32 / RISC-V QEMU libs use (VELXIO_BINARY_BASE_URL + VELXIO_LICENSE_KEY). - `LocalDirectoryDownloader` — for tests + in-prod use where the licence-module storage is already on the same filesystem (saves the loopback HTTP roundtrip on a 1.4 GiB blob). * `build_downloader_from_env()` picks one — local-dir wins if both sets of env vars are present, so the prod box short-circuits to direct disk reads automatically. * Lifespan hook in qemu_manager.py pre-warms the cache on container boot so first-time user requests don't pay the 30-60 s download + decompress latency. Adding a future board kind (Pi 4 / Pi 5) is now: upload assets via upload-binary.sh, append an entry to manifest.json, register a lifespan pre-warm in the new board's service module. Zero edits to provider.py / downloader.py. Manifest entries for raspberry-pi-3: kernel8.img 9 695 883 bytes (uncompressed) bcm2710-rpi-3-b.dtb 34 687 bytes (uncompressed) raspios-trixie-armhf.img 5 729 419 264 bytes raw / 1 488 002 803 bytes .zst on wire (zstd -19) source: 2026-04-21 build from raspberrypi.com Tests: 21 new unit tests covering manifest parsing, integrity helpers, both downloaders, and the provider's idempotent / concurrent / integrity / decompression / warmup paths. In-process FakeDownloader keeps the suite under 1 s and httpx-free. Docs: new docs/BOOT_IMAGES.md describes the architecture, on-disk layout, named-volume operation, and the procedure for adding a new image set.
2026-05-16 10:41:01 +07:00
}
}
]
}
}
}