Extends the applier past the filesystem to the two types the workloads
need: a container and the private network it joins. The workloads are
the bulk of what a cutover re-declares (research 009), so this is what
makes a workload manifest actually appliable.
- container: run/reconcile/remove over the runtime. Up to date means a
container that is ours (a spec-hash label matches this exact
declaration) AND running; anything else — a changed spec, a stopped
container, or a foreign one the old control plane left by that name —
is recreated into ours. Safe because a container carries no state:
its data is in bind-mounted directories declared separately, and
recreating it never touches them. Read-back asks the runtime whether
it is actually running on the declared spec, because 'started' only
means the runtime returned.
- network: create if absent, adopt if present, remove only what it
created.
- The runtime is driven through a Runner, faked in unit tests and
exercised for real in a smoke test that stands a container up, proves
idempotency, and tears it down — skipped, never failed, where the
runtime is absent.
The store's per-resource reference generalises from a path to a ref:
a path for files and directories, a name for containers and networks.
Verified end to end through the binary: a container on a bind mount,
then dropped from the declaration — the container is removed and the
data directory survives, which is the migration property itself.
Still deferred: sealed secrets, and package/service/archive/user/action
— refused whole until built, never half-applied.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
Stage 2 begins. The host stops only reporting and starts doing its one
job (ADR 0037): take an ordered list of typed resources and make the
machine match it, from a local file, with no mesh present.
What lands in this slice — the network-free vocabulary ADR 0043 names
first:
- Parse: JSON, refused WHOLE on an unknown version, type, field, a
missing id/type/path, or a duplicate id. An older host cannot be
handed a newer vocabulary and do half of it.
- directory and file appliers, each reading back after it writes —
mode and owner asserted against the machine, content compared byte
for byte. A value that did not take is a failed apply, not a success.
- store: the applied-state record, authoritative while disconnected,
written atomically. It is what makes removal possible.
- Convergence: apply in the stated order (the host never reorders),
record each success AFTER it works (ADR 0035), and remove what was
applied before and is no longer declared — in reverse order, so a
file goes before the directory that held it.
- The data-loss guard: the host removes ONLY what it created, never
what it adopted, and a created directory that now holds data is
refused (os.Remove, never RemoveAll) rather than deleted (ADR 0018,
0030). created is sticky across re-applies — caught by running the
real binary, not just the unit tests: recomputing it from disk made
a re-applied resource look adopted and leak on the next drop.
- Addressing: a declaration for another node is refused; a host with
no identity yet applies its bundle (the first-node path).
Not yet: sealed secrets, and the types that need the network or a
runtime (container, package, network, service, archive, user, action)
— they follow, and until then the host refuses them rather than doing
part of a declaration.
CLI: mesh-host apply [--store P] FILE.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF