apply: container and network resources, over the container runtime

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
This commit is contained in:
2026-09-02 22:48:27 +02:00
parent 7414da96ed
commit c80f671203
7 changed files with 524 additions and 20 deletions
+5 -3
View File
@@ -28,9 +28,11 @@ type Store struct {
// removed, which is the same rule that ADR 0018 exists to enforce: never act on a path you did
// not create.
type Record struct {
ID string `json:"id"`
Type string `json:"type"`
Path string `json:"path"`
ID string `json:"id"`
Type string `json:"type"`
// Ref is how the resource is found again for removal: a filesystem path for files and
// directories, a container or network name for those.
Ref string `json:"ref"`
Created bool `json:"created"`
}