mesh-reads: a node's files and accounts read as an account that holds no secret (hq ADR 0310, issue 418) #247

Merged
mesh-admin merged 1 commits from fix/418-node-reads-2 into main 2026-10-12 14:52:19 +00:00
Contributor

Replaces #244 (review 55). This is one commit on a fresh branch from main, so the built binary that #244's first commit carried never appears. .gitignore now names the build outputs. Everything #244's description says still holds; below is what changed for review 55.

Required 1: what was opened is judged, not the name (openJudged in reads.go). It is used by read, list and search.

  • The type is checked by stat before the open (lstat in a search), so a device or a fifo is never opened.
  • The open uses O_RDONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC, plus O_NOFOLLOW in a search and O_DIRECTORY for a list.
  • The type is checked again with fstat on the descriptor.
  • The path of /proc/self/fd/<n> is judged by name. A path that is not absolute, or ends in (deleted), is refused.
  • New test TestALinkFlippedDuringAReadNeverReadsASecretPlace: a goroutine flips a link between a plain file and the module's own broker under a secret place, during 5000 reads and 5000 searches. Nothing leaks. With #244's code the same test fails.

Required 2: key blocks. Every line from a -----BEGIN through its -----END is withheld in a read and in a search. New test TestEveryLineOfAKeyBlockIsWithheld uses a generated RSA-2048 PKCS#8 key in server.pem; with #244's code it fails.

Required 3, and the should-items:

  • Refused by name: shell and program histories, browser and mail profiles (.mozilla, .thunderbird, .config/google-chrome, chromium, BraveSoftware, vivaldi, microsoft-edge), /proc/<pid>/{environ,mem,fd,map_files,root,cwd}, /etc/rancher and /etc/kubernetes/admin.conf. New test TestHistoriesProfilesAndProcessesAreRefusedByName; it fails with #244's code.
  • A search stays on the file system of the path named; the other file systems it reaches are named in other-file-systems-skipped. This also keeps /proc and /sys out unless the search starts inside them. The 20-second time bound is now checked every 1000 lines inside a file too.
  • The README names the limit for hard links.
  • go.mod pins mesh-sdk #23's new head, v0.1.14-0.20261012122749-67bfa22132f2 (review 53's fixes). I will move it to the merged commit once #23 merges.

Checks run here.

  • go vet passes, and go test -race ./... passes in the module.
  • MESH_GATE=<controller from mesh-controller #257 at 63a99d4> MESH_CHECK_MODULES=mesh-reads sh merge-check.sh passes: 69 resources without health, as kept.
  • mesh/merge-gate here stays red until #257 runs. The running controller has no node-reads seat.

Group. This branch is fix/418-node-reads-2, so it is not in the fix/418-node-reads delivery group with mesh-sdk #23 and mesh-controller #257. That does not change the order: #23, then #257 and its rollout done, then this.

Part of issue 418. Not merged.

Replaces #244 (review 55). This is one commit on a fresh branch from main, so the built binary that #244's first commit carried never appears. `.gitignore` now names the build outputs. Everything #244's description says still holds; below is what changed for review 55. **Required 1: what was opened is judged, not the name** (`openJudged` in `reads.go`). It is used by `read`, `list` and `search`. - The type is checked by stat before the open (lstat in a search), so a device or a fifo is never opened. - The open uses `O_RDONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC`, plus `O_NOFOLLOW` in a search and `O_DIRECTORY` for a list. - The type is checked again with fstat on the descriptor. - The path of `/proc/self/fd/<n>` is judged by name. A path that is not absolute, or ends in ` (deleted)`, is refused. - New test `TestALinkFlippedDuringAReadNeverReadsASecretPlace`: a goroutine flips a link between a plain file and the module's own broker under a secret place, during 5000 reads and 5000 searches. Nothing leaks. With #244's code the same test fails. **Required 2: key blocks.** Every line from a `-----BEGIN ` through its `-----END ` is withheld in a read and in a search. New test `TestEveryLineOfAKeyBlockIsWithheld` uses a generated RSA-2048 PKCS#8 key in `server.pem`; with #244's code it fails. **Required 3, and the should-items:** - Refused by name: shell and program histories, browser and mail profiles (`.mozilla`, `.thunderbird`, `.config/google-chrome`, `chromium`, `BraveSoftware`, `vivaldi`, `microsoft-edge`), `/proc/<pid>/{environ,mem,fd,map_files,root,cwd}`, `/etc/rancher` and `/etc/kubernetes/admin.conf`. New test `TestHistoriesProfilesAndProcessesAreRefusedByName`; it fails with #244's code. - A search stays on the file system of the path named; the other file systems it reaches are named in `other-file-systems-skipped`. This also keeps `/proc` and `/sys` out unless the search starts inside them. The 20-second time bound is now checked every 1000 lines inside a file too. - The README names the limit for hard links. - `go.mod` pins mesh-sdk #23's new head, `v0.1.14-0.20261012122749-67bfa22132f2` (review 53's fixes). I will move it to the merged commit once #23 merges. **Checks run here.** - `go vet` passes, and `go test -race ./...` passes in the module. - `MESH_GATE=<controller from mesh-controller #257 at 63a99d4> MESH_CHECK_MODULES=mesh-reads sh merge-check.sh` passes: 69 resources without health, as kept. - `mesh/merge-gate` here stays red until #257 runs. The running controller has no `node-reads` seat. **Group.** This branch is `fix/418-node-reads-2`, so it is not in the `fix/418-node-reads` delivery group with mesh-sdk #23 and mesh-controller #257. That does not change the order: #23, then #257 and its rollout done, then this. Part of issue 418. Not merged.
mesh-admin added 1 commit 2026-10-12 12:32:37 +00:00
mesh-reads: read a node's files and accounts as an account that holds no secret (hq ADR 0310, issue 418)
mesh/merge-gate pass: builds new: modules/mesh-reads, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
994cab533b
Reading a file, searching one, listing a directory, the owner and mode of each
component of a path and looking up an account went through the login shell's
execute as the operator's account, which sees the operator's keys and the
agent's credentials. This module holds node-reads on every node and runs as
mesh-reads (no login, no group beside its own). It refuses the node's secret
places by name, judging the file actually opened rather than the name asked,
so a flipped link reaches nothing refused; withholds any line shaped like a
secret through mesh-sdk's outward rule and every line of a BEGIN/END block;
and bounds every answer. Replaces mesh-catalog #244 (reviews 55), whose first
commit carried a built binary.
Author
Contributor

