nix: hyperhive owns nixpkgs pin via follows; bump to nixos-26.05 (#526)
Drops the hardcoded `nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"`
from the meta flake renderer. meta now declares:
nixpkgs.follows = "hyperhive/nixpkgs";
nixpkgs-unstable.follows = "hyperhive/nixpkgs-unstable";
so every agent-level `inputs.<X>.inputs.nixpkgs.follows = "nixpkgs"`
resolves transitively to hyperhive's own pin. One channel decision
in the whole tree (hyperhive/flake.nix line 5), no second source
to drift.
`closes #317` invariant still holds: `nixpkgs` is a single canonical
name in the meta tree, it just resolves through hyperhive instead
of being its own root input.
Also:
- bump hyperhive/flake.nix line 5: `nixos-25.11` → `nixos-26.05`,
flake.lock relocked
- flake_check.rs fixtures bumped cosmetically (synthetic data, not
shape-affecting)
- rename + rewrite `render_flake_declares_canonical_nixpkgs` →
`render_flake_aliases_nixpkgs_to_hyperhive`; asserts the new
follows-form AND the absence of any literal `nixpkgs.url`
- drop the now-redundant `render_flake_collapses_hyperhive_nixpkgs_via_follows`
test (the old indirection it covered no longer exists)
Closes #526.
This commit is contained in:
parent
34f0c11936
commit
a43a95cc90
4 changed files with 44 additions and 45 deletions
8
flake.lock
generated
8
flake.lock
generated
|
|
@ -17,16 +17,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778737229,
|
"lastModified": 1779971959,
|
||||||
"narHash": "sha256-6xWoytx8jFW4PF1GjRm/i/53trbpKGfz6zjzQGBr4cI=",
|
"narHash": "sha256-R5nauXyqyfRUFiZycFFZdkF7wl6eaUpPLst35+2nJQY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d7a713c0b7e47c908258e71cba7a2d77cc8d71d5",
|
"rev": "ec942ba042dad5ef097e2ef3a3effc034241f011",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-25.11",
|
"ref": "nixos-26.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
description = "hyperhive — multi-Claude-Code-agent orchestration on nixos-containers";
|
description = "hyperhive — multi-Claude-Code-agent orchestration on nixos-containers";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
|
||||||
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
# Crane (replaces naersk #538). Stateless — no nixpkgs input to
|
# Crane (replaces naersk #538). Stateless — no nixpkgs input to
|
||||||
# follow; `crane.mkLib pkgs` returns the lib at whatever pkgs we
|
# follow; `crane.mkLib pkgs` returns the lib at whatever pkgs we
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ mod tests {
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {"rev": "aaa"},
|
"locked": {"rev": "aaa"},
|
||||||
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-25.11", "type": "github"}
|
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-26.05", "type": "github"}
|
||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {"rev": "bbb"},
|
"locked": {"rev": "bbb"},
|
||||||
|
|
@ -335,15 +335,15 @@ mod tests {
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {"rev": "aaa"},
|
"locked": {"rev": "aaa"},
|
||||||
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-25.11", "type": "github"}
|
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-26.05", "type": "github"}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {"rev": "ccc"},
|
"locked": {"rev": "ccc"},
|
||||||
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-25.11", "type": "github"}
|
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-26.05", "type": "github"}
|
||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {"rev": "ddd"},
|
"locked": {"rev": "ddd"},
|
||||||
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-25.11", "type": "github"}
|
"original": {"owner": "NixOS", "repo": "nixpkgs", "ref": "nixos-26.05", "type": "github"}
|
||||||
},
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"locked": {"rev": "eee"},
|
"locked": {"rev": "eee"},
|
||||||
|
|
|
||||||
|
|
@ -333,21 +333,24 @@ where
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
out.push_str("{\n description = \"hyperhive deployed agents\";\n inputs = {\n");
|
out.push_str("{\n description = \"hyperhive deployed agents\";\n inputs = {\n");
|
||||||
// Pin canonical nixpkgs revisions at the meta level so every input
|
// hyperhive's own flake.nix is the single channel-pin authority
|
||||||
// that pulls a nixpkgs sub-input can `follows = "nixpkgs"` and
|
// (closes #526). meta declares `nixpkgs` + `nixpkgs-unstable` as
|
||||||
// collapse to one shared node (closes #317). hyperhive's own
|
// aliases for hyperhive's sub-inputs via `follows`, so every
|
||||||
// flake.nix picks `nixos-25.11`; we mirror that here so meta and
|
// agent-level `inputs.<X>.inputs.nixpkgs.follows = "nixpkgs"`
|
||||||
// hyperhive don't diverge into two stable channels by default.
|
// directive resolves transitively to hyperhive's pin. One
|
||||||
// Operator can override these at the meta layer to slide every
|
// channel decision in the whole tree, no second source to drift.
|
||||||
// dependent agent onto a different channel in one move.
|
//
|
||||||
out.push_str(" nixpkgs.url = \"github:NixOS/nixpkgs/nixos-25.11\";\n");
|
// Operators who want to slide the whole swarm onto a different
|
||||||
out.push_str(" nixpkgs-unstable.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\";\n");
|
// channel do it at the host level via
|
||||||
|
// `inputs.hyperhive.inputs.nixpkgs.follows = "nixpkgs"`, which
|
||||||
|
// makes hyperhive's nixpkgs = the host's nixpkgs and cascades
|
||||||
|
// through to every agent. (closes #317 also stays satisfied —
|
||||||
|
// `nixpkgs` is still a single canonical name in the meta tree,
|
||||||
|
// it just resolves through hyperhive instead of being its own
|
||||||
|
// root input.)
|
||||||
let _ = writeln!(out, " hyperhive.url = \"{hyperhive_flake}\";");
|
let _ = writeln!(out, " hyperhive.url = \"{hyperhive_flake}\";");
|
||||||
// Collapse hyperhive's own `nixpkgs` + `nixpkgs-unstable` inputs
|
out.push_str(" nixpkgs.follows = \"hyperhive/nixpkgs\";\n");
|
||||||
// into meta's. Without this, hyperhive's flake.nix declarations
|
out.push_str(" nixpkgs-unstable.follows = \"hyperhive/nixpkgs-unstable\";\n");
|
||||||
// become independent `nixpkgs_N` nodes in meta/flake.lock.
|
|
||||||
out.push_str(" hyperhive.inputs.nixpkgs.follows = \"nixpkgs\";\n");
|
|
||||||
out.push_str(" hyperhive.inputs.nixpkgs-unstable.follows = \"nixpkgs-unstable\";\n");
|
|
||||||
for spec in agents {
|
for spec in agents {
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
out,
|
out,
|
||||||
|
|
@ -563,7 +566,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn render_flake_declares_canonical_nixpkgs() {
|
fn render_flake_aliases_nixpkgs_to_hyperhive() {
|
||||||
let out = render_flake(
|
let out = render_flake(
|
||||||
"github:example/hyperhive",
|
"github:example/hyperhive",
|
||||||
8000,
|
8000,
|
||||||
|
|
@ -571,28 +574,24 @@ mod tests {
|
||||||
&std::collections::HashMap::new(),
|
&std::collections::HashMap::new(),
|
||||||
&[sample_spec("alice", false, 9001)],
|
&[sample_spec("alice", false, 9001)],
|
||||||
);
|
);
|
||||||
// Top-level nixpkgs inputs pinned by meta — every nested
|
// Meta's `nixpkgs` + `nixpkgs-unstable` are aliases for
|
||||||
// nixpkgs input can follow these instead of resolving its own
|
// hyperhive's sub-inputs (closes #526). Single channel-pin
|
||||||
// (closes #317).
|
// authority: hyperhive's own flake.nix.
|
||||||
assert!(out.contains("nixpkgs.url = \"github:NixOS/nixpkgs/nixos-25.11\""));
|
assert!(
|
||||||
assert!(out.contains("nixpkgs-unstable.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\""));
|
out.contains("nixpkgs.follows = \"hyperhive/nixpkgs\""),
|
||||||
}
|
"missing nixpkgs follows alias:\n{out}"
|
||||||
|
);
|
||||||
#[test]
|
assert!(
|
||||||
fn render_flake_collapses_hyperhive_nixpkgs_via_follows() {
|
out.contains("nixpkgs-unstable.follows = \"hyperhive/nixpkgs-unstable\""),
|
||||||
let out = render_flake(
|
"missing nixpkgs-unstable follows alias:\n{out}"
|
||||||
"github:example/hyperhive",
|
);
|
||||||
8000,
|
// And conversely: no literal channel ref baked in. If this
|
||||||
"she/her",
|
// assertion fails, someone reintroduced a hardcoded ref —
|
||||||
&std::collections::HashMap::new(),
|
// see #526 for why that drifts.
|
||||||
&[],
|
assert!(
|
||||||
|
!out.contains("nixpkgs.url ="),
|
||||||
|
"no literal `nixpkgs.url` should be emitted (hyperhive owns the pin):\n{out}"
|
||||||
);
|
);
|
||||||
// hyperhive's own `nixpkgs` + `nixpkgs-unstable` declarations
|
|
||||||
// get redirected at meta's. Without these, meta/flake.lock
|
|
||||||
// ends up with separate `nixpkgs_N` nodes for hyperhive's
|
|
||||||
// copy (the pre-#317 status quo).
|
|
||||||
assert!(out.contains("hyperhive.inputs.nixpkgs.follows = \"nixpkgs\""));
|
|
||||||
assert!(out.contains("hyperhive.inputs.nixpkgs-unstable.follows = \"nixpkgs-unstable\""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue