Repository navigation
feat(modules): export the Sensorica event profile once (#33) - #59
Conversation
Add nixosModules.sensorica-event-node, exporting the workshop event
profile (Holochain 0.6 line, hREA/Kando/Requests & Offers, one network
seed, the installer timeout and the two metrics options) as a single
NixOS module layered on holochain-edgenode. examples/sensorica-fleet
now imports it instead of computing fleetLine/fleetHapps itself, and
modules/sensorica-happs.nix (moved from examples/sensorica-fleet/happs.nix)
is the one place the three hApp bundles are fetched.
checks.eventProfileParity (examples/sensorica-fleet/flake.nix) fails
evaluation under nix flake check --no-build if edgenode-01's effective
package, hApp srcs, seeds, installer timeout or metrics enables ever
diverge from the module's own defaults.
happs is set leaf by leaf with mkDefault rather than as one
mkDefault {...} attrset: attrsOf submodule merging does not push an
outer mkDefault recursively through a raw nested attribute set, so a
host overriding one hApp's networkSeed left its src undefined until
this was corrected (verified empirically before landing).
The previous commit's happs = mkDefault {...} whole-attrset default was
never actually staged in that form after the empirical fix described
in its own commit message and header comment landed on disk; this
commit is that fix, staged. attrsOf submodule merging does not push an
outer mkDefault recursively through a raw nested attribute set, so a
host overriding one hApp's networkSeed left its src undefined. Each
happs.<app>.src and happs.<app>.networkSeed now carries its own
mkDefault, which does survive a sibling override (reproduced both ways
with a minimal lib.evalModules case and against the real module).
…a-event-node Once #59 and #61 are both in, hosts/common.nix no longer reads fleetLine and fleetHapps: the fleet imports nixosModules.sensorica-event-node for them. holoportTarget still passed the old arguments, so the installed system had no hApps, no installer unit, and vmTestHoloportInstall failed ("holochain-happ-installer.service is inactive and there are no pending jobs"). It now imports the module the fleet imports, and the check passes: hrea, kando and requests-and-offers enabled 20 to 43 s after boot.
…stalled = false A plain happs assignment is merged with the profile's keys, since happs is attrsOf submodule, so the per-leaf defaults still fill in every workshop hApp. The module comment and the fleet README claimed otherwise.
Review fixes pushed (407b5ff, f047c15)Blocking item fixed: the false override claim. Evidence, evaluated against
Merge of Local checks on f047c15:
VM tests were not run locally: neither change touches a module the VM tests exercise. Not done here, still open from the review: lab commit 92cf87f has to ride with whichever of #59 and #61 merges second. It is not needed on this branch while #61 is unmerged. After this merges, |
…a-event-node Once #59 and #61 are both in, hosts/common.nix no longer reads fleetLine and fleetHapps: the fleet imports nixosModules.sensorica-event-node for them. holoportTarget still passed the old arguments, so the installed system had no hApps, no installer unit, and vmTestHoloportInstall failed ("holochain-happ-installer.service is inactive and there are no pending jobs"). It now imports the module the fleet imports, and the check passes: hrea, kando and requests-and-offers enabled 20 to 43 s after boot.
Closes #33.
Why
The Sensorica workshop event profile (Holochain 0.6 line, three hApps, one network seed) existed twice:
examples/sensorica-fleet/flake.nixcomputedfleetLine/fleetHappsfrom the root flake's ownholochain-0_6/hc-0_6outputs andhapps.nix, and Soushi's private homelab rehearses the same workshop node by importingexamples/sensorica-fleet/happs.nixby path and repeating the line, the three hApps and the seed. Two copies drift.What
modules/sensorica-event-node.nix(new): a NixOS module, exported asnixosModules.sensorica-event-node, that setsservices.holochain-edgenode'spackage,hcPackage,happs(hREA, Kando, Requests & Offers, all on network seedsensorica-workshop-2026),installerTimeout(900s) and the two metrics enables (metricsExporter,conductorMetrics), all viamkDefaultso a host overrides any one of them with an ordinary assignment. Declares no options of its own. Deliberately not part ofnixosModules.default— the other four modules are generic capabilities, and this one is the workshop's opinionated hApp set.modules/sensorica-happs.nix(moved fromexamples/sensorica-fleet/happs.nix): the three hApp bundles, fetched by hash, hash-and-URL comments intact. Nothing binary entered git before or after.examples/sensorica-fleet:flake.nixnow importsnixosModules.sensorica-event-nodeinfleetModulesinstead of computingfleetLine/fleetHappsitself;hosts/common.nixdropped the now-redundantpackage/hcPackage/happs/installerTimeout/metrics settings (keptenable/openFirewall, which stay host-specific); a new inputholonix-0_6.follows = "nixos-holochain/holonix-0_6"was added (the profile module resolves its 0.6-line packages through that input, the same way the existingholonixfollow servesholochain-edgenode's own default package);flake.lockwas relocked for that one new input only (verified: 4-line diff, no repin ofnixos-holochain).checks.eventProfileParity(new, inexamples/sensorica-fleet/flake.nix): fails evaluation ifedgenode-01's effective package, hApp srcs, network seeds, installer timeout or metrics enables ever diverge from the module's own defaults (evaluated fresh vialib.evalModuleswith_module.check = false, the same trickdocs/module-options.md's generator already uses). The assertion is forced while the check derivation is constructed, sonix flake check --no-build— what CI and the review commands run — catches a divergence without building anything.docs/module-options.md: unchanged. The new module declares no options, so a freshnix build .#options-docdiffs identical to the committed file (verified).A correctness finding along the way
The first version of the module set
happs = lib.mkDefault { hrea = {...}; kando = {...}; requests-and-offers = {...}; };as one whole-attrset default, on the assumption that NixOS's module system pushes an outermkDefaultrecursively down through a nested attribute set (pushDownProperties). Verified empirically (minimallib.evalModulesreproduction, then confirmed against the real modules) that this does not hold forattrsOf (submodule ...): a host overriding just one hApp'snetworkSeedleft that hApp'ssrc"accessed but has no value defined" — the sibling override discarded the whole-set default rather than leaving it in place. Fixed by settinghapps.<app>.srcandhapps.<app>.networkSeedeach as their ownmkDefault, which does survive a sibling override (reproduced and confirmed both ways). The module's header comment documents this.How to test
From a checkout of this branch:
Falsifier, run and reverted before this PR: added
services.holochain-edgenode.happs.hrea.networkSeed = "drifted-seed";tohosts/edgenode-01/configuration.nix, reran the example'snix flake check --no-build --override-input ...:exit 1, no build attempted. Reverted, reran, exit 0 again.
docs/module-options.mdsync also checked directly:diff <(nix build .#options-doc --print-out-paths) docs/module-options.md— no diff, exit 0 (matches what CI's "Option reference is in sync" step checks).Consumer snippet (external host, e.g. the homelab)
That is the whole profile. Documented in
examples/sensorica-fleet/README.mdunder "Consuming the event profile from another host".Not covered
checks.*(vmTest*,conductorMetricsJq, etc.) importnixosModules.sensorica-event-nodeornixosModules.default, and this PR doesn't touchholochain-edgenode.nixor any other module those checks exercise, so none needed rerunning.nix buildof a VM check isn't possible in this sandbox anyway (no/dev/kvm).docs/architecture.md: scoped to the four generic modules' internal mechanics (systemd units, network config generation); the new module adds no options or units, so left untouched. The consumer-facing documentation lives in the example README per the issue's own "done when" wording..github/workflows/ci.yml's "Build the VM tests" step) wasn't extended to nameeventProfileParity: that check lives in the example flake's ownchecks, not the root flake's, andnix flake check --no-build(already run against the example in thecheckjob) fully exercises it — verified above, since the assertion is forced during evaluation, not during build.