Files
Nomarchy/bin/utils/nomarchy-eval-matrix
Bernardo Magri 3bdfc3552e feat: bump to NixOS 26.05 (Yarara) — WIP, desktop unverified on hardware
Bumps nixpkgs nixos-25.11 -> nixos-26.05, home-manager release-25.11 ->
release-26.05, and pins stylix to release-26.05 (was unpinned master).
`nix flake check --no-build` and `nomarchy-eval-matrix` are both clean and
the full system builds (nixos-system-nomarchy-26.05).

Breaking-change fixes required by 26.05:
- stylix-compat: drop the `programs.neovim.initLua` shim — HM 26.05 declares
  it natively, so the shim was a duplicate-option error.
- swww was renamed to awww (binaries gone, no `init` subcommand). Dropped swww
  entirely and unified the wallpaper path on swaybg (the daemon this distro
  actually runs): nomarchy-theme-bg-next now delegates to nomarchy-theme-bg-set,
  swaybg added to the theme-engine script deps, swww removed from package lists.
- default config: add a placeholder `fileSystems."/"` — 26.05's systemd stage-1
  forces fsType during plain toplevel eval (the VM build overrides it).
- services.resolved: extraConfig removed, domains/fallbackDns renamed -> migrated
  to settings.Resolve.* (RFC42).
- systemd.sleep.extraConfig removed -> settings.Sleep.HibernateDelaySec (RFC42).
- X11 'virtio' video driver removed -> dropped from vm-guest.nix and
  nomarchy-live.nix (modesetting drives virtio-gpu).
- nomarchy-eval-matrix: define /persist + /home in the impermanence scenarios
  (26.05 maps fsType over every neededForBoot filesystem).
- README/MIGRATION/installer: stale swww references -> swaybg.

KNOWN BLOCKER (why this is on a branch, not main):
In a headless QEMU VM, Hyprland boots and inits GL (virgl) fine but is
OOM-killed after ~19s (3.4 GB peak). Likely a no-display-consumer artifact of
headless rendering (unthrottled frames), but a real Hyprland-26.05 memory
regression can't be ruled out without a real display. Verify on real hardware
(a fresh ISO install) before merging to main; if the desktop is stable there,
the OOM was the headless VM and this can merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:46:17 +01:00

