Files
mesh-host/examples
jschoubben 4bff67ec69 A machine waiting to be enrolled is not a broken one
The launcher already ran `host run`, and `run` on a machine with no identity
exited with an error. So a freshly installed host, sitting exactly as intended
waiting for somebody to bring it a token, would have counted three failed
starts and rolled back its own installation.

It waits now, and says what it is waiting for. That is the *hosted* state from
the lifecycle: the host is running, it has no identity, and there is nobody to
link to. Every machine passes through it.

An identity that exists and cannot be read is still a fault rather than a wait.
Treating that as "not enrolled yet" would leave a node sitting quietly for ever
while the mesh believes it is a member.

Also: a node now says it is there once a minute. Nothing but its name, because
anything more would be a report, and reports are rare where this is constant --
reading one as the other would make a quiet node look like a stale one. Not
published mandatory, unlike a report: losing one is nothing, the next is a
minute away, and the mesh reads a gap rather than counting arrivals.

Verified in the lab: a node was stopped and the mesh said "out of touch 4m",
then it was started and the mesh said "here" again, without anything else being
touched.
2026-08-29 20:32:18 +02:00
..

Examples

substrate-first-node.lock

What a machine must be before a mesh exists — steps 0 to 4 of the bootstrap in novox/hq 07-the-substrate.md:

0  a container runtime
1  the store runs
2  a database per context        one today, `inventory`
3  that context's schema         mesh-control migrate
4  the broker runs

It stops there, and the file says why. Step 5 is a virtual host, a credential and a certificate; step 6 is the control plane running. Nothing consumes any of them yet, and a bundle whose last step cannot be checked is worse than a shorter one.

Build a host carrying it:

make host SYSTEM=arch BUNDLE=examples/substrate-first-node.lock

The registry address and digests have to be replaced before this is useful. They are written as 192.0.2.250:5000/…@sha256:… because a digest belongs to whatever registry serves it — here, one a lab scenario raises, which reports its digests when it comes up. That is not a placeholder to be tidied away: a bundle is built for a target, and which registry that target pulls from is part of the target.

What was verified, and how

On a lab machine confirmed sealed — curl https://example.com times out, the lab registry answers 200 — the whole bundle applied from bare: eight resources, inventory created and mesh nowhere, the node table present with its indexes, the migration recorded, and LavinMQ answering lavinmqctl status with AMQP listening on 5672.

Three consecutive reconciles after that: already matches — 8 resource(s) checked, each time.

Then the machine was rebooted, and everything came back: docker from boot: enabled, both containers because the host creates every container --restart unless-stopped (internal/apply/apply.go), the schema intact in its named volume, and reconcile still finding nothing to do.

The reboot is worth doing rather than assuming. Nothing in the declaration asks for a container to return, so that it does is a property of the host, and the only way to know it holds is to take the machine away and give it back.