Files

121 lines
74 KiB
Go

// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package nodeengine
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/node-engine/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "asked on the node's subject", subject: "mesh.seat.node-engine.event.asked.ace", given: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"state\":\"asked\",\"subject\":\"/srv/media\"}", wire: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"state\":\"asked\",\"subject\":\"/srv/media\"}",
decode: func(b []byte) (any, error) { var v AskedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.asked\\.[A-Za-z0-9_-]+$")},
{name: "done on the node's subject", subject: "mesh.seat.node-engine.event.done.ace", given: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"handed over: owner media, group media, mode 2775\",\"state\":\"done\",\"subject\":\"/srv/media\"}", wire: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"handed over: owner media, group media, mode 2775\",\"state\":\"done\",\"subject\":\"/srv/media\"}",
decode: func(b []byte) (any, error) { var v DoneEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.done\\.[A-Za-z0-9_-]+$")},
{name: "refused on the node's subject", subject: "mesh.seat.node-engine.event.refused.ace", given: "{\"act\":\"access-act\",\"ask\":\"access-act-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"the operator said no\",\"state\":\"refused\",\"subject\":\"library:music\"}", wire: "{\"act\":\"access-act\",\"ask\":\"access-act-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"the operator said no\",\"state\":\"refused\",\"subject\":\"library:music\"}",
decode: func(b []byte) (any, error) { var v RefusedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.refused\\.[A-Za-z0-9_-]+$")},
{name: "manifest-reads-changed when the engine started", subject: "mesh.seat.node-engine.event.manifest-reads-changed.ace", given: "{\"at\":\"2026-11-04T10:00:00Z\",\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"v\":1,\"why\":\"started\"}", wire: "{\"at\":\"2026-11-04T10:00:00Z\",\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"v\":1,\"why\":\"started\"}",
decode: func(b []byte) (any, error) {
var v ManifestReadsChangedEvent
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.manifest-reads-changed\\.[A-Za-z0-9_-]+$")},
{name: "manifest-reads-changed when the node returned, from an engine that states none", subject: "mesh.seat.node-engine.event.manifest-reads-changed.g14", given: "{\"at\":\"2026-11-04T10:05:00Z\",\"node\":\"g14\",\"v\":1,\"why\":\"returned\"}", wire: "{\"at\":\"2026-11-04T10:05:00Z\",\"node\":\"g14\",\"v\":1,\"why\":\"returned\"}",
decode: func(b []byte) (any, error) {
var v ManifestReadsChangedEvent
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.manifest-reads-changed\\.[A-Za-z0-9_-]+$")},
{name: "the finding of a seat list unread, as the engine writes it", subject: "", given: "{\"at\":\"2026-11-05T14:00:00Z\",\"key\":\"machine.ace.seat-list-unread\",\"kind\":\"seat-list-unread\",\"observer\":\"mesh-host\",\"severity\":\"warning\",\"source\":\"node-engine.seat-list\",\"subject\":{\"id\":\"ace\",\"machine\":\"ace\",\"scope\":\"machine\"},\"summary\":\"the seat list has not been read for five minutes\",\"v\":1}", wire: "{\"at\":\"2026-11-05T14:00:00Z\",\"key\":\"machine.ace.seat-list-unread\",\"kind\":\"seat-list-unread\",\"observer\":\"mesh-host\",\"severity\":\"warning\",\"source\":\"node-engine.seat-list\",\"subject\":{\"id\":\"ace\",\"machine\":\"ace\",\"scope\":\"machine\"},\"summary\":\"the seat list has not been read for five minutes\",\"v\":1}",
decode: func(b []byte) (any, error) { var v FindingsByKeyValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a node's packages, present and absent (captured from ace, shortened)", subject: "", given: "{\"node\":\"ace\",\"packages\":[{\"absent\":false,\"modules\":[\"avahi\"],\"package\":\"avahi\"},{\"absent\":false,\"modules\":[\"mesh-build-go\",\"mesh-build-node\"],\"package\":\"bubblewrap\"},{\"absent\":true,\"modules\":[\"time-sync\"],\"package\":\"ntp\"}]}", wire: "{\"node\":\"ace\",\"packages\":[{\"absent\":false,\"modules\":[\"avahi\"],\"package\":\"avahi\"},{\"absent\":false,\"modules\":[\"mesh-build-go\",\"mesh-build-node\"],\"package\":\"bubblewrap\"},{\"absent\":true,\"modules\":[\"time-sync\"],\"package\":\"ntp\"}]}",
decode: func(b []byte) (any, error) { var v PackagesByNodeValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "buildah composed on ace (resources captured from the declaration of 2026-10-24; the fingerprint stands in for the indexer's)", subject: "", given: "{\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"module\":\"buildah\",\"node\":\"ace\",\"resources\":[{\"id\":\"buildah.buildah\",\"module\":\"buildah\",\"package\":\"buildah\",\"type\":\"package\"}],\"v\":1}", wire: "{\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"module\":\"buildah\",\"node\":\"ace\",\"resources\":[{\"id\":\"buildah.buildah\",\"module\":\"buildah\",\"package\":\"buildah\",\"type\":\"package\"}],\"v\":1}",
decode: func(b []byte) (any, error) {
var v ComposedByNodeModuleFingerprintValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "node-tools composed with a filled file (captured; the fingerprint stands in)", subject: "", given: "{\"fp\":\"src2:6e6f64652d6e6f64652d6e6f64652d6e6f64652d6e6f64652d6e6f64652d6e6f\",\"module\":\"node-tools\",\"node\":\"ace\",\"resources\":[{\"id\":\"node-tools.mesh-state\",\"mode\":\"0755\",\"module\":\"node-tools\",\"path\":\"/var/lib/mesh/node-tools\",\"type\":\"directory\"},{\"id\":\"node-tools.interpreter\",\"module\":\"node-tools\",\"package\":\"nodejs\",\"type\":\"package\"},{\"digest\":\"sha256:ef790876783d817903b337b8418b1eb21fb49d34128a390bbf7c3d08a4b2be8a\",\"env\":{\"MESH_AGENT_ACCOUNT\":\"ace\",\"MESH_AGENT_HOME\":\"/home/ace\",\"MESH_BROKER_FILE\":\"/var/lib/mesh/node-tools/broker\",\"MESH_OPERATOR_ACCOUNT\":\"ace\",\"MESH_OPERATOR_HOME\":\"/home/ace\",\"MESH_TOOL_ENV\":\"{\\\"baserow\\\":{\\\"MESH_BASEROW_CONFIG_FILE\\\":\\\"/var/lib/mesh/baserow/config.json\\\",\\\"MESH_BASEROW_URL\\\":\\\"http://127.0.0.1:20011\\\"},\\\"bazarr\\\":{\\\"MESH_BAZARR_CONFIG_DIR\\\":\\\"/var/lib/bazarr/config\\\",\\\"MESH_BAZARR_CONFIG_FILE\\\":\\\"/var/lib/bazarr/config.json\\\",\\\"MESH_BAZARR_CONTAINER\\\":\\\"bazarr\\\",\\\"MESH_BAZARR_URL\\\":\\\"http://127.0.0.1:20020\\\"},\\\"bookshelf\\\":{\\\"MESH_BOOKSHELF_CONFIG_DIR\\\":\\\"/var/lib/bookshelf/config\\\",\\\"MESH_BOOKSHELF_URL\\\":\\\"http://127.0.0.1:20021\\\"},\\\"claude-code\\\":{\\\"MESH_CLAUDE_CODE_FACTS\\\":\\\"/var/lib/claude-code/facts.json\\\",\\\"MESH_CLAUDE_CODE_SETTINGS\\\":\\\"/var/lib/claude-code/settings.json\\\",\\\"MESH_CLAUDE_CODE_STATE\\\":\\\"/var/lib/claude-code\\\"},\\\"grafana\\\":{\\\"MESH_GRAFANA_CONFIG_FILE\\\":\\\"/var/lib/mesh/grafana/config.json\\\",\\\"MESH_GRAFANA_URL\\\":\\\"http://127.0.0.1:20012\\\"},\\\"home-assistant\\\":{\\\"MESH_HOMEASSISTANT_CONFIG_FILE\\\":\\\"/var/lib/mesh/home-assistant/config.json\\\",\\\"MESH_HOMEASSISTANT_TOKEN_FILE\\\":\\\"/var/lib/mesh/home-assistant/token\\\",\\\"MESH_HOMEASSISTANT_URL\\\":\\\"http://127.0.0.1:8123\\\"},\\\"icecast\\\":{\\\"MESH_ICECAST_ADMIN_PASSWORD_FILE\\\":\\\"/var/lib/icecast/admin.secret\\\",\\\"MESH_ICECAST_CONFIG_FILE\\\":\\\"/var/lib/mesh/icecast/config.json\\\",\\\"MESH_ICECAST_URL\\\":\\\"http://127.0.0.1:20005\\\"},\\\"influxdb\\\":{\\\"MESH_INFLUXDB_CONFIG_FILE\\\":\\\"/var/lib/mesh/influxdb/config.json\\\",\\\"MESH_INFLUXDB_TOKEN_FILE\\\":\\\"/var/lib/influxdb/admin-token.secret\\\",\\\"MESH_INFLUXDB_URL\\\":\\\"http://127.0.0.1:8086\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/influxdb/grants/mesh.json\\\"},\\\"jackett\\\":{\\\"MESH_JACKETT_API_KEY_FILE\\\":\\\"/var/lib/mesh/jackett/api-key\\\",\\\"MESH_JACKETT_CONFIG_DIR\\\":\\\"/var/lib/jackett/config\\\",\\\"MESH_JACKETT_CONFIG_FILE\\\":\\\"/var/lib/jackett/config.json\\\",\\\"MESH_JACKETT_URL\\\":\\\"http://127.0.0.1:20004\\\"},\\\"kometa\\\":{\\\"MESH_KOMETA_CONFIG_DIR\\\":\\\"/var/lib/kometa/config\\\",\\\"MESH_KOMETA_CONFIG_FILE\\\":\\\"/var/lib/kometa/config.yml\\\"},\\\"letta\\\":{\\\"MESH_LETTA_CONFIG_FILE\\\":\\\"/var/lib/mesh/letta/config.json\\\",\\\"MESH_LETTA_URL\\\":\\\"http://127.0.0.1:20002\\\"},\\\"lidarr\\\":{\\\"MESH_LIDARR_API_KEY_FILE\\\":\\\"/var/lib/mesh/lidarr/api-key\\\",\\\"MESH_LIDARR_CONFIG_DIR\\\":\\\"/var/lib/lidarr/config\\\",\\\"MESH_LIDARR_RECYCLE_BIN\\\":\\\"/recycle/\\\",\\\"MESH_LIDARR_RECYCLE_DAYS\\\":\\\"7\\\",\\\"MESH_LIDARR_URL\\\":\\\"http://127.0.0.1:20022\\\",\\\"MESH_PLEX_BIND_FILE\\\":\\\"/var/lib/lidarr/plex-api.json\\\",\\\"MESH_PLEX_TOKEN_FILE\\\":\\\"/var/lib/lidarr/plex-api.secret\\\"},\\\"media-importer\\\":{\\\"MESH_MEDIA_IMPORTER_SETTINGS\\\":\\\"/var/lib/media-importer/settings.json\\\",\\\"MESH_MEDIA_IMPORTER_STATE\\\":\\\"/var/lib/media-importer\\\",\\\"MESH_MEDIA_LIBRARY\\\":\\\"/storage/media/poc\\\"},\\\"mesh-files\\\":{\\\"MESH_FILES_STATE\\\":\\\"/var/lib/mesh-files\\\",\\\"MESH_OWNED_PATHS\\\":\\\"{\\\\\\\"/etc/NetworkManager/conf.d/50-mesh.conf\\\\\\\":\\\\\\\"networkmanager (its own tools)\\\\\\\",\\\\\\\"/etc/claude-code\\\\\\\":\\\\\\\"claude-code (its own tools)\\\\\\\",\\\\\\\"/etc/claude-code/agent-account\\\\\\\":\\\\\\\"claude-code (its own tools)\\\\\\\",\\\\\\\"/etc/dnsmasq.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/docker/daemon.json\\\\\\\":\\\\\\\"docker (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/action.d\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/action.d/iptables-allports-dualchain.conf\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/filter.d\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.d\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.d/recidive.conf\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.d/sshd.conf\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.local\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/mesh-own-addresses.json\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/hostname\\\\\\\":\\\\\\\"hostname (node-hostname)\\\\\\\",\\\\\\\"/etc/hosts\\\\\\\":\\\\\\\"hostname (node-hostname)\\\\\\\",\\\\\\\"/etc/locale.conf\\\\\\\":\\\\\\\"localization (its own tools)\\\\\\\",\\\\\\\"/etc/logrotate.conf\\\\\\\":\\\\\\\"logrotate (its own tools)\\\\\\\",\\\\\\\"/etc/logrotate.d/fail2ban\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/after-boot\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/after-wake\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/before-shutdown\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/before-sleep\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/on-battery\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/on-mains\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-resolver/nodes.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-resolver/zones.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/nfs-server\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/nfs-server/machines\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/nfs-server/shares.conf\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/nfs.conf.d/50-mesh.conf\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/pacman.conf\\\\\\\":\\\\\\\"pacman (its own tools)\\\\\\\",\\\\\\\"/etc/pacman.d/hooks/90-mesh-kernel-boot-entries.hook\\\\\\\":\\\\\\\"kernel (its own tools)\\\\\\\",\\\\\\\"/etc/resolv.conf\\\\\\\":\\\\\\\"networkmanager (node-uplink)\\\\\\\",\\\\\\\"/etc/ssh/sshd_config.d/10-mesh.conf\\\\\\\":\\\\\\\"sshd (its own tools)\\\\\\\",\\\\\\\"/etc/sudoers.d/10-mesh-operator\\\\\\\":\\\\\\\"sudo (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/logind.conf.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/logind.conf.d/power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/dnsmasq.service.d\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/dnsmasq.service.d/mesh.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/docker-prune.service\\\\\\\":\\\\\\\"docker (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/docker-prune.timer\\\\\\\":\\\\\\\"docker (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hibernate.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hibernate.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hybrid-sleep.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hybrid-sleep.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-ca-trust.service\\\\\\\":\\\\\\\"ca-trust (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-filter.service\\\\\\\":\\\\\\\"nftables (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-kernel-boot-entries.service\\\\\\\":\\\\\\\"kernel (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-kernel-huge-pages.service\\\\\\\":\\\\\\\"kernel (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-after-boot.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-after-wake.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-before-shutdown.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-before-sleep.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-supply.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/nftables.service.d/mesh.conf\\\\\\\":\\\\\\\"nftables (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/sleep.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/sleep.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend-then-hibernate.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend-then-hibernate.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/timesyncd.conf.d/50-mesh.conf\\\\\\\":\\\\\\\"time-sync (its own tools)\\\\\\\",\\\\\\\"/etc/udev/rules.d/90-mesh-power.rules\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/vconsole.conf\\\\\\\":\\\\\\\"localization (its own tools)\\\\\\\",\\\\\\\"/etc/xdg/reflector/reflector.conf\\\\\\\":\\\\\\\"pacman (its own tools)\\\\\\\",\\\\\\\"/run/mesh-power\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/run/nfs-server\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/usr/lib/nox-mesh-host/launch\\\\\\\":\\\\\\\"mesh-host (its own tools)\\\\\\\",\\\\\\\"/usr/lib/nox-mesh-host/versions/4e121b6e88f1\\\\\\\":\\\\\\\"mesh-host (its own tools)\\\\\\\",\\\\\\\"/usr/local/bin\\\\\\\":\\\\\\\"mesh-cli (its own tools)\\\\\\\",\\\\\\\"/usr/local/bin/claude-agent\\\\\\\":\\\\\\\"claude-code (its own tools)\\\\\\\",\\\\\\\"/usr/local/lib/mesh-power\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/var/lib/dnsmasq-watch\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/var/lib/mesh-fail2ban\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/var/lib/mesh-fail2ban/own-addresses\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/var/lib/mesh-store\\\\\\\":\\\\\\\"postgres (its own tools)\\\\\\\",\\\\\\\"/var/lib/nfs-server\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/var/lib/nfs-server/from-bus\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/var/lib/postgres\\\\\\\":\\\\\\\"postgres (its own tools)\\\\\\\",\\\\\\\"/var/lib/route-proxy/acme\\\\\\\":\\\\\\\"route-proxy (its own tools)\\\\\\\",\\\\\\\"/var/lib/route-proxy/ca\\\\\\\":\\\\\\\"route-proxy (its own tools)\\\\\\\",\\\\\\\"/var/lib/route-proxy/routes\\\\\\\":\\\\\\\"route-proxy (its own tools)\\\\\\\",\\\\\\\"/var/lib/systemd\\\\\\\":\\\\\\\"systemd (its own tools)\\\\\\\",\\\\\\\"/var/log/fail2ban.log\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/var/run/fail2ban\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\"}\\\",\\\"MESH_SECRET_PLACES\\\":\\\"[\\\\\\\"/var/lib/baserow\\\\\\\",\\\\\\\"/var/lib/bazarr/radarr-api.secret\\\\\\\",\\\\\\\"/var/lib/bazarr/sonarr-api.secret\\\\\\\",\\\\\\\"/var/lib/bookshelf/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/bookshelf/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/bookshelf/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/car-hunter\\\\\\\",\\\\\\\"/var/lib/claude-code/gitea-read.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/lidarr-api.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/mqtt-topic.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/radarr-api.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/sonarr-api.secret\\\\\\\",\\\\\\\"/var/lib/icecast/admin.secret\\\\\\\",\\\\\\\"/var/lib/icecast/relay.secret\\\\\\\",\\\\\\\"/var/lib/icecast/source.secret\\\\\\\",\\\\\\\"/var/lib/influxdb\\\\\\\",\\\\\\\"/var/lib/kometa\\\\\\\",\\\\\\\"/var/lib/letta\\\\\\\",\\\\\\\"/var/lib/lidarr/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/lidarr/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/lidarr/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/lidarr/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/mesh-delivery-assigner\\\\\\\",\\\\\\\"/var/lib/mesh-provisioner-client\\\\\\\",\\\\\\\"/var/lib/mesh-reads\\\\\\\",\\\\\\\"/var/lib/mesh/dnsmasq\\\\\\\",\\\\\\\"/var/lib/mesh/grafana\\\\\\\",\\\\\\\"/var/lib/mesh/home-assistant\\\\\\\",\\\\\\\"/var/lib/mesh/jackett\\\\\\\",\\\\\\\"/var/lib/mesh/lidarr\\\\\\\",\\\\\\\"/var/lib/mesh/mosquitto\\\\\\\",\\\\\\\"/var/lib/mesh/node-tools\\\\\\\",\\\\\\\"/var/lib/mesh/nodered\\\\\\\",\\\\\\\"/var/lib/mesh/nzbget\\\\\\\",\\\\\\\"/var/lib/mesh/ombi\\\\\\\",\\\\\\\"/var/lib/mesh/pacman\\\\\\\",\\\\\\\"/var/lib/mesh/postgres\\\\\\\",\\\\\\\"/var/lib/mesh/qbittorrent\\\\\\\",\\\\\\\"/var/lib/mesh/radarr\\\\\\\",\\\\\\\"/var/lib/mesh/route-proxy\\\\\\\",\\\\\\\"/var/lib/mesh/searxng\\\\\\\",\\\\\\\"/var/lib/mesh/sonarr\\\\\\\",\\\\\\\"/var/lib/mesh/unifi\\\\\\\",\\\\\\\"/var/lib/mosquitto/grants\\\\\\\",\\\\\\\"/var/lib/mssql\\\\\\\",\\\\\\\"/var/lib/n8n/database.secret\\\\\\\",\\\\\\\"/var/lib/nodered/mqtt-topic.secret\\\\\\\",\\\\\\\"/var/lib/nzbgeek\\\\\\\",\\\\\\\"/var/lib/ombi/lidarr-api.secret\\\\\\\",\\\\\\\"/var/lib/ombi/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/ombi/radarr-api.secret\\\\\\\",\\\\\\\"/var/lib/ombi/sonarr-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/redis/default.secret\\\\\\\",\\\\\\\"/var/lib/redis/grants\\\\\\\",\\\\\\\"/var/lib/restic\\\\\\\",\\\\\\\"/var/lib/sonarr/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/sonarr/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/sonarr/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/sonarr/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/supabase\\\\\\\",\\\\\\\"/var/lib/tautulli/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/txt-game/database.secret\\\\\\\"]\\\"},\\\"mosquitto\\\":{\\\"MESH_MQTT_CTRL_CONTAINER\\\":\\\"mosquitto\\\",\\\"MESH_PROVISION_ADMIN_USER\\\":\\\"mesh-admin\\\",\\\"MESH_PROVISION_MQTT\\\":\\\"127.0.0.1:1883\\\",\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/mesh/mosquitto/admin\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/mosquitto/grants/mesh.json\\\"},\\\"mssql\\\":{\\\"MESH_MSSQL_READER_PASSWORD_FILE\\\":\\\"/var/lib/mssql/reader.secret\\\",\\\"MESH_PROVISION_MSSQL\\\":\\\"mssql://sa@127.0.0.1:4848/master\\\",\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/mssql/sa.secret\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/mssql/grants/mesh.json\\\"},\\\"nodered\\\":{\\\"MESH_NODERED_CONFIG_FILE\\\":\\\"/var/lib/mesh/nodered/config.json\\\",\\\"MESH_NODERED_URL\\\":\\\"http://127.0.0.1:20006\\\"},\\\"nzbgeek\\\":{\\\"MESH_NZBGEEK_KEY_FILE\\\":\\\"/var/lib/nzbgeek/api-key.secret\\\",\\\"MESH_NZBGEEK_SETTINGS\\\":\\\"/var/lib/nzbgeek/settings.json\\\"},\\\"nzbget\\\":{\\\"MESH_NZBGET_CONFIG_DIR\\\":\\\"/var/lib/nzbget/config\\\",\\\"MESH_NZBGET_CONFIG_FILE\\\":\\\"/var/lib/nzbget/config.json\\\",\\\"MESH_NZBGET_PASSWORD_FILE\\\":\\\"/var/lib/mesh/nzbget/password\\\",\\\"MESH_NZBGET_SECRETS_DIR\\\":\\\"/var/lib/mesh/nzbget\\\",\\\"MESH_NZBGET_STATE\\\":\\\"/var/lib/nzbget\\\",\\\"MESH_NZBGET_URL\\\":\\\"http://127.0.0.1:20017\\\"},\\\"ombi\\\":{\\\"MESH_OMBI_API_KEY_FILE\\\":\\\"/var/lib/mesh/ombi/api-key\\\",\\\"MESH_OMBI_CONFIG_FILE\\\":\\\"/var/lib/mesh/ombi/config.json\\\",\\\"MESH_OMBI_URL\\\":\\\"http://127.0.0.1:20024\\\"},\\\"pacman\\\":{\\\"PACMAN_KEEPER_CONFIG\\\":\\\"/var/lib/mesh/pacman/keeper.json\\\"},\\\"plex\\\":{\\\"MESH_PLEX_CONFIG_DIR\\\":\\\"/mnt/plex/config\\\",\\\"MESH_PLEX_URL\\\":\\\"http://127.0.0.1:32400\\\"},\\\"postgres\\\":{\\\"MESH_CONSUMERS_FILE\\\":\\\"/var/lib/mesh/postgres/consumers.json\\\",\\\"MESH_POSTGRES_READER_PASSWORD_FILE\\\":\\\"/var/lib/mesh/postgres/reader.secret\\\",\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/mesh/postgres/superuser.secret\\\",\\\"MESH_PROVISION_POSTGRES\\\":\\\"postgres://postgres@127.0.0.1:5434/postgres?sslmode=disable\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/mesh/postgres/grants/mesh.json\\\"},\\\"qbittorrent\\\":{\\\"MESH_QBITTORRENT_CONFIG_DIR\\\":\\\"/var/lib/qbittorrent/config\\\",\\\"MESH_QBITTORRENT_CONFIG_FILE\\\":\\\"/var/lib/qbittorrent/config.json\\\",\\\"MESH_QBITTORRENT_PASSWORD_FILE\\\":\\\"/var/lib/mesh/qbittorrent/password\\\",\\\"MESH_QBITTORRENT_URL\\\":\\\"http://127.0.0.1:8112\\\"},\\\"radarr\\\":{\\\"MESH_PLEX_BIND_FILE\\\":\\\"/var/lib/radarr/plex-api.json\\\",\\\"MESH_PLEX_TOKEN_FILE\\\":\\\"/var/lib/radarr/plex-api.secret\\\",\\\"MESH_RADARR_API_KEY_FILE\\\":\\\"/var/lib/mesh/radarr/api-key\\\",\\\"MESH_RADARR_CONFIG_DIR\\\":\\\"/var/lib/radarr/config\\\",\\\"MESH_RADARR_URL\\\":\\\"http://127.0.0.1:20019\\\"},\\\"redis\\\":{\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/redis/default.secret\\\",\\\"MESH_PROVISION_REDIS\\\":\\\"127.0.0.1:20003\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/redis/grants/mesh.json\\\"},\\\"restic\\\":{\\\"MESH_BACKUP_DATA\\\":\\\"/var/lib/restic/data.conf\\\",\\\"MESH_BACKUP_DECLARED\\\":\\\"/var/lib/restic/backups.conf\\\",\\\"MESH_BACKUP_PASSWORD_FILE\\\":\\\"/var/lib/restic/repository.secret\\\",\\\"MESH_BACKUP_REPOSITORY\\\":\\\"/storage/restic\\\",\\\"MESH_BACKUP_STATE\\\":\\\"/var/lib/restic\\\"},\\\"searxng\\\":{\\\"MESH_SEARXNG_CONFIG_FILE\\\":\\\"/var/lib/mesh/searxng/config.json\\\",\\\"MESH_SEARXNG_URL\\\":\\\"http://127.0.0.1:20000\\\"},\\\"sonarr\\\":{\\\"MESH_PLEX_BIND_FILE\\\":\\\"/var/lib/sonarr/plex-api.json\\\",\\\"MESH_PLEX_TOKEN_FILE\\\":\\\"/var/lib/sonarr/plex-api.secret\\\",\\\"MESH_SONARR_API_KEY_FILE\\\":\\\"/var/lib/mesh/sonarr/api-key\\\",\\\"MESH_SONARR_CONFIG_DIR\\\":\\\"/var/lib/sonarr/config\\\",\\\"MESH_SONARR_RECYCLE_DIR\\\":\\\"/var/lib/sonarr/recycle-bin\\\",\\\"MESH_SONARR_URL\\\":\\\"http://127.0.0.1:20018\\\"},\\\"systemd\\\":{\\\"MESH_SYSTEMD_STATE\\\":\\\"/var/lib/mesh/systemd\\\"},\\\"tautulli\\\":{\\\"MESH_TAUTULLI_CONFIG_DIR\\\":\\\"/var/lib/tautulli/config\\\",\\\"MESH_TAUTULLI_CONFIG_FILE\\\":\\\"/var/lib/mesh/tautulli/config.json\\\",\\\"MESH_TAUTULLI_CONTAINER\\\":\\\"tautulli\\\",\\\"MESH_TAUTULLI_URL\\\":\\\"http://127.0.0.1:20023\\\"},\\\"unifi\\\":{\\\"MESH_UNIFI_CONFIG_FILE\\\":\\\"/var/lib/mesh/unifi/config.json\\\",\\\"MESH_UNIFI_URL\\\":\\\"https://127.0.0.1:8443\\\"},\\\"youtube\\\":{\\\"MESH_YOUTUBE_DOWNLOADS\\\":\\\"/storage/downloads/youtube\\\",\\\"MESH_YOUTUBE_SETTINGS\\\":\\\"/var/lib/youtube/settings.json\\\"},\\\"zsh\\\":{\\\"ZSH_TOOLS_CONF\\\":\\\"/var/lib/zsh/tools.conf\\\"}}\",\"MESH_TOOL_MODULES\":\"avahi=/var/lib/mesh/bundles/avahi/tools/avahi-tools,baserow=/var/lib/mesh/bundles/baserow/tools/tools/index.serve.mjs,bazarr=/var/lib/mesh/bundles/bazarr/code/index.serve.mjs,bazarr=/var/lib/mesh/bundles/bazarr/code/tools/index.serve.mjs,bookshelf=/var/lib/mesh/bundles/bookshelf/code/index.serve.mjs,bookshelf=/var/lib/mesh/bundles/bookshelf/code/tools/index.serve.mjs,claude-code=/var/lib/mesh/bundles/claude-code/tools/claude-code,dbus=/var/lib/mesh/bundles/dbus/tools-go/dbus-tools,disk-load=/var/lib/mesh/bundles/disk-load/tools-go/disk-load,dnsmasq=/var/lib/mesh/bundles/dnsmasq/tools/dnsmasq-tools,docker=/var/lib/mesh/bundles/docker/tools/docker-tools,fail2ban=/var/lib/mesh/bundles/fail2ban/tools/fail2ban-tools,grafana=/var/lib/mesh/bundles/grafana/code/index.serve.mjs,grafana=/var/lib/mesh/bundles/grafana/code/tools/index.serve.mjs,home-assistant=/var/lib/mesh/bundles/home-assistant/code/index.serve.mjs,home-assistant=/var/lib/mesh/bundles/home-assistant/code/tools/index.serve.mjs,hostname=/var/lib/mesh/bundles/hostname/tools/hostname-tools,icecast=/var/lib/mesh/bundles/icecast/code/index.serve.mjs,icecast=/var/lib/mesh/bundles/icecast/code/tools/index.serve.mjs,influxdb=/var/lib/mesh/bundles/influxdb/code/provisioner/index.serve.mjs,influxdb=/var/lib/mesh/bundles/influxdb/code/tools/index.serve.mjs,jackett=/var/lib/mesh/bundles/jackett/code/tools/index.serve.mjs,kernel=/var/lib/mesh/bundles/kernel/tools/kernel-tools,kometa=/var/lib/mesh/bundles/kometa/code/tools/index.serve.mjs,letta=/var/lib/mesh/bundles/letta/tools/tools/index.serve.mjs,lidarr=/var/lib/mesh/bundles/lidarr/tools-go/lidarr,localization=/var/lib/mesh/bundles/localization/tools/localization-tools,logrotate=/var/lib/mesh/bundles/logrotate/tools/logrotate-tools,media-importer=/var/lib/mesh/bundles/media-importer/tools/media-importer,mesh-files=/var/lib/mesh/bundles/mesh-files/tools/mesh-files,mosquitto=/var/lib/mesh/bundles/mosquitto/code/index.serve.mjs,mosquitto=/var/lib/mesh/bundles/mosquitto/code/provisioner/index.serve.mjs,mosquitto=/var/lib/mesh/bundles/mosquitto/code/tools/index.serve.mjs,mssql=/var/lib/mesh/bundles/mssql/code/index.serve.mjs,mssql=/var/lib/mesh/bundles/mssql/code/provisioner/index.serve.mjs,mssql=/var/lib/mesh/bundles/mssql/code/tools/index.serve.mjs,netcheck=/var/lib/mesh/bundles/netcheck/tools-go/netcheck,netcheck=/var/lib/mesh/bundles/netcheck/tools-typescript/tools/index.serve.mjs,networkmanager=/var/lib/mesh/bundles/networkmanager/tools/uplink-tools,nfs-server=/var/lib/mesh/bundles/nfs-server/tools/nfs-server,nftables=/var/lib/mesh/bundles/nftables/tools/tools/index.serve.mjs,nodered=/var/lib/mesh/bundles/nodered/code/tools/index.serve.mjs,nzbgeek=/var/lib/mesh/bundles/nzbgeek/tools/nzbgeek,nzbget=/var/lib/mesh/bundles/nzbget/code/nzbget,ombi=/var/lib/mesh/bundles/ombi/code/index.serve.mjs,ombi=/var/lib/mesh/bundles/ombi/code/tools/index.serve.mjs,pacman=/var/lib/mesh/bundles/pacman/tools/pacman-tools,plex=/var/lib/mesh/bundles/plex/code/plex,postgres=/var/lib/mesh/bundles/postgres/code/postgres-provider,power=/var/lib/mesh/bundles/power/tools-go/power,qbittorrent=/var/lib/mesh/bundles/qbittorrent/code/qbittorrent,radarr=/var/lib/mesh/bundles/radarr/tools-go/radarr,redis=/var/lib/mesh/bundles/redis/code/index.serve.mjs,redis=/var/lib/mesh/bundles/redis/code/provisioner/index.serve.mjs,redis=/var/lib/mesh/bundles/redis/code/tools/index.serve.mjs,restic=/var/lib/mesh/bundles/restic/tools/restic-backups,route-proxy=/var/lib/mesh/bundles/route-proxy/provider/route-provider,searxng=/var/lib/mesh/bundles/searxng/tools/tools/index.serve.mjs,sonarr=/var/lib/mesh/bundles/sonarr/code/index.serve.mjs,sonarr=/var/lib/mesh/bundles/sonarr/code/tools/index.serve.mjs,ssh-client=/var/lib/mesh/bundles/ssh-client/tools/ssh-client-tools,sudo=/var/lib/mesh/bundles/sudo/tools/sudo-tools,systemd=/var/lib/mesh/bundles/systemd/tools/systemd-tools,tautulli=/var/lib/mesh/bundles/tautulli/code/index.serve.mjs,tautulli=/var/lib/mesh/bundles/tautulli/code/tools/index.serve.mjs,time-sync=/var/lib/mesh/bundles/time-sync/tools/time-sync-tools,unifi=/var/lib/mesh/bundles/unifi/tools/tools/index.serve.mjs,youtube=/var/lib/mesh/bundles/youtube/tools/youtube,zsh=/var/lib/mesh/bundles/zsh/tools/tools/index.serve.mjs\"},\"id\":\"node-tools.runtime\",\"module\":\"node-tools\",\"name\":\"node-tools\",\"restart-on\":[\"avahi.bundle-tools\",\"baserow.bundle-tools\",\"bazarr.bundle-code\",\"bookshelf.bundle-code\",\"claude-code.bundle-tools\",\"dbus.bundle-tools-go\",\"disk-load.bundle-tools-go\",\"dnsmasq.bundle-tools\",\"docker.bundle-tools\",\"fail2ban.bundle-tools\",\"grafana.bundle-code\",\"home-assistant.bundle-code\",\"hostname.bundle-tools\",\"icecast.bundle-code\",\"influxdb.bundle-code\",\"jackett.bundle-code\",\"kernel.bundle-tools\",\"kometa.bundle-code\",\"letta.bundle-tools\",\"lidarr.bundle-tools-go\",\"localization.bundle-tools\",\"logrotate.bundle-tools\",\"media-importer.bundle-tools\",\"mesh-files.bundle-tools\",\"mosquitto.bundle-code\",\"mssql.bundle-code\",\"netcheck.bundle-tools-go\",\"netcheck.bundle-tools-typescript\",\"networkmanager.bundle-tools\",\"nfs-server.bundle-tools\",\"nftables.bundle-tools\",\"node-tools.needs-broker\",\"nodered.bundle-code\",\"nzbgeek.bundle-tools\",\"nzbget.bundle-code\",\"ombi.bundle-code\",\"pacman.bundle-tools\",\"plex.bundle-code\",\"postgres.bundle-code\",\"power.bundle-tools-go\",\"qbittorrent.bundle-code\",\"radarr.bundle-tools-go\",\"redis.bundle-code\",\"restic.bundle-tools\",\"route-proxy.bundle-provider\",\"searxng.bundle-tools\",\"sonarr.bundle-code\",\"ssh-client.bundle-tools\",\"sudo.bundle-tools\",\"systemd.bundle-tools\",\"tautulli.bundle-code\",\"time-sync.bundle-tools\",\"unifi.bundle-tools\",\"youtube.bundle-tools\",\"zsh.bundle-tools\",\"baserow.runtime-config\",\"bazarr.runtime-config\",\"claude-code.facts\",\"claude-code.settings\",\"grafana.runtime-config\",\"home-assistant.needs-token\",\"home-assistant.runtime-config\",\"icecast.runtime-config\",\"icecast.secret-admin\",\"influxdb.needs-admin-token\",\"influxdb.received-influxdb-api\",\"influxdb.runtime-config\",\"jackett.needs-api-key\",\"jackett.runtime-config\",\"kometa.settings\",\"letta.runtime-config\",\"lidarr.bound-plex-api\",\"lidarr.needs-api-key\",\"lidarr.secret-plex-api\",\"media-importer.settings\",\"mosquitto.needs-admin\",\"mosquitto.received-mqtt-topic\",\"mssql.needs-reader\",\"mssql.needs-sa\",\"mssql.received-mssql-database\",\"nodered.runtime-config\",\"nzbgeek.needs-api-key\",\"nzbgeek.settings\",\"nzbget.needs-password\",\"nzbget.runtime-config\",\"ombi.needs-api-key\",\"ombi.runtime-config\",\"pacman.keeper-config\",\"postgres.consumers\",\"postgres.needs-reader\",\"postgres.needs-superuser\",\"postgres.received-postgres-database\",\"qbittorrent.needs-password\",\"qbittorrent.runtime-config\",\"radarr.bound-plex-api\",\"radarr.needs-api-key\",\"radarr.secret-plex-api\",\"redis.received-redis-cache\",\"redis.secret-secret\",\"restic.data-declared\",\"restic.declared\",\"restic.needs-repository\",\"searxng.runtime-config\",\"sonarr.bound-plex-api\",\"sonarr.needs-api-key\",\"sonarr.secret-plex-api\",\"tautulli.runtime-config\",\"unifi.runtime-config\",\"youtube.settings\",\"zsh.tools-conf\"],\"run\":[\"./node-tools\"],\"source\":\"http://novox.internal:5100/v2/node-tools/runtime/blobs/sha256:ef790876783d817903b337b8418b1eb21fb49d34128a390bbf7c3d08a4b2be8a\",\"type\":\"process\",\"user\":\"ace\"}],\"v\":1}", wire: "{\"fp\":\"src2:6e6f64652d6e6f64652d6e6f64652d6e6f64652d6e6f64652d6e6f64652d6e6f\",\"module\":\"node-tools\",\"node\":\"ace\",\"resources\":[{\"id\":\"node-tools.mesh-state\",\"mode\":\"0755\",\"module\":\"node-tools\",\"path\":\"/var/lib/mesh/node-tools\",\"type\":\"directory\"},{\"id\":\"node-tools.interpreter\",\"module\":\"node-tools\",\"package\":\"nodejs\",\"type\":\"package\"},{\"digest\":\"sha256:ef790876783d817903b337b8418b1eb21fb49d34128a390bbf7c3d08a4b2be8a\",\"env\":{\"MESH_AGENT_ACCOUNT\":\"ace\",\"MESH_AGENT_HOME\":\"/home/ace\",\"MESH_BROKER_FILE\":\"/var/lib/mesh/node-tools/broker\",\"MESH_OPERATOR_ACCOUNT\":\"ace\",\"MESH_OPERATOR_HOME\":\"/home/ace\",\"MESH_TOOL_ENV\":\"{\\\"baserow\\\":{\\\"MESH_BASEROW_CONFIG_FILE\\\":\\\"/var/lib/mesh/baserow/config.json\\\",\\\"MESH_BASEROW_URL\\\":\\\"http://127.0.0.1:20011\\\"},\\\"bazarr\\\":{\\\"MESH_BAZARR_CONFIG_DIR\\\":\\\"/var/lib/bazarr/config\\\",\\\"MESH_BAZARR_CONFIG_FILE\\\":\\\"/var/lib/bazarr/config.json\\\",\\\"MESH_BAZARR_CONTAINER\\\":\\\"bazarr\\\",\\\"MESH_BAZARR_URL\\\":\\\"http://127.0.0.1:20020\\\"},\\\"bookshelf\\\":{\\\"MESH_BOOKSHELF_CONFIG_DIR\\\":\\\"/var/lib/bookshelf/config\\\",\\\"MESH_BOOKSHELF_URL\\\":\\\"http://127.0.0.1:20021\\\"},\\\"claude-code\\\":{\\\"MESH_CLAUDE_CODE_FACTS\\\":\\\"/var/lib/claude-code/facts.json\\\",\\\"MESH_CLAUDE_CODE_SETTINGS\\\":\\\"/var/lib/claude-code/settings.json\\\",\\\"MESH_CLAUDE_CODE_STATE\\\":\\\"/var/lib/claude-code\\\"},\\\"grafana\\\":{\\\"MESH_GRAFANA_CONFIG_FILE\\\":\\\"/var/lib/mesh/grafana/config.json\\\",\\\"MESH_GRAFANA_URL\\\":\\\"http://127.0.0.1:20012\\\"},\\\"home-assistant\\\":{\\\"MESH_HOMEASSISTANT_CONFIG_FILE\\\":\\\"/var/lib/mesh/home-assistant/config.json\\\",\\\"MESH_HOMEASSISTANT_TOKEN_FILE\\\":\\\"/var/lib/mesh/home-assistant/token\\\",\\\"MESH_HOMEASSISTANT_URL\\\":\\\"http://127.0.0.1:8123\\\"},\\\"icecast\\\":{\\\"MESH_ICECAST_ADMIN_PASSWORD_FILE\\\":\\\"/var/lib/icecast/admin.secret\\\",\\\"MESH_ICECAST_CONFIG_FILE\\\":\\\"/var/lib/mesh/icecast/config.json\\\",\\\"MESH_ICECAST_URL\\\":\\\"http://127.0.0.1:20005\\\"},\\\"influxdb\\\":{\\\"MESH_INFLUXDB_CONFIG_FILE\\\":\\\"/var/lib/mesh/influxdb/config.json\\\",\\\"MESH_INFLUXDB_TOKEN_FILE\\\":\\\"/var/lib/influxdb/admin-token.secret\\\",\\\"MESH_INFLUXDB_URL\\\":\\\"http://127.0.0.1:8086\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/influxdb/grants/mesh.json\\\"},\\\"jackett\\\":{\\\"MESH_JACKETT_API_KEY_FILE\\\":\\\"/var/lib/mesh/jackett/api-key\\\",\\\"MESH_JACKETT_CONFIG_DIR\\\":\\\"/var/lib/jackett/config\\\",\\\"MESH_JACKETT_CONFIG_FILE\\\":\\\"/var/lib/jackett/config.json\\\",\\\"MESH_JACKETT_URL\\\":\\\"http://127.0.0.1:20004\\\"},\\\"kometa\\\":{\\\"MESH_KOMETA_CONFIG_DIR\\\":\\\"/var/lib/kometa/config\\\",\\\"MESH_KOMETA_CONFIG_FILE\\\":\\\"/var/lib/kometa/config.yml\\\"},\\\"letta\\\":{\\\"MESH_LETTA_CONFIG_FILE\\\":\\\"/var/lib/mesh/letta/config.json\\\",\\\"MESH_LETTA_URL\\\":\\\"http://127.0.0.1:20002\\\"},\\\"lidarr\\\":{\\\"MESH_LIDARR_API_KEY_FILE\\\":\\\"/var/lib/mesh/lidarr/api-key\\\",\\\"MESH_LIDARR_CONFIG_DIR\\\":\\\"/var/lib/lidarr/config\\\",\\\"MESH_LIDARR_RECYCLE_BIN\\\":\\\"/recycle/\\\",\\\"MESH_LIDARR_RECYCLE_DAYS\\\":\\\"7\\\",\\\"MESH_LIDARR_URL\\\":\\\"http://127.0.0.1:20022\\\",\\\"MESH_PLEX_BIND_FILE\\\":\\\"/var/lib/lidarr/plex-api.json\\\",\\\"MESH_PLEX_TOKEN_FILE\\\":\\\"/var/lib/lidarr/plex-api.secret\\\"},\\\"media-importer\\\":{\\\"MESH_MEDIA_IMPORTER_SETTINGS\\\":\\\"/var/lib/media-importer/settings.json\\\",\\\"MESH_MEDIA_IMPORTER_STATE\\\":\\\"/var/lib/media-importer\\\",\\\"MESH_MEDIA_LIBRARY\\\":\\\"/storage/media/poc\\\"},\\\"mesh-files\\\":{\\\"MESH_FILES_STATE\\\":\\\"/var/lib/mesh-files\\\",\\\"MESH_OWNED_PATHS\\\":\\\"{\\\\\\\"/etc/NetworkManager/conf.d/50-mesh.conf\\\\\\\":\\\\\\\"networkmanager (its own tools)\\\\\\\",\\\\\\\"/etc/claude-code\\\\\\\":\\\\\\\"claude-code (its own tools)\\\\\\\",\\\\\\\"/etc/claude-code/agent-account\\\\\\\":\\\\\\\"claude-code (its own tools)\\\\\\\",\\\\\\\"/etc/dnsmasq.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/docker/daemon.json\\\\\\\":\\\\\\\"docker (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/action.d\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/action.d/iptables-allports-dualchain.conf\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/filter.d\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.d\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.d/recidive.conf\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.d/sshd.conf\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/jail.local\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/fail2ban/mesh-own-addresses.json\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/hostname\\\\\\\":\\\\\\\"hostname (node-hostname)\\\\\\\",\\\\\\\"/etc/hosts\\\\\\\":\\\\\\\"hostname (node-hostname)\\\\\\\",\\\\\\\"/etc/locale.conf\\\\\\\":\\\\\\\"localization (its own tools)\\\\\\\",\\\\\\\"/etc/logrotate.conf\\\\\\\":\\\\\\\"logrotate (its own tools)\\\\\\\",\\\\\\\"/etc/logrotate.d/fail2ban\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/after-boot\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/after-wake\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/before-shutdown\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/before-sleep\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/on-battery\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-power/moments/on-mains\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-resolver/nodes.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/mesh-resolver/zones.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/nfs-server\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/nfs-server/machines\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/nfs-server/shares.conf\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/nfs.conf.d/50-mesh.conf\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/etc/pacman.conf\\\\\\\":\\\\\\\"pacman (its own tools)\\\\\\\",\\\\\\\"/etc/pacman.d/hooks/90-mesh-kernel-boot-entries.hook\\\\\\\":\\\\\\\"kernel (its own tools)\\\\\\\",\\\\\\\"/etc/resolv.conf\\\\\\\":\\\\\\\"networkmanager (node-uplink)\\\\\\\",\\\\\\\"/etc/ssh/sshd_config.d/10-mesh.conf\\\\\\\":\\\\\\\"sshd (its own tools)\\\\\\\",\\\\\\\"/etc/sudoers.d/10-mesh-operator\\\\\\\":\\\\\\\"sudo (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/logind.conf.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/logind.conf.d/power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/dnsmasq.service.d\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/dnsmasq.service.d/mesh.conf\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/docker-prune.service\\\\\\\":\\\\\\\"docker (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/docker-prune.timer\\\\\\\":\\\\\\\"docker (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hibernate.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hibernate.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hybrid-sleep.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/hybrid-sleep.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-ca-trust.service\\\\\\\":\\\\\\\"ca-trust (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-filter.service\\\\\\\":\\\\\\\"nftables (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-kernel-boot-entries.service\\\\\\\":\\\\\\\"kernel (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-kernel-huge-pages.service\\\\\\\":\\\\\\\"kernel (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-after-boot.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-after-wake.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-before-shutdown.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-before-sleep.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/mesh-power-supply.service\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/nftables.service.d/mesh.conf\\\\\\\":\\\\\\\"nftables (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/sleep.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/sleep.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend-then-hibernate.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend-then-hibernate.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend.target.d\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/system/suspend.target.d/mesh-power.conf\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/systemd/timesyncd.conf.d/50-mesh.conf\\\\\\\":\\\\\\\"time-sync (its own tools)\\\\\\\",\\\\\\\"/etc/udev/rules.d/90-mesh-power.rules\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/etc/vconsole.conf\\\\\\\":\\\\\\\"localization (its own tools)\\\\\\\",\\\\\\\"/etc/xdg/reflector/reflector.conf\\\\\\\":\\\\\\\"pacman (its own tools)\\\\\\\",\\\\\\\"/run/mesh-power\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/run/nfs-server\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/usr/lib/nox-mesh-host/launch\\\\\\\":\\\\\\\"mesh-host (its own tools)\\\\\\\",\\\\\\\"/usr/lib/nox-mesh-host/versions/4e121b6e88f1\\\\\\\":\\\\\\\"mesh-host (its own tools)\\\\\\\",\\\\\\\"/usr/local/bin\\\\\\\":\\\\\\\"mesh-cli (its own tools)\\\\\\\",\\\\\\\"/usr/local/bin/claude-agent\\\\\\\":\\\\\\\"claude-code (its own tools)\\\\\\\",\\\\\\\"/usr/local/lib/mesh-power\\\\\\\":\\\\\\\"power (its own tools)\\\\\\\",\\\\\\\"/var/lib/dnsmasq-watch\\\\\\\":\\\\\\\"dnsmasq (its own tools)\\\\\\\",\\\\\\\"/var/lib/mesh-fail2ban\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/var/lib/mesh-fail2ban/own-addresses\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/var/lib/mesh-store\\\\\\\":\\\\\\\"postgres (its own tools)\\\\\\\",\\\\\\\"/var/lib/nfs-server\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/var/lib/nfs-server/from-bus\\\\\\\":\\\\\\\"nfs-server (its own tools)\\\\\\\",\\\\\\\"/var/lib/postgres\\\\\\\":\\\\\\\"postgres (its own tools)\\\\\\\",\\\\\\\"/var/lib/route-proxy/acme\\\\\\\":\\\\\\\"route-proxy (its own tools)\\\\\\\",\\\\\\\"/var/lib/route-proxy/ca\\\\\\\":\\\\\\\"route-proxy (its own tools)\\\\\\\",\\\\\\\"/var/lib/route-proxy/routes\\\\\\\":\\\\\\\"route-proxy (its own tools)\\\\\\\",\\\\\\\"/var/lib/systemd\\\\\\\":\\\\\\\"systemd (its own tools)\\\\\\\",\\\\\\\"/var/log/fail2ban.log\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\",\\\\\\\"/var/run/fail2ban\\\\\\\":\\\\\\\"fail2ban (its own tools)\\\\\\\"}\\\",\\\"MESH_SECRET_PLACES\\\":\\\"[\\\\\\\"/var/lib/baserow\\\\\\\",\\\\\\\"/var/lib/bazarr/radarr-api.secret\\\\\\\",\\\\\\\"/var/lib/bazarr/sonarr-api.secret\\\\\\\",\\\\\\\"/var/lib/bookshelf/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/bookshelf/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/bookshelf/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/car-hunter\\\\\\\",\\\\\\\"/var/lib/claude-code/gitea-read.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/lidarr-api.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/mqtt-topic.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/radarr-api.secret\\\\\\\",\\\\\\\"/var/lib/home-assistant/sonarr-api.secret\\\\\\\",\\\\\\\"/var/lib/icecast/admin.secret\\\\\\\",\\\\\\\"/var/lib/icecast/relay.secret\\\\\\\",\\\\\\\"/var/lib/icecast/source.secret\\\\\\\",\\\\\\\"/var/lib/influxdb\\\\\\\",\\\\\\\"/var/lib/kometa\\\\\\\",\\\\\\\"/var/lib/letta\\\\\\\",\\\\\\\"/var/lib/lidarr/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/lidarr/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/lidarr/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/lidarr/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/mesh-delivery-assigner\\\\\\\",\\\\\\\"/var/lib/mesh-provisioner-client\\\\\\\",\\\\\\\"/var/lib/mesh-reads\\\\\\\",\\\\\\\"/var/lib/mesh/dnsmasq\\\\\\\",\\\\\\\"/var/lib/mesh/grafana\\\\\\\",\\\\\\\"/var/lib/mesh/home-assistant\\\\\\\",\\\\\\\"/var/lib/mesh/jackett\\\\\\\",\\\\\\\"/var/lib/mesh/lidarr\\\\\\\",\\\\\\\"/var/lib/mesh/mosquitto\\\\\\\",\\\\\\\"/var/lib/mesh/node-tools\\\\\\\",\\\\\\\"/var/lib/mesh/nodered\\\\\\\",\\\\\\\"/var/lib/mesh/nzbget\\\\\\\",\\\\\\\"/var/lib/mesh/ombi\\\\\\\",\\\\\\\"/var/lib/mesh/pacman\\\\\\\",\\\\\\\"/var/lib/mesh/postgres\\\\\\\",\\\\\\\"/var/lib/mesh/qbittorrent\\\\\\\",\\\\\\\"/var/lib/mesh/radarr\\\\\\\",\\\\\\\"/var/lib/mesh/route-proxy\\\\\\\",\\\\\\\"/var/lib/mesh/searxng\\\\\\\",\\\\\\\"/var/lib/mesh/sonarr\\\\\\\",\\\\\\\"/var/lib/mesh/unifi\\\\\\\",\\\\\\\"/var/lib/mosquitto/grants\\\\\\\",\\\\\\\"/var/lib/mssql\\\\\\\",\\\\\\\"/var/lib/n8n/database.secret\\\\\\\",\\\\\\\"/var/lib/nodered/mqtt-topic.secret\\\\\\\",\\\\\\\"/var/lib/nzbgeek\\\\\\\",\\\\\\\"/var/lib/ombi/lidarr-api.secret\\\\\\\",\\\\\\\"/var/lib/ombi/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/ombi/radarr-api.secret\\\\\\\",\\\\\\\"/var/lib/ombi/sonarr-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/radarr/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/redis/default.secret\\\\\\\",\\\\\\\"/var/lib/redis/grants\\\\\\\",\\\\\\\"/var/lib/restic\\\\\\\",\\\\\\\"/var/lib/sonarr/jackett-api.secret\\\\\\\",\\\\\\\"/var/lib/sonarr/nzbget-api.secret\\\\\\\",\\\\\\\"/var/lib/sonarr/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/sonarr/qbittorrent-api.secret\\\\\\\",\\\\\\\"/var/lib/supabase\\\\\\\",\\\\\\\"/var/lib/tautulli/plex-api.secret\\\\\\\",\\\\\\\"/var/lib/txt-game/database.secret\\\\\\\"]\\\"},\\\"mosquitto\\\":{\\\"MESH_MQTT_CTRL_CONTAINER\\\":\\\"mosquitto\\\",\\\"MESH_PROVISION_ADMIN_USER\\\":\\\"mesh-admin\\\",\\\"MESH_PROVISION_MQTT\\\":\\\"127.0.0.1:1883\\\",\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/mesh/mosquitto/admin\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/mosquitto/grants/mesh.json\\\"},\\\"mssql\\\":{\\\"MESH_MSSQL_READER_PASSWORD_FILE\\\":\\\"/var/lib/mssql/reader.secret\\\",\\\"MESH_PROVISION_MSSQL\\\":\\\"mssql://sa@127.0.0.1:4848/master\\\",\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/mssql/sa.secret\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/mssql/grants/mesh.json\\\"},\\\"nodered\\\":{\\\"MESH_NODERED_CONFIG_FILE\\\":\\\"/var/lib/mesh/nodered/config.json\\\",\\\"MESH_NODERED_URL\\\":\\\"http://127.0.0.1:20006\\\"},\\\"nzbgeek\\\":{\\\"MESH_NZBGEEK_KEY_FILE\\\":\\\"/var/lib/nzbgeek/api-key.secret\\\",\\\"MESH_NZBGEEK_SETTINGS\\\":\\\"/var/lib/nzbgeek/settings.json\\\"},\\\"nzbget\\\":{\\\"MESH_NZBGET_CONFIG_DIR\\\":\\\"/var/lib/nzbget/config\\\",\\\"MESH_NZBGET_CONFIG_FILE\\\":\\\"/var/lib/nzbget/config.json\\\",\\\"MESH_NZBGET_PASSWORD_FILE\\\":\\\"/var/lib/mesh/nzbget/password\\\",\\\"MESH_NZBGET_SECRETS_DIR\\\":\\\"/var/lib/mesh/nzbget\\\",\\\"MESH_NZBGET_STATE\\\":\\\"/var/lib/nzbget\\\",\\\"MESH_NZBGET_URL\\\":\\\"http://127.0.0.1:20017\\\"},\\\"ombi\\\":{\\\"MESH_OMBI_API_KEY_FILE\\\":\\\"/var/lib/mesh/ombi/api-key\\\",\\\"MESH_OMBI_CONFIG_FILE\\\":\\\"/var/lib/mesh/ombi/config.json\\\",\\\"MESH_OMBI_URL\\\":\\\"http://127.0.0.1:20024\\\"},\\\"pacman\\\":{\\\"PACMAN_KEEPER_CONFIG\\\":\\\"/var/lib/mesh/pacman/keeper.json\\\"},\\\"plex\\\":{\\\"MESH_PLEX_CONFIG_DIR\\\":\\\"/mnt/plex/config\\\",\\\"MESH_PLEX_URL\\\":\\\"http://127.0.0.1:32400\\\"},\\\"postgres\\\":{\\\"MESH_CONSUMERS_FILE\\\":\\\"/var/lib/mesh/postgres/consumers.json\\\",\\\"MESH_POSTGRES_READER_PASSWORD_FILE\\\":\\\"/var/lib/mesh/postgres/reader.secret\\\",\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/mesh/postgres/superuser.secret\\\",\\\"MESH_PROVISION_POSTGRES\\\":\\\"postgres://postgres@127.0.0.1:5434/postgres?sslmode=disable\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/mesh/postgres/grants/mesh.json\\\"},\\\"qbittorrent\\\":{\\\"MESH_QBITTORRENT_CONFIG_DIR\\\":\\\"/var/lib/qbittorrent/config\\\",\\\"MESH_QBITTORRENT_CONFIG_FILE\\\":\\\"/var/lib/qbittorrent/config.json\\\",\\\"MESH_QBITTORRENT_PASSWORD_FILE\\\":\\\"/var/lib/mesh/qbittorrent/password\\\",\\\"MESH_QBITTORRENT_URL\\\":\\\"http://127.0.0.1:8112\\\"},\\\"radarr\\\":{\\\"MESH_PLEX_BIND_FILE\\\":\\\"/var/lib/radarr/plex-api.json\\\",\\\"MESH_PLEX_TOKEN_FILE\\\":\\\"/var/lib/radarr/plex-api.secret\\\",\\\"MESH_RADARR_API_KEY_FILE\\\":\\\"/var/lib/mesh/radarr/api-key\\\",\\\"MESH_RADARR_CONFIG_DIR\\\":\\\"/var/lib/radarr/config\\\",\\\"MESH_RADARR_URL\\\":\\\"http://127.0.0.1:20019\\\"},\\\"redis\\\":{\\\"MESH_PROVISION_PASSWORD_FILE\\\":\\\"/var/lib/redis/default.secret\\\",\\\"MESH_PROVISION_REDIS\\\":\\\"127.0.0.1:20003\\\",\\\"MESH_RECEIVES\\\":\\\"/var/lib/redis/grants/mesh.json\\\"},\\\"restic\\\":{\\\"MESH_BACKUP_DATA\\\":\\\"/var/lib/restic/data.conf\\\",\\\"MESH_BACKUP_DECLARED\\\":\\\"/var/lib/restic/backups.conf\\\",\\\"MESH_BACKUP_PASSWORD_FILE\\\":\\\"/var/lib/restic/repository.secret\\\",\\\"MESH_BACKUP_REPOSITORY\\\":\\\"/storage/restic\\\",\\\"MESH_BACKUP_STATE\\\":\\\"/var/lib/restic\\\"},\\\"searxng\\\":{\\\"MESH_SEARXNG_CONFIG_FILE\\\":\\\"/var/lib/mesh/searxng/config.json\\\",\\\"MESH_SEARXNG_URL\\\":\\\"http://127.0.0.1:20000\\\"},\\\"sonarr\\\":{\\\"MESH_PLEX_BIND_FILE\\\":\\\"/var/lib/sonarr/plex-api.json\\\",\\\"MESH_PLEX_TOKEN_FILE\\\":\\\"/var/lib/sonarr/plex-api.secret\\\",\\\"MESH_SONARR_API_KEY_FILE\\\":\\\"/var/lib/mesh/sonarr/api-key\\\",\\\"MESH_SONARR_CONFIG_DIR\\\":\\\"/var/lib/sonarr/config\\\",\\\"MESH_SONARR_RECYCLE_DIR\\\":\\\"/var/lib/sonarr/recycle-bin\\\",\\\"MESH_SONARR_URL\\\":\\\"http://127.0.0.1:20018\\\"},\\\"systemd\\\":{\\\"MESH_SYSTEMD_STATE\\\":\\\"/var/lib/mesh/systemd\\\"},\\\"tautulli\\\":{\\\"MESH_TAUTULLI_CONFIG_DIR\\\":\\\"/var/lib/tautulli/config\\\",\\\"MESH_TAUTULLI_CONFIG_FILE\\\":\\\"/var/lib/mesh/tautulli/config.json\\\",\\\"MESH_TAUTULLI_CONTAINER\\\":\\\"tautulli\\\",\\\"MESH_TAUTULLI_URL\\\":\\\"http://127.0.0.1:20023\\\"},\\\"unifi\\\":{\\\"MESH_UNIFI_CONFIG_FILE\\\":\\\"/var/lib/mesh/unifi/config.json\\\",\\\"MESH_UNIFI_URL\\\":\\\"https://127.0.0.1:8443\\\"},\\\"youtube\\\":{\\\"MESH_YOUTUBE_DOWNLOADS\\\":\\\"/storage/downloads/youtube\\\",\\\"MESH_YOUTUBE_SETTINGS\\\":\\\"/var/lib/youtube/settings.json\\\"},\\\"zsh\\\":{\\\"ZSH_TOOLS_CONF\\\":\\\"/var/lib/zsh/tools.conf\\\"}}\",\"MESH_TOOL_MODULES\":\"avahi=/var/lib/mesh/bundles/avahi/tools/avahi-tools,baserow=/var/lib/mesh/bundles/baserow/tools/tools/index.serve.mjs,bazarr=/var/lib/mesh/bundles/bazarr/code/index.serve.mjs,bazarr=/var/lib/mesh/bundles/bazarr/code/tools/index.serve.mjs,bookshelf=/var/lib/mesh/bundles/bookshelf/code/index.serve.mjs,bookshelf=/var/lib/mesh/bundles/bookshelf/code/tools/index.serve.mjs,claude-code=/var/lib/mesh/bundles/claude-code/tools/claude-code,dbus=/var/lib/mesh/bundles/dbus/tools-go/dbus-tools,disk-load=/var/lib/mesh/bundles/disk-load/tools-go/disk-load,dnsmasq=/var/lib/mesh/bundles/dnsmasq/tools/dnsmasq-tools,docker=/var/lib/mesh/bundles/docker/tools/docker-tools,fail2ban=/var/lib/mesh/bundles/fail2ban/tools/fail2ban-tools,grafana=/var/lib/mesh/bundles/grafana/code/index.serve.mjs,grafana=/var/lib/mesh/bundles/grafana/code/tools/index.serve.mjs,home-assistant=/var/lib/mesh/bundles/home-assistant/code/index.serve.mjs,home-assistant=/var/lib/mesh/bundles/home-assistant/code/tools/index.serve.mjs,hostname=/var/lib/mesh/bundles/hostname/tools/hostname-tools,icecast=/var/lib/mesh/bundles/icecast/code/index.serve.mjs,icecast=/var/lib/mesh/bundles/icecast/code/tools/index.serve.mjs,influxdb=/var/lib/mesh/bundles/influxdb/code/provisioner/index.serve.mjs,influxdb=/var/lib/mesh/bundles/influxdb/code/tools/index.serve.mjs,jackett=/var/lib/mesh/bundles/jackett/code/tools/index.serve.mjs,kernel=/var/lib/mesh/bundles/kernel/tools/kernel-tools,kometa=/var/lib/mesh/bundles/kometa/code/tools/index.serve.mjs,letta=/var/lib/mesh/bundles/letta/tools/tools/index.serve.mjs,lidarr=/var/lib/mesh/bundles/lidarr/tools-go/lidarr,localization=/var/lib/mesh/bundles/localization/tools/localization-tools,logrotate=/var/lib/mesh/bundles/logrotate/tools/logrotate-tools,media-importer=/var/lib/mesh/bundles/media-importer/tools/media-importer,mesh-files=/var/lib/mesh/bundles/mesh-files/tools/mesh-files,mosquitto=/var/lib/mesh/bundles/mosquitto/code/index.serve.mjs,mosquitto=/var/lib/mesh/bundles/mosquitto/code/provisioner/index.serve.mjs,mosquitto=/var/lib/mesh/bundles/mosquitto/code/tools/index.serve.mjs,mssql=/var/lib/mesh/bundles/mssql/code/index.serve.mjs,mssql=/var/lib/mesh/bundles/mssql/code/provisioner/index.serve.mjs,mssql=/var/lib/mesh/bundles/mssql/code/tools/index.serve.mjs,netcheck=/var/lib/mesh/bundles/netcheck/tools-go/netcheck,netcheck=/var/lib/mesh/bundles/netcheck/tools-typescript/tools/index.serve.mjs,networkmanager=/var/lib/mesh/bundles/networkmanager/tools/uplink-tools,nfs-server=/var/lib/mesh/bundles/nfs-server/tools/nfs-server,nftables=/var/lib/mesh/bundles/nftables/tools/tools/index.serve.mjs,nodered=/var/lib/mesh/bundles/nodered/code/tools/index.serve.mjs,nzbgeek=/var/lib/mesh/bundles/nzbgeek/tools/nzbgeek,nzbget=/var/lib/mesh/bundles/nzbget/code/nzbget,ombi=/var/lib/mesh/bundles/ombi/code/index.serve.mjs,ombi=/var/lib/mesh/bundles/ombi/code/tools/index.serve.mjs,pacman=/var/lib/mesh/bundles/pacman/tools/pacman-tools,plex=/var/lib/mesh/bundles/plex/code/plex,postgres=/var/lib/mesh/bundles/postgres/code/postgres-provider,power=/var/lib/mesh/bundles/power/tools-go/power,qbittorrent=/var/lib/mesh/bundles/qbittorrent/code/qbittorrent,radarr=/var/lib/mesh/bundles/radarr/tools-go/radarr,redis=/var/lib/mesh/bundles/redis/code/index.serve.mjs,redis=/var/lib/mesh/bundles/redis/code/provisioner/index.serve.mjs,redis=/var/lib/mesh/bundles/redis/code/tools/index.serve.mjs,restic=/var/lib/mesh/bundles/restic/tools/restic-backups,route-proxy=/var/lib/mesh/bundles/route-proxy/provider/route-provider,searxng=/var/lib/mesh/bundles/searxng/tools/tools/index.serve.mjs,sonarr=/var/lib/mesh/bundles/sonarr/code/index.serve.mjs,sonarr=/var/lib/mesh/bundles/sonarr/code/tools/index.serve.mjs,ssh-client=/var/lib/mesh/bundles/ssh-client/tools/ssh-client-tools,sudo=/var/lib/mesh/bundles/sudo/tools/sudo-tools,systemd=/var/lib/mesh/bundles/systemd/tools/systemd-tools,tautulli=/var/lib/mesh/bundles/tautulli/code/index.serve.mjs,tautulli=/var/lib/mesh/bundles/tautulli/code/tools/index.serve.mjs,time-sync=/var/lib/mesh/bundles/time-sync/tools/time-sync-tools,unifi=/var/lib/mesh/bundles/unifi/tools/tools/index.serve.mjs,youtube=/var/lib/mesh/bundles/youtube/tools/youtube,zsh=/var/lib/mesh/bundles/zsh/tools/tools/index.serve.mjs\"},\"id\":\"node-tools.runtime\",\"module\":\"node-tools\",\"name\":\"node-tools\",\"restart-on\":[\"avahi.bundle-tools\",\"baserow.bundle-tools\",\"bazarr.bundle-code\",\"bookshelf.bundle-code\",\"claude-code.bundle-tools\",\"dbus.bundle-tools-go\",\"disk-load.bundle-tools-go\",\"dnsmasq.bundle-tools\",\"docker.bundle-tools\",\"fail2ban.bundle-tools\",\"grafana.bundle-code\",\"home-assistant.bundle-code\",\"hostname.bundle-tools\",\"icecast.bundle-code\",\"influxdb.bundle-code\",\"jackett.bundle-code\",\"kernel.bundle-tools\",\"kometa.bundle-code\",\"letta.bundle-tools\",\"lidarr.bundle-tools-go\",\"localization.bundle-tools\",\"logrotate.bundle-tools\",\"media-importer.bundle-tools\",\"mesh-files.bundle-tools\",\"mosquitto.bundle-code\",\"mssql.bundle-code\",\"netcheck.bundle-tools-go\",\"netcheck.bundle-tools-typescript\",\"networkmanager.bundle-tools\",\"nfs-server.bundle-tools\",\"nftables.bundle-tools\",\"node-tools.needs-broker\",\"nodered.bundle-code\",\"nzbgeek.bundle-tools\",\"nzbget.bundle-code\",\"ombi.bundle-code\",\"pacman.bundle-tools\",\"plex.bundle-code\",\"postgres.bundle-code\",\"power.bundle-tools-go\",\"qbittorrent.bundle-code\",\"radarr.bundle-tools-go\",\"redis.bundle-code\",\"restic.bundle-tools\",\"route-proxy.bundle-provider\",\"searxng.bundle-tools\",\"sonarr.bundle-code\",\"ssh-client.bundle-tools\",\"sudo.bundle-tools\",\"systemd.bundle-tools\",\"tautulli.bundle-code\",\"time-sync.bundle-tools\",\"unifi.bundle-tools\",\"youtube.bundle-tools\",\"zsh.bundle-tools\",\"baserow.runtime-config\",\"bazarr.runtime-config\",\"claude-code.facts\",\"claude-code.settings\",\"grafana.runtime-config\",\"home-assistant.needs-token\",\"home-assistant.runtime-config\",\"icecast.runtime-config\",\"icecast.secret-admin\",\"influxdb.needs-admin-token\",\"influxdb.received-influxdb-api\",\"influxdb.runtime-config\",\"jackett.needs-api-key\",\"jackett.runtime-config\",\"kometa.settings\",\"letta.runtime-config\",\"lidarr.bound-plex-api\",\"lidarr.needs-api-key\",\"lidarr.secret-plex-api\",\"media-importer.settings\",\"mosquitto.needs-admin\",\"mosquitto.received-mqtt-topic\",\"mssql.needs-reader\",\"mssql.needs-sa\",\"mssql.received-mssql-database\",\"nodered.runtime-config\",\"nzbgeek.needs-api-key\",\"nzbgeek.settings\",\"nzbget.needs-password\",\"nzbget.runtime-config\",\"ombi.needs-api-key\",\"ombi.runtime-config\",\"pacman.keeper-config\",\"postgres.consumers\",\"postgres.needs-reader\",\"postgres.needs-superuser\",\"postgres.received-postgres-database\",\"qbittorrent.needs-password\",\"qbittorrent.runtime-config\",\"radarr.bound-plex-api\",\"radarr.needs-api-key\",\"radarr.secret-plex-api\",\"redis.received-redis-cache\",\"redis.secret-secret\",\"restic.data-declared\",\"restic.declared\",\"restic.needs-repository\",\"searxng.runtime-config\",\"sonarr.bound-plex-api\",\"sonarr.needs-api-key\",\"sonarr.secret-plex-api\",\"tautulli.runtime-config\",\"unifi.runtime-config\",\"youtube.settings\",\"zsh.tools-conf\"],\"run\":[\"./node-tools\"],\"source\":\"http://novox.internal:5100/v2/node-tools/runtime/blobs/sha256:ef790876783d817903b337b8418b1eb21fb49d34128a390bbf7c3d08a4b2be8a\",\"type\":\"process\",\"user\":\"ace\"}],\"v\":1}",
decode: func(b []byte) (any, error) {
var v ComposedByNodeModuleFingerprintValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a module the engine could not compose", subject: "", given: "{\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"module\":\"nzbget\",\"node\":\"ace\",\"refused\":\"a secret the vault does not hold\",\"resources\":[],\"v\":1}", wire: "{\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"module\":\"nzbget\",\"node\":\"ace\",\"refused\":\"a secret the vault does not hold\",\"resources\":[],\"v\":1}",
decode: func(b []byte) (any, error) {
var v ComposedByNodeModuleFingerprintValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "the node's own composition", subject: "", given: "{\"node\":\"ace\",\"own\":{\"adoption\":{\"taken\":[\"avahi\"],\"untaken\":{\"plex\":[\"plex.bundle-code\"]}},\"groups\":[{\"gid\":1002,\"name\":\"mesh-media\"}],\"identities\":[{\"gid\":1001,\"groups\":[1002],\"module\":\"plex\",\"name\":\"plex\",\"runner\":\"plex\",\"uid\":1001}],\"libraries\":[{\"gid\":1002,\"group\":\"mesh-media\",\"home\":false,\"library\":\"movies\",\"paths\":[\"/srv/media/movies\"],\"root\":\"/srv/media/movies\",\"taken\":true}],\"provisioner_account\":\"mesh-provisioner-client\"},\"resources\":[],\"v\":1}", wire: "{\"node\":\"ace\",\"own\":{\"adoption\":{\"taken\":[\"avahi\"],\"untaken\":{\"plex\":[\"plex.bundle-code\"]}},\"groups\":[{\"gid\":1002,\"name\":\"mesh-media\"}],\"identities\":[{\"gid\":1001,\"groups\":[1002],\"module\":\"plex\",\"name\":\"plex\",\"runner\":\"plex\",\"uid\":1001}],\"libraries\":[{\"gid\":1002,\"group\":\"mesh-media\",\"home\":false,\"library\":\"movies\",\"paths\":[\"/srv/media/movies\"],\"root\":\"/srv/media/movies\",\"taken\":true}],\"provisioner_account\":\"mesh-provisioner-client\"},\"resources\":[],\"v\":1}",
decode: func(b []byte) (any, error) {
var v ComposedByNodeNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a module running (typed from the engine's own values; no read tool answers a have key)", subject: "", given: "{\"build\":\"b1\",\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"health\":\"ok\",\"phase\":\"running\",\"sealed\":[\"web.secret\"],\"sealed-at\":{\"web.secret#sealed\":\"box1\"},\"v\":1}", wire: "{\"build\":\"b1\",\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"health\":\"ok\",\"phase\":\"running\",\"sealed\":[\"web.secret\"],\"sealed-at\":{\"web.secret#sealed\":\"box1\"},\"v\":1}",
decode: func(b []byte) (any, error) { var v HaveByNodeModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a failed apply waiting on a store's holder (typed from the engine's values)", subject: "", given: "{\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"detail\":\"the pull met a store that is not settled\",\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"health\":\"failed\",\"phase\":\"failed\",\"pull-wait\":{\"began\":\"2026-11-05T12:00:00Z\",\"holder\":\"gitea\",\"image\":\"registry.example/web:1\",\"retried\":\"the holder settled\",\"retried-at\":\"2026-11-05T12:05:00Z\",\"seat\":\"container-image-registry\"},\"v\":1}", wire: "{\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"detail\":\"the pull met a store that is not settled\",\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"health\":\"failed\",\"phase\":\"failed\",\"pull-wait\":{\"began\":\"2026-11-05T12:00:00Z\",\"holder\":\"gitea\",\"image\":\"registry.example/web:1\",\"retried\":\"the holder settled\",\"retried-at\":\"2026-11-05T12:05:00Z\",\"seat\":\"container-image-registry\"},\"v\":1}",
decode: func(b []byte) (any, error) { var v HaveByNodeModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a move waiting for a person's yes", subject: "", given: "{\"build-alone\":true,\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"health\":\"ok\",\"judgement\":\"recreates\",\"kept\":[\"tool runner not declared\"],\"phase\":\"waiting-yes\",\"v\":1,\"waits\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"}", wire: "{\"build-alone\":true,\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fp\":\"src2:62756c6c6462756c6c6462756c6c6462756c6c6462756c6c6462756c6c646275\",\"health\":\"ok\",\"judgement\":\"recreates\",\"kept\":[\"tool runner not declared\"],\"phase\":\"waiting-yes\",\"v\":1,\"waits\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"}",
decode: func(b []byte) (any, error) { var v HaveByNodeModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "the bus module's have carries the user list written (typed from the engine's values)", subject: "", given: "{\"health\":\"ok\",\"phase\":\"running\",\"user-list\":{\"at\":\"2026-11-05T12:00:00Z\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"follows\":\"grants\",\"handed\":{\"at\":\"2026-11-05T12:00:00Z\",\"box\":{\"ct\":\"c\",\"eph\":\"e\",\"iv\":\"i\",\"tag\":\"t\",\"v\":1},\"from\":\"ace\",\"to\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"users\":3},\"key\":\"-----BEGIN PUBLIC KEY-----\",\"revision\":7,\"source\":\"user-list\",\"users\":3,\"wanted\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"v\":1}", wire: "{\"health\":\"ok\",\"phase\":\"running\",\"user-list\":{\"at\":\"2026-11-05T12:00:00Z\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"follows\":\"grants\",\"handed\":{\"at\":\"2026-11-05T12:00:00Z\",\"box\":{\"ct\":\"c\",\"eph\":\"e\",\"iv\":\"i\",\"tag\":\"t\",\"v\":1},\"from\":\"ace\",\"to\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"users\":3},\"key\":\"-----BEGIN PUBLIC KEY-----\",\"revision\":7,\"source\":\"user-list\",\"users\":3,\"wanted\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"v\":1}",
decode: func(b []byte) (any, error) { var v HaveByNodeModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a node's own facts with its record and an answer to a candidate (typed from the engine's values)", subject: "", given: "{\"candidates\":{\"p1\":{\"added\":[{\"module\":\"db\",\"unissued\":[\"db.secret\"]}],\"differs\":[{\"bodies\":[{\"id\":\"api.cfg\",\"paths\":[\"/etc/api.conf\"],\"why\":\"content\"}],\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"api\",\"running\":\"sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\",\"why\":\"a file differs\"}],\"proposal\":\"p1\",\"refusals\":[{\"module\":\"mail\",\"today\":\"runs\",\"why\":\"a value is missing\"}],\"removed\":[\"old\"],\"revision\":4,\"same\":[\"web\"],\"verdict\":\"differs\"}},\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"composes\":\"own\",\"record\":{\"capabilities\":[\"docker\"],\"contract\":3,\"networks\":[{\"link\":\"eth0\",\"network\":\"192.0.2.0/24\"}],\"networks-said\":true,\"node\":\"ace\",\"tunnel-key\":\"k\",\"v\":1},\"v\":1}", wire: "{\"candidates\":{\"p1\":{\"added\":[{\"module\":\"db\",\"unissued\":[\"db.secret\"]}],\"differs\":[{\"bodies\":[{\"id\":\"api.cfg\",\"paths\":[\"/etc/api.conf\"],\"why\":\"content\"}],\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"api\",\"running\":\"sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\",\"why\":\"a file differs\"}],\"proposal\":\"p1\",\"refusals\":[{\"module\":\"mail\",\"today\":\"runs\",\"why\":\"a value is missing\"}],\"removed\":[\"old\"],\"revision\":4,\"same\":[\"web\"],\"verdict\":\"differs\"}},\"composed\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"composes\":\"own\",\"record\":{\"capabilities\":[\"docker\"],\"contract\":3,\"networks\":[{\"link\":\"eth0\",\"network\":\"192.0.2.0/24\"}],\"networks-said\":true,\"node\":\"ace\",\"tunnel-key\":\"k\",\"v\":1},\"v\":1}",
decode: func(b []byte) (any, error) { var v HaveByNodeNodeValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a module's data items on a node (typed from the engine's values)", subject: "", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"items\":[{\"class\":\"database\",\"covered_by\":\"/var/lib/postgres\",\"item\":\"cluster\",\"measure\":\"dataset\",\"module\":\"postgres\",\"path\":\"/var/lib/postgres\",\"protection\":\"backup\"}],\"module\":\"postgres\",\"node\":\"ace\",\"v\":1}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"items\":[{\"class\":\"database\",\"covered_by\":\"/var/lib/postgres\",\"item\":\"cluster\",\"measure\":\"dataset\",\"module\":\"postgres\",\"path\":\"/var/lib/postgres\",\"protection\":\"backup\"}],\"module\":\"postgres\",\"node\":\"ace\",\"v\":1}",
decode: func(b []byte) (any, error) { var v DataByNodeModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a node's health (typed from the engine's values)", subject: "", given: "{\"at\":\"2026-11-05T12:00:00Z\",\"contract\":3,\"network\":{\"parts\":[{\"part\":\"resolver\",\"since\":\"2026-11-05T10:00:00Z\",\"state\":\"running\"}],\"since\":\"2026-11-05T10:00:00Z\",\"state\":\"running\"},\"node\":\"ace\",\"peers\":[{\"addresses\":[\"198.51.100.1\"],\"key\":\"k\",\"seen\":true}],\"relogin\":[{\"account\":\"web\",\"reason\":\"password changed\",\"since\":\"2026-11-05T11:00:00Z\"}],\"units\":{\"failed\":[{\"result\":\"exit-code\",\"scope\":\"system\",\"since\":\"2026-11-05T11:00:00Z\",\"unit\":\"x.service\"}],\"state\":\"degraded\"},\"v\":1}", wire: "{\"at\":\"2026-11-05T12:00:00Z\",\"contract\":3,\"network\":{\"parts\":[{\"part\":\"resolver\",\"since\":\"2026-11-05T10:00:00Z\",\"state\":\"running\"}],\"since\":\"2026-11-05T10:00:00Z\",\"state\":\"running\"},\"node\":\"ace\",\"peers\":[{\"addresses\":[\"198.51.100.1\"],\"key\":\"k\",\"seen\":true}],\"relogin\":[{\"account\":\"web\",\"reason\":\"password changed\",\"since\":\"2026-11-05T11:00:00Z\"}],\"units\":{\"failed\":[{\"result\":\"exit-code\",\"scope\":\"system\",\"since\":\"2026-11-05T11:00:00Z\",\"unit\":\"x.service\"}],\"state\":\"degraded\"},\"v\":1}",
decode: func(b []byte) (any, error) { var v HealthByNodeValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "manifest-reads answers what the engine reads and when it stated it", subject: "", given: "{\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"stated-at\":\"2026-11-04T10:00:00Z\",\"v\":1}", wire: "{\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"stated-at\":\"2026-11-04T10:00:00Z\",\"v\":1}",
decode: func(b []byte) (any, error) { var v ManifestReadsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "manifest-reads of an engine built before it said them is the baseline", subject: "", given: "{\"node\":\"g14\",\"stated-at\":\"2026-11-04T10:05:00Z\",\"v\":1}", wire: "{\"node\":\"g14\",\"stated-at\":\"2026-11-04T10:05:00Z\",\"v\":1}",
decode: func(b []byte) (any, error) { var v ManifestReadsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "compose-candidate asks the candidate and, as a boolean, its composition input", subject: "", given: "{\"candidate\":\"mesh-host.0123abcd\",\"input\":true}", wire: "{\"candidate\":\"mesh-host.0123abcd\",\"input\":true}",
decode: func(b []byte) (any, error) { var v ComposeCandidateInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "compose-candidate answers per module and the node's own", subject: "", given: "{\"candidate\":\"mesh-host.0123abcd\",\"modules\":[{\"changed\":true,\"digest\":\"sha256:aa\",\"fp\":\"fp-1\",\"module\":\"plex\",\"state\":\"composed\"}],\"node\":\"ace\",\"own\":{\"digest\":\"sha256:bb\",\"module\":\"node\",\"state\":\"composed\"},\"took\":1200,\"v\":1,\"verdict\":\"composed\"}", wire: "{\"candidate\":\"mesh-host.0123abcd\",\"modules\":[{\"changed\":true,\"digest\":\"sha256:aa\",\"fp\":\"fp-1\",\"module\":\"plex\",\"state\":\"composed\"}],\"node\":\"ace\",\"own\":{\"digest\":\"sha256:bb\",\"module\":\"node\",\"state\":\"composed\"},\"took\":1200,\"v\":1,\"verdict\":\"composed\"}",
decode: func(b []byte) (any, error) { var v ComposeCandidateAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "acts answers each act kept", subject: "", given: "{\"acts\":[{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"at\":\"2026-11-04T09:00:00Z\",\"caller\":\"mesh-tools\",\"expires\":\"2026-11-05T09:00:00Z\",\"id\":\"hand-over-1\",\"state\":\"asked\",\"subject\":\"/srv/media\"}],\"node\":\"ace\"}", wire: "{\"acts\":[{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"at\":\"2026-11-04T09:00:00Z\",\"caller\":\"mesh-tools\",\"expires\":\"2026-11-05T09:00:00Z\",\"id\":\"hand-over-1\",\"state\":\"asked\",\"subject\":\"/srv/media\"}],\"node\":\"ace\"}",
decode: func(b []byte) (any, error) { var v ActsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "seat-list answers what the engine holds and what it waits for", subject: "", given: "{\"health\":\"the seat list is held from the bootstrap and nothing new is acted on\",\"status\":{\"heard\":false,\"held\":[{\"seat\":\"node-engine\",\"source\":\"bootstrap\"},{\"digest\":\"3f2a9c\",\"seat\":\"node-files\",\"source\":\"trunk\"}],\"last-error\":\"no answer\",\"waiting\":[\"node-engine\"]}}", wire: "{\"health\":\"the seat list is held from the bootstrap and nothing new is acted on\",\"status\":{\"heard\":false,\"held\":[{\"seat\":\"node-engine\",\"source\":\"bootstrap\"},{\"digest\":\"3f2a9c\",\"seat\":\"node-files\",\"source\":\"trunk\"}],\"last-error\":\"no answer\",\"waiting\":[\"node-engine\"]}}",
decode: func(b []byte) (any, error) { var v SeatListAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "seat-list-again answers the error when the read failed", subject: "", given: "{\"error\":\"seatlist: no answer\",\"health\":\"the seat list is held from the bootstrap\",\"status\":{\"heard\":false,\"held\":[{\"seat\":\"node-engine\",\"source\":\"bootstrap\"}],\"waiting\":[\"node-engine\"]}}", wire: "{\"error\":\"seatlist: no answer\",\"health\":\"the seat list is held from the bootstrap\",\"status\":{\"heard\":false,\"held\":[{\"seat\":\"node-engine\",\"source\":\"bootstrap\"}],\"waiting\":[\"node-engine\"]}}",
decode: func(b []byte) (any, error) { var v SeatListAgainAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}