Skip to content

Latest commit

 

History

History
845 lines (686 loc) · 46.7 KB

MATRIX-STATUS.md

File metadata and controls

845 lines (686 loc) · 46.7 KB

Matrix status — what is actually verified

Regenerated daily at 06:00 UTC by scripts/gen-matrix-status.py (workflow: .github/workflows/matrix-status.yml). It pushes only when a cell moves. Every cell traces to the run that proved it. This page infers nothing. A combination that no run has tested reads as untested, not as a blank.

That distinction is the point of this document. Before it existed, "no result" and "a pass" looked identical from outside. Three defects then survived for weeks, because the absence of evidence read as evidence of absence.

Meaning
✅ A named run asserted it and passed
❌ A named run asserted it and failed
⬜ Never tested. Not a pass. Not a fail. No data at all.

0. What green means

We raised the bar on 2026-08-17: green means the image works, not that it built. GREEN-CRITERIA.md defines the criteria, and .github/green-criteria.yml is the machine readable source. The criteria are these: the desktop is present and it starts, the image boots to a session, the ISO installs, the installation completes, update and rollback work, the image matches upstream, it omits no package in silence, it still rebuilds, and every architecture resolves.

One rule makes the list mean anything: skipped, never-tested and stale all count as not green. The axes below hold the evidence for each criterion.

1. Scope: what each axis proves

A pass on one axis says nothing about the others. This caught us out repeatedly, so the page states it first.

Workflow Proves Does not prove
Build The image builds and pushes That it boots
Desktop Contract Sweep The published image's desktop packages/session/DM actually landed (verify-desktop-experience.sh against the pulled image, no boot) That it boots, or that the session actually starts on real hardware
LUKS E2E ISO boots, installs to an encrypted disk, the installed system boots and unlocks That a desktop session starts, or that the installer GUI works — it drives fisherman over SSH
Installer smoke The compositor starts, autologin works, the installer frontend is running That the install completes
Live overlay The live payload (installer flatpak, autologin, polkit) builds for that variant That it works at runtime

A variant can pass LUKS E2E and still ship an ISO nobody can use, because LUKS E2E never looks at the screen. yellowfin:cosmic was exactly that: LUKS green on 2026-07-23, and nobody had once looked at its installer GUI.

