Starts stage 2 of the node host — the biggest unproven claim in the work breakdown. The host stops only reporting (profile/inventory) 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.
This slice implements the network-free vocabulary ADR 0043 names as first:
Parse — JSON, refused whole on an unknown version / type / field, a missing id·type·path, or a duplicate id. An older host can't be handed a newer vocabulary and do half of it.
directory and file appliers, each reading back after writing — mode and owner asserted against the machine, content compared byte-for-byte. A value that didn't take is a failed apply, not a success.
store — the applied-state record, authoritative while disconnected, written atomically. It's what makes removal possible.
Convergence — apply in the stated order (host never reorders, ADR 0037), record each success after it works (ADR 0035), remove what was applied before and is no longer declared (reverse order, so a file goes before its directory).
Data-loss guard — the host removes only what it created, never what it adopted; a created directory that now holds data is refused (os.Remove, never RemoveAll), per ADR 0018/0030. created is sticky across re-applies.
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 needing 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.
Testing:go test ./... green; the apply suite covers refuse-whole, idempotency, sticky-created, adopted-never-removed, failed-step-fails-and-records-only-what-landed, addressing, and read-back. Verified on the real binary too — which is how the sticky-created bug was caught (the unit test that applied once masked it; running apply twice then dropping a resource exposed a leaked file).
One field-shape note for reviewers: internal/apply/declaration.go's shapes table is the host's copy of the wire contract whose other half is mesh-control's examples/modules/modules_test.go. Deliberately duplicated (the host shares no code with other tiers, ADR 0041) and checked on both sides.
Starts stage 2 of the node host — the biggest unproven claim in the work breakdown. The host stops only reporting (`profile`/`inventory`) 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.
**This slice** implements the network-free vocabulary ADR 0043 names as first:
- **Parse** — JSON, refused *whole* on an unknown version / type / field, a missing id·type·path, or a duplicate id. An older host can't be handed a newer vocabulary and do half of it.
- **`directory` and `file` appliers**, each reading back after writing — mode and owner asserted against the machine, content compared byte-for-byte. A value that didn't take is a failed apply, not a success.
- **`store`** — the applied-state record, authoritative while disconnected, written atomically. It's what makes removal possible.
- **Convergence** — apply in the stated order (host never reorders, ADR 0037), record each success *after* it works (ADR 0035), remove what was applied before and is no longer declared (reverse order, so a file goes before its directory).
- **Data-loss guard** — the host removes only what it *created*, never what it adopted; a created directory that now holds data is refused (`os.Remove`, never `RemoveAll`), per ADR 0018/0030. `created` is sticky across re-applies.
- **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 needing 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.
**Testing:** `go test ./...` green; the apply suite covers refuse-whole, idempotency, sticky-created, adopted-never-removed, failed-step-fails-and-records-only-what-landed, addressing, and read-back. Verified on the real binary too — which is how the sticky-`created` bug was caught (the unit test that applied once masked it; running `apply` twice then dropping a resource exposed a leaked file).
One field-shape note for reviewers: `internal/apply/declaration.go`'s `shapes` table is the host's copy of the wire contract whose other half is mesh-control's `examples/modules/modules_test.go`. Deliberately duplicated (the host shares no code with other tiers, ADR 0041) and checked on both sides.
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
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
Closing without merging. This was built on main, which is 39 commits behind initialization — the live development branch. initialization already implements a more complete apply than this PR: node identity and sealing, the link and enrolment, the pinned bundle, and every resource type (container, archive, bytes, package, service, action, user, file, directory), on the real wire format ({"declaration":1,…}). It also gets things this PR got wrong: network is a container field, not a separate resource type; failure is per-resource with actions fail-fast, not a blanket stop.
Nothing here should land — it would fork the codebase into a less-complete parallel. Recorded as a lesson: check the active branch (initialization, not main) before starting, the same way mesh-control develops on initialization.
Closing without merging. This was built on `main`, which is 39 commits behind `initialization` — the live development branch. `initialization` already implements a more complete apply than this PR: node identity and **sealing**, the link and enrolment, the pinned bundle, and every resource type (container, archive, bytes, package, service, action, user, file, directory), on the real wire format (`{"declaration":1,…}`). It also gets things this PR got wrong: `network` is a container field, not a separate resource type; failure is per-resource with actions fail-fast, not a blanket stop.
Nothing here should land — it would fork the codebase into a less-complete parallel. Recorded as a lesson: check the active branch (`initialization`, not `main`) before starting, the same way mesh-control develops on `initialization`.
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.
Starts stage 2 of the node host — the biggest unproven claim in the work breakdown. The host stops only reporting (
profile/inventory) 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.This slice implements the network-free vocabulary ADR 0043 names as first:
directoryandfileappliers, each reading back after writing — mode and owner asserted against the machine, content compared byte-for-byte. A value that didn't take is a failed apply, not a success.store— the applied-state record, authoritative while disconnected, written atomically. It's what makes removal possible.os.Remove, neverRemoveAll), per ADR 0018/0030.createdis sticky across re-applies.Not yet: sealed secrets, and the types needing 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.Testing:
go test ./...green; the apply suite covers refuse-whole, idempotency, sticky-created, adopted-never-removed, failed-step-fails-and-records-only-what-landed, addressing, and read-back. Verified on the real binary too — which is how the sticky-createdbug was caught (the unit test that applied once masked it; runningapplytwice then dropping a resource exposed a leaked file).One field-shape note for reviewers:
internal/apply/declaration.go'sshapestable is the host's copy of the wire contract whose other half is mesh-control'sexamples/modules/modules_test.go. Deliberately duplicated (the host shares no code with other tiers, ADR 0041) and checked on both sides.https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
Closing without merging. This was built on
main, which is 39 commits behindinitialization— the live development branch.initializationalready implements a more complete apply than this PR: node identity and sealing, the link and enrolment, the pinned bundle, and every resource type (container, archive, bytes, package, service, action, user, file, directory), on the real wire format ({"declaration":1,…}). It also gets things this PR got wrong:networkis a container field, not a separate resource type; failure is per-resource with actions fail-fast, not a blanket stop.Nothing here should land — it would fork the codebase into a less-complete parallel. Recorded as a lesson: check the active branch (
initialization, notmain) before starting, the same way mesh-control develops oninitialization.Pull request closed