fix(#2213): decouple docs drvs from self store path via narrow nixSrc

The docs evaluation referenced self.nixosConfigurations.agent-base and
self.nixosModules.default — both tied to self's full flake store path.
Every commit produces a new self hash (even when only Rust or frontend
files change), so docs drvs change on every commit and the remote
builder (muede-pc2) must rebuild them from scratch each time.

Fix: use builtins.path on the nix/ directory with
builtins.unsafeDiscardStringContext to produce a content-addressed store
path (nixSrc) that only changes when .nix files change. Evaluate both
hostEval and agentEval from nixSrc using stub package args (pkgs.emptyFile /
pkgs.emptyDirectory) instead of self.overlays.default, which avoids
pulling in the Rust and frontend build closures.

Now docs drvs only change when a .nix file changes. PRs that touch only
Rust or frontend code hit the remote builder cache instead of forcing a
rebuild. Closes the disk-pressure-induced CI failure loop on muede-pc2.

Forge URLs in transformOptions updated to prepend nix/ prefix correctly
(nixSrc is a copy of nix/, so stripped paths need nix/ re-added).
This commit is contained in:
atlas 2026-07-04 14:04:52 +02:00 committed by mara
commit eadb25fc07

View file

@ -11,17 +11,50 @@
# prose `/docs/` tree. Full pipeline + subtree-pick / output-tree # prose `/docs/` tree. Full pipeline + subtree-pick / output-tree
# rationale: docs/gotchas.md::Nix options reference. # rationale: docs/gotchas.md::Nix options reference.
let let
# Content-addressed narrow source covering only the nix/ directory.
# `builtins.unsafeDiscardStringContext` strips `self`'s store-path
# context so `builtins.path` hashes only the nix/ file content, not
# the full flake source (Rust, frontend, markdown, …). Result: the
# docs drvs only change when a .nix file changes, not on every
# commit — the muede-pc2 remote builder can reuse its cached result
# for any commit that doesn't touch nix/.
nixSrc = builtins.path {
path = builtins.unsafeDiscardStringContext (toString self + "/nix");
name = "hyperhive-nix-src";
};
# Stub overlay that satisfies pkgs.hyperhive-* references in module
# option defaults without depending on self's Rust / frontend builds.
# nixosOptionsDoc renders `defaultText` for these options anyway; the
# stubs just prevent attribute-missing eval errors.
docsStubOverlay = _final: _prev: {
hyperhive = pkgs.emptyFile;
hyperhive-frontend = pkgs.emptyDirectory;
hyperhive-assets = pkgs.emptyDirectory;
hyperhive-docs = pkgs.emptyDirectory;
};
# Stub host system: every hyperhive subsystem `mkForce false` so # Stub host system: every hyperhive subsystem `mkForce false` so
# heavy build inputs (matrix container, forge, etc.) stay out of # heavy build inputs (matrix container, forge, etc.) stay out of
# the eval — only option *declarations* matter for the doc walk. # the eval — only option *declarations* matter for the doc walk.
# Import hive-c0re.nix from the content-addressed nixSrc with stub
# package args so the eval doesn't depend on self's Rust builds.
hostEval = nixosSystem { hostEval = nixosSystem {
system = pkgs.stdenv.hostPlatform.system; system = pkgs.stdenv.hostPlatform.system;
modules = [ modules = [
self.nixosModules.default (import "${nixSrc}/modules/hive-c0re.nix" {
hyperhivePackage = _system: pkgs.emptyFile;
hyperhiveFrontend = _system: pkgs.emptyFile;
hyperhiveAssets = _system: pkgs.emptyDirectory;
hyperhiveFlake = "";
hyperhiveDocs = "";
agentBaseToplevel = pkgs.emptyFile;
managerToplevel = pkgs.emptyFile;
})
( (
{ lib, ... }: { lib, ... }:
{ {
nixpkgs.overlays = [ self.overlays.default ]; nixpkgs.overlays = [ docsStubOverlay ];
fileSystems."/" = { fileSystems."/" = {
device = "/dev/null"; device = "/dev/null";
fsType = "tmpfs"; fsType = "tmpfs";
@ -35,14 +68,23 @@ let
]; ];
}; };
# Reuse the already-evaluated agent-base config — its options tree is # Agent module eval from the content-addressed nixSrc. Relative
# identical to what a real agent container sees, no second eval needed. # imports inside agent-base.nix (e.g. ./harness-base.nix) resolve
agentEval = self.nixosConfigurations.agent-base; # correctly against the nixSrc directory tree.
agentEval = nixosSystem {
system = pkgs.stdenv.hostPlatform.system;
modules = [
"${nixSrc}/templates/agent-base.nix"
{ nixpkgs.overlays = [ docsStubOverlay ]; }
];
};
# Rewrite option declaration paths from nix-store absolute paths to # Rewrite option declaration paths from nix-store absolute paths to
# forge URLs so rendered docs link back to source. # forge URLs so rendered docs link back to source.
# nixSrc is a content-addressed copy of nix/; strip its store prefix
# and prepend nix/ to recover the repo-relative path.
forgeRoot = "https://forge.darkest.space/hyperhive/hyperhive/src/branch/main"; forgeRoot = "https://forge.darkest.space/hyperhive/hyperhive/src/branch/main";
storePrefix = toString self + "/"; nixSrcPrefix = builtins.unsafeDiscardStringContext (toString nixSrc + "/");
transformOptions = transformOptions =
opt: opt:
opt opt
@ -52,8 +94,8 @@ let
let let
declStr = toString decl; declStr = toString decl;
relPath = relPath =
if lib.hasPrefix storePrefix declStr then if lib.hasPrefix nixSrcPrefix declStr then
lib.removePrefix storePrefix declStr "nix/" + lib.removePrefix nixSrcPrefix declStr
else else
baseNameOf declStr; baseNameOf declStr;
in in
@ -136,7 +178,7 @@ let
`hyperhive.forge.*`, `hyperhive.matrix.*`, `hyperhive.gui.*`). `hyperhive.forge.*`, `hyperhive.matrix.*`, `hyperhive.gui.*`).
Regenerate with `nix build .#docs` (bundle), `.#docs-host`, or Regenerate with `nix build .#docs` (bundle), `.#docs-host`, or
`.#docs-agent`. `.#docs-agent`. Consumed by the website repo to render `/options/`.
''; '';
hostMD = mkMarkdownPage "docs-host" "hyperhive host options" hostDoc; hostMD = mkMarkdownPage "docs-host" "hyperhive host options" hostDoc;