A variant can also pass Build and still ship the wrong desktop entirely, with nothing else here in place to catch it. marlin:kde published with no /usr/share/wayland-sessions/ at all: the AUR-only input-remapper package failed the whole kde package set in silence (tunaOS#858). Neither LUKS E2E nor Installer smoke asks which desktop is present, only that something boots. Desktop Contract Sweep is the axis for exactly that gap, and it needs no boot.


The configured image matrix now has 147 cells. Eleven of them are Tuna Desktop (formerly Roost) cells for amd64: Marlin, Yellowfin, Albacore, Skipjack, Wahoo, Bonito, Bonito Rawhide, Grouper, Flounder, Flounder Sid and Sailfin. The guppy:gnome cell is back (2026-10-07, #2450). This status snapshot is from before these additions and does not mark them green; each needs its own image, desktop and boot evidence.

Generated by scripts/gen-matrix-status.py — do not edit this block by hand. It changes only when a cell moves, so the git history of this file records when each combination flipped.

Composite green — the bar

.github/green-criteria.yml sets the bar. A cell is green only when every criterion that blocks it, and applies to it, has a current affirmative result. A criterion that nobody ran, nobody asserted, or that CI skipped renders ⬜, and it does not count as satisfied. These criteria block today: builds, desktop, boots, parity, no_silent_omissions. These are advisory — the sections below measure them, and they do not block yet: install, lifecycle, rebuildable, arch_honesty. Unimplemented: iso. To graduate a criterion, edit enforcement: in that file. This table and the README count then tighten with no code change.

124 of 147 published cells are composite-green.

Variant gnome kde cosmic niri xfce
albacore ✅ ✅ ✅ ✅ ✅
bonito ✅ ✅ ✅ ✅ ✅
bonito-rawhide ⬜ ✅ ✅ ✅ ✅
flounder — ❌ — — ❌
flounder-sid ⬜ ⬜ — — ⬜
grouper ❌ ❌ ❌ — ❌
guppy ❌ ✅ — — ✅
hummingbird ⬜ — ❌ — —
marlin ✅ ✅ ✅ ✅ ✅
sailfin ✅ ✅ ✅ ✅ ✅
skipjack ✅ ✅ ✅ ✅ ✅
wahoo ⬜ ⬜ ⬜ — —
yellowfin ✅ ✅ ✅ ✅ ✅

Cells outside the desktop columns (base, hwe, nvidia and friends) are in the count above but not the table; only builds applies to them today.

Per-cell provenance — which run asserted which criterion, when — is machine-readable in matrix-provenance.json, regenerated with this document.

Silent omissions

52 of 52 cells clean (52 read, 0 never read).

Green criterion 8 (no_silent_omissions): the sweep runs checks/verify-package-wishlist.sh against every published image it pulls. That is the same gate new builds pass at build time. So an image that drops a package in silence, outside package-miss-allowlist.txt, reads ❌ here even when it predates the gate. A cell whose image the sweep never read — no image, a pull error, a lost job — is ⬜, not clean.

Variant gnome kde cosmic niri xfce
albacore ✅ ✅ ✅ ✅ ✅
bonito ✅ ✅ ✅ ✅ ✅
bonito-rawhide ✅ ✅ ✅ ✅ ✅
flounder — ✅ — — ✅
flounder-sid ✅ ✅ — — ✅
grouper ✅ ✅ ✅ — ✅
guppy ✅ ✅ — — ✅
hummingbird ✅ — ✅ — —
marlin ✅ ✅ ✅ ✅ ✅
sailfin ✅ ✅ ✅ ✅ ✅
skipjack ✅ ✅ ✅ ✅ ✅
wahoo ✅ ✅ ✅ — —
yellowfin ✅ ✅ ✅ ✅ ✅

Package parity

43 of 52 cells at parity (49 measured, 3 never measured).

Green criterion 7 (parity), first cadence: package-parity.yml runs scripts/package-parity.sh --audit daily, and audits every desktop package set against its own base. That shape exposes a build that applies no desktop at all (#858). ❌ covers BROKEN (no more packages than the base) and suspect (fewer than 25 added). A diff against each variant upstream reference comes next, and nothing asserts it yet.

Variant gnome kde cosmic niri xfce
albacore ✅ ✅ ✅ ✅ ✅
bonito ✅ ✅ ✅ ✅ ✅
bonito-rawhide ✅ ✅ ✅ ✅ ✅
flounder ❌ ❌ — — ❌
flounder-sid ⬜ ⬜ — — ⬜
grouper ❌ ❌ ❌ — ❌
guppy ✅ ✅ — — ✅
hummingbird ✅ ❌ ✅ ❌ —
marlin ✅ ✅ ✅ ✅ ✅
sailfin ✅ ✅ ✅ ✅ ✅
skipjack ✅ ✅ ✅ ✅ ✅
wahoo ✅ ✅ ✅ — —
yellowfin ✅ ✅ ✅ ✅ ✅

LUKS E2E

13 of 52 cells green (52 tested, 0 never tested).

The denominator is the set luks-e2e.yml schedules: every published desktop image (build_image), not only the ones that ship an ISO. That is wider than the ISO matrix below on purpose. The browser ISO builder can make an ISO from any image, so the image-only variants (sailfin, guppy, flounder-sid) need boot and install coverage too.

Variant gnome kde cosmic niri xfce
albacore ❌ ❌ ❌ ❌ ❌
bonito ❌ ✅ ✅ ❌ ✅
bonito-rawhide ❌ ✅ ✅ ❌ ❌
flounder ❌ ❌ ❌ — ❌
flounder-sid ❌ ❌ — — ❌
grouper ❌ ✅ ❌ — ❌
guppy ❌ ❌ — — ❌
gurnard — — — — —
hummingbird ❌ — ❌ — —
marlin ❌ ❌ ✅ ✅ ❌
sailfin ❌ ❌ ❌ ❌ ❌
skipjack ❌ ❌ ✅ ❌ ✅
wahoo ❌ ❌ ❌ — —
yellowfin ❌ ✅ ✅ ❌ ✅

NVIDIA cells are out of scope for this workflow — luks-e2e.yml excludes them deliberately, because -nvidia takes the identical LUKS path in headless QEMU. 39 stale pre-exclusion result(s) remain from before that change; they are not a gap and will age out.

The table above still shows a result for flounder:cosmic, flounder:gnome. .github/build-config.yml no longer declares those flavours, so luks-e2e.yml cannot schedule them and no run will ever turn them green. They are excluded from the count above — a last-measured verdict kept visible, not a gap. Same reasoning as the NVIDIA note.

Newest result 2026-10-01, oldest still-authoritative result 2026-08-06. Results older than the most recent round of fixes are the best available data, not current data.

Desktop Contract Sweep

50 of 52 cells satisfy build_scripts/checks/verify-desktop-experience.sh (52 tested, 0 never tested).

The sweep pulls the published image and runs the contract script against it directly (podman run, with no boot). It uses the same denominator as LUKS E2E above: build_image, limited to the five desktop flavors. This catches a desktop whose packages never landed, and it does not depend on whether hosted CI can boot the image at all.

Variant gnome kde cosmic niri xfce
albacore ✅ ✅ ✅ ✅ ✅
bonito ✅ ✅ ✅ ✅ ✅
bonito-rawhide ✅ ✅ ✅ ✅ ✅
flounder — ✅ — — ✅
flounder-sid ✅ ✅ — — ✅
grouper ✅ ✅ ✅ — ✅
guppy ❌ ✅ — — ✅
hummingbird ✅ — ❌ — —
marlin ✅ ✅ ✅ ✅ ✅
sailfin ✅ ✅ ✅ ✅ ✅
skipjack ✅ ✅ ✅ ✅ ✅
wahoo ✅ ✅ ✅ — —
yellowfin ✅ ✅ ✅ ✅ ✅

Newest result 2026-10-17.

Bootc Lifecycle

39 of 52 cells green (52 tested, 0 never tested).

Validates bootc image update, rebase, rollback, alias resolution, and post-switch system contracts across published stream deployments.

Variant gnome kde cosmic niri xfce
albacore ✅ ✅ ✅ ✅ ✅
bonito ✅ ✅ ✅ ✅ ✅
bonito-rawhide ❌ ❌ ❌ ❌ ❌
flounder ✅ ✅ — — ✅
flounder-sid ❌ ❌ — — ❌
grouper ✅ ✅ ✅ — ✅
guppy ✅ ✅ — — ✅
gurnard — — — — —
hummingbird ❌ ❌ ❌ ❌ —
marlin ✅ ✅ ✅ ✅ ✅
sailfin ✅ ✅ ✅ ✅ ✅
skipjack ✅ ✅ ✅ ✅ ✅
wahoo ❌ ❌ ❌ — —
yellowfin ✅ ✅ ✅ ✅ ✅

Newest result 2026-10-15.

Installer smoke

29 of 33 non-NVIDIA ISO cells have ever been tested — 88% coverage. 0 of those pass.

This is the only axis that checks whether a human could install the image. For 4 combinations, nobody has confirmed the installer appears on screen.

Variant gnome kde cosmic niri xfce
albacore ❌ ❌ ❌ ❌ ❌
bonito ❌ ❌ ❌ ❌ ❌
bonito-rawhide ❌ ❌ ❌ ❌ ❌
flounder ❌ ⬜ — — —
grouper ❌ ⬜ — — ⬜
gurnard — — — — —
hummingbird ❌ ❌ ❌ ❌ —
marlin ❌ ⬜ — — —
skipjack ❌ ❌ ❌ ❌ ❌
yellowfin ❌ ❌ ❌ ❌ ❌

cosmic, niri, xfwl4 and kde do not bring a session up on hosted CI. Nobody has diagnosed the cause -- gnome starts on the same guest, which has a render node but no 3D. See Known systemic gaps.

Live overlay

53 tags published.

Missing for 4 ISO cell(s): gurnard-pantheon, hummingbird-base, hummingbird-cosmic, hummingbird-gnome

Provenance

The run that last asserted each verdict above. A re-run of a cell moves a row here without moving the cell, so this table refreshes only when a verdict changes. Treat the dates as "no older than".

Date Run Cells
2026-10-17 39030481433 52
2026-10-15 38713238238 112
2026-10-08 37771441491 1
2026-10-01 36875090451 11
2026-10-01 36873532817 98
2026-09-10 34487443208 5
2026-09-10 34479027185 1
2026-09-10 34459513536 5
2026-09-03 33737812664 5
2026-09-01 33506738063 15
2026-08-20 32335146969 2
2026-08-19 32238167029 38

3. Known systemic gaps

NVIDIA is out of scope, not failing. luks-e2e.yml excludes -nvidia on purpose (commit 5c730e9). Those flavors take the identical LUKS path in headless QEMU, so a test there proves nothing about NVIDIA. The stale results above predate that change, and they will age out.

The honest position: NVIDIA is untested, not broken. No workflow today can test it, because a real test needs a host with an NVIDIA GPU. That is a different problem from the render-node gap above, and iso-e2e-gpu.sh does not solve it.

We plan this work; we did not abandon it. NVIDIA coverage waits on GPU capacity from the AWS grant, through runs-on. Two steps follow that capacity: add -nvidia back to the matrix filter in luks-e2e.yml, then point it at those runners. tuna-os#848 comes first, because no stage-3 flavor can build a dev ISO at all today. Until then, read the ⬜ and stale cells above as not yet covered, not as a backlog of broken cells.

The boot gate for cosmic/niri/xfwl4 is out of scope, because it cannot start. This failure differs from everything else in this section. The problem is not a compositor that will not render. It is a job that never runs. verify_boot routes those flavors to the GPU runner group for a real DRM render node. The account vCPU limit for that instance bucket is 0, so AWS rejects the fleet request and no runner ever attaches:

Failed to launch runner: failed to create fleet: VcpuLimitExceeded
... vCPU limit of 0 ... AllowedInstanceTypes:["g4dn*"]

Two independent runs confirm it: 33848074014 job 101038352430 on main, and 33948918141 job 101266051600 on a branch. Each ends No files were found ... verify-out/serial.log. No serial log, no screenshot, no compositor, because no step ran.

The scoring gave those cells ❌ on boots, which asserted a boot failure nobody observed. green-criteria.yml now puts them out of scope for that criterion, next to -asahi. Read that as not measured: ⬜ means measured and unproven, ❌ means measured and failed, and only the first holds here. The exclusion moves no cell to green, because every one still fails another blocking criterion. It reverts the moment g4dn capacity exists (tuna-os#2123). A test holds the excluded prefixes equal to the workflow routing, so the two cannot drift apart.

Not four of five. Four of five are measured, and three of them START. This section used to say that cosmic, niri, xfwl4 and kde all need a DRM render node, that GitHub runners have none, and that "no configuration change alters this". Measurement from inside the guest, not from the runner host, contradicts every part of that.

What we measure today:

flavor compositor starts? installer window what actually fails
gnome gnome-shell ✅ mapped, drives nothing — green (run 32704425971)
kde kwin_wayland ✅ mapped, page=welcome does not advance past welcome
cosmic cosmic-comp (Smithay) ✅ mapped, page=welcome, OCR matches does not advance past welcome
xfce xfwl4 (Smithay) ❌ — aborts: err=NoRenderNode
niri niri (Smithay) ? ? never measured with these diagnostics

The niri row has no measurement for a blunt reason: on albacore the image never built, so nothing existed to measure. install-zirconium.sh points greetd at dms-greeter for every niri image, and niri.sh installed the DMS suite only for AlmaLinux Kitten and CentOS Stream 10. albacore is plain AlmaLinux 10, so it got the greeter config without the greeter. The el10 list in niri.yaml ships no wallpaper daemon either, because test_niri_wallpaper_daemon.bats expects el10 to "pass through the dms branch". albacore passed through neither:

FAIL: greetd launches dms-greeter but /usr/share/quickshell/dms-greeter/DMSGreeter.qml is missing
FAIL: no wallpaper daemon (swaybg/swww/wpaperd) and no dms — background will be blank
TUNAOS_BRANDING_NIRI_FAIL variant=albacore failures=2

The build then died after three attempts, and published no image. Both ISO legs refused to build from a tag that still held a previous one. That is why niri was the only desktop red on BOTH architectures, where the rest were red on arm64 alone. The missing installer Flatpak was the arm64 half; this was the amd64 half.

The exclusion cited "Qt 6.10+", and plain AlmaLinux 10 ships qt6-qtbase-6.10.1, so the condition was narrower than its own reason. Every EL10 variant now takes the DMS branch. This makes reality match a contract the repo had already written down: verify-desktop-experience.sh says "Fedora and EL10 use DMS (quickshell) while openSUSE uses the wlroots stack". albacore was the one EL10 variant where that was false.

The arm64 ISO axis had three blockers stacked, not one

The missing arm64 installer Flatpak was not the only blocker. Once it cleared, the arm64 ISO stayed red, because a second and independent arm64 bug sat underneath. The distinction is worth a record, because the first fix looked like a failure.

Run 33997358111, albacore:kde, dispatched precisely because its amd64 ISO already passed and only arm64 failed. The Flatpak now installs — Installing app/org.tunaos.InstallerKde/aarch64/master — where it died before on error: Nothing matches org.tunaos.InstallerKde in remote tuna-os. The build then got four steps further and stopped somewhere new:

++ bash /run/tbox-customize/1/installer-recipe-backend.sh
ERROR: cannot determine the bootc backend of this image.
       No bootupd payload, no composefs pin in prepare-root.conf,
       and no systemd-boot EFI binary.

The image is not unclassifiable. The published layers of ghcr.io/tuna-os/albacore:kde-linux-arm64, read straight out of the registry, hold a complete legacy bootupd payload:

usr/lib/bootupd/updates/EFI/almalinux/grubaa64.efi
usr/lib/bootupd/updates/EFI/almalinux/shimaa64.efi
usr/lib/bootupd/updates/EFI/BOOT/BOOTAA64.EFI

That is branch 1 of the probe. The probe spelled the filename grubx64.efi, and the EFI binary suffix is the EFI architecture: x64 on x86_64, aa64 on aarch64. So both copies of the probe missed every branch on every arm64 image and took the deliberate "never guess" exit. The two copies live in live-iso/common/src/installer-recipe-backend.sh and in TUNAOS_BACKEND_PROBE_SH in scripts/lib/backend.sh. Both now glob the names, which is what the branches always meant to ask.

The test file shows why this reached production. Every fixture in test_installer_recipe_backend.bats built an x64 tree, so a suite that covered all four branches proved nothing about half the matrix. The fixtures now take the EFI arch as a parameter, and the suite asserts the aarch64 shapes next to the x64 ones.

With the probe fixed (run 34001369641, same cell), Build Live ISO passed on arm64 for the first time and produced a 5.7 GB albacore-kde-10.2-aarch64.iso. The boot gate then failed in 36 seconds:

==> Accel: tcg, CPU: max, MEM: 4096M, CPUS: 4
qemu-system-aarch64: type is NULL
qemu-system-aarch64: Virtio VGA not available. Perhaps you want to install qemu-system-modules-opengl package?
ERROR: QEMU failed to daemonize

iso-e2e.sh already chose the aarch64 emulator, the virt machine and AAVMF by host architecture. Its display device was still -vga virtio, shorthand for virtio-vga: a virtio-gpu behind a VGA-compatible PCI region, which exists only on targets with legacy VGA. The virt machine has virtio-gpu-pci, and the script now uses that there. QEMU's package hint is wrong, because the step before it had installed qemu-system-modules-opengl. The packages the runner installed show the mechanism (qemu-system-common and qemu-system-modules-opengl 8.2.2+ds-0ubuntu1.18, arm64). They ship hw-display-virtio-vga.so, but the built-in modinfo table in the aarch64 binary registers only the virtio-gpu family: hw-display-virtio-gpu, -gpu-pci, -gpu-gl and -gpu-pci-gl. So the type lookup for virtio-vga returns nothing and the file on disk never loads, where virtio-gpu-pci does.

Two things stay on record as unmeasured, not assumed. First, the gate ran under TCG (Accel: tcg), because hosted ubuntu-24.04-arm runners expose no /dev/kvm. The next run measures whether a KDE live ISO reaches its readiness marker within the 900 s timeout on four emulated vCPUs. Second, scripts/run-walkthrough.sh is still x86-only: qemu-system-x86_64, OVMF, -machine pc, -vga virtio. It is advisory in the ISO job, so arm64 cells get no installer screenshots until it learns the same three things.

Three of the four measured desktops come up and render on a GPU-less runner. Only xfwl4 aborts.

A generalisation published earlier in this branch — "kwin degrades to software, the Smithay compositors abort" — is WRONG and is withdrawn here. cosmic-comp is Smithay and it starts, renders 9/9 non-blank frames, maps its installer window and reaches the welcome screen. Whatever stops xfwl4 is specific to xfwl4, not a property of its toolkit.

Smoke run 32681262659, yellowfin:xfce, read from the live session itself:

crw-rw----+ 1 root video  226,   1 card1
crw-rw-rw-. 1 root render 226, 128 renderD128
[drm] pci: virtio-vga detected at 0000:00:02.0
[drm] features: -virgl +edid -resource_blob -host_visible

The guest has a render node. What it lacks is 3D: the two ends never negotiate virgl, because the host QEMU has no node of its own to pass through. Those are different claims, and the evidence supports only the second. Somebody collected the earlier eglinfo evidence on the runner HOST, which says nothing about what the guest can do.

gnome is the counter-example, and we now measure it instead of an assumption. On the same run it boots. gnome-shell starts through the software path in Mesa (libEGL warning: egl: failed to create dri2 screen), the installer frontend launches and stamps a window, and the walkthrough captures 9 non-blank frames across 8 distinct visual states. So a compositor CAN come up on this hardware.

The arm64 ISO axis is measured: albacore:kde boots on both architectures

Run 34006244094 (main @ 1735625f, both probe and display fixes merged) is the first run in which an arm64 live ISO went all the way through its own gate:

step iso:kde (linux-amd64) iso:kde (linux-arm64)
Provenance gate (this run published the image) pass pass
Build Live ISO pass, 6 min pass, 5.5 min
Boot gate (scripts/iso-e2e.sh) pass, 15 min 18 s, KVM pass, 15 min 21 s, TCG
Checksum, sign, verify pass pass
Upload signed ISO artifact pass pass
Installer walkthrough (advisory) cancelled at 03:18Z, see below no-op (x86-only script)
Upload to R2 skipped (walkthrough cancelled first) cancelled at 03:18Z, see below

The TCG number answers the open question from the previous section. A KDE live ISO on four emulated aarch64 vCPUs reaches its readiness marker in about 15 minutes, inside the 900 s boot-gate budget with margin. The image legs, the manifest, the signature, the KVM boot gate and the desktop contract all passed on the same run. Attest SBOM failed on Sigstore, the #1560 shape, and Promote still ran, by design.

The fan-out cancelled itself. Once kde went green, we dispatched gnome, xfce, cosmic and niri back to back at 03:18Z. Every generated build-<variant>.yml used concurrency.group: build-<variant>-${{ github.ref }} with cancel-in-progress: true, so four dispatches on main became four members of one group. Runs 299, 300 and 301 (gnome, xfce and cosmic, in dispatch order) died at birth. The newest one also cancelled the kde run above, which still had the amd64 walkthrough to capture and the arm64 ISO to upload to R2. The gates had already passed, and only the two trailing steps were lost. The group now varies per run for workflow_dispatch (${{ github.event_name == 'workflow_dispatch' && github.run_id || github.event_name }}), the same rule iso-e2e.yml and live-iso-bootc.yml already followed, and tests/test_expensive_builds_collapse_redundant_pr_runs.py asserts it for every workflow .github/build-config.yml generates. gnome, xfce and cosmic are therefore still unmeasured on the arm64 ISO axis: not failed, never run.

niri fails its own gate, on every architecture, before any ISO exists. Run 34008659578 is the first albacore:niri build under the #2349 branding gate, and the gate did its job. All three image legs (amd64, amd64-v2, arm64) end with:

  ok: greeter command dms-greeter present
  FAIL: greetd launches dms-greeter but /usr/share/quickshell/dms-greeter/DMSGreeter.qml is missing
  FAIL: no wallpaper daemon (swaybg/swww/wpaperd) and no dms — background will be blank
TUNAOS_BRANDING_NIRI_FAIL variant=albacore failures=2

The ISO jobs then failed at the provenance gate, because no image reached the registry. That is the correct consequence. The cause lies in upstream packaging, not in the package list in the manifest. The transaction installed exactly what the manifest asks for: dms-greeter 1:1.6.0-1.el10 and quickshell-git from the avengemedia/danklinux COPR, and dms and dms-cli 2:0.0.git.4694 from avengemedia/dms-git. None of those RPMs carries a .qml file. The filelists.xml of each COPR for epel-10-x86_64 says so: dms-greeter holds /usr/bin/dms-greeter plus sysusers, tmpfiles and completions, dms-cli holds /usr/bin/dms, and dms is a shell of .desktop, service and icon files.

The 1.6 line provisions the greeter and shell QML at runtime, through dms-greeter enable and dms-greeter sync. So an image built from those COPRs can never satisfy an offline check for DMSGreeter.qml, and the "no dms" branch of the background check trips on the same missing directory. The tunaos-packages recipes (dms, dms-cli, dms-greeter, quickshell) install the QML payload where the gate looks (usr/share/quickshell/dms-greeter, usr/share/dankmaterialshell), and they target el10. The factory status still lists all four as needed, not built, for el10/x86_64 and el10/aarch64. Until somebody publishes them, the el10 niri cell has no COPR-free path to green, and its COPR path is red by construction. The niri gate issue filed with this run tracks it.

What kde does — it starts, and the old claim was wrong

This page recorded kde as the flavor whose greeter and autologin session "both die instantly", on run 30234237855, and credited the render-node theory. That entry stood because the smoke capture named only greetd and cosmic-greeter in its journal line. kde runs sddm, so the capture held no unit for kde and nobody ever read what it said.

Smoke run 32704425971 is the first run that read it. kde comes up:

sddm-helper: pam_unix(sddm-autologin:session): session opened for user liveuser
sddm-helper: Starting Wayland user session: "/etc/sddm/wayland-session" ...
session 1: VTNr=1 Seat=seat0 Type=wayland Class=user Active=yes State=active

A properly seated session on seat0, VT 1. And the checks agree:

ok - compositor running (kwin_wayland)
ok - installer frontend launched (org.tunaos.InstallerKde)
ok - kde: installer is frontmost at session start
ok - kde: screen is not blank
ok - kde: screen changes between steps

kwin hits the same missing DRM node as everyone else —

kwin_wayland: Failed to open drm node : No such file or directory
kwin_wayland: couldn't find dev node for drm device
libEGL warning: egl: failed to create dri2 screen      (everywhere, llvmpipe)

— and carries on regardless. That is the difference that matters. kwin degrades to software, and xfwl4 aborts. An earlier draft of this sentence said "the Smithay compositors abort". cosmic-comp is Smithay and does not abort, so the split does not follow the toolkit. See the table above. "These desktops need a render node" is not one claim about four desktops. It is false for kde and gnome, and for xfwl4 it describes an abort, not an absence.

kde fails one step later:

not ok - installer readiness stamp present
not ok - kde: reached 'welcome' screen        (and disk, encryption, summary, install, done)

The frontend runs and the screen paints, but nothing identifies an installer window and OCR matches no screen in the spec. One file would settle which: the installer's own debug log, which records do_activate called, the window class it built, and any traceback. The capture had never collected that file on this flavor, because it read ~/.var/app/org.bootcinstaller.Installer/..., which is the gnome app id. kde is org.tunaos.InstallerKde. So the capture printed "(no installer-debug.log found)" on four of five flavors, and that string reads like a fact about the guest when it is a fact about the path. The path is fixed, and the next kde run carries the log.

What cosmic and kde share — the installer will not advance

Both come up. Both map the installer window on the welcome page. Neither gets past it.

cosmic, run 32718219267:

ok - compositor running (cosmic-comp)
ok - installer frontend launched (org.tunaos.InstallerCosmic)
ok - cosmic: screen is not blank        # 9/9 frames above stddev
ok - cosmic: reached 'welcome' screen   # seen on visual state(s) [0, 1]
not ok - cosmic: reached 'disk' screen  # not found on any state the installer advanced to
  # 1/8 transitions changed >500px; primary action activated with 'spc'
  # 2 distinct visual state(s) across 9 frames

Its readiness stamp agrees: app_id=org.tunaos.InstallerCosmic signal=first-frame page=welcome. The kde stamp says the same thing, window=ApplicationWindow signal=frame-swapped page=welcome. It matched no OCR keyword at all.

So the open question for both is not the render path, the seat, or DRM. The keyboard drive in the walkthrough — ret, then spc, then a wider focus search — does not move these frontends off their first page. gnome advances 7/8 transitions on the same harness. Nobody has yet established whether the walkthrough is the limit or the two frontends hold a real defect, and this page does not guess.

What xfce does — measured, not inferred

greetd reports only its own bookkeeping: greeter exited without creating a session, five times, up to start-limit-hit. So the compositor's own reason went nowhere for five rounds of this. The live adapters now run the session under systemd-cat -t tunaos-live-session, and smoke run 32691426582 is the first run to capture what xfwl4 itself says:

INFO  xfwl4: Starting xfwl4 on a tty using udev
INFO  xfwl4::backend::udev: Using renderD128 as primary GPU
INFO  smithay::wayland::socket: Created new socket name=Some("wayland-1")
INFO  xfwl4::core::state: Listening on wayland socket name="wayland-1"
WARN  smithay::backend::drm::device::fd: Unable to become drm master, assuming unprivileged mode
INFO  smithay::backend::drm::device: DrmDevice initializing
INFO  smithay::backend::egl::display: Successfully selected EGL platform: PLATFORM_GBM_KHR
INFO  smithay::backend::egl::display: EGL Initialized
INFO  smithay::backend::egl::display: EGL Version: (1, 5)
WARN  xfwl4::backend::udev::device: failed to initialize gpu err=NoRenderNode
ERROR xfwl4: Failed to initialize primary GPU node

So the compositor starts, it finds the render node and names it, it opens a Wayland socket and listens, and it initialises EGL on GBM. It then dies at err=NoRenderNode, from the udev device init in Smithay. That happens after it selects renderD128, and after it fails to become DRM master.

So "these desktops need a DRM render node" is worse than unproven. The compositor's own log contradicts it: the node is present, and xfwl4 names the one it picked. The open question is now specific and much smaller. Why does Smithay report NoRenderNode for a device it has just selected, and is the earlier Unable to become drm master the cause or a separate symptom? This page does not guess, because the previous five attempts guessed.

The same log shows a second and independent defect. It is a packaging bug, not a graphics one:

INFO xfwl4::core::config::xfwl4_config: Failed to reload defaults:
     /usr/local/share/xfce4/xfwl4/defaults does not exist; using hard-coded defaults
WARN xfwl4::core::util::rc: Missing value for required setting box_move
... ~45 more required settings missing ...

A distribution package does not install data under /usr/local/share, so xfwl4 ships and then looks for a defaults file its own packaging never puts there. This is not the fatal error, and it deserves a fix on its own.

kde failed the same way on run 30234237855: the plasmalogin autologin session and its greeter both exit at once (plasmalogin-helper exited with 5), in a restart loop. Somebody collected the eglinfo output cited next to it — no EGL_EXT_device_drm at all — on the runner HOST, not in the guest. It says nothing about the environment kwin_wayland runs in, and this page no longer offers it as evidence.

gnome is no longer an assumption. This page described it as "the only desktop still thought verifiable without a render node", and nobody had tested it, because the smoke matrix had never run it. It has now run, on 32681262659: it boots, the compositor and installer frontend both come up, and the walkthrough captures 9 non-blank frames over 8 visual states. It reaches welcome, encryption and summary; it does not reach the disk screen, which was a keyword gap in the screen contract — the contract had been measured against the other four frontends and never against this one.

Two real defects that run surfaced, neither of them about graphics:

  • The installer starts behind the GNOME Activities overview. The walkthrough had to press esc before it could drive anything, and records it as a failure precisely because a user booting this ISO sees the same thing. Reproduced on runs 32450214451 and 32681262659.
  • e2e-installer-gui-checks.sh had never executed. It resolved its TAP helpers to a path the guest does not have, so every assertion was command not found and the harness printed the shell's 127 as a count of failures. The per-flavor compositor and frontend assertions have therefore never run, on any flavor, in any smoke run.

scripts/iso-e2e-gpu.sh runs the harness on a GPU host and is the intended answer; somebody must drive it by hand today.

Screenshots on the GPU path. screendump returns Error: no surface once a guest scans out through virgl, and attaching VNC does not rescue it — the VNC client path does. iso-e2e.sh handles this as of #844; note that installer-walkthrough.py, run-walkthrough.sh and the weekly screenshot workflows still call screendump directly and will silently produce nothing on a GPU host.

Confirmed working, so nobody re-debugs it. The plasmalogin autologin drop-in (#833) is being read — run 30234237855 shows pam_unix(plasmalogin-autologin:session): session opened for user liveuser before the session dies on the GPU limitation above. Autologin is not the kde blocker.

Failures that look like successes. Recurring shape, worth checking for in any new harness code:

  • pgrep -f <pattern> run via bash -c matches its own command line. The bracket trick ([t]una-installer) is the fix; installer-smoke.yml documents it and other call sites still do not use it.

  • gh pr checks renders a cancelled run as fail. A superseded run is not a broken build.

  • After a partial workflow_dispatch, a bare tag such as guppy:base may still point at the previous build. Check org.opencontainers.image.version before concluding anything from it.

  • install_available skips unresolvable packages by design, so missing packages never fail a build. They surface only in /usr/share/tunaos/missing-on-*.txt inside the built image, which nothing reads on a schedule. Three package gaps were found this way in one morning: tunaos-packages#120, #121, #122.

  • A failing install cell blames the registry when the real fault is 90 lines earlier. iso-e2e.sh probes the ISO's embedded offline store and falls back to a network pull when it misses. That fallback fails after four retries ten minutes apart, so the last line of the log is a TLS timeout against ghcr.io — 40 minutes after the actual mistake, which was that the probe looked for the wrong name. Nine cells in run 30249218614 looked like a flaky registry and were not; all nine had already passed their live-ISO checks. One grep separates the two:

    passing: ==> Found canonical offline image ghcr.io/... — bootcDirect
    failing: ==> No local image in offline store, falling back to network pull
    

    Note also that (mount failed) in the offline-store diagnostics is benign — it means "already mounted", and passing cells print it too.

Two different denominators, on purpose. LUKS E2E is measured against build_image (every published desktop image), because luks-e2e.yml builds its matrix that way: the browser ISO builder can make an ISO from any image, so image-only variants (sailfin, guppy, flounder-sid) need boot and install coverage too. Installer smoke is measured against build_iso. The two totals answer different questions and should not be compared directly.


4. Apple Silicon (Asahi) hardware support

None of the axes above say anything about this — they run in QEMU/KVM on x86, and Apple Silicon needs its own kernel, DTBs, and boot chain (build_scripts/overlay/asahi.sh) that no x86 guest ever exercises. That gap is exactly how six of the eight promoted :gnome-asahi tags turned out to be unbootable on real hardware despite every other axis being green (tunaOS#776) — a tag existing in ghcr only means some build promoted it once, never that the image boots on a Mac.

scripts/verify-asahi-image.sh is the check that looks: it unpacks the image and inspects it for the asahi kernel, the 12 hardware-critical modules, Apple DTBs, the m1n1/U-Boot payloads, and the audio stack, graded against a known-working Fedora Asahi Remix image. .github/workflows/ verify-asahi.yml runs it in sweep mode daily at 05:40 UTC against every promoted :gnome-asahi tag (workflow_dispatch for one flavor at a time), so — same principle as the rest of this document — a result decays on its own if nobody re-runs it; the workflow's run history is the live, current answer. This document does not mirror it into a generated table. Only two flavors are wired up at all, where the three axes above cover many. The per-check state on this axis is also why the numbers below carry their own tracking issues instead of one matrix cell each.

As of the last full sweep:

Variant Harness Status
bonito 36 / 0 ✅ verified
grouper 36 / 0 ✅ verified
yellowfin, skipjack 29 / 7 ❌ no update-m1n1 — tunaOS#777
sailfin 27 / 9 ❌ no Apple DTBs, no U-Boot payload — tunaOS#914
marlin, flounder 23 / 13, 21 / 15 ❌ overlay never applied — stock kernel — tunaOS#911
albacore 11 / 25 ❌ stock kernel not removed — tunaOS#912
guppy — not offered — overlay is stubbed, not broken, and deliberately excluded from the sweep matrix

Only bonito and grouper are safe to hand to a user today. The installer catalog agrees. The catalog.json of bootc-installer-asahi ships exactly one hand-written entry, bonito, and does not list every *-asahi tag. Its README documents the same six-of-eight gap (tuna-os/bootc-installer-asahi#42).


5. Regenerating this document

The tables between the GENERATED markers are rewritten by scripts/gen-matrix-status.py; everything else is hand-written and the generator will not touch it. Add narrative freely outside the markers.

scripts/gen-matrix-status.py           # rewrite the block in place
scripts/gen-matrix-status.py --check   # exit 1 if it would change

It runs daily at 06:00 UTC and pushes only when something changed, so the file's git history doubles as a record of when each cell flipped.

The underlying queries, if you want to check a cell by hand:

# LUKS E2E, per cell
gh run view <run-id> --repo tuna-os/tunaOS --json jobs \
  --jq '.jobs[] | select(.name|test("^LUKS ")) | "\(.conclusion)\t\(.name)"'

# Installer smoke, per flavor
gh run view <run-id> --repo tuna-os/tunaOS --json jobs \
  --jq '.jobs[] | select(.name|test(":")) | "\(.conclusion)\t\(.name)"'

# Published overlay tags
TOK=$(curl -s 'https://ghcr.io/token?scope=repository:tuna-os/live-overlay:pull' | jq -r .token)
curl -s -H "Authorization: Bearer $TOK" \
  https://ghcr.io/v2/tuna-os/live-overlay/tags/list \
  | jq -r '[.tags[] | select(test("^sha256-")|not)] | sort | .[]'

# The ISO matrix this is measured against
yq -r '.variants[] | .id as $v | .flavors[]
       | select(.build_iso == true) | "\($v)\t\(.id)"' .github/build-config.yml

What the generator will not do

It never downgrades a cell on error. When the API call fails, the script raises and the workflow fails loudly. It does not rewrite cells to ⬜. A status page that degrades itself in quiet is worse than no status page, and it would recreate the "absence of evidence" failure this document exists to prevent.

It also reads only the conclusion values success and failure. It ignores cancelled and skipped runs, because gh reports a cancelled run in a form that a reader can easily mistake for a failure.