new site-config.nix holds values previously duplicated across hosts:
domain, old_domain, contact_email, timezone, binary_cache (url + pubkey),
dns_servers, lan (cidr + gateway), hosts.{muffin,yarn} (ip/alias/ssh_host_key),
ssh_keys.{laptop,desktop,ci_deploy}.
threaded through specialArgs on all three hosts + home-manager extraSpecialArgs +
homeConfigurations.primary + serverLib. service-configs.nix now takes
{ site_config } as a function arg and drops its https namespace; per-service
domains (gitea/matrix/ntfy/mollysocket/livekit/firefox-sync/grafana) are
derived from site_config.domain. ~15 service files and 6 vm tests migrated.
breakage fixes rolled in:
- home/progs/zen/dark-reader.nix: 5 stale *.gardling.com entries in
disabledFor rewritten to *.sigkill.computer (caddy 301s the old names so
these never fired and the new sigkill urls were getting dark-reader applied)
- modules/desktop-common.nix: drop unused hugepagesz=1G/hugepages=3
kernelParams (no consumer on mreow or yarn; xmrig on muffin still reserves
its own via services/monero/xmrig.nix)
verification: muffin toplevel is bit-identical to pre-refactor baseline.
mreow/yarn toplevels differ only in boot.json kernelParams + darkreader
storage.js (nix-diff verified). deployGuardTest and fail2banVaultwardenTest
(latter exercises site_config.domain via bitwarden.nix) pass.
Three edge cases broke annotations on reboot or interrupted sessions:
- state.pop() ran before grafana_close(), so a failed PATCH (Grafana
still restarting after reboot) permanently lost the grafana_id and
left the annotation open forever in Grafana.
- a single poll with no sessions closed every active annotation, so
Jellyfin restarts or client reconnects produced spurious close +
duplicate-open pairs.
- timeEnd was always now_ms, so a reboot during playback wrote an
annotation reading as if the user watched through the outage.
Fix: track last_seen_ms and missing_count in state; retain entries
until grafana_close succeeds (retry indefinitely); require
MISSING_THRESHOLD absent polls before close; clamp close_time to
last_seen_ms + (MISSING_THRESHOLD + 1) * POLL_INTERVAL.
Adds three subtests in tests/jellyfin-annotations.nix that each fail
on the old code and pass on the new.
Reset u->freezer_state to FREEZER_RUNNING when a unit transitions to
inactive/failed. Without this, any SIGKILL path to a frozen unit
(systemctl kill, OOM, watchdog SIGABRT-then-KILL, segfault) leaves
the unit stranded at FreezerState=frozen with no recovery short of
a reboot. Complements upstream PR #38528 which covers only the
watchdog path.
xmrig-auto-pause never calls `systemctl freeze` itself (direct
cgroup.freeze writes bypass the bug class entirely), so the patch
is defensive: benefits systemd-homed on lock, user-session freezing
on suspend, or anything else that may freeze units on muffin.
Patching systemd cascades udev-check-hook hash changes into fuse3 -->
e2fsprogs and into fish. Two test-suite workarounds ride along:
drop e2fsprogs m_hugefile (4 GiB sparse file, fails on some build
sandboxes) and fish doCheck=false (cargo pexpect TTY tests). Both
are environmental, unrelated to the patch.
Unified CI on nixos repo is proven end-to-end (CI run on 836f80a deployed to
muffin successfully and yarn's pull URL now serves from the new build). The
two per-repo git-crypt keys are no longer in use by any active pipeline.
Old dotfiles and server-config repos had Gitea Actions disabled before this
commit, so no CI race possible.
Bundles Phases 5.5 + 6.2 + 6.3 into one invocation. Order-sensitive: pre-seed
must happen BEFORE the deploy-rs run so yarn's pull-update URL stays resolvable
across the harmonia /var/lib/dotfiles-deploy \u2192 /var/lib/nix-deploy rename.
The two legacy entries git-crypt-key-{dotfiles,server-config} stay until
muffin has deployed this config at least once and the new CI pipeline is
green. Phase 6 removes them after cutover.
- .gitattributes declares secrets/** covered by git-crypt filter
- New symmetric key at $HOME/.nixos-git-crypt.key (chmod 400, not committed)
- All 36 files under secrets/ re-encrypted via the clean filter on 'git add':
- 5 files in secrets/desktop/ (wifi, secureboot, disk pw, cache netrc, hash)
- 3 files in secrets/home/ (hm api keys + steam id)
- 26 files in secrets/server/ (.age + .nix + .tar + livekit_keys)
- 2 files in secrets/usb-secrets/ (agenix identity)
'git-crypt status' confirms 36 encrypted, 150 non-encrypted.
Old git-crypt keys from the two subtree-merged repos are in the historical subtree commits (pre-Phase 2). To decrypt pre-unify history one still needs the old GPG-encrypted keys, which survive at:
~/nixos-migration-aux-*.tar.gz
URL contract (https://nix-cache.sigkill.computer/deploy/<host>) is preserved;
only the on-disk Caddy root and the tmpfiles directory change. Phase 6 seeds
/var/lib/nix-deploy/ from the old path before deploying the new config, so the
pull-update on yarn stays working across the cutover.
- .gitea/workflows/deploy.yml: three jobs (mreow, yarn, muffin) sharing a single git-crypt unlock step. muffin job retains the healthcheck + ntfy success/failure notifications from the old server-config pipeline verbatim.
- CI writes to /var/lib/nix-deploy/ (renamed from /var/lib/dotfiles-deploy/). The URL path /deploy/<host> is preserved; only the on-disk directory name changes. Harmonia's Caddy root is updated in Phase 6.
- deploy.sh: inspects hostname, dispatches to nixos-rebuild for desktops or deploy-rs for muffin. Accepts boot/switch/test/build/muffin.
- AGENTS.md: intersected rules from both repos, split into host-agnostic conventions + muffin-specific service pattern. Rewritten layout section reflects the new tree.