This builds hq ADR 0251 §1–3 and to-be 51 ("The artifact store"), recorded in hq PR #200.
It differs from the ADR's wording on two points, because the controller requires it.
The tools are a second module, artifact-store-tools, not the distribution module's own. The first push failed the gate. A module that provides artifact-store cannot also build an artifact, because building publishes to the store. The refusal says such tools are a second module. That module must be assigned to the machine that holds the store. Anywhere else, its tools answer that the store's container is not there.
The tools are named artifact_store_*, not store_*. In the glossary, "store" alone means the database server.
The parts:
distribution drops its unbuilt TypeScript (client, events, tools). It also drops the image.pushed event, which was declared but never emitted and which nothing in the catalogue consumes. Nothing else in it changes.
artifact-store-tools is a Go bundle with four tools:
artifact_store_repositories (r): every repository with its tags, its manifest count and its size.
artifact_store_usage (r): the total size, the largest repositories, the bytes shared between repositories, and the bytes no manifest marks.
artifact_store_references (r): the state of each manifest (kept, holder of a kept archive, eligible, holder of an eligible archive, let go yet present, named document, unrecorded), plus what the records keep that the store does not hold.
artifact_store_collect (a): a dry run by default. A real run needs why and asks the controller.
The bundle reads the store's files (the listing and each manifest's content) through docker exec mesh-registry, read-only. It never deletes. Nothing removes an unrecorded manifest.
invokes lists seat:mesh-controller.artifacts and seat:mesh-controller.collect. This depends on the controller PR that adds those verbs.
Locally, go vet and go test -race pass. merge-check.sh passes with a controller built from the controller fork's working tree as MESH_GATE: both manifests are ok, and the count of resources without health is 70, as kept.
This builds hq ADR 0251 §1–3 and to-be 51 ("The artifact store"), recorded in hq PR #200.
**It differs from the ADR's wording on two points, because the controller requires it.**
- **The tools are a second module, `artifact-store-tools`, not the `distribution` module's own.** The first push failed the gate. A module that provides `artifact-store` cannot also build an artifact, because building publishes to the store. The refusal says such tools are a second module. That module must be assigned to the machine that holds the store. Anywhere else, its tools answer that the store's container is not there.
- **The tools are named `artifact_store_*`, not `store_*`.** In the glossary, "store" alone means the database server.
The parts:
- `distribution` drops its unbuilt TypeScript (client, events, tools). It also drops the `image.pushed` event, which was declared but never emitted and which nothing in the catalogue consumes. Nothing else in it changes.
- `artifact-store-tools` is a Go bundle with four tools:
- `artifact_store_repositories` (r): every repository with its tags, its manifest count and its size.
- `artifact_store_usage` (r): the total size, the largest repositories, the bytes shared between repositories, and the bytes no manifest marks.
- `artifact_store_references` (r): the state of each manifest (kept, holder of a kept archive, eligible, holder of an eligible archive, let go yet present, named document, unrecorded), plus what the records keep that the store does not hold.
- `artifact_store_collect` (a): a dry run by default. A real run needs `why` and asks the controller.
- The bundle reads the store's files (the listing and each manifest's content) through `docker exec mesh-registry`, read-only. It never deletes. Nothing removes an unrecorded manifest.
- `invokes` lists `seat:mesh-controller.artifacts` and `seat:mesh-controller.collect`. **This depends on the controller PR that adds those verbs.**
Locally, go vet and go test -race pass. merge-check.sh passes with a controller built from the controller fork's working tree as MESH_GATE: both manifests are ok, and the count of resources without health is 70, as kept.
mesh/merge-gate fail: builds distribution → novox; no bus step; a manifest the change touches fails the module check: modules/distribution/module.json: thi…
The store had no working tools: its TypeScript client was never built, and nothing could count what
the store holds that no record names. A Go bundle lists the store's files through its own container,
reads each manifest through its door, and sets that beside the controller's records. Collection is
asked of the controller, which decides and records; the store's tools never delete. The image.pushed
event was declared and never emitted, and nothing consumes it, so it goes.
Deliverynovox/mesh-catalog@24ce702360d8 — failed since 2026-10-08T11:21:28Z
Covered: covered after its failure: a later walk that contains it was delivered: plan-1792260860441586760 (novox/mesh-catalog at 5e7567e5 into main, done, contains its merge 86077780)
Delivery plan — builds distribution, new: modules/artifact-store-tools → novox; no bus step
tier 0: distribution
novox: receives distribution
distribution provides artifact-store: its consumers are sent again after it
distribution keeps data (ADR 0233): what it holds is backed up before it moves
Machines
docker on ace: passed — healthy 3 times over 2m19s
openrazer on g14: failed — not healthy within 10m0s of its apply: its unit openrazer.daemon on g14 is unhealthy: failed in the account's own service manager (exit-code)
distribution on novox: passed — healthy 3 times over 4m2s
gitea on novox: passed — judged with distribution: healthy 3 times over 4m2s
distribution on the rest running it: sent
gitea on the rest running it: sent
Transitions
2026-10-08 10:04 (new) → proposed (announced): novox/mesh-catalog#123's head announced
2026-10-08 10:06 proposed → checked (checked): the verdict names this commit
2026-10-08 10:06 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-08 11:07 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-08 11:07 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path
2026-10-08 11:21 delivering → failed (failed): its walk failed: a gate on a first machine (what it carried put back), a build, a machine
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@24ce702360d8` — **failed** since 2026-10-08T11:21:28Z
**Covered**: covered after its failure: a later walk that contains it was delivered: plan-1792260860441586760 (novox/mesh-catalog at 5e7567e5 into main, done, contains its merge 86077780)
**Delivery plan** — builds distribution, new: modules/artifact-store-tools → novox; no bus step
- tier 0: distribution
- novox: receives distribution
- distribution provides artifact-store: its consumers are sent again after it
- distribution keeps data (ADR 0233): what it holds is backed up before it moves
**Machines**
- docker on ace: passed — healthy 3 times over 2m19s
- openrazer on g14: failed — not healthy within 10m0s of its apply: its unit openrazer.daemon on g14 is unhealthy: failed in the account's own service manager (exit-code)
- distribution on novox: passed — healthy 3 times over 4m2s
- gitea on novox: passed — judged with distribution: healthy 3 times over 4m2s
- distribution on the rest running it: sent
- gitea on the rest running it: sent
**Transitions**
- 2026-10-08 10:04 (new) → proposed (announced): novox/mesh-catalog#123's head announced
- 2026-10-08 10:06 proposed → checked (checked): the verdict names this commit
- 2026-10-08 10:06 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-08 11:07 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-08 11:07 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path
- 2026-10-08 11:21 delivering → failed (failed): its walk failed: a gate on a first machine (what it carried put back), a build, a machine
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
mesh/merge-gate: FAIL — a manifest the change touches fails the module check: modules/distribution/module.json: this manifest cannot be used: (modules: distribution)
mesh/repo-check: FAIL — its merge-check.sh failed: long-running resources without health: 69
Delivery plan — builds distribution → novox; no bus step
tier 0: distribution
novox: receives distribution
distribution provides artifact-store: its consumers are sent again after it
distribution keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as build-1791453609839977946 (builds --log build-1791453609839977946).
--- the gate: distribution
modules/distribution/module.json: this manifest cannot be used:
- distribution provides "artifact-store" and also builds 1 artifact(s), which cannot both be true: building publishes to the artifact store, so this asks the mesh to put an artifact into the thing that artifact is needed to create. A module that provides the store names its image instead. One that wants more beside it — an interface, a tool server — is a second module, mirrored in the ordinary way once this one is running
long-running resources without health: 0
mesh-controller: 1 problem(s) in 1 manifest(s)
--- the same manifests on main
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)
long-running resources without health: 1
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
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words, none in the 29070 strings of 537 files
mesh-controller: 1 problem(s) in 115 manifest(s)
modules/distribution/module.json: this manifest cannot be used:
- distribution provides "artifact-store" and also builds 1 artifact(s), which cannot both be true: building publishes to the artifact store, so this asks the mesh to put an artifact into the thing that artifact is needed to create. A module that provides the store names its image instead. One that wants more beside it — an interface, a tool server — is a second module, mirrored in the ordinary way once this one is running
adwaita: ok, 4 tool(s)
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
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, 40 tool(s), keeps state servers, holdings, config, reads claude-licence-manager.bindings, keeps agent-home (valuable)
claude-licence-manager: ok, keeps state bindings, reads claude-code.holdings
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)
disk-load: ok, 4 tool(s)
dmenu: ok, 2 tool(s)
dnsmasq: ok; 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)
docker: ok, 20 tool(s); 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, 5 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
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
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)
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: 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: 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: 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-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, keeps state deliveries, groups
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
messenger: ok, 4 tool(s), invokes seat:node-notifier.send, seat:mesh-controller.conditions, keeps state open, sent
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
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, 8 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, 3 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)
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
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)
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); 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, keeps repository (rebuildable), state (cache)
rofi: ok, 3 tool(s)
route-adapter: ok
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: 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)
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, 3 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: 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
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: 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)
xorg: ok, 8 tool(s)
xterm: ok, 2 tool(s)
zsh: ok, 1 tool(s)
zsh-autosuggestions: ok
zsh-syntax-highlighting: ok
long-running resources without health: 69
**Merge check** at `5f22ebbe`
- `mesh/merge-gate`: **FAIL** — a manifest the change touches fails the module check: modules/distribution/module.json: this manifest cannot be used: (modules: distribution)
- `mesh/repo-check`: **FAIL** — its merge-check.sh failed: long-running resources without health: 69
**Delivery plan** — builds distribution → novox; no bus step
- tier 0: distribution
- novox: receives distribution
- distribution provides artifact-store: its consumers are sent again after it
- distribution keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as `build-1791453609839977946` (`builds --log build-1791453609839977946`).
```
--- the gate: distribution
modules/distribution/module.json: this manifest cannot be used:
- distribution provides "artifact-store" and also builds 1 artifact(s), which cannot both be true: building publishes to the artifact store, so this asks the mesh to put an artifact into the thing that artifact is needed to create. A module that provides the store names its image instead. One that wants more beside it — an interface, a tool server — is a second module, mirrored in the ordinary way once this one is running
long-running resources without health: 0
mesh-controller: 1 problem(s) in 1 manifest(s)
--- the same manifests on main
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)
long-running resources without health: 1
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
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words, none in the 29070 strings of 537 files
mesh-controller: 1 problem(s) in 115 manifest(s)
modules/distribution/module.json: this manifest cannot be used:
- distribution provides "artifact-store" and also builds 1 artifact(s), which cannot both be true: building publishes to the artifact store, so this asks the mesh to put an artifact into the thing that artifact is needed to create. A module that provides the store names its image instead. One that wants more beside it — an interface, a tool server — is a second module, mirrored in the ordinary way once this one is running
adwaita: ok, 4 tool(s)
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
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, 40 tool(s), keeps state servers, holdings, config, reads claude-licence-manager.bindings, keeps agent-home (valuable)
claude-licence-manager: ok, keeps state bindings, reads claude-code.holdings
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)
disk-load: ok, 4 tool(s)
dmenu: ok, 2 tool(s)
dnsmasq: ok; 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)
docker: ok, 20 tool(s); 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, 5 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
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
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)
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: 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: 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: 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-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, keeps state deliveries, groups
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
messenger: ok, 4 tool(s), invokes seat:node-notifier.send, seat:mesh-controller.conditions, keeps state open, sent
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
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, 8 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, 3 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)
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
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)
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); 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, keeps repository (rebuildable), state (cache)
rofi: ok, 3 tool(s)
route-adapter: ok
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: 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)
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, 3 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: 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
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: 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)
xorg: ok, 8 tool(s)
xterm: ok, 2 tool(s)
zsh: ok, 1 tool(s)
zsh-autosuggestions: ok
zsh-syntax-highlighting: ok
long-running resources without health: 69
```
mesh/merge-gate pass: builds distribution, new: modules/artifact-store-tools → novox; no bus step; every machine composes with the change as it did without…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792260860441586760 (novox/mesh-catalog at 5e7567e5 into main,…
A module that provides the artifact store cannot build an artifact: building publishes to the store,
so the store would be needed to create itself, and the module check refuses it. The tools become
artifact-store-tools, assigned beside the store, and read manifests from the store's files through its
container as they already read the listing, so they need no address for the store's door. Named for
the artifact store, because "store" alone is the database server (hq glossary).
mesh-admin
changed title from distribution: the store's tools say what it holds and what the records name (hq ADR 0251) to artifact-store-tools: say what the artifact store holds and what the records name (hq ADR 0251)2026-10-08 10:04:45 +00:00
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: distribution, new:modules/artifact-store-tools)
mesh/repo-check: PASS — its merge-check.sh passed
Delivery plan — builds distribution, new: modules/artifact-store-tools → novox; no bus step
tier 0: distribution
novox: receives distribution
distribution provides artifact-store: its consumers are sent again after it
distribution keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as build-1791453885213591661 (builds --log build-1791453885213591661).
--- the gate: distribution, new:modules/artifact-store-tools
artifact-store-tools: ok, 4 tool(s), invokes seat:mesh-controller.artifacts, seat:mesh-controller.collect
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)
long-running resources without health: 1
2 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 2 module(s) changed against 4 machine(s), as the snapshot of 2026-10-08T10:04:03Z 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-08T10:04:03Z
modules the change moves:
- artifact-store-tools (added)
- distribution (changed)
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 1 module(s) in 1 tier(s): distribution
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words, none in the 29084 strings of 539 files
long-running resources without health: 70, as kept
testing modules/artifact-store-tools
ok artifactstoretools/cmd/artifact-store-tools 1.024s
**Merge check** at `24ce7023`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: distribution, new:modules/artifact-store-tools)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds distribution, new: modules/artifact-store-tools → novox; no bus step
- tier 0: distribution
- novox: receives distribution
- distribution provides artifact-store: its consumers are sent again after it
- distribution keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as `build-1791453885213591661` (`builds --log build-1791453885213591661`).
```
--- the gate: distribution, new:modules/artifact-store-tools
artifact-store-tools: ok, 4 tool(s), invokes seat:mesh-controller.artifacts, seat:mesh-controller.collect
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)
long-running resources without health: 1
2 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 2 module(s) changed against 4 machine(s), as the snapshot of 2026-10-08T10:04:03Z 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-08T10:04:03Z
modules the change moves:
- artifact-store-tools (added)
- distribution (changed)
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 1 module(s) in 1 tier(s): distribution
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words, none in the 29084 strings of 539 files
long-running resources without health: 70, as kept
testing modules/artifact-store-tools
ok artifactstoretools/cmd/artifact-store-tools 1.024s
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
This builds hq ADR 0251 §1–3 and to-be 51 ("The artifact store"), recorded in hq PR #200.
It differs from the ADR's wording on two points, because the controller requires it.
artifact-store-tools, not thedistributionmodule's own. The first push failed the gate. A module that providesartifact-storecannot also build an artifact, because building publishes to the store. The refusal says such tools are a second module. That module must be assigned to the machine that holds the store. Anywhere else, its tools answer that the store's container is not there.artifact_store_*, notstore_*. In the glossary, "store" alone means the database server.The parts:
distributiondrops its unbuilt TypeScript (client, events, tools). It also drops theimage.pushedevent, which was declared but never emitted and which nothing in the catalogue consumes. Nothing else in it changes.artifact-store-toolsis a Go bundle with four tools:artifact_store_repositories(r): every repository with its tags, its manifest count and its size.artifact_store_usage(r): the total size, the largest repositories, the bytes shared between repositories, and the bytes no manifest marks.artifact_store_references(r): the state of each manifest (kept, holder of a kept archive, eligible, holder of an eligible archive, let go yet present, named document, unrecorded), plus what the records keep that the store does not hold.artifact_store_collect(a): a dry run by default. A real run needswhyand asks the controller.docker exec mesh-registry, read-only. It never deletes. Nothing removes an unrecorded manifest.invokeslistsseat:mesh-controller.artifactsandseat:mesh-controller.collect. This depends on the controller PR that adds those verbs.Locally, go vet and go test -race pass. merge-check.sh passes with a controller built from the controller fork's working tree as MESH_GATE: both manifests are ok, and the count of resources without health is 70, as kept.
Delivery
novox/mesh-catalog@24ce702360d8— failed since 2026-10-08T11:21:28ZCovered: covered after its failure: a later walk that contains it was delivered: plan-1792260860441586760 (novox/mesh-catalog at
5e7567e5into main, done, contains its merge86077780)Delivery plan — builds distribution, new: modules/artifact-store-tools → novox; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
5f22ebbemesh/merge-gate: FAIL — a manifest the change touches fails the module check: modules/distribution/module.json: this manifest cannot be used: (modules: distribution)mesh/repo-check: FAIL — its merge-check.sh failed: long-running resources without health: 69Delivery plan — builds distribution → novox; no bus step
Run by the build seat on ace as
build-1791453609839977946(builds --log build-1791453609839977946).distribution: the store's tools say what it holds and what the records name (hq ADR 0251)to artifact-store-tools: say what the artifact store holds and what the records name (hq ADR 0251)Merge check at
24ce7023mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: distribution, new:modules/artifact-store-tools)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds distribution, new: modules/artifact-store-tools → novox; no bus step
Run by the build seat on ace as
build-1791453885213591661(builds --log build-1791453885213591661).