From c63c3079bebc434c222b028dae483039da104322 Mon Sep 17 00:00:00 2001 From: alexion Date: Mon, 20 Jul 2026 10:21:24 -0400 Subject: [PATCH] feat(nix): bound the store, generations and boot menu (task 0014) Garbage collection and store optimisation each run weekly, on separate days so they never contend, and retained boot configurations are capped at 15. --- .claude/tasks/0014-nix-store-housekeeping.md | 22 +++++++++++++++----- system/default.nix | 20 ++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.claude/tasks/0014-nix-store-housekeeping.md b/.claude/tasks/0014-nix-store-housekeeping.md index 8e8c03d..f04bd85 100644 --- a/.claude/tasks/0014-nix-store-housekeeping.md +++ b/.claude/tasks/0014-nix-store-housekeeping.md @@ -10,9 +10,21 @@ Retained boot configurations are capped at 15. Each generation stores a kernel a ## Acceptance criteria -- [ ] Automatic garbage collection is enabled weekly, deleting generations older than 30 days -- [ ] Store optimisation is scheduled weekly, rather than performed at build time -- [ ] Retained boot configurations are capped at 15 -- [ ] These are declared as plumbing in the shared base config, so every future `Host` inherits them -- [ ] `nix flake check` builds the `neogaia` toplevel +- [x] Automatic garbage collection is enabled weekly, deleting generations older than 30 days +- [x] Store optimisation is scheduled weekly, rather than performed at build time +- [x] Retained boot configurations are capped at 15 +- [x] These are declared as plumbing in the shared base config, so every future `Host` inherits them +- [x] `nix flake check` builds the `neogaia` toplevel - [ ] Manual confirmation after a rebuild: the collection and optimisation timers exist and are scheduled + +## Implementation Notes + +The two schedules are named days rather than the bare `weekly` keyword. +systemd expands `weekly` to `Mon *-*-* 00:00:00`, which would have started collection and deduplication at the same instant every week, leaving `nix-optimise` hard-linking paths `nix-gc` was concurrently deleting. +Collection now runs `Mon 03:15` and optimisation `Thu 03:45`, which keeps both weekly and keeps them apart. + +The boot configuration cap sits in the shared base as the task asks, and is inert rather than an error on a host that does not use systemd-boot. +A future host on another bootloader therefore inherits no cap, which is the one place the "every future host inherits them" promise does not reach. + +The last criterion is left open: confirming the timers on a running system needs a `nixos-rebuild switch`, which needs a sudo credential this session did not have. +It closes the way tasks 0013, 0016 and 0017 did, in a follow-up commit once the operator has switched the machine and read `systemctl list-timers`. diff --git a/system/default.nix b/system/default.nix index f056835..f638be6 100644 --- a/system/default.nix +++ b/system/default.nix @@ -58,6 +58,26 @@ in nix.settings.extra-trusted-public-keys = [ "nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk=" ]; + + # A month of generations is kept, because on a rolling channel with a + # third-party kernel an old generation is a known-good system to boot when + # an update breaks something. + nix.gc.automatic = true; + nix.gc.dates = "Mon 03:15"; + nix.gc.options = "--delete-older-than 30d"; + + # Deduplication runs on a timer, off the rebuild path, so it never adds + # latency to a `nixos-rebuild switch`. + # It falls on a different day from collection, so the two never contend. + nix.optimise.automatic = true; + nix.optimise.dates = [ "Thu 03:45" ]; + + # The EFI system partition holds a kernel and an initrd per entry at roughly + # 70 MiB apiece, and is fixed in size. + # An exhausted one fails at bootloader installation, after the build has + # already succeeded. + boot.loader.systemd-boot.configurationLimit = 15; + environment.systemPackages = [ pkgs.git ]; # Caps Lock is a second Escape; Shift+Caps Lock still toggles Caps Lock.