fix(installer): generate state.json from lib/state-schema.nix
Closes the last source-of-truth split after the state-defaults
centralization batches. The installer's heredoc was the only remaining
place that hardcoded the state.json literal — adding a default to the
schema previously required a parallel edit here, and silent drift was
exactly the bug class we kept fixing.
Before:
cat > /mnt/etc/nixos/state.json <<JSON_EOF
{
"theme": "nord",
"timezone": "${_state_tz}",
"dns": "DHCP",
...
}
JSON_EOF
After:
nix eval --impure --raw --expr "
let
flake = builtins.getFlake \"$NOMARCHY_REPO\";
lib = flake.inputs.nixpkgs.lib;
schema = import \"$NOMARCHY_REPO/lib/state-schema.nix\"
{ inherit lib; };
state = schema.system // { timezone = \"$_state_tz\"; };
in builtins.toJSON state
" | nrun jq '.' > /mnt/etc/nixos/state.json
Uses the flake's own pinned `inputs.nixpkgs` (matching what the rest of
Nomarchy resolves against), so the schema evaluates with the same `lib`
the consumer modules see. `nrun jq` pretty-prints for human inspection.
Behavioural notes:
- Output is identical to the old heredoc modulo alphabetical key
ordering — `builtins.toJSON` sorts keys, the heredoc was in
declaration order. Toggle scripts read/write via `jq` so it's
invisible to them.
- Dry-run path unchanged. `execute_dry_run` already bind-mounts a fake
/mnt for the generator; the generator's absolute paths still resolve.
- New schema fields show up automatically on the next install; no
parallel edit needed.
- `bash -n` + `shellcheck --severity=error` clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,7 @@ Each PR description should reference the row(s) in `docs/SCRIPTS.md` it closes,
|
||||
|
||||
(Move items here when they land — keep them brief, link the commit/PR.)
|
||||
|
||||
- _2026-05-18_ — Installer state.json is now schema-driven. Replaced the heredoc in `installer/install.sh` that hardcoded the JSON literal (theme/dns/wifi/features/etc.) with a `nix eval` of `lib/state-schema.nix`'s `system` block, overlaid with the installer-chosen timezone. Closes the last source-of-truth split after the centralization batch — adding a new default in the schema now reaches the installer with no further plumbing. Output is identical modulo alphabetical key ordering (Nix's `builtins.toJSON` sorts keys; toggle scripts read/write via `jq` so it's invisible to them). Dry-run path unchanged (still bind-mounts a fake `/mnt` so the generator's absolute paths resolve correctly). `bash -n` + `shellcheck --severity=error` clean.
|
||||
- _2026-05-18_ — Complete the hybrid-GPU wiring + fix unoverridable state-derived options. Two related fixes shipped together. **(1)** `nomarchy.system.features.hybridGPU = true` now wires the full NVIDIA driver stack (`services.xserver.videoDrivers = ["nvidia"]`, `hardware.graphics.{enable,enable32Bit}`, `hardware.nvidia.{modesetting,powerManagement}.enable`, `package = nvidiaPackages.stable`, `boot.kernelParams += "nvidia-drm.modeset=1"`) — was previously enabling only `supergfxd` mode-switching while leaving the system with no NVIDIA driver loaded, so mode switches silently no-op'd. All knobs use `lib.mkDefault` so a downstream `system.nix` can pin a beta driver, flip to the open kernel module, etc. Bus-ID prime config (per-machine) stays user-supplied — `docs/OPTIONS.md` has the full recipe. **(2)** Both `core/system/state.nix` and `core/home/state.nix` now use `lib.mkDefault` on every state.json-derived assignment, fixing a class of "I set X in my system.nix but it doesn't take effect" bugs (the state-derived value was at default priority and conflicted with the user's same-priority override). Side-effect cleanup: `core/system/state.nix` now also reads from `lib/state-schema.nix` like `core/home/state.nix` does, completing the schema-centralization started two batches ago. Verified `nix flake check` + an override test that flips hybridGPU via an overlay and confirms the entire driver stack engages.
|
||||
- _2026-05-18_ — Pillar 4: pre-flight resume polish. Fixed four resume-flow gaps in `installer/install.sh`: (1) `--resume` with a missing state file now errors loudly with a tmpfs explanation instead of silently falling through to a fresh prompt cycle (the most common operator confusion was "rebooted, forgot tmpfs eats /tmp/, watched the installer start over without realising"); (2) on resume, the saved target drive is validated as a block device before any disk-phase step runs — catches the live-ISO USB-unplugged / non-deterministic /dev/sdX class of mid-install failures; (3) `save_state` now stamps an ISO-8601 timestamp and `load_state` shows a `(saved Xm ago)` banner plus a `Target: /dev/X → user @ host` summary line, so the user can `Ctrl-C` if they're resuming onto the wrong host before any destructive prompt fires; (4) `--help` now documents the tmpfs limitation. `shellcheck --severity=error` passes.
|
||||
- _2026-05-18_ — Declarative-state defaults centralization. Made `lib/state-schema.nix` the single source of truth for every state-default that previously lived in three places (the schema itself, `core/system/options.nix` / `core/home/options.nix` `default = …` clauses, and `core/home/state.nix` `or …` fallbacks). Replaced ~25 hardcoded literals with `schema.<scope>.<key>` reads. Side-effect: fixed a lingering bug where `core/home/options.nix:theme` still defaulted to `"summer-night"` after the system-side was moved to `"nord"` — half the codebase's home option resolved to the wrong theme when state.json was missing/blank. `nix flake check --no-build` confirms zero semantic change for every other field. Doesn't touch the installer-written `state.json` (separate batch — needs schema → JSON generation).
|
||||
|
||||
@@ -1799,30 +1799,29 @@ EOF
|
||||
}
|
||||
EOF
|
||||
|
||||
# state.json — consumed by core/system/state.nix at every nixos-rebuild and
|
||||
# mutated by toggle scripts (nomarchy-tz-select, nomarchy-setup-fido2,
|
||||
# state.json — consumed by core/system/state.nix at every nixos-rebuild
|
||||
# and mutated by toggle scripts (nomarchy-tz-select, nomarchy-setup-fido2,
|
||||
# nomarchy-toggle-hybrid-gpu, nomarchy-wifi-powersave, ...). Those scripts
|
||||
# `jq` the file in place and fail hard if it doesn't exist or isn't valid
|
||||
# JSON, so a fresh install MUST ship one. Shape must match lib/state-schema.nix.
|
||||
# Quoted heredoc — no shell expansion except the explicit $TIMEZONE below.
|
||||
# `jq` the file in place and fail hard if it doesn't exist or isn't
|
||||
# valid JSON, so a fresh install MUST ship one.
|
||||
#
|
||||
# Source of truth: lib/state-schema.nix. We eval its `system` block and
|
||||
# overlay the installer-chosen timezone, so this generator no longer
|
||||
# drifts from the schema or the *.nix consumers — the previous heredoc
|
||||
# was the last source-of-truth split after the state centralization.
|
||||
# Adding a new default in the schema now reaches the installer without
|
||||
# any further plumbing.
|
||||
local _state_tz="${TIMEZONE:-UTC}"
|
||||
cat > /mnt/etc/nixos/state.json <<JSON_EOF
|
||||
{
|
||||
"theme": "nord",
|
||||
"timezone": "${_state_tz}",
|
||||
"dns": "DHCP",
|
||||
"customDns": [],
|
||||
"wifi": {
|
||||
"powersave": true
|
||||
},
|
||||
"features": {
|
||||
"fingerprint": false,
|
||||
"fido2": false,
|
||||
"hybridGPU": false,
|
||||
"makima": false
|
||||
}
|
||||
}
|
||||
JSON_EOF
|
||||
nix --extra-experimental-features 'nix-command flakes' eval \
|
||||
--impure --raw \
|
||||
--expr "
|
||||
let
|
||||
flake = builtins.getFlake \"$NOMARCHY_REPO\";
|
||||
lib = flake.inputs.nixpkgs.lib;
|
||||
schema = import \"$NOMARCHY_REPO/lib/state-schema.nix\" { inherit lib; };
|
||||
state = schema.system // { timezone = \"$_state_tz\"; };
|
||||
in builtins.toJSON state
|
||||
" | nrun jq '.' > /mnt/etc/nixos/state.json
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user