Some checks failed
Check / eval-and-lint (push) Failing after 6m40s
The per-toggle + per-palette matrix did ~39 full-system evaluations (16
toggle toplevels + 21 palettes each via a full extendModules eval + 2
home) and ran ~2h55m on the small self-hosted runner — long enough to hit
act_runner's 3h container lifetime (sleep 10800) and get killed.
Redesign:
* Combine compatible toggles into 3 configs (laptop-stack, desktop-stack,
impermanence-multi) instead of one eval per toggle. A failure means
re-run the suspect toggle alone; the trace hint covers that.
* Check palettes directly via the lib — the per-palette risk is the pure
base00 -> RGB hex math in plymouth.nix, which needs no module-system
instantiation. Forcing the palette attrset also catches a missing one.
* Drop the home configs; the per-output flake-check step already forces
both homeConfigurations.
~39 full evals -> 3, plus a near-instant palette pass. Runs in ~1m locally
(warm). AGENT.md updated for the new combined-scenario structure.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
150 lines
5.6 KiB
Bash
Executable File
150 lines
5.6 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;
|
|
|
|
# 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; };
|
|
};
|
|
};
|
|
|
|
# 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"; };
|
|
};
|
|
};
|
|
|
|
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."
|