refactor: drop specialArgs and anonymous module imports #1286

Open
lytedev wants to merge 6 commits from propose/special-args-cleanup into main
Owner

Please review commit by commit; each message has the rationale and how it was tested.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh

Please review commit by commit; each message has the rationale and how it was tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
beefcake, battleship, router, rascal, htpc and htpc2 imported
nixos-hardware modules through a `hardware` module argument that only
lib/host.nix's specialArgs provided, and htpc2 did the same with
`diskoConfigurations`. Every other host already lists them by name in
`hardwareModules` / `diskConfig`, which lib/host.nix resolves outside
the module system, so these hosts now do the same. generic.nix took
`diskoConfigurations` without using it.

This is the first half of dropping specialArgs entirely; see
https://ysun.co/special/ for why an injected module argument makes a
module depend on whoever evaluates it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
No module reads `hardware` or `diskoConfigurations` as a module
argument any more, and darwinHost's specialArgs was already empty.
Without specialArgs a module in this flake can only depend on what it
is curried with or what it imports, so it evaluates the same in any
nixosSystem call.

Tested by evaluating every nixosConfigurations.<host> toplevel drvPath
before and after this and the previous commit, with lyte.flakeStorePath
and system.configurationRevision pinned (both embed the flake's own
source, which changes with any edit): all 30 identical. router needed
lyte.router.netboot.enable forced off as well, because it embeds the
netboot image's closure, where the pin does not reach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
`import path` hands the module system an anonymous function, so an
evaluation error in a host file names no file and the module gets no
key to deduplicate by. Passing the path lets the module system import
it and record where it came from. hostImportsFor still needs the
imported value to read hardwareModules and diskConfig out of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
battleship.nix and battleship/ci-runner-vm.nix read `nixvirt` as a
module argument that an extra module in packages/hosts/default.nix set
through `_module.args`. A module argument set that way cannot be used
in `imports` (it needs `config`, which needs `imports` first), and two
modules setting it conflict even when the values agree. Both files now
take nixvirt as a static argument applied with lib.modules.importApply,
which keeps the file name in evaluation errors. baseHost grows
`hostModuleStaticArgs` so a host file can be curried while
hostImportsFor still reads hardwareModules out of it.

importApply wraps the module one level deeper, which changes the order
that list-typed definitions merge in. battleship's toplevel drv
therefore changes, but only by order: system-path holds the same
package set, the set of derivations in the closure is identical, and
the otel metrics pipeline lists the same three receivers (node,
smartctl, zfs) in a different order. Applying the curried module
without the wrapper and setting _file/key on its result by hand keeps
the drv byte-identical, but reimplements importApply to avoid a change
no service can observe, so I did not keep it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
htpifour.nix and base.nix take an `outputs` module argument that
nothing in this flake provides, and generic-headless.nix defines
lyte.shell.enable twice, which nix rejects at parse time. None of them
is wired into packages/hosts/default.nix. History keeps them if one is
ever wanted as a starting point.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
refactor(beefcake): import service modules by path
All checks were successful
/ check-format (push) Successful in 11s
/ build (push) Successful in 10m9s
d83630b4ef
`builtins.map import` handed the module system anonymous functions,
which gives an evaluation error no file name and gives the module no
key to deduplicate by. beefcake/daniel.nix was listed twice, and
because nothing deduplicated it, its definitions merged twice: daniel
appeared two or three times in wheel, users, caddy, jellyfin and the
other groups it joins, and postgresql-setup ran the ensure statements
for the daniel database and role twice. Importing by path deduplicates
it, so beefcake's closure changes by exactly those duplicates. Both
were idempotent, so nothing observable changes on the host. The second
listing is deleted too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Asr2hJ2uNCVY7UH8yPE4Vh
All checks were successful
/ check-format (push) Successful in 11s
Required
Details
/ build (push) Successful in 10m9s
Required
Details
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin propose/special-args-cleanup:propose/special-args-cleanup
git switch propose/special-args-cleanup
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lytedev/nix!1286
No description provided.