162 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# nomarchy-eval-matrix
#
# Evaluates the opt-in nomarchy.* surface that the per-output flake check
# never touches. flake check only evaluates the default configs, so a bug
# that only fires when a toggle is flipped — a renamed option, a failed
# assertion, a stale reference — sails straight through. Two such bugs
# shipped to main before this existed (the vscode option rename and the
# impermanence systemd-stage-1 assertion); both would have been caught
# here.
#
# Cost matters: this runs in CI on a small self-hosted runner, and the
# first cut (one full `extendModules` eval per individual toggle, plus one
# per palette) did ~39 whole-system evaluations and ran ~3h. So:
#
# * Compatible toggles are COMBINED into a few configs (a failure means
# re-run the offending toggle alone to pinpoint it — see the trace hint
# at the end). laptop vs desktop formFactor conflict, so they split;
# impermanence's multi-disk variant gets its own config for the alt
# mainLuksName.
# * Palettes are checked DIRECTLY via the lib — the per-palette risk is
# the system-side Plymouth base00 → RGB math (fromHexString of 2-char
# slices in themes/engine/plymouth.nix), which is pure and needs no
# module-system instantiation. Forcing the whole palette attrset also
# catches a missing/garbled palette.
# * The standalone homeConfigurations aren't re-checked here — the
# per-output flake-check step already forces both.
#
# Net: a handful of full evals instead of ~39. Results come from
# builtins.tryEval so one failure doesn't mask the rest.
#
# nomarchy-eval-matrix # run the matrix, table + exit code
#
# Add a new opt-in option's coverage by dropping it into the relevant
# combined scenario in the `scenarios` attrset below.
set -u
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$repo_root"
NIX=(nix --extra-experimental-features 'nix-command flakes')
read -r -d '' EXPR <<'NIXEOF' || true
let
f = builtins.getFlake (toString ./.);
lib = f.inputs.nixpkgs.lib;
nl = import ./lib { inherit lib; };
default = f.nixosConfigurations.default;
forced = x: (builtins.tryEval (builtins.seq x true)).success;
# Real impermanence installs define /persist + /home via disko; the eval
# scenarios must too, because nixpkgs 26.05's systemd stage-1 maps fsType
# over every neededForBoot filesystem and impermanence marks both
# neededForBoot (core/system/impermanence.nix). Without device+fsType here,
# the toplevel eval throws on a config that has no disko layer.
impermanenceFs = {
"/persist" = { device = "/dev/disk/by-label/persist"; fsType = "ext4"; };
"/home" = { device = "/dev/disk/by-label/home"; fsType = "ext4"; };
};
# Combined opt-in scenarios. Each enables as many compatible toggles as
# possible so CI does ~3 full-system evals, not one per toggle. Home-side
# options go under home-manager.users.nomarchy.nomarchy.*.
scenarios = {
# laptop formFactor + every compatible system/home toggle + impermanence.
"laptop-stack" = {
nomarchy.system = {
formFactor = "laptop";
laptop.enable = true;
accessibility.enable = true;
gaming.enable = true;
features.hybridGPU = true;
hibernation.enable = true;
virtualization.docker.enable = true;
impermanence.enable = true;
};
nomarchy.hardware.fwupd = true;
home-manager.users.nomarchy.nomarchy = {
accessibility.enable = true;
gaming.enable = true;
overrides.enable = true;
panelPosition = "bottom";
keymap = { layout = "de"; variant = "nodeadkeys"; };
toggles = { waybar = false; idle = false; nightlight = false; };
};
fileSystems = impermanenceFs;
};
# desktop preset — conflicts with the laptop formFactor, so its own eval.
"desktop-stack" = {
nomarchy.system = { formFactor = "desktop"; desktop.enable = true; };
};
# impermanence multi-disk variant (alternate mainLuksName).
"impermanence-multi" = {
nomarchy.system.impermanence = { enable = true; mainLuksName = "crypted_main"; };
fileSystems = impermanenceFs;
};
};
evalToplevel = mod:
forced (default.extendModules { modules = [ mod ]; }).config.system.build.toplevel.drvPath;
# base00 → the three byte values the Plymouth template substitutes; plus
# the whole palette attrset, so a missing/garbled palette is caught.
paletteOk = name:
let
p = nl.getPalette name;
b = p.base00;
bytes = [
(lib.fromHexString (lib.substring 0 2 b))
(lib.fromHexString (lib.substring 2 2 b))
(lib.fromHexString (lib.substring 4 2 b))
];
in forced (builtins.deepSeq [ p bytes ] true);
in {
scenarios = builtins.mapAttrs (_: evalToplevel) scenarios;
palettes = builtins.listToAttrs (map (n: { name = n; value = paletteOk n; }) nl.themeNames);
}
NIXEOF
echo "Evaluating combined toggle scenarios + per-palette colour math..."
json="$("${NIX[@]}" eval --impure --json --expr "$EXPR" 2>/tmp/eval-matrix.err)"
status=$?
if [[ $status -ne 0 || -z "$json" ]]; then
echo "ERROR: the matrix evaluation aborted before producing results." >&2
echo "This usually means an uncatchable error (abort/infinite recursion) in one" >&2
echo "scenario, or a syntax error in the expression. Full output:" >&2
cat /tmp/eval-matrix.err >&2
exit 1
fi
# Render each section and tally failures.
fails=0
render() {
local section="$1"
echo
echo "=== $section ==="
while IFS=$'\t' read -r name ok; do
if [[ "$ok" == "true" ]]; then
printf ' ok %s\n' "$name"
else
printf ' FAIL %s\n' "$name"
fails=$((fails + 1))
fi
done < <(echo "$json" | jq -r --arg s "$section" '.[$s] | to_entries[] | "\(.key)\t\(.value)"' | sort)
}
render scenarios
render palettes
echo
if [[ $fails -gt 0 ]]; then
echo "$fails scenario(s) failed to evaluate. A combined scenario bundles several"
echo "toggles — re-run the suspects individually for the trace, e.g.:"
echo " nix eval --impure --show-trace --expr 'let f = builtins.getFlake (toString ./.); in (f.nixosConfigurations.default.extendModules { modules = [ { <the toggle> } ]; }).config.system.build.toplevel.drvPath'"
exit 1
fi
echo "All scenarios evaluated cleanly."