Files
nix-config/docs/nixos-modernization-options.md
T
Ryan Yin 1324131c6d docs: correct statements that no longer match the configuration
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00

539 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NixOS Modernization — Options and Decision Record
> **Purpose:** let the maintainer decide, per candidate, whether it is worth adopting — by comparing
> it against what this repository does **today**. A plan derived from this file is only approved
> work once its card here says **adopt**. The plans are not on `main`: they exist only on the local,
> unpushed git tag `modernization-plans-wip`, under `docs/plans/`:
> `2026-10-07-boot-chain-limine-uki-repart.md`, `2026-10-07-host-level-modernization.md` and
> `2026-10-07-lab-experimental-etc-init.md` (`git show modernization-plans-wip:docs/plans/<file>`).
>
> Researched against nixpkgs `nixos-unstable` on 2026-10-07. Option names and upstream wording are
> quoted from the module sources cited in each card. The **Current:** sections were re-checked
> against this repository on 2026-10-21; the upstream research was not redone.
## How to use this file
1. Read the card, not the plan.
2. Fill in **Decision** with one of:
- **adopt** — replace the current mechanism; the matching plan task becomes approved work.
- **watch** — not now; the card's _Trigger to adopt_ says what would change the answer.
- **reject** — decide against, with a one-line reason, so it is not re-litigated.
3. Recommendations below are mine; they are inputs, not conclusions.
Ordering rule used throughout: a candidate earns a plan task only if it **replaces a mechanism this
repository already runs** or **unlocks a concrete need**. "It exists and is newer" is not enough.
---
# A. Host services and networking
## A1. Tailscale Serve instead of caddy vhosts
**Current:** one caddy instance on `youko` fronts 17 vhosts on `*.writefor.fun` by Host/SNI, with
two TLS chains — a private `ecc-ca` (only repo machines trust it) and a lego/Cloudflare DNS-01
wildcard for phone/TV clients — plus `file_server`, `header_up Host` (SigV4), a wildcard 404
fallback, and a root-readable Cloudflare token in agenix.
**Proposed:** `services.tailscale.serve` for the services whose only clients are tailnet devices.
**Pros:** certificates become automatic and every tailnet device trusts them (today a phone without
`ecc-ca` gets a certificate error); removes the Cloudflare token and the DNS-01 propagation
workaround from those services; access control moves from "IP trust zone" to tailnet identity/ACL,
which is exactly the limitation `SECURITY.md` records; `--tcp=<port>` can also expose raw TCP.
**Cons:** Serve routes by mount path on one name, or (via the nixpkgs module) as Tailscale Services
with `tcp:<port>` endpoints only — there is no Host/SNI vhost equivalent, so path-sensitive apps
(gitea, rustfs) and base-url assumptions are a problem; rustfs S3 is SigV4-signed on the Host header
and cannot move; `file_server` and the wildcard 404 have no equivalent; Android TV/Jellyfin/Immich
native apps do not run Tailscale; LAN-local traffic would detour through WireGuard/DERP.
**Reversibility:** high — caddy config stays until each vhost is deleted deliberately.
**Trigger to adopt:** only for admin-only UIs (grafana, prometheus, alertmanager, vmalert,
uptime-kuma, s3-console) and for LAN-only services whose clients are all repo machines.
**Recommendation:** **partial adopt** — migrate admin UIs only; keep caddy for immich, jellyfin,
rustfs, file server, and the 404 fallback. The bigger win is retiring the private-CA chain if every
LAN-only client can run Tailscale.
**Decision:** _pending_
## A2. systemd-resolved
**Current:** `services.resolved.enable` evaluates `true` on 14 of the 15 NixOS hosts (all but
`akane`): nixpkgs enables it by default with systemd-networkd
(`nixos/modules/system/boot/networkd.nix`), and `shoukei`, which runs NetworkManager, enables it
through `modules.networking.mihomo.resolvedIntegration` (asserted by the eval test
`outputs/aarch64-linux/tests/mihomo-dns`). On `ai`, a mihomo lifecycle hook points the link's
resolved DNS at mihomo (`hosts/idols-ai/default.nix`). `DNSOverTLS` and `DNSSEC` evaluate `false`.
The `services.resolved.settings.Resolve.MulticastDNS = false` in
`modules/nixos/base/networking/mdns.nix` is therefore live; mDNS itself is provided by avahi.
**Proposed:** `DNSOverTLS`/DNSSEC and caching settings on the resolved instance the hosts already
run (`services.resolved.enable = true` would still be new on `akane`).
**Pros:** DoT/DNSSEC available; the caching resolver and a consistent stub across hosts already come
with the resolved instance in use, and the mDNS caveat is already handled by the existing setting.
**Cons:** the LAN gateway `suzi` is a mihomo transparent proxy that **hijacks DNS to fake IPs that
are only routable through the proxy** — DoT/DoH on a host would bypass that hijack and break proxied
domains (the same reason `transmission.nix` deliberately resolves through real resolvers instead of
the host resolver). Hosts running mihomo (idols-ai, shoukei) are the sensitive ones. Also interacts
with the transmission network namespace and container DNS.
**Reversibility:** high (one option, one service restart).
**Trigger to adopt:** a host that has no dependency on suzi's DNS hijack, or after the proxy setup
changes.
**Recommendation:** **watch** — the fake-IP dependency makes this riskier than it looks.
**Decision:** _pending_
## A3. systemd-networkd instead of dhcpcd
**Current:** dhcpcd is not used anywhere in this repo. `networking.useNetworkd = true` is set on 13
of the 15 hosts: every VM host (`lib/genVmHostModule.nix`) and MicroVM guest
(`lib/genMicrovmGuestModule.nix`), plus `ai`, `aquamarine`, `kana` and `ruby`; only `shoukei` and
`akane` run NetworkManager. VM hosts and MicroVM guests use static config with `useDHCP = false`.
The `br0` bridge on VM hosts is declared through `systemd.network.netdevs/networks` already.
**Proposed:** systemd-networkd on the remaining NetworkManager hosts, through the options the other
hosts already use: `networking.useNetworkd` and `systemd.network.{networks,netdevs}`. The
`networking.networkd.enable` / `networking.networks` / `networkdOptions` names first recorded here
do not exist in the locked nixpkgs.
**Pros:** declarative per-interface config, one implementation for stage 1 and stage 2, no dhcpcd
anywhere in the path (nothing in this repo uses it), and VM hosts already speak `systemd.network`
for the bridge.
**Cons:** bigger blast radius than any other item — a mistake on a `br0` VM host cuts the guests and
possibly remote reachability; migration touches every DHCP host; behaviour differences around
lease/renew and DNS handling.
**Reversibility:** medium — reversible in config, but only if you can still reach the host.
**Trigger to adopt:** guest-only first, then a non-VM host with console access.
**Recommendation:** **watch**, guest-only experiment (`lab-experimental-etc-init.md`, Task 5). The
corrected facts make that experiment moot — every MicroVM guest already runs networkd, and the plan
task uses the non-existent option names above — so the open call is whether `shoukei` and `akane`
move off NetworkManager.
**Decision:** _pending_
## A4. Native journald shipping instead of per-host scraping only
**Current:** metrics are centralised (node_exporter on the LAN IP, smartctl exporter,
VictoriaMetrics on youko); logs stay on each host.
**Proposed:** `services.journald.upload` on hosts → `services.journald.remote` on youko (both
supported; `services.journald.gateway` exposes a read API).
**Pros:** first-class systemd path, no promtail/filebeat/GELF sidecar, structured fields survive,
per-host logs searchable in one place.
**Cons:** new listening port and its firewall rule plus eval test; youko becomes the retention owner
(disk, rotation); upload failures are silent unless monitored; TLS configuration is on you to get
right.
**Reversibility:** high.
**Trigger to adopt:** when needing to correlate logs across hosts, or when the first host with a
missing-log incident shows up.
**Recommendation:** **adopt** (low risk, clear operational win).
**Decision:** _pending_
## A5. zram-generator instead of zramSwap
**Current:** a local module `modules/nixos/base/zram.nix` wraps `zramSwap` and adds sysctl tunings
(swappiness, readahead), disabled on idols-ai (disk swapfile) and aquamarine, memoryPercent-tuned on
shoukei, and not imported on akane. In the locked nixpkgs `zramSwap` is itself implemented on
zram-generator (`nixos/modules/config/zram.nix` sets `services.zram-generator.enable`, which youko
evaluates `true`).
**Proposed:** `services.zram-generator.enable` with a `zram0` definition.
**Pros:** systemd-native unit generator, config expressed as data, upstream-maintained, no
NixOS-specific script — all but writing the `zram0` settings directly already come with `zramSwap`
(see Current).
**Cons:** your module couples zram presence to sysctl tunings — the migration must keep that logic
working when zram is off; two zram implementations are easy to have half-enabled during the change;
the gain over a working `zramSwap` is mostly cosmetic.
**Reversibility:** high.
**Trigger to adopt:** whenever the zram module is next touched anyway.
**Recommendation:** **watch** — no current pain; fold into the next zram change.
**Decision:** _pending_
## A6. nixos-facter instead of hand-written hardware-configuration.nix
**Current:** 4 hosts carry hand-written `hardware-configuration.nix` (`shoryu`, `shoukei`, `ai`,
`aquamarine`; `shushou` and `youko` import `shoryu`'s, and the qemu guests use the shared
`modules/nixos/server/qemu-guest-hardware-configuration.nix`), plus deliberate per-host quirks such
as the NVMe APST workaround WA-008 and USB-SATA mitigations WA-009.
**Proposed:** `hardware.facter` from nixpkgs (nixos-facter-modules upstreamed), report generated on
the machine.
**Pros:** hardware changes (disk swap, new NIC, RAM) no longer require regenerating a file by hand;
consistent with `nixos-anywhere` provisioning.
**Cons:** the report must live somewhere (repo or machine) and be regenerated on hardware change;
defaults become less transparent than a file you can read in the diff; your deliberate deviations
(kernel params, module options) still live in host config, so only part of the file is replaced.
**Reversibility:** high.
**Trigger to adopt:** on a new host build, or when a hardware change forces a regeneration anyway.
**Recommendation:** **watch** — adopt on the next new host rather than retrofitting four.
**Decision:** _pending_
## A7. attic self-hosted binary cache
**Current:** substituters are the two Chinese mirrors plus numtide's cache; a cachix endpoint exists
in the config but is unused.
**Proposed:** `services.networking.atticd` on youko.
**Cons:** another service to run, back up, and monitor on the host that already carries the most
state; keys and tokens become a security surface (`modules/base/nix.nix` treats substituter trust as
a boundary); it solves a problem (cache misses / CI egress) that is not currently reported as pain.
**Pros:** control over retention, faster cross-host reuse, no third-party dependency for private
artifacts.
**Reversibility:** high.
**Trigger to adopt:** measurably slow rebuilds across hosts, or a need to cache artifacts that
cannot go to a public cache.
**Recommendation:** **watch**.
**Decision:** _pending_
## A8. nix-servd and the non-root daemon features
**Current:** static `nix.buildMachines` (`modules/nixos/base/remote-builders.nix`); the plain user
is deliberately not a trusted user on the clients, though the builder host trusts its builder login;
Nix 2.35 via `nixVersions.latest` (WA-023). `auto-allocate-uids` (with `cgroups`) is already enabled
in `modules/nixos/base/nix.nix` for nixpkgs' nspawn-based tests, and the locked nixpkgs has no
`nix-servd` module or package.
**Proposed:** `nix-servd` for scheduling, plus the `local-overlay-store` experimental feature
(`auto-allocate-uids` is already on, see Current).
**Pros:** dynamic builder selection and health checks instead of a hand-maintained list; the
experimental features move toward running the daemon without root, consistent with the
no-trusted-user policy; `local-overlay-store` can cut store duplication for remote builds.
**Cons:** experimental features in a repo whose value is reproducibility; `nix-servd` is young;
misconfiguration shows up as flaky builds rather than a clean failure; benefit is unclear while the
current three-arch remote build setup works.
**Reversibility:** medium (builds can be re-pointed, but half-migrated builders are confusing).
**Trigger to adopt:** when the static builder list starts causing real friction.
**Recommendation:** **watch**.
**Decision:** _pending_
## A9. sched_ext (scx-loader)
**Current:** default kernel scheduler (EEVDF); desktop latency is not currently reported as a
problem.
**Proposed:** `services.scx-loader.enable` with an scx scheduler (kernel 6.12+; the desktop runs a
recent kernel).
**Pros:** a scheduler that can be swapped per workload, userspace-recoverable if it misbehaves,
active upstream development.
**Cons:** another daemon; scheduler changes can produce subtle latency/throughput regressions that
are hard to attribute; no measured problem to solve yet.
**Reversibility:** high (stop the service).
**Trigger to adopt:** a benchmark showing a win on the desktop, or a workload that needs it.
**Recommendation:** **watch**, easy to trial.
**Decision:** _pending_
---
# B. Boot, images, VMs
## B1. limine instead of systemd-boot + lanzaboote
**Current:** systemd-boot on akane, shoukei and the VM hosts (shoryu, shushou, youko); GRUB on
`/dev/vda` on the libvirt guests kana and ruby; no bootloader on the MicroVM guests; on idols-ai and
aquamarine, lanzaboote provides Secure Boot with a `/etc/secureboot` (lzpt) bundle. The lanzaboote
flake input must track a rust-overlay follow (WA-003).
**Proposed:** `boot.loader.limine` — in nixpkgs, with `secureBoot`, `validateChecksums`,
`panicOnChecksumMismatch`, `biosSupport`, `maxGenerations`, graphical menu.
**Pros:** one bootloader for UEFI and BIOS (covers the qemu guests' GRUB case); Secure Boot without
the lanzaboote flake input and its rust-overlay pin (WA-003 disappears); checksum validation of
kernel and initrd; nicer menu.
**Cons:** different trust model — it signs **limine itself** and validates artifacts by checksum,
rather than shipping a firmware-verified UKI, so `SECURITY.md` and the threat model must be updated;
key enrollment is a manual firmware dance (Setup Mode + `sbctl enroll-keys`) and is the one change
in this repository that can leave a machine unbootable; the existing lzpt bundle may or may not be
reusable; less NixOS mileage than systemd-boot.
**Reversibility:** low on the physical desktop (firmware + ESP state), high on a VM.
**Trigger to adopt:** wanting one loader across BIOS/UEFI targets, or the lanzaboote pin becoming
actual maintenance pain.
**Recommendation:** **watch for the desktop, adopt on a disposable guest first** — the value is real
but it is the highest-risk item on this list.
**Decision:** _pending_
## B2. boot.uki / system.build.uki
**Current:** lanzaboote already produces and signs a UKI on idols-ai and aquamarine; other hosts
boot kernel+initrd.
**Proposed:** `boot.uki`.
**Pros:** standard UKI with `ukify` settings, single signed artifact, clear story for measured boot.
**Cons:** largely redundant where lanzaboote exists; adopting it interacts with B1 (who signs, who
validates); no benefit for hosts without Secure Boot.
**Reversibility:** medium.
**Recommendation:** **reject for now** — revisit together with B1.
**Decision:** _pending_
## B3. Declarative images with systemd-repart
**Current:** libvirt guest images are one-time reflink copies of the VMs' former KubeVirt disks
(`hosts/12kingdoms-shoryu/libvirtd.nix`); k8s guests are MicroVMs booting declared state images
against a read-only host store, with no OS image built at all.
**Proposed:** `image.repart.enable` + `system.build.images.{qemu,raw-efi,raw,sd-card}`.
**Pros:** images become a declared output of the system rather than a separate generator; GPT layout
in `repart.d`; upstream direction; pairs with `nixos-anywhere` and vmspawn testing.
**Cons:** new subsystem with less mileage; the artifacts are consumed by `~/codes/k8s-gitops`, so
every change is a two-repo change; must prove boot and state-image compatibility before replacing
anything.
**Reversibility:** high (additive while the old pipeline stays).
**Trigger to adopt:** next time the image pipeline needs a change anyway.
**Recommendation:** **adopt as an additive experiment**, not a replacement.
**Decision:** _pending_
## B4. systemd-repart at boot (partition growth)
**Current:** manual partition sizing; no automatic growth.
**Proposed:** `boot.initrd.systemd.repart.enable`.
**Pros:** images and SD-card installs grow themselves; GPT-only and declarative.
**Cons:** another initrd-stage moving part; only useful once B3 or a disk-image workflow exists.
**Reversibility:** high.
**Recommendation:** **watch** — depends on B3.
**Decision:** _pending_
## B5. systemd-sysupdate (A/B updates)
**Current:** generation switching through `nixos-rebuild` + bootloader entries — already atomic and
rollbackable.
**Proposed:** `systemd.sysupdate.enable` with transfer definitions and a timer.
**Pros:** A/B image updates with signature verification.
**Cons:** duplicates functionality the generation model already provides; adds a second update path
and its own state; unclear what problem it solves here.
**Recommendation:** **reject**.
**Decision:** _pending_
## B6. Measured boot phases / FIDO2 credentials
**Current:** Secure Boot via lanzaboote on ai and aquamarine, whose LUKS volumes are enrolled for
TPM2 unlock bound to PCRs 0+7, with the passphrase slot as fallback (`hosts/idols-ai/README.md`,
`hosts/idols-aquamarine/README.md`). `boot.initrd.systemd.tpm2.enable` evaluates `true` on every
host except the MicroVM guests, and on ai and aquamarine `systemd.tpm2.enable` and
`boot.initrd.systemd.fido2.enable` are `true` as well (nixpkgs defaults from the systemd package).
Not adopted: `systemd.tpm2.pcrphases.enable` is `false`, and the READMEs document no FIDO2
credential, only TPM2 and passphrase slots.
**Proposed:** `systemd.tpm2.enable`, `systemd.tpm2.pcrphases.enable`,
`boot.initrd.systemd.tpm2.enable`, `boot.initrd.systemd.fido2.enable`.
**Pros:** PCR phases make boot-phase measurement usable for sealing policies; FIDO2 gives a physical
second factor for LUKS.
**Cons:** PCR policies must be re-sealed whenever the boot chain changes (kernel updates, bootloader
change B1), which converts an update into a maintenance event; CPU microcode/firmware updates can
invalidate sealed state.
**Reversibility:** medium.
**Recommendation:** **watch** — revisit after B1 is settled.
**Decision:** _pending_
## B7. systemd-vmspawn
**Current:** libvirt domains (generated XML) for qemu guests; MicroVMs for k8s guests.
**Proposed:** hand-written `systemd.services` calling `systemd-vmspawn` (`--network-bridge=br0`,
`--image-disk-type=`, `--coco=`, vTPM).
**Pros:** throwaway VMs in one command; boots the B3 images directly; confidential-computing
options; no libvirt stack.
**Cons:** no nixpkgs module and no `.vmspawn` unit type, so it is hand-written unit code; no
declarative state-image management (MicroVM keeps `{etc,var,home}.img` and MAC-pinned NICs); libvirt
stays for existing guests anyway.
**Reversibility:** high (delete the unit).
**Recommendation:** **adopt narrowly** — for testing B3 images only.
**Decision:** _pending_
---
# C. Repository tooling (low risk, no service impact)
## C1. Literal lint settings
**Current:** no `lint-url-literals`. **Proposed:** `nix.settings.lint-url-literals = "warn"` (plus
the short/absolute-path variants). **Pros:** catches deprecated literal syntax before it becomes an
error. **Cons:** warning noise on first run. **Recommendation:** **adopt**. **Decision:** _pending_
## C2. nix-unit
**Current:** hand-rolled `expr.nix`/`expected.nix` pairs run by `just test`. **Proposed:**
`nix-unit` alongside them. **Pros:** assertions on options, warnings, and thrown errors; clearer
failures. **Cons:** a second test runner and a migration that can silently lose coverage if pairs
are deleted early. **Recommendation:** **adopt additively**. **Decision:** _pending_
## C3. nix-fast-build
**Current:** CI (`.github/workflows/flake_evaltests.yml`) runs one `nix eval .#evalTests` and one VM
test (`checks.x86_64-linux.security-exporters`) on GitHub-hosted `ubuntu-latest` runners.
**Proposed:** `nix-fast-build` over the eval tests and the three host systems; the remote builder
(aquamarine, over SSH from repo machines) serves only a local Justfile run, not the hosted CI
runners. **Pros:** parallel eval/build, no new CI infra. **Cons:** one more tool in the Justfile; CI
already gates merges. **Recommendation:** **adopt**. **Decision:** _pending_
## C4. Cleanups (no decision needed)
WA-001 (smartctl pin) should be dropped once nixpkgs carries the upstream fix; the "nixfmt with
width 100" sentence in `AGENTS.md` should be checked against the formatter `just fmt` actually
resolves to. Checked 2026-10-21: the locked nixpkgs still ships smartctl_exporter 0.14.0, which
lacks the #329 fix (`overlays/smartctl-exporter/`), so WA-001 stays; `just fmt` runs the dev shell's
nixfmt 1.5.0, whose default width is 100, and `pre-commit-check` sets width 100
(`outputs/default.nix`), so the `AGENTS.md` sentence is correct. **Recommendation:** **adopt**.
**Decision:** _pending_
## C5. jj
Personal workflow change only; no repository impact. **Recommendation:** out of scope. **Decision:**
_pending_
---
# D. Lab-only experimental group
The whole group shares one characteristic: upstream labels it experimental, and a mistake can
prevent boot or login. **Recommendation for the group: evaluate in a disposable guest
(`lab-experimental-etc-init.md` on the plans tag), adopt individually only afterwards.**
| # | Candidate | Current | Main pro | Main con | Recommendation |
| --- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| D1 | `system.etc.overlay.enable` | /etc generated by the perl activation script | /etc becomes an EROFS + overlay mount; foundation for an immutable /etc | upstream: _"This is currently experimental. Only enable this option if you are confident that you can recover your system if it breaks."_; every /etc writer must be audited | lab only |
| D2 | `systemd.sysusers.enable` / `services.userborn.enable` | `update-users-groups.pl` | removes the perl script; prerequisite for an immutable /etc | experimental; uid/gid migration risk | lab only |
| D3 | `system.etc.overlay.mutable = false` | writable /etc | truly immutable /etc | **blocked**: agenix writes `/etc/agenix` (see the `environment.etc` copies in `secrets/nixos.nix`), so secrets must move to /run or to sops-nix first | lab only, after secrets move |
| D4 | `system.nixos-init.enable` | `activationScripts` | bashless init | makes `activationScripts` a silent no-op — youko's `data-ro-backing`, `installCaddyWallpapers` and `installHomepageDashboardConfig` would stop running without an error | lab only |
| D5 | `security.pam.services.<name>.rules` | per-service booleans | freeform PAM config | upstream marks it subject to breaking changes; a mistake locks you out | lab only |
| D6 | `security.shadow.enable = false` + greetd | shadow suite provides login/su | fewer setuid programs | assertion couples the two; changes VT login semantics | lab only |
| D7 | `security.apparmor.policies` | `policies.sudo` already in use (`hardening/apparmor/default.nix`); the old `profiles` option is removed upstream | policy set is now data | writing profiles is real work and breakage-prone; `SECURITY.md` explicitly warns against untested profiles | lab only |
---
# E. Considered and rejected (kept so they are not re-litigated)
| Candidate | What it is | Why not here |
| ------------------------ | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| systemd-sysext / confext | overlay read-only images onto `/usr`/`/etc` of an immutable OS | solves the ostree/Flatcar problem NixOS does not have: generations are already atomic and rollbackable. Layering via sysext means something escaped the rebuild. |
| Portable services | attach/detach a service image at runtime | aimed at distributing services to foreign systemd distros; generation switching is strictly stronger here. |
| Quadlet | podman generator turning `.container` files into units | NixOS already has `virtualisation.oci-containers` (in use on servers); Quadlet would move unit definitions out of Nix evaluation. A downgrade, not a modernization. |
| Landlock | unprivileged per-process LSM (network rules since 6.12) | already an active default LSM (`security/lsm` includes it); the missing piece is per-application policy, and this repo's answer to that is nixpak/bwrap. Watch trigger: nixpak/bwrap gain network-restriction policy. |
| Incus | LXD fork, container + VM management plane | no bridge option in the module (it creates `incusbr0`; attaching to `br0` needs `preseed`); it is a management plane, not a hypervisor replacement, and does not remove libvirt or MicroVM. If adopted, it needs its own disposable host. |
| Gateway API | k8s ingress successor | cross-repo: it belongs to `~/codes/k8s-gitops` with a matching branch here only if host networking changes. ingress-nginx is EOL, so this is real work — just not this repo's plan. |
| bcachefs | copy-on-write filesystem, out of experimental upstream | current storage (btrfs + btrbk + restic) works; migration cost is high and unrelated to any pain. Watch only. |
---
# F. Decision summary
Fill this in as cards are decided; the plan documents (on the `modernization-plans-wip` tag, see the
header) should then be trimmed to **adopt** items only.
| Card | Candidate | Decision | Date | Note |
| ----- | --------------------------- | -------- | ---- | ---- |
| A1 | Tailscale Serve (partial) | | | |
| A2 | systemd-resolved | | | |
| A3 | systemd-networkd | | | |
| A4 | journald upload/remote | | | |
| A5 | zram-generator | | | |
| A6 | nixos-facter | | | |
| A7 | attic | | | |
| A8 | nix-servd + daemon features | | | |
| A9 | sched_ext | | | |
| B1 | limine + Secure Boot | | | |
| B2 | boot.uki | | | |
| B3 | systemd-repart images | | | |
| B4 | initrd repart | | | |
| B5 | sysupdate | | | |
| B6 | measured boot / FIDO2 | | | |
| B7 | systemd-vmspawn | | | |
| C1–C5 | tooling + cleanups | | | |
| D1–D7 | lab-only group | | | |
| E | rejected set | | | |
## References
- nixpkgs modules: `system/etc/etc.nix`, `system/activation/nixos-init.nix`,
`system/boot/loader/limine/limine.nix`,
`system/boot/systemd/{repart,sysupdate,tpm2,fido2,journald-*}.nix`, `image/{images,repart}.nix`,
`services/networking/{tailscale-serve,dhcpcd,nat-nftables}.nix`,
`services/system/{userborn,nix-daemon,zram-generator}.nix`,
`services/monitoring/prometheus/exporters.nix`.
- NixOS 26.05 release notes; Nix manual, Experimental Features.
- Repo context: `SECURITY.md` (trust zones and control limits), `WORKAROUNDS.md` (WA-001, WA-003,
WA-008, WA-009, WA-023), `modules/nixos/base/networking/mdns.nix`,
`hosts/12kingdoms-youko/homelab-services/caddy.nix`,
`hosts/12kingdoms-youko/homelab-services/README.md`.