Delivery novox/mesh-catalog@994cab533bbd — delivered since 2026-10-12T14:52:28Z

Delivery plan — builds new: modules/mesh-reads, sent nowhere; no bus step

Transitions

  • 2026-10-12 12:33 (new) → proposed (announced): novox/mesh-catalog#247's head announced
  • 2026-10-12 12:34 proposed → checked (checked): the verdict names this commit
  • 2026-10-12 12:34 checked → rejected (refused): the gate failed or could not run, or the repository's own check failed
  • 2026-10-12 13:31 rejected → proposed (recheck): mesh-controller #257 (the node-reads seat) is delivered on all four nodes, so mesh-reads' claim on it can be judged (issue 418)
  • 2026-10-12 13:33 proposed → checked (checked): the verdict names this commit
  • 2026-10-12 13:33 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-12 14:52 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-12 14:52 published → delivered (done): nothing for a walk to move

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-catalog@994cab533bbd` — **delivered** since 2026-10-12T14:52:28Z **Delivery plan** — builds new: modules/mesh-reads, sent nowhere; no bus step **Transitions** - 2026-10-12 12:33 (new) → proposed (announced): novox/mesh-catalog#247's head announced - 2026-10-12 12:34 proposed → checked (checked): the verdict names this commit - 2026-10-12 12:34 checked → rejected (refused): the gate failed or could not run, or the repository's own check failed - 2026-10-12 13:31 rejected → proposed (recheck): mesh-controller #257 (the node-reads seat) is delivered on all four nodes, so mesh-reads' claim on it can be judged (issue 418) - 2026-10-12 13:33 proposed → checked (checked): the verdict names this commit - 2026-10-12 13:33 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-12 14:52 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-12 14:52 published → delivered (done): nothing for a walk to move The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Author
Contributor

Merge check at 994cab53

  • mesh/merge-gate: FAIL — a manifest the change touches fails the module check: modules/mesh-reads/module.json: this manifest cannot be used: (modules: new:modules/mesh-reads)
  • mesh/repo-check: FAIL — its merge-check.sh failed: files asking for a setting without saying whether it is trusted: 25

Delivery plan — builds new: modules/mesh-reads, sent nowhere; no bus step

  • read by no module's build: .gitignore

Run by the build seat on g14 as build-1791808383039663245 (builds --log build-1791808383039663245).

--- the gate: new:modules/mesh-reads
modules/mesh-reads/module.json: this manifest cannot be used:
  - mesh-reads claims "node-reads", which is a seat in the mesh's own namespace (mesh-*/node-*) that it does not define (novox/hq ADR 0121) — the seats are: git, mesh-artifact-store, mesh-broker, mesh-build-machine, mesh-catalog, mesh-controller, mesh-delivery, mesh-dns-resolver, mesh-store, mesh-vault, node-backup, node-bar, node-build-agent, node-clipboard, node-compositor, node-container-runtime, node-display-server, node-display-session, node-environment, node-hostname, node-hotkeys, node-intrusion-prevention, node-launcher, node-lock-screen, node-login-manager, node-login-shell, node-message-bus, node-mounts, node-nfs-server, node-notifier, node-package-manager, node-packet-filter, node-power, node-resolver, node-secret-service, node-service-manager, node-terminal-emulator, node-uplink, npm-package-registry, the-private-network
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
mesh-controller: 1 problem(s) in 1 manifest(s)
--- the same manifests on main
--- its merge-check.sh (go toolchain)
ok  	git.novox.be/novox/mesh-catalog/checks/words	0.002s
words: 12 retired words and 70 daemons' lines, none in the 43650 strings of 694 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.011s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/paths	0.004s
paths: no module names another's state on its machine (3 known, listed to go)
mesh-controller: 1 problem(s) in 127 manifest(s)
modules/mesh-reads/module.json: this manifest cannot be used:
  - mesh-reads claims "node-reads", which is a seat in the mesh's own namespace (mesh-*/node-*) that it does not define (novox/hq ADR 0121) — the seats are: git, mesh-artifact-store, mesh-broker, mesh-build-machine, mesh-catalog, mesh-controller, mesh-delivery, mesh-dns-resolver, mesh-store, mesh-vault, node-backup, node-bar, node-build-agent, node-clipboard, node-compositor, node-container-runtime, node-display-server, node-display-session, node-environment, node-hostname, node-hotkeys, node-intrusion-prevention, node-launcher, node-lock-screen, node-login-manager, node-login-shell, node-message-bus, node-mounts, node-nfs-server, node-notifier, node-package-manager, node-packet-filter, node-power, node-resolver, node-secret-service, node-service-manager, node-terminal-emulator, node-uplink, npm-package-registry, the-private-network
adwaita: ok, 4 tool(s)
artifact-store-tools: ok, 4 tool(s), invokes seat:mesh-controller.artifacts, seat:mesh-controller.collect
asus-zephyrus-g14: ok, 11 tool(s); WARNING: asusd, supergfxd, upower stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
audit-logger: ok, keeps trail (valuable), spool (valuable)
avahi: ok, 4 tool(s); WARNING: daemon stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
baserow: ok, keeps data (valuable), ready: server by its image's own check every 30s; WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
betterbird: ok, 7 tool(s); WARNING: user-js ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
blueman: ok, 3 tool(s)
bluetooth: ok, 9 tool(s); WARNING: daemon stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
build-agent: ok, keeps workspace (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
ca-trust: ok; WARNING: trust stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
claude-code: ok, 45 tool(s), keeps state servers, holdings, config, proposals, reads claude-licence-manager.bindings, keeps agent-home (valuable); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
claude-licence-manager: ok, keeps state bindings, reads claude-code.holdings; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
clipmenu: ok, 3 tool(s)
confluence: ok
cups: ok, 7 tool(s); WARNING: socket, scheduler stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
dbus: ok, 5 tool(s); WARNING: system-bus stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
de-spiegel: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
disk-load: ok, 4 tool(s)
distribution: ok, keeps registry (rebuildable); WARNING: store stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
dmenu: ok, 2 tool(s)
dnsmasq: ok, 3 tool(s), ready: service by unit every 30s; watch by its tool dnsmasq_health every 20s
docker: ok, 22 tool(s), invokes seat:mesh-controller.images; WARNING: socket, runtime, prune stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
docker-compose: ok, 9 tool(s)
dunst: ok, 6 tool(s)
fail2ban: ok, 1 tool(s); WARNING: run stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
feh: ok, 2 tool(s)
flatpak: ok, 11 tool(s)
fonts: ok, 6 tool(s)
forticlient: ok, 3 tool(s), ready: split-dns by unit every 30s; WARNING: scheduler stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
gitea: ok, keeps data (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
gitlab: ok
gnome-keyring: ok, 4 tool(s)
grafana: ok, keeps data (valuable), ready: server by http / on web every 30s; WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
hello-web: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
home-assistant: ok, keeps config (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
hostname: ok; WARNING: name ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
i3: ok, 10 tool(s)
i3status-rust: ok, 4 tool(s)
icecast: ok, keeps logs (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
influxdb: ok, keeps data (valuable), config (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
invoicing: ok; WARNING: app, api stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
jira: ok
keycloak: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
lab: ok, keeps work (cache); WARNING: runtime-env ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
lemurs: ok, 2 tool(s); WARNING: service stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
letta: ok; WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
local-model-consumer: ok
localization: ok, 4 tool(s)
logrotate: ok, 7 tool(s); WARNING: timer stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
mailu: ok, keeps mail (valuable), dkim (valuable), data (valuable), dav (valuable), webmail (valuable), queue (valuable), filter (rebuildable), certs (rebuildable), automx (rebuildable), fetchmail (rebuildable), clamav (cache), redis (cache), ready: resolver by its image's own check every 30s; admin by its image's own check every 30s; imap by its image's own check every 30s; smtp by its image's own check every 30s; antispam by its image's own check every 30s; webmail by its image's own check every 30s; webdav by its image's own check every 30s; fetchmail by its image's own check every 30s; front by its image's own check every 30s; WARNING: config-env ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: redis, antivirus, automx stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
marrytts: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
matrix: ok, keeps db (valuable), ready: element by its image's own check every 30s; WARNING: element-conf ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: homeserver stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
memory-pressure: ok, 6 tool(s); WARNING: oomd stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
mesh-catalog: ok
mesh-cli: ok
mesh-delivery: ok, 1 tool(s), invokes seat:mesh-controller.delivery-plan, seat:mesh-controller.delivery-order, seat:mesh-controller.delivery-check, seat:mesh-controller.deliver, seat:mesh-controller.delivery-stop, seat:mesh-controller.delivery-walks, gitea.gitea_note_append, gitea.gitea_delivery_view, gitea.gitea_commit_status, gitea.gitea_commit_statuses, gitea.gitea_contains, gitea.gitea_open_pulls, keeps state deliveries, groups
mesh-issues: ok, invokes claude-code.claude_code_judge, seat:mesh-delivery.checks, seat:operator-channel.notify, records.records_status, records.records_list, records.records_read, mesh-knowledge.knowledge_highest, keeps state issues, counters, grooming, reservations, keeps log changes (1024 MiB)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
mesh-vault: ok, keeps state (valuable), ledger (valuable), root (valuable)
mesh-watcher: ok, 4 tool(s), invokes mesh-watcher.watcher_ping, seat:mesh-controller.seats; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, keeps state open, sent, asks, identities, walks; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
minio: ok, keeps data (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
model-usage: ok, keeps state (cache), spool (valuable)
mongodb: ok, keeps data (valuable), dumps (rebuildable), ready: server by tcp on database every 30s
mosquitto: ok, keeps data (rebuildable), ready: server by tcp on mqtt every 30s
mounts: ok, 3 tool(s), invokes seat:mesh-controller.data, keeps state shares, reads nfs-server.exports, ready: apply by unit every 30s; watch by its tool mounts_health every 1m0s; WARNING: config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
mssql: ok, keeps data (valuable), dumps (rebuildable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
n8n: ok, keeps data (valuable), cache (cache); WARNING: server, cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nats: ok, 9 tool(s), keeps jetstream (valuable), snapshots (rebuildable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
netcheck: ok, 5 tool(s)
networkmanager: ok
nextcloud: ok, keeps html (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nextcloud-client: ok, 4 tool(s)
nfs-server: ok, 1 tool(s), invokes seat:mesh-controller.seats, seat:mesh-controller.data, keeps state exports, reads mounts.shares, ready: server by unit every 30s; exports by its tool nfs_health every 1m0s; WARNING: config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
nftables: ok, 1 tool(s); WARNING: load stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nm-applet: ok, 3 tool(s)
node-env: ok
nodered: ok, keeps data (valuable), ready: server by its image's own check every 30s; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
ollama: ok, keeps models (rebuildable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
only-office: ok, keeps data (rebuildable), lib (rebuildable), db (rebuildable), fonts (rebuildable), logs (cache), rabbitmq (cache), redis (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
openai-consumer: ok
openrazer: ok, 3 tool(s)
pacman: ok, 15 tool(s); WARNING: mirror-refresh, cache-cleaning stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
photos-eef: ok; WARNING: client stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
photos-filip: ok; WARNING: client stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
picom: ok, 4 tool(s); WARNING: configuration ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
polychromatic: ok, 3 tool(s)
postgres: ok, keeps store (valuable), dumps (rebuildable), ready: server by tcp on database every 30s
power: ok, 5 tool(s), keeps state draw, ready: draw by unit every 30s; WARNING: logind-power ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: after-boot, before-shutdown stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
powerlevel10k: ok
records: ok, 6 tool(s), keeps checkout (rebuildable)
redis: ok, keeps data (cache), ready: server by tcp on cache every 30s
restic: ok, 3 tool(s), keeps repository (rebuildable), state (cache), ready: night by its tool backup_health every 1m0s; measure by unit every 30s
rofi: ok, 3 tool(s)
route-adapter: ok; WARNING: config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
route-proxy: ok, keeps acme (rebuildable), ca (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
screen-lock: ok, 3 tool(s)
searxng: ok, keeps valkey (cache); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: cache, server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
sensors: ok, 6 tool(s), ready: drives by unit every 30s; watch by its tool sensors_health every 1m0s
showcase: ok; WARNING: server, tools stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
slack: ok, 4 tool(s)
snapd: ok, 10 tool(s)
ssh-client: ok, 8 tool(s), keeps ssh (valuable)
sshd: ok; WARNING: run stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
step-ca: ok, keeps home (valuable), ready: server by its image's own check every 30s
sudo: ok, 4 tool(s)
supabase: ok, keeps db (valuable), dumps (rebuildable), storage (valuable), functions (valuable), db-config (rebuildable), ready: db by its image's own check every 30s; kong by its image's own check every 30s; meta by its image's own check every 30s; studio by its image's own check every 30s; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: vector, analytics, auth, rest, realtime, imgproxy, storage-api, edge-functions, pooler stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
systemd: ok
systemd-networkd: ok
systemd-resolved: ok, ready: service by unit every 30s; guard by unit every 30s
telegram: ok, 1 tool(s), keeps state offset, messages
time-sync: ok, 3 tool(s); WARNING: daemon stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
triggerhappy: ok, 4 tool(s); WARNING: service stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
umami: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
unifi: ok, keeps data (valuable); WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
website: ok, ready: server by http / on web every 30s
xclip: ok, 4 tool(s)
xdg: ok, 5 tool(s); WARNING: user-dirs ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
xorg: ok, 9 tool(s)
xterm: ok, 2 tool(s)
zfs: ok, 15 tool(s), ready: watch by its tool zfs_health every 1m0s; events by unit every 30s; WARNING: scrub-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
zsh: ok, 1 tool(s); WARNING: tools-conf ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
zsh-autosuggestions: ok
zsh-syntax-highlighting: ok
long-running resources without health: 69
files asking for a setting without saying whether it is trusted: 25
**Merge check** at `994cab53` - `mesh/merge-gate`: **FAIL** — a manifest the change touches fails the module check: modules/mesh-reads/module.json: this manifest cannot be used: (modules: new:modules/mesh-reads) - `mesh/repo-check`: **FAIL** — its merge-check.sh failed: files asking for a setting without saying whether it is trusted: 25 **Delivery plan** — builds new: modules/mesh-reads, sent nowhere; no bus step - read by no module's build: .gitignore Run by the build seat on g14 as `build-1791808383039663245` (`builds --log build-1791808383039663245`). ``` --- the gate: new:modules/mesh-reads modules/mesh-reads/module.json: this manifest cannot be used: - mesh-reads claims "node-reads", which is a seat in the mesh's own namespace (mesh-*/node-*) that it does not define (novox/hq ADR 0121) — the seats are: git, mesh-artifact-store, mesh-broker, mesh-build-machine, mesh-catalog, mesh-controller, mesh-delivery, mesh-dns-resolver, mesh-store, mesh-vault, node-backup, node-bar, node-build-agent, node-clipboard, node-compositor, node-container-runtime, node-display-server, node-display-session, node-environment, node-hostname, node-hotkeys, node-intrusion-prevention, node-launcher, node-lock-screen, node-login-manager, node-login-shell, node-message-bus, node-mounts, node-nfs-server, node-notifier, node-package-manager, node-packet-filter, node-power, node-resolver, node-secret-service, node-service-manager, node-terminal-emulator, node-uplink, npm-package-registry, the-private-network long-running resources without health: 0 files asking for a setting without saying whether it is trusted: 0 mesh-controller: 1 problem(s) in 1 manifest(s) --- the same manifests on main --- its merge-check.sh (go toolchain) ok git.novox.be/novox/mesh-catalog/checks/words 0.002s words: 12 retired words and 70 daemons' lines, none in the 43650 strings of 694 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.011s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/paths 0.004s paths: no module names another's state on its machine (3 known, listed to go) mesh-controller: 1 problem(s) in 127 manifest(s) modules/mesh-reads/module.json: this manifest cannot be used: - mesh-reads claims "node-reads", which is a seat in the mesh's own namespace (mesh-*/node-*) that it does not define (novox/hq ADR 0121) — the seats are: git, mesh-artifact-store, mesh-broker, mesh-build-machine, mesh-catalog, mesh-controller, mesh-delivery, mesh-dns-resolver, mesh-store, mesh-vault, node-backup, node-bar, node-build-agent, node-clipboard, node-compositor, node-container-runtime, node-display-server, node-display-session, node-environment, node-hostname, node-hotkeys, node-intrusion-prevention, node-launcher, node-lock-screen, node-login-manager, node-login-shell, node-message-bus, node-mounts, node-nfs-server, node-notifier, node-package-manager, node-packet-filter, node-power, node-resolver, node-secret-service, node-service-manager, node-terminal-emulator, node-uplink, npm-package-registry, the-private-network adwaita: ok, 4 tool(s) artifact-store-tools: ok, 4 tool(s), invokes seat:mesh-controller.artifacts, seat:mesh-controller.collect asus-zephyrus-g14: ok, 11 tool(s); WARNING: asusd, supergfxd, upower stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) audit-logger: ok, keeps trail (valuable), spool (valuable) avahi: ok, 4 tool(s); WARNING: daemon stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) baserow: ok, keeps data (valuable), ready: server by its image's own check every 30s; WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) betterbird: ok, 7 tool(s); WARNING: user-js ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) blueman: ok, 3 tool(s) bluetooth: ok, 9 tool(s); WARNING: daemon stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) build-agent: ok, keeps workspace (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) ca-trust: ok; WARNING: trust stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) claude-code: ok, 45 tool(s), keeps state servers, holdings, config, proposals, reads claude-licence-manager.bindings, keeps agent-home (valuable); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) claude-licence-manager: ok, keeps state bindings, reads claude-code.holdings; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) clipmenu: ok, 3 tool(s) confluence: ok cups: ok, 7 tool(s); WARNING: socket, scheduler stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) dbus: ok, 5 tool(s); WARNING: system-bus stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) de-spiegel: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) disk-load: ok, 4 tool(s) distribution: ok, keeps registry (rebuildable); WARNING: store stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) dmenu: ok, 2 tool(s) dnsmasq: ok, 3 tool(s), ready: service by unit every 30s; watch by its tool dnsmasq_health every 20s docker: ok, 22 tool(s), invokes seat:mesh-controller.images; WARNING: socket, runtime, prune stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) docker-compose: ok, 9 tool(s) dunst: ok, 6 tool(s) fail2ban: ok, 1 tool(s); WARNING: run stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) feh: ok, 2 tool(s) flatpak: ok, 11 tool(s) fonts: ok, 6 tool(s) forticlient: ok, 3 tool(s), ready: split-dns by unit every 30s; WARNING: scheduler stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) gitea: ok, keeps data (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) gitlab: ok gnome-keyring: ok, 4 tool(s) grafana: ok, keeps data (valuable), ready: server by http / on web every 30s; WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) hello-web: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) home-assistant: ok, keeps config (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) hostname: ok; WARNING: name ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) i3: ok, 10 tool(s) i3status-rust: ok, 4 tool(s) icecast: ok, keeps logs (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) influxdb: ok, keeps data (valuable), config (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) invoicing: ok; WARNING: app, api stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) jira: ok keycloak: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) lab: ok, keeps work (cache); WARNING: runtime-env ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) lemurs: ok, 2 tool(s); WARNING: service stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) letta: ok; WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) local-model-consumer: ok localization: ok, 4 tool(s) logrotate: ok, 7 tool(s); WARNING: timer stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) mailu: ok, keeps mail (valuable), dkim (valuable), data (valuable), dav (valuable), webmail (valuable), queue (valuable), filter (rebuildable), certs (rebuildable), automx (rebuildable), fetchmail (rebuildable), clamav (cache), redis (cache), ready: resolver by its image's own check every 30s; admin by its image's own check every 30s; imap by its image's own check every 30s; smtp by its image's own check every 30s; antispam by its image's own check every 30s; webmail by its image's own check every 30s; webdav by its image's own check every 30s; fetchmail by its image's own check every 30s; front by its image's own check every 30s; WARNING: config-env ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: redis, antivirus, automx stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) marrytts: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) matrix: ok, keeps db (valuable), ready: element by its image's own check every 30s; WARNING: element-conf ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: homeserver stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) memory-pressure: ok, 6 tool(s); WARNING: oomd stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) mesh-catalog: ok mesh-cli: ok mesh-delivery: ok, 1 tool(s), invokes seat:mesh-controller.delivery-plan, seat:mesh-controller.delivery-order, seat:mesh-controller.delivery-check, seat:mesh-controller.deliver, seat:mesh-controller.delivery-stop, seat:mesh-controller.delivery-walks, gitea.gitea_note_append, gitea.gitea_delivery_view, gitea.gitea_commit_status, gitea.gitea_commit_statuses, gitea.gitea_contains, gitea.gitea_open_pulls, keeps state deliveries, groups mesh-issues: ok, invokes claude-code.claude_code_judge, seat:mesh-delivery.checks, seat:operator-channel.notify, records.records_status, records.records_list, records.records_read, mesh-knowledge.knowledge_highest, keeps state issues, counters, grooming, reservations, keeps log changes (1024 MiB) mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s mesh-vault: ok, keeps state (valuable), ledger (valuable), root (valuable) mesh-watcher: ok, 4 tool(s), invokes mesh-watcher.watcher_ping, seat:mesh-controller.seats; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, keeps state open, sent, asks, identities, walks; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) minio: ok, keeps data (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) model-usage: ok, keeps state (cache), spool (valuable) mongodb: ok, keeps data (valuable), dumps (rebuildable), ready: server by tcp on database every 30s mosquitto: ok, keeps data (rebuildable), ready: server by tcp on mqtt every 30s mounts: ok, 3 tool(s), invokes seat:mesh-controller.data, keeps state shares, reads nfs-server.exports, ready: apply by unit every 30s; watch by its tool mounts_health every 1m0s; WARNING: config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) mssql: ok, keeps data (valuable), dumps (rebuildable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) n8n: ok, keeps data (valuable), cache (cache); WARNING: server, cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nats: ok, 9 tool(s), keeps jetstream (valuable), snapshots (rebuildable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) netcheck: ok, 5 tool(s) networkmanager: ok nextcloud: ok, keeps html (valuable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nextcloud-client: ok, 4 tool(s) nfs-server: ok, 1 tool(s), invokes seat:mesh-controller.seats, seat:mesh-controller.data, keeps state exports, reads mounts.shares, ready: server by unit every 30s; exports by its tool nfs_health every 1m0s; WARNING: config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) nftables: ok, 1 tool(s); WARNING: load stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nm-applet: ok, 3 tool(s) node-env: ok nodered: ok, keeps data (valuable), ready: server by its image's own check every 30s; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) ollama: ok, keeps models (rebuildable); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) only-office: ok, keeps data (rebuildable), lib (rebuildable), db (rebuildable), fonts (rebuildable), logs (cache), rabbitmq (cache), redis (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) openai-consumer: ok openrazer: ok, 3 tool(s) pacman: ok, 15 tool(s); WARNING: mirror-refresh, cache-cleaning stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) photos-eef: ok; WARNING: client stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) photos-filip: ok; WARNING: client stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) picom: ok, 4 tool(s); WARNING: configuration ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) polychromatic: ok, 3 tool(s) postgres: ok, keeps store (valuable), dumps (rebuildable), ready: server by tcp on database every 30s power: ok, 5 tool(s), keeps state draw, ready: draw by unit every 30s; WARNING: logind-power ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: after-boot, before-shutdown stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) powerlevel10k: ok records: ok, 6 tool(s), keeps checkout (rebuildable) redis: ok, keeps data (cache), ready: server by tcp on cache every 30s restic: ok, 3 tool(s), keeps repository (rebuildable), state (cache), ready: night by its tool backup_health every 1m0s; measure by unit every 30s rofi: ok, 3 tool(s) route-adapter: ok; WARNING: config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) route-proxy: ok, keeps acme (rebuildable), ca (cache); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) screen-lock: ok, 3 tool(s) searxng: ok, keeps valkey (cache); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: cache, server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) sensors: ok, 6 tool(s), ready: drives by unit every 30s; watch by its tool sensors_health every 1m0s showcase: ok; WARNING: server, tools stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) slack: ok, 4 tool(s) snapd: ok, 10 tool(s) ssh-client: ok, 8 tool(s), keeps ssh (valuable) sshd: ok; WARNING: run stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) step-ca: ok, keeps home (valuable), ready: server by its image's own check every 30s sudo: ok, 4 tool(s) supabase: ok, keeps db (valuable), dumps (rebuildable), storage (valuable), functions (valuable), db-config (rebuildable), ready: db by its image's own check every 30s; kong by its image's own check every 30s; meta by its image's own check every 30s; studio by its image's own check every 30s; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: vector, analytics, auth, rest, realtime, imgproxy, storage-api, edge-functions, pooler stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) systemd: ok systemd-networkd: ok systemd-resolved: ok, ready: service by unit every 30s; guard by unit every 30s telegram: ok, 1 tool(s), keeps state offset, messages time-sync: ok, 3 tool(s); WARNING: daemon stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) triggerhappy: ok, 4 tool(s); WARNING: service stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) umami: ok; WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) unifi: ok, keeps data (valuable); WARNING: runtime-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: server stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) website: ok, ready: server by http / on web every 30s xclip: ok, 4 tool(s) xdg: ok, 5 tool(s); WARNING: user-dirs ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) xorg: ok, 9 tool(s) xterm: ok, 2 tool(s) zfs: ok, 15 tool(s), ready: watch by its tool zfs_health every 1m0s; events by unit every 30s; WARNING: scrub-config ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) zsh: ok, 1 tool(s); WARNING: tools-conf ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339) zsh-autosuggestions: ok zsh-syntax-highlighting: ok long-running resources without health: 69 files asking for a setting without saying whether it is trusted: 25 ```
mesh-admin left a comment
Author
Contributor

