feat(nix): bound the store, generations and boot menu (task 0014) #7

Merged
alexion merged 2 commits from task-0014-nix-store-housekeeping into main 2026-07-20 10:43:51 -04:00
2 changed files with 38 additions and 6 deletions

View File

@@ -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
- [ ] Manual confirmation after a rebuild: the collection and optimisation timers exist and are scheduled
- [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
- [x] 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.
Confirmed on `neogaia` after a switch: `systemctl list-timers 'nix-*'` lists both units, `nix-optimise` next on Thursday and `nix-gc` next on Monday, each `Persistent=true` so a suspended laptop catches up on a missed firing.
`/boot` reports 2 GiB with 113 MiB used, so the cap of 15 sits against the enlarged partition it assumes.

View File

@@ -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.