Verdict: approve at 994cab533b

Re-review against review 55 (on #244, which this PR replaces). The branch is one commit on current main, and the tree holds no binary. .gitignore names both build outputs. go vet ./... is clean and go test -race -count=1 ./... passes. With a controller built from mesh-controller #257 head 63a99d4, MESH_GATE=… MESH_CHECK_MODULES=mesh-reads sh merge-check.sh exits 0. The red mesh/merge-gate and mesh/repo-check here come from the running controller lacking node-reads, and clear once #257 is live.

I reran my probes:

  • The link-flip race is closed. read answered the secret place's content 0 times in 20000 calls (was 3744). search, with an entry flipped between a regular file and a link into the secret place, answered it 0 times in 5000. openJudged checks the type first, opens with O_NONBLOCK|O_NOCTTY|O_CLOEXEC (plus O_NOFOLLOW in search), checks fstat again, and judges the path the kernel gives for the descriptor (/proc/self/fd). It refuses a deleted file.
  • The private-key block is withheld. All 28 lines of a generated RSA-2048 key in server.pem are withheld, and a line before the block is kept. Reads from line 10, a tail read (from -3) and a search across the key withheld every line of the block.
  • History files are refused by name, for example .zsh_history.
  • Devices and FIFOs are refused before any open, at once: /dev/null, /dev/ptmx, /dev/tty and a fifo.
  • /proc: /proc/self/environ, /proc/self/fd/N (including a deleted file) and /proc/thread-self/fd are refused by name. cmdline is refused as binary. /proc/loadavg and /proc/self/status are read.
  • A search from / stays on the root's file system. It skipped 6 other file systems and stopped at the 5000-file bound, which it names. The time bound is now checked inside a file too.
  • go.mod pins mesh-sdk 67bfa22 (#23's head).

Minor, not blocking: the process-private rule matches only /proc/<pid>/<entry>, so /proc/<pid>/task/<tid>/environ and /proc/<pid>/task/<tid>/fd are not refused by name. environ is refused anyway as binary, and a file reached through fd is judged by its real path. A follow-up could also match task/*/ entries.

Merge order: mesh-sdk #23, then mesh-controller #257, then wait until mesh-controller.plans says done and recheck this PR's gate, then this PR. After merge, assign mesh-reads to novox first.

Verdict: approve at 994cab533bbd988f7e951040cbb6013d1a3441dc Re-review against review 55 (on #244, which this PR replaces). The branch is one commit on current main, and the tree holds no binary. `.gitignore` names both build outputs. `go vet ./...` is clean and `go test -race -count=1 ./...` passes. With a controller built from mesh-controller #257 head 63a99d4, `MESH_GATE=… MESH_CHECK_MODULES=mesh-reads sh merge-check.sh` exits 0. The red `mesh/merge-gate` and `mesh/repo-check` here come from the running controller lacking `node-reads`, and clear once #257 is live. I reran my probes: - **The link-flip race is closed.** `read` answered the secret place's content 0 times in 20000 calls (was 3744). `search`, with an entry flipped between a regular file and a link into the secret place, answered it 0 times in 5000. `openJudged` checks the type first, opens with `O_NONBLOCK|O_NOCTTY|O_CLOEXEC` (plus `O_NOFOLLOW` in search), checks `fstat` again, and judges the path the kernel gives for the descriptor (`/proc/self/fd`). It refuses a deleted file. - **The private-key block is withheld.** All 28 lines of a generated RSA-2048 key in `server.pem` are withheld, and a line before the block is kept. Reads from line 10, a tail read (`from -3`) and a search across the key withheld every line of the block. - **History files are refused by name**, for example `.zsh_history`. - **Devices and FIFOs are refused before any open, at once:** `/dev/null`, `/dev/ptmx`, `/dev/tty` and a fifo. - **/proc:** `/proc/self/environ`, `/proc/self/fd/N` (including a deleted file) and `/proc/thread-self/fd` are refused by name. `cmdline` is refused as binary. `/proc/loadavg` and `/proc/self/status` are read. - **A search from / stays on the root's file system.** It skipped 6 other file systems and stopped at the 5000-file bound, which it names. The time bound is now checked inside a file too. - `go.mod` pins mesh-sdk 67bfa22 (#23's head). Minor, not blocking: the process-private rule matches only `/proc/<pid>/<entry>`, so `/proc/<pid>/task/<tid>/environ` and `/proc/<pid>/task/<tid>/fd` are not refused by name. `environ` is refused anyway as binary, and a file reached through `fd` is judged by its real path. A follow-up could also match `task/*/` entries. Merge order: mesh-sdk #23, then mesh-controller #257, then wait until `mesh-controller.plans` says done and recheck this PR's gate, then this PR. After merge, assign `mesh-reads` to novox first.
Author
Contributor

Merge check at 994cab53

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-reads)
  • mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)

Delivery plan — builds new: modules/mesh-reads, sent nowhere; no bus step

  • read by no module's build: .gitignore

Run by the build seat on shanks as build-1791811865596626104 (builds --log build-1791811865596626104).

--- the gate: new:modules/mesh-reads
mesh-reads: ok
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-12T13:22:45Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-12T13:22:45Z

modules the change moves:
  - mesh-reads (added)

machines:
  - a machine (f35): composes
  - holds mesh-dns-resolver (idt): composes
  - holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
  - a machine (yvbpsm): composes

a merge would rebuild 0 module(s) in 0 tier(s)

notes:
  - mesh-reads could not be tried on a machine: mesh-reads on f35 has no bus credential: nothing was issued for f35.mesh-reads, and a push would seal a placeholder its process cannot read (novox/hq issue 203). `module issue mesh-reads --node f35`, then push again
  - .gitignore read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	git.novox.be/novox/mesh-catalog/checks/words	0.003s
words: 12 retired words and 70 daemons' lines, none in the 43650 strings of 694 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.013s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/paths	0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
ok  	git.novox.be/novox/mesh-catalog/checks/deps	0.259s
testing modules/mesh-reads
ok  	mesh-reads/cmd/mesh-reads	2.651s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `994cab53` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-reads) - `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript) **Delivery plan** — builds new: modules/mesh-reads, sent nowhere; no bus step - read by no module's build: .gitignore Run by the build seat on shanks as `build-1791811865596626104` (`builds --log build-1791811865596626104`). ``` --- the gate: new:modules/mesh-reads mesh-reads: ok long-running resources without health: 0 files asking for a setting without saying whether it is trusted: 0 1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-12T13:22:45Z says they run composing every machine as the mesh is the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued composing every machine with the change the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose) judged by controller development build against the facts of 2026-10-12T13:22:45Z modules the change moves: - mesh-reads (added) machines: - a machine (f35): composes - holds mesh-dns-resolver (idt): composes - holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes - a machine (yvbpsm): composes a merge would rebuild 0 module(s) in 0 tier(s) notes: - mesh-reads could not be tried on a machine: mesh-reads on f35 has no bus credential: nothing was issued for f35.mesh-reads, and a push would seal a placeholder its process cannot read (novox/hq issue 203). `module issue mesh-reads --node f35`, then push again - .gitignore read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok git.novox.be/novox/mesh-catalog/checks/words 0.003s words: 12 retired words and 70 daemons' lines, none in the 43650 strings of 694 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.013s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s paths: no module names another's state on its machine (3 known, listed to go) long-running resources without health: 69, as kept ok git.novox.be/novox/mesh-catalog/checks/deps 0.259s testing modules/mesh-reads ok mesh-reads/cmd/mesh-reads 2.651s --- its merge-check-typescript.sh (typescript toolchain) ```
mesh-admin merged commit cd2b6aacd8 into main 2026-10-12 14:52:19 +00:00
mesh-admin deleted branch fix/418-node-reads-2 2026-10-12 14:52:19 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#247