carlos / platform Public

plan: claim Plan 6 rev 0 (draft), box wiring

Tasks 1-5 complete (selection interface, guarded writes, writer
transitions and regional parking composition, strict spawn and timer
adapters); tasks 6-11 wait on eight box-side contracts listed in the plan.
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
codex agent, operated by paul@keymail.dev pushed by claude agent, operated by paul@keymail.dev 2e195a8ae47e67a33520a3d0892eb267a31246a1 parent 3621aae
1 file changed, +1116 −0
  • docs/superpowers/plans/2026-10-05-host-lifecycle-claim-6-box-wiring.md +1116 −0

CI passed — run details

diff --git a/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-6-box-wiring.md b/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-6-box-wiring.md
new file mode 100644
index 000000000..ba78eef88
--- /dev/null
+++ b/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-6-box-wiring.md
@@ -0,0 +1,1116 @@
+# Host lifecycle claim, Plan 6: box wiring
+
+> **For agentic workers:** implement task by task, with the failing test first. Keep `CARLOS_HOST_CLAIM` unset. Missing authority providers refuse enabled work; they never select the legacy path. The production integrations marked with a decision dependency remain unfinished until that contract is settled.
+
+**Goal:** wire claim admission and installation retirement into reconcile, admit writer sessions before wake, run regional at-rest sweeps, and adopt legacy hosts through the shared claim transition. Guard every host-specific writer, including separate root commands.
+
+**Architecture:** `internal/hostwrite` is the dependency-free selection interface passed to existing writers. `internal/hostbox` implements captured work using Plan 3's `hostguard`, and composes writer transitions with Plan 7b's selector and Plan 4's park engine. The agent constructs the providers once. Root adoption and config-sync construct equivalent providers independently, using the same flock and local state. No package-global flag or lifecycle controller is introduced.
+
+**Tech stack:** Go 1.26; existing `hostclaim`, `hostguard`, `stopevidence`, `park`, `genselect`, `cgroup`, `release`, `lease`, `registry`, `appconfig`, `activator`, and `schedule`. No new dependency or production infrastructure work.
+
+**Spec:** `docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md`, rev **6.17**: C4–C7, §5's box-side work, §6.1–6.4a, §9, and **proposed** §7.3 D6. The operative subsection “Admissions, coverage and retirement” takes precedence over the historical readings. Plan 1's roadmap gives Plan 6 reconcile admission/retirement, wake admission, the at-rest sweep and box adoption, depending on Plans **1, 3, 4**. This plan also consumes **7b**; Plan 8 owns activation, execution leases, quarantine and the floor.
+
+**Source baseline:** cached `origin/main` **562f3dfc**, `origin/feat/hostclaim-boxguard` **8c40aca6**, `origin/feat/hostclaim-genselect` **574d9469**, and Plan 1's `hostclaim` worktree/library **47426cc1**. Plan 4 rev 3 supplies its published code and interfaces. At authoring, `feat/hostclaim-park` still points at **8c40aca6** without committed park files. Do not treat that as a completed dependency or consume the builder's uncommitted source. Plans 2, 3, 4, 7 and 7b supply the task/test style; Plans 5 and 8 supply the explicit decision gates.
+
+**Code boundary:** Tasks 2–5 give complete Go files for the dependency-free hook, guarded selections, writer/park adapters, strict spawn and timer-control facade. They compile against the actual dependencies, with the published Plan 4 code substituted in a disposable export. These files do not themselves wire every production caller. Tasks 6–10 specify those callers, refusal boundaries, ordering and required integration tests. Their unresolved authority providers are listed below; an adapter with a permissive test provider is not completed production integration. Do not report Plan 6 complete or enable the flag with those tasks open.
+
+## Global constraints
+
+- **Inert when unset.** Read `CARLOS_HOST_CLAIM` once in `RunAgent` and once in each root `RunAdopt` invocation, including its `-config-only` entry used by config-sync. Match Plan 5/7: trimmed nonempty means enabled, including `0`. Pass the resulting value/providers down. Flag-off branches before provider construction, claim reads, local records, inventory, new fences and strict containment. Existing tests remain unchanged. New tmpfiles provisioning is additive installation setup, not authorization to begin lifecycle work.
+- **Capture at selection.** Capture before grouped config/release fetches, timer delivery, restore planning, goroutine dispatch or restart work. Carry the same selection to every subsequent write and rollback. Never recapture at the final `os.Rename`, `PointLive`, SQL mutation, token write or `cmd.Start`. A legitimately newly admitted writer gets a newly selected work item after its installing CAS and activation; stale work cannot be relabelled as that new item.
+- **Fresh authority under flock.** `Guard.With` checks incarnation, active stamp and a direct claim read. The supplied policy must also check action, role, operation/phase, executor, held config/release and the independently persisted Plan 8 local deadline/quarantine state. Region equality, a row's `Provisioned` bit, an activator entry and a replica lease cannot grant claim admission.
+- **One local lock order.** Select outside the flock. Take hostguard before filesystem mutations or registry transactions. Do not hold a registry transaction or activator mutex while acquiring hostguard. Never nest `With`, `Activate`, `RecordInventory` or local park calls under another hostguard callback. Release the lock before bounce callbacks that synchronously re-enter guarded work. A restart is separately admitted using the original selection.
+- **Scope held checks to the actual action.** `Identity.Config` identifies the selected merged config including default/environment/instance layers; `Identity.Release` identifies the selected signed release. Empty strings are valid only for actions that do not consume that identity. Neither is an invented persisted HELD wire format. The moves-owned provider resolves and checks it (D3).
+- **Admission before all app code.** Claim CAS → inventory/activation as required → error-returning local purge → exact remote restore → Seed/app spawn → readiness → replication uploads. Seed executes app code and therefore also comes after admission. No enabled path uses the legacy “local DB exists, return” shortcut.
+- **Sessions and generations differ from installations.** A new agent always stops an inherited process and admits a new session. A process restart with the same live replicator retains its session. A cold admission normally issues a new stamp/generation; retain the stamp only under the library's `stamp > session` condition and the owning operation's evidence. Publication follows the durable marker, never readiness alone.
+- **Retirement never guesses.** Local retirement requires actual stop evidence and inventory. `retire-artifacts(S)` does not retire the current installation. `retire-installation` fences that installation and parks all its state before acknowledging. A missing cgroup, unavailable `/proc`, missing inventory, failed listing or absent route cannot prove that state is gone.
+- **Sweep only its own regional bucket.** Preserve full discovery under both `instances/<host>/` and `moves/<host>/`, exact versions, all marker versions, the live generation, pins and unfinished predecessors. Use original evidence time and an enforced positive request limit. A listing after `evidence + H`, strictly later, is needed to acknowledge. Do not invent a request-limit default or derive discovery from 32 retained incarnations.
+- **Portable builds.** Keep Linux syscalls in tagged Linux files with refusing stubs elsewhere. The code below uses the existing tagged cgroup/park implementations. Darwin, Windows and Linux/arm64 builds are required. Use the normal Go cache; only if it is read-only use the existing shared on-disk `/home/paulca/.cache/tmp/gocache`, never `/tmp` or a new task cache.
+
+## Decisions the spec does not finish
+
+These numbers belong to this plan, not to the similarly named decisions in Plan 8. Resolve them in the owning design. Enabled callers return an error before dependent mutation/spawn until the real provider exists.
+
+1. **D1 — privileged stop collection and durable evidence.** The agent runs as `carlos`; it cannot inspect every other UID's `/proc/<pid>/fd`. `FenceAndStop` returns process-local evidence, not a root-verifiable durable attestation. Choose the root collector entry point, authenticated agent-to-root request and fence binding, trusted artifact inventory, cgroup identity and boot/controller/op/stamp binding, durable evidence schema, freshness/replay rules, and acknowledgement transport. A root subprocess cannot reconstruct the closed in-memory admission fence merely from a hostname. Coordinate with proposed §7.3 D2/D6 and Plan 8. Until resolved, no stop acknowledgement, local retirement, destructive regional chore or adoption discovery acknowledgement is authorized by the agent alone. Cleanup-only termination may still proceed and report incomplete evidence.
+2. **D2 — complete deployment identity, executor and local inventory.** Share Plan 5's complete inventory and unique executor provider with box adoption. Several boxes can occupy one region; fleets, pools, replicas, static/foreign routes and route-only legacy hosts are not an unambiguous “region's box”. Define this actor's enrollment, authoritative effective region, actual legacy writer, host enumeration for orphan residue in regional buckets, and proof that an untouched box has no artifacts. No first-heartbeat/console-box choice. `park.Local` handles paths beneath `DataDir`, but live links under `OptDir`, root unit/env files, registry/timer rows and current inventories have no complete common retirement transaction. Define their stamp ownership, durable journal and retry/ack ordering, including local-record loss and a successor at the same path. Do not put an entire shared registry DB into one host's inventory or treat missing inventory as empty. Until resolved, refuse admission/retirement for those unsupported shapes; no incomplete success acknowledgement.
+3. **D3 — moves-owned held inputs, marker publication and live view.** `RenderHeld`/`MaterializeHeld` are specified names, not implemented APIs in the inspected main. Plan 7b selects versions and parses a marker; it neither verifies complete restored bytes nor implements a sweep `park.View`, authorized prepared-journal input, marker CAS publisher or held-materialization service. Moves must provide exact operation/phase-bound config/release identities, prepared pin/open-once authority, snapshot/anchor position-zero behavior, and marker publication/retry authority. Bind the sweep view to the exact claim ETag and region, with a total generation classifier for versions already deleted during a retry. Until supplied, refuse probes, prepared restores, publication and destructive sweeps; never parse guessed journal fields or treat `Select` success as a publication receipt.
+4. **D4 — clean-close proof, including amadan #234.** `internal/lease/lease.go:Replicator.Close` drops the initial `SyncAndWait` error. A separate successful sync also cannot exclude the reported Close race or prove all compactions, retention deletes and timed-out originals finished successfully. Define request accounting, close/join order, immutable certificate contents/maximum verification and the replica-lease boundary through certificate publication. The #234 discussion could not be read in this network-restricted session; its detailed race must be read before this provider is implemented. Until then, emit no certificates, refuse warm admissions, and use cold admission only where all other cold evidence is available. Unknown outcomes remain unknown; fixing one returned error is insufficient.
+5. **D5 — regional retirement authority and lease aggregation.** Supply Plan 4's real `Authorize`, `View` and renewing aggregate `Leases` providers, regional worker assignment, durable original evidence, complete host discovery and deployment-wide enforced maximum request duration. Include readable instance and moves staging scopes, not only the replica lock. Define safe retirement evidence for failed admissions, live-session superseded generations, free-host legacy residue, and ownership changes during a run. Until resolved, workers may report missing providers but cannot bind scope, queue destructive work or acknowledge it. No `time.Now()` evidence substitute and no maximum-age guess.
+6. **D6 — cross-process execution denial and returning-box cleanup.** §7.3 D6 is explicitly **PROPOSED**, not an approved contract. Plan 8 owns the lifetime lock, durable pending/active/lost record, boot-clock deadline, loss latch, first-phase acknowledgement and quarantine. Plan 6 needs the approved nonblocking-under-flock reader in every root/background writer, plus startup deny before reattachment, timers or config work. Renewal and acknowledgement network waits must not hold hostguard. Agree cleanup that can proceed during a control outage without ordinary `Guard.With`, and retirement after free/successor claims (Plan 4's current local API requires the old holder). Until then active-operation work and unknown startup/quarantine state refuse; serving's no-execution-lease rule does not bypass quarantine or C4.
+7. **D7 — strict containment for co-spawns and root unit starts.** Main's `spawnInCgroup` uses best-effort `Manager.Start`; parent and co-spawned sidecar share a populated group. `PrepareStrict` requires an empty group and its `Start` permits one attempt. Nested `startUnit`, `seedUnit`, `startSidecarUnit`, observer reattachment and separate root restarts are different launch routes. Define containment and cleanup identities for those routes and for an auxiliary child joining a running host, without weakening the empty-group API. Until resolved, refuse these enabled spawn shapes explicitly; do not silently omit a requested co-spawned sidecar or let systemd reattach/start around the admission path. Flat one-child strict starts can use Task 5 as written.
+8. **D8 — retry state and serving hold representation.** The spec fixes five starts and delays `1,2,4,8,16` seconds, waiting without counting when prerequisites are unavailable; a probe gets one cold session and a 30-second readiness window. It does not settle durable failed-host storage/clear authority or the integration representation of the row's `hold_op` (absent in the inspected registry). Define restart persistence, successful-health clearing and the moves-owned hold fields/release CAS. Until supplied, do not invent a new flag-clearing health signal, reuse status strings as operation identities, or repeatedly admit fresh sessions after an exhausted serving attempt budget. Refuse the dependent automatic retries/hold clearing.
+
+D1–D8 do not excuse leaving straightforward flag plumbing or mutation sites unguarded. They constrain the providers and supported enabled paths. Flag-off work is always the existing implementation, and flag-on missing providers always refuse.
+
+## Review focus
+
+1. Pause a selected writer across UK→US→UK; its old capture must fail even when the operation returns to plain serving.
+2. Reconcile must not remove a row solely because a record listing omitted it. New/kept rows, adoption and removal each need fresh admission and the correct kind scope.
+3. Every replication opening—including `movespass`'s checkpoint and root/sidecar paths—must carry an admitted immutable session prefix. A warm local DB and a same-box restart cannot manufacture a certificate.
+4. Root and agent writers use the same lock and deadline state. Lease loss during a stuck network renewal must prevent writes independently of an activator callback.
+5. Failed/unreadable stop evidence, incomplete inventory, EACCES in `/proc`, EXDEV and partial version listings produce zero acknowledgements.
+6. Tests must exercise the actual mutation sites and absence of effects, not only that a flag field or interface exists.
+
+### Task 1: Establish the implementation base
+
+- [ ] **Step 1: Wait for committed Plan 4, then use these exact commands in a clean implementation checkout.** Do not run them during Markdown authoring.
+
+```bash
+git fetch origin
+git cat-file -e feat/hostclaim-park:internal/park/remote.go
+git cat-file -e feat/hostclaim-park:internal/park/local.go
+git cat-file -e feat/hostclaim-park:internal/hostguard/retirement.go
+git switch -c feat/hostclaim-box feat/hostclaim-park
+git merge --no-edit origin/main
+git merge --no-edit origin/feat/hostclaim-genselect
+git merge-base --is-ancestor feat/hostclaim-park HEAD
+git merge-base --is-ancestor origin/main HEAD
+git merge-base --is-ancestor origin/feat/hostclaim-genselect HEAD
+git status --short
+```
+
+Expected: the file checks and ancestry checks pass; status is clean. A failing file check means wait for Plan 4, not copy its working tree. Resolve merges against main's newer box code and preserve Plan 4's `ParkScope` validation and hostguard retirement extension. No flag is enabled by this branch.
+
+- [ ] **Step 2: Read the exact dependencies and rerun the source inventory before editing.**
+
+```bash
+rg -n 'AdmitWriter|PublishGeneration|CoverRegionPredecessors|func Adopt' internal/hostclaim
+rg -n 'func .*With|func .*Activate|RetireInstallation|RecordInventory' internal/hostguard internal/park
+rg -n 'PointLive|EnsureAdminToken|spawnInCgroup|PrepareStrict|PurgeLocalDBArtifacts' internal
+rg -n 'ReplicateWithLease|\.Replicate\(|lease.Restore|StartWorker|StartSidecar|seedUnit|startUnit' internal
+rg -n 'UpsertTimer|DeleteTimer|MarkTimerFired|FireTimerNow|SetTimerStatus|PruneTimers|DeleteTimersExcept' internal
+rg -n 'RenderHeld|MaterializeHeld|hold_op|HoldOp' internal
+```
+
+The final search may find no implementation. That confirms a dependency in D3/D8; it is not permission to invent one.
+
+### Task 2: Add the inert selection interface
+
+**Files:** create `internal/hostwrite/write_test.go`, then `write.go`. Keep this package dependency-free so `release`, `registry`, `appconfig`, `schedule` and `activator` can use it without a cycle through `hostguard → release` or `stopevidence → activator`.
+
+- [ ] **Step 1: Write the test file below and run the failing test.**
+
+```bash
+go test ./internal/hostwrite -count=1
+```
+
+Expected before implementation: undefined `Enabled`, `Config` and `Work`.
+
+**`internal/hostwrite/write_test.go`**
+
+```go
+package hostwrite
+
+import (
+ "context"
+ "errors"
+ "testing"
+)
+
+type rejectSelector struct{ calls *int }
+
+func (s rejectSelector) Select(context.Context, string, string) (Work, error) {
+ *s.calls++
+ return nil, ErrUnavailable
+}
+
+func TestFlagAndDisabledParity(t *testing.T) {
+ for _, tc := range []struct {
+ value string
+ want bool
+ }{{"", false}, {" \n", false}, {"0", true}, {"1", true}} {
+ calls := 0
+ got := Enabled(func(key string) string {
+ calls++
+ if key != "CARLOS_HOST_CLAIM" {
+ t.Fatal(key)
+ }
+ return tc.value
+ })
+ if got != tc.want || calls != 1 {
+ t.Fatal(tc, got, calls)
+ }
+ }
+ calls, writes := 0, 0
+ work, err := (Config{Selector: rejectSelector{&calls}}).Select(context.Background(), "host", "config")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sentinel := errors.New("legacy error")
+ err = work.With(context.Background(), Identity{}, func() error { writes++; return sentinel })
+ if err != sentinel || calls != 0 || writes != 1 {
+ t.Fatal(err, calls, writes)
+ }
+}
+
+func TestEnabledMissingProviderRefuses(t *testing.T) {
+ work, err := (Config{Enabled: true}).Select(context.Background(), "host", "config")
+ if work != nil || !errors.Is(err, ErrUnavailable) {
+ t.Fatal(work, err)
+ }
+}
+```
+
+- [ ] **Step 2: Write the implementation.**
+
+**`internal/hostwrite/write.go`**
+
+```go
+package hostwrite
+
+import (
+ "context"
+ "errors"
+ "strings"
+)
+
+var ErrUnavailable = errors.New("hostwrite: lifecycle provider unavailable")
+
+type Identity struct {
+ Config string
+ Release string
+}
+
+type Work interface {
+ With(context.Context, Identity, func() error) error
+}
+
+type Selector interface {
+ Select(context.Context, string, string) (Work, error)
+}
+
+type Config struct {
+ Enabled bool
+ Selector Selector
+}
+
+func Enabled(getenv func(string) string) bool {
+ return strings.TrimSpace(getenv("CARLOS_HOST_CLAIM")) != ""
+}
+
+func (c Config) Select(ctx context.Context, host, action string) (Work, error) {
+ if !c.Enabled {
+ return legacy{}, nil
+ }
+ if c.Selector == nil {
+ return nil, ErrUnavailable
+ }
+ return c.Selector.Select(ctx, host, action)
+}
+
+type legacy struct{}
+
+func (legacy) With(_ context.Context, _ Identity, fn func() error) error { return fn() }
+```
+
+- [ ] **Step 3: Run `go test ./internal/hostwrite -count=1`.** Expected: disabled work never invokes the selector and preserves the callback's result; enabled missing providers refuse.
+
+### Task 3: Implement selected work under the real host guard
+
+**Files:** create `internal/hostbox/work_test.go`, then `work.go`.
+
+- [ ] **Step 1: Add the complete tests below.** Run `go test ./internal/hostbox -run TestSelected -count=1`; expect undefined `WorkSource`/`Selection` before implementation. The test-only `Local` callback returns success solely to isolate the stamp test. It must never become the production provider.
+
+**`internal/hostbox/work_test.go`**
+
+```go
+//go:build unix
+
+package hostbox
+
+import (
+ "context"
+ "errors"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/carlosframework/platform/internal/hostclaim"
+ "github.com/carlosframework/platform/internal/hostguard"
+ "github.com/carlosframework/platform/internal/hostwrite"
+ "github.com/carlosframework/platform/internal/release"
+)
+
+func workFixture(t *testing.T) (WorkSource, release.Store, hostclaim.Observed) {
+ t.Helper()
+ ctx := context.Background()
+ dir := t.TempDir()
+ locks := filepath.Join(dir, "locks")
+ for _, p := range []string{locks, filepath.Join(dir, "hostguard")} {
+ if err := os.Mkdir(p, 0770); err != nil {
+ t.Fatal(err)
+ }
+ }
+ store := release.NewDirStore(t.TempDir())
+ obs, err := hostclaim.Read(ctx, store, "shop.example")
+ if err != nil {
+ t.Fatal(err)
+ }
+ obs, err = hostclaim.Update(ctx, store, obs, hostclaim.Adopt(hostclaim.NewHolder{Family: "instance", Key: "apps/acct/app/instances/shop.example.json", Account: "acct", App: "app", Host: "shop.example", Region: "ie"}, "box", nil, nil, "adopt", func() string { return "id" }))
+ if err != nil {
+ t.Fatal(err)
+ }
+ source := WorkSource{Guard: hostguard.Guard{DataDir: dir, LockDir: locks, Claims: hostguard.StoreReader{Store: store}}, Box: "box", Region: "ie", Now: func() time.Time { return time.Unix(100, 0) }}
+ source.Policy = func(_ context.Context, c *hostclaim.Claim, s Selection, _ hostwrite.Identity) error {
+ return Serving(c, s)
+ }
+ source.Local = func(context.Context, *hostclaim.Claim, Selection) error { return nil }
+ if err := source.Guard.Activate(ctx, "shop.example", "box", nil); err != nil {
+ t.Fatal(err)
+ }
+ return source, store, obs
+}
+
+func TestSelectedWorkRejectsChangesAndNeverRecaptures(t *testing.T) {
+ for _, mode := range []string{"phase", "executor", "round-trip", "lease", "held"} {
+ t.Run(mode, func(t *testing.T) {
+ source, store, obs := workFixture(t)
+ localLost, heldChanged := false, false
+ source.Local = func(context.Context, *hostclaim.Claim, Selection) error {
+ if localLost {
+ return ErrUnsupported
+ }
+ return nil
+ }
+ source.Policy = func(_ context.Context, c *hostclaim.Claim, s Selection, i hostwrite.Identity) error {
+ if heldChanged || i.Config != "selected" {
+ return ErrChanged
+ }
+ return Serving(c, s)
+ }
+ ctx := context.Background()
+ work, err := source.Select(ctx, "shop.example", "config")
+ if err != nil {
+ t.Fatal(err)
+ }
+ writes := 0
+ if err := work.With(ctx, hostwrite.Identity{Config: "selected"}, func() error { writes++; return nil }); err != nil {
+ t.Fatal(err)
+ }
+ switch mode {
+ case "phase":
+ _, err = hostclaim.Update(ctx, store, obs, hostclaim.BeginDelete("delete", "test", "etag", time.Unix(1, 0), []string{"ie"}, []string{"box"}))
+ case "executor":
+ _, err = hostclaim.Update(ctx, store, obs, func(c *hostclaim.Claim) error { c.Op.Exec = "other"; c.Op.Participants = []string{"other"}; return nil })
+ case "round-trip":
+ _, err = hostclaim.Update(ctx, store, obs, hostclaim.AdmitWriter(hostclaim.Admission{Box: "box", Mode: "cold", NewGeneration: "next", Region: "ie", PredecessorRegion: "ie"}))
+ if err == nil {
+ err = source.Guard.Activate(ctx, "shop.example", "box", nil)
+ }
+ case "lease":
+ localLost = true
+ case "held":
+ heldChanged = true
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := work.With(ctx, hostwrite.Identity{Config: "selected"}, func() error { writes++; return nil }); err == nil {
+ t.Fatal("stale write admitted")
+ }
+ if writes != 1 {
+ t.Fatal(writes)
+ }
+ })
+ }
+}
+
+func TestSelectedWorkNeedsLocalRecordAndProviders(t *testing.T) {
+ source, _, _ := workFixture(t)
+ source.Local = nil
+ if _, err := source.Select(context.Background(), "shop.example", "env"); !errors.Is(err, ErrUnsupported) {
+ t.Fatal(err)
+ }
+ source.Local = func(context.Context, *hostclaim.Claim, Selection) error { return nil }
+ if err := os.Remove(filepath.Join(source.Guard.DataDir, "hostguard", "shop.example.json")); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := source.Select(context.Background(), "shop.example", "env"); !errors.Is(err, hostguard.ErrNoRecord) {
+ t.Fatal(err)
+ }
+}
+```
+
+- [ ] **Step 2: Write the complete guard adapter.**
+
+**`internal/hostbox/work.go`**
+
+```go
+package hostbox
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "github.com/carlosframework/platform/internal/hostclaim"
+ "github.com/carlosframework/platform/internal/hostguard"
+ "github.com/carlosframework/platform/internal/hostwrite"
+)
+
+var ErrChanged = errors.New("hostbox: selected authority changed")
+var ErrUnsupported = errors.New("hostbox: unresolved lifecycle contract")
+
+type Selection struct {
+ Host, Action, Box, Region string
+ Captured hostguard.Captured
+ Kind, Op, Phase, Generation string
+ Session uint64
+}
+
+type WorkSource struct {
+ Guard hostguard.Guard
+ Box, Region string
+ Now func() time.Time
+ // Policy checks the action's role/phase and the selected config/release.
+ Policy func(context.Context, *hostclaim.Claim, Selection, hostwrite.Identity) error
+ // Local checks quarantine, execution deadlines and failed cleanup under flock.
+ Local func(context.Context, *hostclaim.Claim, Selection) error
+}
+
+type selectedWork struct {
+ source WorkSource
+ selection Selection
+}
+
+func (s WorkSource) Select(ctx context.Context, host, action string) (hostwrite.Work, error) {
+ if ctx == nil || s.Box == "" || s.Region == "" || action == "" || s.Guard.Claims == nil || s.Policy == nil || s.Local == nil || s.Now == nil {
+ return nil, ErrUnsupported
+ }
+ captured, err := hostguard.Capture(s.Guard.DataDir, host)
+ if err != nil {
+ return nil, err
+ }
+ obs, err := s.Guard.Claims.Read(ctx, host)
+ if err != nil {
+ return nil, err
+ }
+ if obs.Absent || obs.Host != host || obs.Claim == nil || obs.Claim.Holder == nil || obs.Claim.Host != host {
+ return nil, ErrChanged
+ }
+ c := obs.Claim
+ if c.Holder.Incarnation != captured.Incarnation || c.Holder.Stamp != captured.Stamp || captured.Stamp == 0 {
+ return nil, ErrChanged
+ }
+ w := selectedWork{source: s, selection: Selection{Host: host, Action: action, Box: s.Box, Region: s.Region, Captured: captured, Kind: c.Op.Kind, Op: c.Op.ID, Phase: c.Op.Phase, Generation: c.Holder.Generation, Session: c.Holder.Session}}
+ return w, nil
+}
+
+func (w selectedWork) With(ctx context.Context, identity hostwrite.Identity, fn func() error) error {
+ s, selected := w.source, w.selection
+ return s.Guard.With(ctx, selected.Host, selected.Captured, func(c *hostclaim.Claim) error {
+ if c.Op.Kind != selected.Kind || c.Op.ID != selected.Op || c.Op.Phase != selected.Phase || c.Holder.Stamp != selected.Captured.Stamp || c.Holder.Session != selected.Session || c.Holder.Generation != selected.Generation {
+ return ErrChanged
+ }
+ switch selected.Action {
+ case "install", "restore", "spawn", "seed", "writer":
+ if until, ok := c.QuietAfter[s.Region]; ok && !s.Now().After(until) {
+ return ErrChanged
+ }
+ }
+ if err := s.Local(ctx, c, selected); err != nil {
+ return err
+ }
+ return s.Policy(ctx, c, selected, identity)
+ }, fn)
+}
+
+// Serving permits ordinary host writes only. Operations need their own policy.
+func Serving(c *hostclaim.Claim, selected Selection) error {
+ if c.Holder == nil || c.Op.Kind != hostclaim.KindServing || c.Op.ID != "" || c.Op.Phase != "" || c.Op.Exec != selected.Box {
+ return ErrChanged
+ }
+ for _, box := range c.Lost {
+ if box == selected.Box {
+ return ErrChanged
+ }
+ }
+ return nil
+}
+```
+
+- [ ] **Step 3: Run the guard tests and keep the existing Plan 3 process-lock tests.**
+
+```bash
+go test ./internal/hostwrite ./internal/hostbox ./internal/hostguard -count=1 -race
+```
+
+`WorkSource.Select` captures before the caller fetches config/release or enqueues a write. `With` never captures. The strict operation/session comparison rejects an old pass even if its bytes happen to match a new operation. The separate `Policy` and `Local` providers are mandatory. `Serving` is only one component: it does not validate held identities, record ownership or deployment-wide quarantine.
+
+Do not import `hostbox` into `release` or `registry`. Those packages receive `hostwrite.Config` or `Work`; only box composition imports the concrete provider.
+
+### Task 4: Compose writer transitions and regional parking
+
+**Files:** create `internal/hostbox/writer_test.go`, `park_test.go`, then `writer.go`, `park.go`.
+
+- [ ] **Step 1: Add the tests and run them before implementation.**
+
+```bash
+go test ./internal/hostbox -run 'TestWriterRefuses|TestRegionalMissing' -count=1
+```
+
+Expected: missing `Writer`/`Regional` symbols. These are refusal/transition tests, not end-to-end wake, certificate, restore or sweep coverage.
+
+**`internal/hostbox/writer_test.go`**
+
+```go
+//go:build unix
+
+package hostbox
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/genselect"
+ "github.com/carlosframework/platform/internal/hostclaim"
+)
+
+func TestWriterRefusesMissingEvidenceAndStaleCAS(t *testing.T) {
+ _, store, obs := workFixture(t)
+ ctx := context.Background()
+ in := hostclaim.Admission{Box: "box", Mode: "cold", NewGeneration: "next", Region: "ie", PredecessorRegion: "ie"}
+ writer := Writer{Claims: store, Box: "box", Region: "ie"}
+ if _, err := writer.Admit(ctx, obs, in, nil); !errors.Is(err, ErrUnsupported) {
+ t.Fatal(err)
+ }
+ checks := 0
+ writer.AdmissionEvidence = func(context.Context, hostclaim.Observed, hostclaim.Admission, *genselect.Plan) error {
+ checks++
+ return nil
+ }
+ admitted, err := writer.Admit(ctx, obs, in, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if admitted.Claim.Holder.Session <= obs.Claim.Holder.Session || admitted.Claim.Holder.Generation != "next" {
+ t.Fatal(admitted)
+ }
+ if _, err := writer.Admit(ctx, obs, in, nil); err == nil {
+ t.Fatal("stale observation admitted")
+ }
+ if checks != 2 {
+ t.Fatal(checks)
+ }
+ current, err := hostclaim.Read(ctx, store, obs.Host)
+ if err != nil || current.Claim.Holder.Session != admitted.Claim.Holder.Session {
+ t.Fatal(current, err)
+ }
+ if _, err := writer.Published(ctx, admitted); !errors.Is(err, ErrUnsupported) {
+ t.Fatal(err)
+ }
+ writer.NewID = func() string { return "chore" }
+ writer.PublicationEvidence = func(context.Context, hostclaim.Observed) error { return ErrChanged }
+ if _, err := writer.Published(ctx, admitted); !errors.Is(err, ErrChanged) {
+ t.Fatal(err)
+ }
+ prefix, err := GenerationPrefix(*admitted.Claim.Holder)
+ if err != nil || prefix != "instances/shop.example/g-next/" {
+ t.Fatal(prefix, err)
+ }
+}
+```
+
+**`internal/hostbox/park_test.go`**
+
+```go
+package hostbox
+
+import (
+ "context"
+ "errors"
+ "testing"
+ "time"
+
+ "github.com/carlosframework/platform/internal/park"
+)
+
+func TestRegionalMissingAuthorityNeverRuns(t *testing.T) {
+ r := Regional{}
+ if err := r.Run(context.Background(), park.Work{Host: "shop.example", ID: "id", Op: "op"}); !errors.Is(err, ErrUnsupported) {
+ t.Fatal(err)
+ }
+ if _, err := r.Sweep(context.Background(), "shop.example", "", time.Now(), time.Second); !errors.Is(err, ErrUnsupported) {
+ t.Fatal(err)
+ }
+}
+```
+
+- [ ] **Step 2: Write both complete adapters.**
+
+**`internal/hostbox/writer.go`**
+
+```go
+package hostbox
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/carlosframework/platform/internal/genselect"
+ "github.com/carlosframework/platform/internal/hostclaim"
+ "github.com/carlosframework/platform/internal/release"
+)
+
+// Writer supplies transition adapters, not stop, certificate or marker evidence.
+type Writer struct {
+ Claims release.Store
+ Data genselect.Reader
+ Bucket, Region, Box string
+ AdmissionEvidence func(context.Context, hostclaim.Observed, hostclaim.Admission, *genselect.Plan) error
+ PublicationEvidence func(context.Context, hostclaim.Observed) error
+ NewID func() string
+}
+
+func (w Writer) Baseline(ctx context.Context, observed hostclaim.Observed) (*genselect.Plan, error) {
+ if w.Data == nil || w.Bucket == "" || w.Region == "" || observed.Absent || observed.Claim == nil || observed.Claim.Holder == nil {
+ return nil, ErrUnsupported
+ }
+ return genselect.Select(ctx, w.Data, genselect.Request{Bucket: w.Bucket, Region: w.Region, Host: observed.Host, Holder: *observed.Claim.Holder})
+}
+
+func (w Writer) Admit(ctx context.Context, observed hostclaim.Observed, in hostclaim.Admission, baseline *genselect.Plan) (hostclaim.Observed, error) {
+ if w.Claims == nil || w.AdmissionEvidence == nil || w.Box == "" || w.Region == "" || observed.Absent || observed.Claim == nil || observed.Claim.Holder == nil || in.Box != w.Box || in.Region != w.Region {
+ return hostclaim.Observed{}, ErrUnsupported
+ }
+ if baseline != nil && baseline.MaxTXID != in.RemoteMaxTXID {
+ return hostclaim.Observed{}, ErrChanged
+ }
+ if err := w.AdmissionEvidence(ctx, observed, in, baseline); err != nil {
+ return hostclaim.Observed{}, err
+ }
+ // Exactly one attempt. A conflict requires new evidence, not an internal retry.
+ return hostclaim.Update(ctx, w.Claims, observed, hostclaim.AdmitWriter(in))
+}
+
+func (w Writer) Published(ctx context.Context, observed hostclaim.Observed) (hostclaim.Observed, error) {
+ if w.Claims == nil || w.PublicationEvidence == nil || w.NewID == nil || w.Box == "" || w.Region == "" || observed.Absent || observed.Claim == nil || observed.Claim.Holder == nil || observed.Claim.Op.Exec != w.Box {
+ return hostclaim.Observed{}, ErrUnsupported
+ }
+ if err := w.PublicationEvidence(ctx, observed); err != nil {
+ return hostclaim.Observed{}, err
+ }
+ c := observed.Claim
+ return hostclaim.Update(ctx, w.Claims, observed, hostclaim.PublishGeneration(c.Op.ID, c.Op.Phase, c.Holder.Session, c.Holder.Generation, w.Region, w.NewID))
+}
+
+func GenerationPrefix(holder hostclaim.Holder) (string, error) {
+ generation := holder.Generation
+ if holder.Session == 0 || generation == "" || generation == hostclaim.RootGeneration || generation == "." || generation == ".." || strings.ContainsAny(generation, "/\\\x00") || holder.Location == "" {
+ return "", ErrUnsupported
+ }
+ return fmt.Sprintf("%s/g-%s/", strings.TrimSuffix(holder.Location, "/"), generation), nil
+}
+```
+
+**`internal/hostbox/park.go`**
+
+```go
+package hostbox
+
+import (
+ "context"
+ "time"
+
+ "github.com/carlosframework/platform/internal/hostclaim"
+ "github.com/carlosframework/platform/internal/park"
+)
+
+type Regional struct {
+ Engine park.Engine
+ // Owner checks complete deployment membership and this worker's assignment.
+ Owner func(context.Context, hostclaim.Observed) error
+}
+
+func (r Regional) observe(ctx context.Context, host string) (hostclaim.Observed, error) {
+ e := r.Engine
+ if e.Claims == nil || e.Store == nil || e.Leases == nil || e.View == nil || e.Authorize == nil || e.Now == nil || e.NewID == nil || e.Bucket == "" || e.Region == "" || r.Owner == nil {
+ return hostclaim.Observed{}, ErrUnsupported
+ }
+ obs, err := hostclaim.Read(ctx, e.Claims, host)
+ if err != nil {
+ return hostclaim.Observed{}, err
+ }
+ if obs.Absent || obs.Claim == nil {
+ return hostclaim.Observed{}, ErrUnsupported
+ }
+ if err := r.Owner(ctx, obs); err != nil {
+ return hostclaim.Observed{}, err
+ }
+ return obs, nil
+}
+
+func (r Regional) Run(ctx context.Context, work park.Work) error {
+ obs, err := r.observe(ctx, work.Host)
+ if err != nil {
+ return err
+ }
+ for _, ob := range obs.Claim.Obligations {
+ if ob.ID != work.ID || ob.Op != work.Op {
+ continue
+ }
+ if ob.Region != r.Engine.Region || ob.Owner != "region:"+r.Engine.Region || (ob.Kind != "park-replica" && ob.Kind != "park-generation") {
+ return ErrUnsupported
+ }
+ return r.Engine.Run(ctx, work)
+ }
+ return nil // Already acknowledged; no mutation.
+}
+
+func (r Regional) Sweep(ctx context.Context, host, legacyIncarnation string, evidenceAt time.Time, requestLimit time.Duration) (park.Decision, error) {
+ if _, err := r.observe(ctx, host); err != nil {
+ return park.Decision{}, err
+ }
+ if evidenceAt.IsZero() || requestLimit <= 0 {
+ return park.Decision{}, ErrUnsupported
+ }
+ return r.Engine.Sweep(ctx, host, legacyIncarnation, evidenceAt, requestLimit)
+}
+```
+
+- [ ] **Step 3: Run `go test ./internal/hostbox ./internal/genselect ./internal/park -count=1`.** The transition uses the supplied ETag once. On conflict or ambiguous response, return to the owning coordinator to re-establish evidence; no automatic CAS retry.
+
+`AdmissionEvidence` proves this host/incarnation, observation, executor, role/phase, remote plan/maximum, old-writer stop, certificate or coverage, and new generation identity. A nil baseline requires proof of the specified first empty bootstrap. `Baseline` propagates `ErrEmpty` and listing errors; it never turns them into an empty DB. Prepared restores use the moves-authorized `SelectPrepared` path, not a fabricated marker. `PublicationEvidence` verifies the durable marker for the exact observed session/generation before the coverage CAS. Neither provider may be a production no-op.
+
+`Regional.Owner` is an initial assignment check; `Engine.Authorize` must recheck assignment and evidence at every engine authorization point, including completion. `Engine.View` supplies the exact ETag-bound marker/live set. An initial check cannot authorize a whole later run. Unbound chores first pass `Engine.Bind` with approved original `ParkScope`; `Run` invents no scope.
+
+### Task 5: Add strict spawn and timer-control adapters
+
+**Files:** create `internal/activator/claimspawn_test.go`, `claimspawn.go`, `internal/schedule/claimtimers_test.go`, `claimtimers.go`.
+
+- [ ] **Step 1: Add the tests and run them before implementation.**
+
+```bash
+go test ./internal/activator ./internal/schedule -run 'TestClaimSpawn|TestSelectedTimer' -count=1
+```
+
+Expected: undefined adapter symbols. No test starts an uncontained process.
+
+**`internal/activator/claimspawn_test.go`**
+
+```go
+package activator
+
+import (
+ "context"
+ "errors"
+ "os/exec"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/cgroup"
+ "github.com/carlosframework/platform/internal/hostwrite"
+)
+
+type claimSpawnWork struct {
+ deny bool
+ calls *int
+}
+
+func (w claimSpawnWork) With(_ context.Context, _ hostwrite.Identity, fn func() error) error {
+ *w.calls++
+ if w.deny {
+ return hostwrite.ErrUnavailable
+ }
+ return fn()
+}
+func TestClaimSpawnNeverFallsBack(t *testing.T) {
+ calls, builds := 0, 0
+ build := func() *exec.Cmd { builds++; return exec.Command("must-not-execute") }
+ for _, deny := range []bool{true, false} {
+ cmd, err := spawnClaimed(context.Background(), true, nil, "shop.example", cgroup.TierDefault, claimSpawnWork{deny, &calls}, hostwrite.Identity{}, build)
+ if err == nil || cmd != nil {
+ t.Fatal(cmd, err)
+ }
+ if deny && !errors.Is(err, hostwrite.ErrUnavailable) {
+ t.Fatal(err)
+ }
+ }
+ if builds != 0 || calls != 2 {
+ t.Fatal(builds, calls)
+ }
+}
+```
+
+**`internal/schedule/claimtimers_test.go`**
+
+```go
+package schedule
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/hostwrite"
+ "github.com/carlosframework/platform/internal/registry"
+)
+
+type timerDeny struct{}
+
+func (timerDeny) With(context.Context, hostwrite.Identity, func() error) error {
+ return hostwrite.ErrUnavailable
+}
+func TestSelectedTimerRejectsRetiredProducer(t *testing.T) {
+ // A nil underlying pointer would panic if a denied write reached the registry.
+ var reg *registry.Registry
+ store := SelectedTimers{Store: reg, Work: timerDeny{}, Context: context.Background(), Host: "shop.example"}
+ if err := store.UpsertTimer(registry.Timer{Host: "shop.example"}); !errors.Is(err, hostwrite.ErrUnavailable) {
+ t.Fatal(err)
+ }
+ if err := store.DeleteTimer("shop.example", "one"); !errors.Is(err, hostwrite.ErrUnavailable) {
+ t.Fatal(err)
+ }
+ if err := store.DeleteTimer("other.example", "one"); !errors.Is(err, errTimerHost) {
+ t.Fatal(err)
+ }
+}
+```
+
+- [ ] **Step 2: Write the complete implementations.**
+
+**`internal/activator/claimspawn.go`**
+
+```go
+package activator
+
+import (
+ "context"
+ "os/exec"
+
+ "github.com/carlosframework/platform/internal/cgroup"
+ "github.com/carlosframework/platform/internal/hostwrite"
+)
+
+func spawnClaimed(ctx context.Context, enabled bool, manager *cgroup.Manager, host string, limit cgroup.Limit, selected hostwrite.Work, identity hostwrite.Identity, build func() *exec.Cmd) (*exec.Cmd, error) {
+ if !enabled {
+ return manager.Start(host, limit, build)
+ }
+ if selected == nil || build == nil {
+ return nil, hostwrite.ErrUnavailable
+ }
+ var cmd *exec.Cmd
+ err := selected.With(ctx, identity, func() error {
+ prepared, err := manager.PrepareStrict(host, limit)
+ if err != nil {
+ return err
+ }
+ defer prepared.Close()
+ cmd = build()
+ return prepared.Start(cmd)
+ })
+ return cmd, err
+}
+```
+
+**`internal/schedule/claimtimers.go`**
+
+```go
+package schedule
+
+import (
+ "context"
+ "errors"
+
+ "github.com/carlosframework/platform/internal/hostwrite"
+ "github.com/carlosframework/platform/internal/registry"
+)
+
+var errTimerHost = errors.New("schedule: selected timer host differs")
+
+type SelectedTimers struct {
+ Store TimerStore
+ Work hostwrite.Work
+ Context context.Context
+ Host string
+}
+
+func (s SelectedTimers) write(host string, fn func() error) error {
+ if s.Store == nil || s.Work == nil || s.Context == nil {
+ return hostwrite.ErrUnavailable
+ }
+ if host != s.Host {
+ return errTimerHost
+ }
+ return s.Work.With(s.Context, hostwrite.Identity{}, fn)
+}
+func (s SelectedTimers) UpsertTimer(t registry.Timer) error {
+ return s.write(t.Host, func() error { return s.Store.UpsertTimer(t) })
+}
+func (s SelectedTimers) DeleteTimer(host, name string) error {
+ return s.write(host, func() error { return s.Store.DeleteTimer(host, name) })
+}
+func (s SelectedTimers) GetTimer(host, name string) (*registry.Timer, error) {
+ if s.Store == nil {
+ return nil, hostwrite.ErrUnavailable
+ }
+ if host != s.Host {
+ return nil, errTimerHost
+ }
+ return s.Store.GetTimer(host, name)
+}
+func (s SelectedTimers) TimersFor(host string) ([]registry.Timer, error) {
+ if s.Store == nil {
+ return nil, hostwrite.ErrUnavailable
+ }
+ if host != s.Host {
+ return nil, errTimerHost
+ }
+ return s.Store.TimersFor(host)
+}
+func (s SelectedTimers) CountTimers(host, kind string) (int, error) {
+ if s.Store == nil {
+ return 0, hostwrite.ErrUnavailable
+ }
+ if host != s.Host {
+ return 0, errTimerHost
+ }
+ return s.Store.CountTimers(host, kind)
+}
+
+var _ TimerStore = SelectedTimers{}
+```
+
+- [ ] **Step 3: Run the focused tests and cross-compile both packages.** The strict helper returns the command even after a construction/start error, so the caller retains any process handle for cleanup. `Prepared.Close` closes descriptors; it is not stop evidence. Production callers still own waiting, cleanup and `OpenCleanup` reconstruction.
+
+`SelectedTimers` covers only the control socket's five-method `TimerStore` interface. Capture its work at process admission; construct a per-request facade with the request context and that saved work. Never give an old control socket a fresh installation ticket per request. Runner/converger mutations need their own selections in Task 6.
+
+### Task 6: Inject startup configuration and cover every local writer
+
+**Files:** `internal/host/agent.go`, `schedule_wiring.go`, `internal/appconfig/syncexec.go`, `sync.go`, `internal/release/adopt.go`, `versions.go`, `internal/activator/backend_exec.go`, `admintoken.go`, `internal/schedule/control.go`, `converge.go`, `runner.go`, `internal/registry/timers.go`; new integration tests beside each package.
+
+**Decision dependencies:** D2/D3/D6 for production providers; D7 for restarts. The generic interface above is implementable now; enabling a consumer with a missing provider must refuse. The following is the integration contract, not a claim that the production provider code has already been supplied.
+
+- [ ] **Step 1: Write the startup parity tests first.** Add `TestHostClaimStartupFlagOnce` around agent/root construction with a counting getter and a provider constructor that panics if called flag-off. Add `TestHostClaimEnabledMissingProvider` for both roots and every writer entry in the table below: assert an error/recorded refusal and unchanged filesystem/registry, not merely absence of panic. Run the tests red before adding plumbing.
+
+The actual config-sync root entry is **`RunAdopt` with `-config-only`**, invoked by `carlos-config-sync.service`; there is no separate `RunConfigSync` function in this baseline. Read once at entry, before branching on `-config-only`, and pass the same configured value into config sync. Do not add a second environment read for that branch. Root stage/restart-only invocations also pass this startup value.
+
+- [ ] **Step 2: Thread `hostwrite.Config` explicitly.** Add a `HostWrites hostwrite.Config` field to `activator.Config`, `ExecBackend`, `provision.ReconcileConfig`, `schedule.Converger` and `schedule.Runner` (or their existing constructor options). Add a `hostWrites hostwrite.Config` field and `WithHostWrites(hostwrite.Config) PassOption` to release's `passConfig`. For `Sync`/`SyncExec`, add an optional final `...hostwrite.Config` parameter, preserving all current callers, and reject more than one supplied configuration. Default zero values keep legacy behavior. Use one local value in `RunAgent`; pass it through `adoptLoop`, `configSyncLoop`, `configGenLoop`, `syncExecSerialized`, `fastConvergeLoop`/`fastDeps`, `instancesLoop`, `materializeHook`, schedule construction and the root `RunAdopt` paths. Existing mutexes do not replace the host guard.
+
+Pass selection errors back through existing per-host error reporting and skip the dependent work. Do not log an error and continue into the unguarded body. Root/agent provider construction errors with the flag on leave the corresponding work closed. No provider is cached in `armedMovesWorker`, a package variable, or an environment lookup inside a low-level helper.
+
+- [ ] **Step 3: Capture at the points below, before reading the selected inputs.** Carry a per-host work value beside the selected route/record/timer. Call its `With` around each final mutation. If there is no local installation, normal writers refuse; only Task 7's authorized initialization may create one. A route list is discovery, never fresh admission.
+
+| Writer / real source functions | Selection point | Guarded effects and refusal cases |
+|---|---|---|
+| `appconfig.SyncExec` → `syncExecHost` | Immediately after selecting each route, before cached default/environment/instance resolutions | Flat and nested `.config.env` writes, temporary files, renames and removal-on-absence; validate all merged identities under the guard. Bounce uses the same selection in a separate admitted action. An absent *config* is not an absent claim. |
+| `reapConfigEnv`, `reapNestedConfigEnv` | When selecting each inventory-owned artifact, before examining it for removal | Temporary-file deletion is a write too. Existing pathname/route absence heuristics cannot authorize retirement under the flag. Route-less/retired leftovers go to Task 8; preserve ambiguous flat names and incomplete-read refusals. |
+| `appconfig.Sync` → `syncHost`, `reap` | Each selected unit route before grouped resolution | `/etc/carlos/apps/<host>.env`, remove/rename and restart. D2 must enroll external-root files before the first write. Do not mistake this file for the flat backend's `/data/<host>.env`; both exist. |
+| `release.Pass`/`PassFilter` → `adoptHost` | At route selection, before channel/pointer fetch or staging | Live symlink, capabilities/drop-ins, registry version/status, acceptance/rollback writes and any host-specific state files. Shared immutable release downloads may happen outside the host guard. `PointLive` has several callers; protect every one. |
+| `PointLive` rollback after a failed restart | Reuse the original adoption selection | Never recapture to restore an old symlink over a new installation. If authorization changed, preserve the new installation and report incomplete old cleanup. Rollback's root `startUnit` also needs admission. |
+| `materializeHook` and backend materialization | Wake's saved selection | All host live-link changes and admin token/env materialization. Under an operation use held release/config materializers (Task 9), not the ordinary channel resolver. |
+| `EnsureAdminToken`, `EnsureAdminTokenBeneath` | Process/Seed selection, before env resolution | The read-modify-write and temp/rename operation in one `With`; do not guard only the final rename. Pass the work value to nested and flat callers. |
+| `schedule.Mount` | Process admission; preserve its selection through requests | Construct `SelectedTimers` with the request's context and the producer's saved work. An old socket/token must not mutate a new installation. |
+| `schedule.Converger.Pass`/`convergeHost` | Before declaration/run-signal reads for each route | `UpsertTimer`, `FireTimerNow`, status, deletion of undeclared schedules and unit-flip cleanup. Preserve each timer's existing registration comparison. |
+| `schedule.Runner.Tick`/`fire`/`record` | Before dispatching each due timer or token lookup | Delivery admission, bad-spec/path registration deletion, completion `MarkTimerFired`, retry/status changes and due-state updates. Completion carries the pre-delivery selection even if HTTP returned after retirement. |
+| `Runner.prune`, `Converger.Pass` pruning; registry bulk APIs | Snapshot candidate rows with their host and captured installation before work | Split bulk `PruneTimers`/`DeleteTimersExcept` effects by host for guarded execution; registry registration/expected-row checks stay atomic inside the SQL transaction. No transaction spans network admission. A missing local record defers to retirement; do not invent a new ticket for a deleted row. |
+| Reconcile/version/status/worker due writers | Record/route selection in the owning pass | Every host-specific registry mutation, including `SetVersions`, `SetWorkerNextDue`, unit observation and completion callbacks. Read-only metrics are not a license to write a host row outside the guard. |
+| Restart passes, retention, alias cleanup and capability repair | At host work selection | Any discovered host-specific write must join this table or be refused flag-on. Whole-pass serialization does not close a separate root-process path. |
+
+For configuration/release writers, separate rendering/read-only staging from guarded final writes; a callback must not re-enter hostguard synchronously through a bounce. For timer HTTP delivery, authorize the dispatch and retain the ticket for completion; do not hold flock over an unbounded request. The activator independently admits any wake. At a later operation boundary, in-flight work is drained or refused at its next write (C7).
+
+- [ ] **Step 4: Add actual-site race tests, one per table row.** Use real temp files or a real temporary registry, with channels that pause between selection and mutation. Run these variants: claim changes to deleting; phase changes without a stamp change; local activation changes S→T→U while returning to serving; held config/release changes; local lease loss occurs; claim read fails. Resume and assert no bytes, symlinks, permissions, SQL rows, spawn, acknowledgement or rollback effects. Include rename failure and a root subprocess competing for the same flock. Existing Plan 3 process-lock tests do not establish that these callers passed their old capture.
+
+```bash
+go test ./internal/appconfig ./internal/release ./internal/activator ./internal/schedule ./internal/registry ./internal/host -run 'HostClaim|Selected|ClaimSpawn' -count=1 -race
+```
+
+Expected: flag-off parity tests pass unchanged; enabled stale work leaves state untouched. Keep task open until each table row has a named passing regression.
+
+### Task 7: Reconcile admission, installation activation and box adoption
+
+**Files:** `internal/provision/reconcile.go`, sidecar reconcile implementation, `internal/host/claimreconcile.go` and tests; shared adoption coordinator from Plan 5. **Decisions:** D1/D2/D6/D8.
+
+- [ ] **Step 1: Write admission/retirement tests before changing reconcile.** Cover instance and sidecar independently, preserving their kind-scoped removal authority. Required cases: wrong incarnation; same-region wrong executor; creating not yet serving; stale listing after a new claim; unreadable claim/record; orphan record; absent claim with a real legacy record; zero `CreatedAt` adoption; missing local record; old retired stamp; late record from a cancelled create; and operation change after initialization but before row mutation. `DryRun` makes zero claim/local/registry writes.
+
+- [ ] **Step 2: Inject lifecycle reconcile behavior before create, keep or remove decisions.** Obtain the record's exact ETag and incarnation, then read its claim directly. Preserve existing scope, shape, route ownership and sidecar exclusions. A malformed or omitted listing entry is not evidence of absence. With a claim present, only the holder's matching record can be admitted; obsolete records remain refused and are handed to Plan 5's conditional orphan cleanup. Reconcile never bare-deletes a control record to repair a claim conflict.
+
+For a new/kept row, require the correct role/phase and executor, and wait through `quiet_after` before installation. Initialize only through `Guard.Activate` with the authoritative installing `holder.stamp`; never `Claim.Gen`. `Activate`'s participant callback is a role predicate, **not** a general validation callback: it is short-circuited when `op.exec` already equals this box. Wrap the fresh `ClaimReader` used for activation with all required admission checks, so executors receive quarantine, record/phase and local-state checks too. A stale precheck followed by an unrestricted `Activate` is insufficient.
+
+After activation, capture a new work item for this newly selected installation, enroll its exact inventory with `park.Local.RecordInventory` **before any** route/materialization writes, then perform those writes in `With`. Do not recursively call `RecordInventory` from inside `With`; it takes the same flock itself. If the claim moves in the gap, the later write refuses. A crash after activation but before inventory/materialization resumes without authorizing unrecorded files.
+
+For an existing held row, preserve it while the owning operation needs it. Clear an obsolete `hold_op` only after a fresh claim names this box executor of a serving host and the stored hold does not name the current operation (CC10). D8 supplies the row/hold transition; an absent field cannot be inferred from `Status == "moving"`.
+
+- [ ] **Step 3: Delegate removal to local lifecycle retirement.** Stop new route admission, select and preserve the original installation capture, and enqueue/resume the owned `park-local` chore. Do not call `reg.Delete`/`RetireExcept` and regard that as stopped. Task 8 proves stop and parks artifacts; only the complete durable retirement path removes the matching row and timers and acknowledges. A successor row is preserved. Missing control records do not permit unguarded cleanup. A claim already free or naming another holder needs D6's approved returning-box retirement path; Plan 4's current `Local.chore` rejects that shape.
+
+- [ ] **Step 4: Adopt legacy hosts through the one transition.** Call the shared adoption coordinator, whose only claim transition is `hostclaim.Adopt`, with a direct absent observation. Use the real record family/key/account/app/name/creation time and effective region, plus the actual serving box and full other-region/other-box census (D2). Preserve the legacy location `instances/<host>` and `writer_box`; do not synthesize a new creation time for a legacy record. A conflicting adoption rereads and validates the winner; it is not permission to overwrite it.
+
+Discovery obligations carry the adoption op ID and survive return to serving. Each regional/local owner completes only its own work using that chore's `Op`, not today's `claim.Op.ID`. Preserve `Touched.DiscoveryOp`; the final discovery acknowledgement sets complete in the same library CAS. Do not silently drop an unreachable box from the census. An untouched box needs proved absence and explicit empty inventory, then `AcknowledgeEmpty`; no missing-entry shortcut. While discovery is incomplete, delete still includes the entire deployment.
+
+The serving box may initialize its local record after the adoption CAS, but it must stop/clean up pre-release children before admitting its first new writer session. Adoption does not certify old best-effort containment or the old database. Its first admission is cold, with certified-remote restore; empty bootstrap needs a complete empty remote observation and explicit bootstrap authority.
+
+- [ ] **Step 5: Run focused reconcile/adoption tests.**
+
+```bash
+go test ./internal/provision ./internal/host ./internal/hostclaim -run 'Claim|Adopt|Reconcile|Sidecar' -count=1
+```
+
+Expected: the off path retains all existing behavior; no enabled kept/created row bypasses C4, and no missing record alone triggers destructive retirement.
+
+### Task 8: Provision parking and wire stop/retirement owners
+
+**Files:** `internal/host/bootstrap.go`, `units_isolation_test.go`, new `claimstop.go`/`claimpark.go` plus platform-specific collector files after D1, and tests. **Decisions:** D1/D2/D5/D6.
+
+- [ ] **Step 1: Write the tmpfiles test first.** Write this complete file, retaining the existing Plan 3 guard-directory assertions in their own tests.
+
+**`internal/host/claimdirs_test.go`**
+
+```go
+package host
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestHostClaimParkedTmpfiles(t *testing.T) {
+ line := "d /data/.parked 2770 " + serviceUser + " " + serviceUser + " -\n"
+ if strings.Count(tmpfilesConf, line) != 1 {
+ t.Fatalf("missing or duplicate parked directory: %q", line)
+ }
+}
+```
+
+Run `go test ./internal/host -run '^TestHostClaimParkedTmpfiles$' -count=1`; expect the missing-line failure. Apply the exact edit below, then run the same test and expect success.
+
+```bash
+python3 - <<'PYEDIT'
+from pathlib import Path
+p = Path('internal/host/bootstrap.go')
+s = p.read_text()
+old = 'const tmpfilesConf = '
+assert s.count(old) == 1
+s = s.replace(old, 'const tmpfilesConf = "d /data/.parked 2770 " + serviceUser + " " + serviceUser + " -\\n" +\n\t', 1)
+p.write_text(s)
+PYEDIT
+gofmt -w internal/host/bootstrap.go internal/host/claimdirs_test.go
+go test ./internal/host -run '^TestHostClaimParkedTmpfiles$' -count=1
+```
+
+Tmpfiles owns directory provisioning. No agent-side `MkdirAll`, pathname `Chown` or runtime privilege expansion is added. Confirm `/data` is writable in the existing unit sandbox and the parked source/destination are on the same filesystem; mount-point/nested `EXDEV` remains a refusal, not copy-and-delete fallback. A nondefault `DataDir` must be provisioned by its operator with the same ownership/durability properties. Any additional bind/mount design belongs to D2. Production bootstrap or deployment changes are not authorized by this plan.
+
+- [ ] **Step 2: Write stop-evidence failure tests before implementing D1's collector.** Exercise a running child and grandchild; an app that already exited with open descendant FDs; missing delegation; missing cgroup; unreadable `cgroup.events`; nonempty members; EACCES in an unrelated live UID's fd directory; DB/WAL/SHM descriptor holders; still-open replicator; pending spawn; stale fence; incomplete inventory; and a process-local fence lost across agent restart. Each failed case returns no durable evidence and no chore acknowledgement. Test normal successful collection only with complete visibility.
+
+Compose the actual APIs: `svc.FenceAndStop(ctx, host, fenceGeneration)` closes admission and joins starts; `Manager.OpenCleanup(host)` reopens without spawn permission; `stopevidence.Cleanup` kills/drains; `stopevidence.Collect` consumes the matching fence, cleanup observation, trusted DB paths and explicitly proved replicator closure. The activator fence generation is its fence identity, not automatically `holder.generation` (a string), writer session or installation stamp. D1 binds those identities in the durable receipt.
+
+Do not reuse `movespass`'s legacy rule that swallows `ErrStopUnproven` and relies on `Quiesced`. That path only established its old protocol's in-memory fence. Under the flag, full §6.1 evidence is mandatory. Failed cleanup leaves admission closed. Evidence collection is Linux-only; Darwin/Windows return unsupported and still compile.
+
+- [ ] **Step 3: Reconstruct and persist original retirement work.** Select `{host, incarnation, installation stamp, chore ID, chore op, retirement ID}` once, before stopping, and persist it with the approved evidence/inventory journal. On retry use that original capture. Under Plan 4's extended guard, call `Local.RetireInstallation` for delete/move-away or `Local.RetireArtifacts(..., predecessorStamp)` for an installed successor's predecessor artifacts. Never manually clear local stamp fields, invent an empty record, or use ordinary `With` after marking the installation inactive.
+
+Plan 4's current engine performs its completion CAS internally. D2's registry/timer/external-root retirement must therefore extend the approved retirement transaction **before** that CAS; deleting rows after `Local.RetireInstallation` returns success is too late, because the claim may already be acknowledged/free. Include an injected crash between filesystem completion, SQL completion, their durable journal marks and acknowledgement. Preserve successor rows using their installation identity; a host string alone is insufficient.
+
+Flat inventory includes the DB, WAL/SHM, both Litestream metadata directories, host directory, env/config/sidecar-env files, keys, generation/lineage markers and other host state. Nested inventory names the resolved instance directory and avoids overlapping child entries. D2 supplies ownership for external live links, root files and SQL rows. Enroll before first materialization and on layout changes. Reused paths with a different artifact stamp refuse until the predecessor has been retired.
+
+- [ ] **Step 4: Test durable local retirement.** Kill/restart the worker after each rename, directory fsync, stamp write, registry transaction and completion CAS. Repeat with empty inventory, missing artifact, an already parked artifact, destination conflict, symlink, source replacement, EXDEV and a successor installation. Assert exact original work is resumed, acknowledgements occur only after every artifact/row is durable, and the successor remains byte-identical. Preserve Plan 4's test that an inactive-stamp retry still repairs durability before invoking the parking callback.
+
+```bash
+go test ./internal/host ./internal/stopevidence ./internal/hostguard ./internal/park -run 'Claim|Stop|Local|Retire|Tmpfiles' -count=1 -race
+```
+
+### Task 9: Wire the writer session into wake, Seed, probes and replication
+
+**Files:** `internal/activator/activator.go`, `backend_exec.go`, `maintenance.go`, `unitproc.go`; `internal/lease/lease.go` and generation-bound replica/restore client files; `internal/host/claimwriter.go`, `movespass.go`; held materializers owned with moves. **Decisions:** D1–D4/D6–D8.
+
+- [ ] **Step 1: Write a trace-based wake test before changing `doWake`.** Inject real claim storage, a versioned fake with exact-version files, and effects recording `admit`, `purge`, `restore`, `seed`, `spawn`, `ready`, `upload`, `marker`, `publish`. Use barriers at each boundary. A claim CAS must precede any app code; purge failure must yield no restore/start; marker failure must yield no coverage CAS; no effects may follow a failed fresh admission. Retain the entire legacy wake suite unchanged for flag-off.
+
+- [ ] **Step 2: Split enabled wake from the existing legacy path before its first mutation.** `doWake` currently refreshes the route, acquires a replica lease, calls a restore that trusts an existing DB, seeds, starts, waits and opens replication. After the read-only route/classifier checks, dispatch the enabled path to the session coordinator. Never enter legacy `Acquire`/`Restore`/Seed as a fallback when that coordinator refuses. Worker boot, request wakes, scheduled delivery and sidecar wakes all reach the same admission. Startup must deny and clean up inherited units before timers and `runWorkerBootPass` can start them.
+
+Within the enabled coordinator:
+
+1. Close/join the prior local writer and process or prove there is none, under D1/D6; establish ownership of the local session controller. Refresh the claim and control record, check quarantine, role/phase, executor, installation, held inputs and `quiet_after`. Restore/writer lease acquisition is separate from Plan 8's execution lease. Follow the approved phase's first-ack barrier before doing its work.
+2. Read the remote baseline through `genselect.Select` using the observation's holder and its authoritative region. For a prepared landing/push/dirty return, use `SelectPrepared` from a validated, completed moves journal. Complete listings are required even if the new generation appears empty. Metadata-only, tombstone-only, gap, mismatched marker, wrong-region and unknown-empty states refuse. No legacy staging-prefix promotion or current-key fallback.
+3. Re-establish the actual certificate/coverage/stop evidence for that exact observation. Construct `hostclaim.Admission` with observed op ID/phase/session/generation, executor, modes, regions, remote maximum and coverage. Call `Writer.Admit` once before any app/Seed start. A conflict or ambiguous response invalidates the attempt; stop and re-establish evidence rather than blindly read/retry. Record/alert `writes_lost` from the actual predecessor admissions entry. Never suppress that declaration merely because the writer box is unchanged.
+4. Activate the resulting installing stamp with checked fresh authority. Register the new installation's complete inventory, retiring predecessor artifacts when the operation requires it. Select new work for this new session; do not change a stale caller's ticket in place.
+5. Under the new selection, use an **error-returning** purge of local DB, WAL, SHM and both metadata directories. The current `PurgeLocalDBArtifacts` returns no error and ignores every removal failure, so it is forbidden here. Preserve it on the legacy path; implement the checked, pinned-directory variant as part of D2's resolved filesystem contract. Failed purge means no restore/start. Never decide “fresh” from the mere absence of a local file.
+6. Restore the selected exact object versions into the approved local location. Verify full LTX checksums/ranges, snapshot identity, final TXID/checksum, SQLite integrity and local file/directory durability. `genselect` reads only a root header and is not this verification. The existing `lease.Restore` uses a mutable current-key Litestream client; it cannot consume a selected plan unchanged. Add the exact-version restore adapter and test it against the actual pinned Litestream version. Replace an object after selection and prove the adapter still reads the selected version or refuses, never current bytes.
+7. If this is the separately proved initial empty bootstrap, start with no LTX at TXID 0; never write a zero-TXID LTX. Run Seed only for that authorized bootstrap. Render held config and materialize held release before every lifecycle probe, including retries. Preserve normal identity/secret ownership rules and the guarded admin-token write. Then use `spawnClaimed` for each supported direct child; refuse D7's unsupported spawn shapes before any partial startup.
+8. Wait for readiness under the operation's policy, then open replication into the immutable `{location, generation, session}` chosen at admission. Construct the replica client once with `GenerationPrefix`; never reread `holder.generation` to retarget a live writer. Validate every level-0, compaction, snapshot and retention key against that prefix. No outside-prefix request reaches storage. Parent- or sibling-generation keys, traversal and marker keys must be refused by the client.
+9. Once the moves-owned marker is durable for that generation, verify it and call `Writer.Published`. This CAS walks local predecessors and queues deduplicated retirement chores; no chore before marker publication. Foreign-region predecessors remain uncovered until their own publication or `CoverRegionPredecessors` inside the region's whole-location park CAS. Retrying publication revalidates session, operation, marker and region.
+10. On clean shutdown, stop app writes, close/join replication and all its request producers, and prove every request completed successfully before a create-only `closed/<session>.json` certificate. Include compaction, snapshots, retention and timed-out originals. Keep the replica lease boundary required by D4. A failed/unknown close emits no certificate. Warm admission compares the current session's certificate maximum with the certified remote maximum, restores from remote anyway, and advances session in one CAS. An earlier session's certificate cannot authorize continuation.
+
+A same-agent app crash with a still-live replicator remains in its admitted session; do not purge the DB or reopen a second replicator just to restart the child. If the replicator closed or its ownership is uncertain, that is a new admission. Agent restart always stops inherited processes and takes a new session before restarting, including nested systemd units; never reattach to a dead agent's writer.
+
+- [ ] **Step 3: Apply the retry policy without session churn.** Keep each session across its allowed process starts. Use the specified five attempts and doubling delays, with environment-not-ready waits excluded. A serving host exhausted at five is marked failed through D8's durable state and stays closed until an authorized clear. One probe uses one cold admission, at most five starts, one 30-second readiness deadline and one operation-budget charge; it never marks the serving host failed. Do not repeatedly create empty generations on every tick. Before D8 is supplied, refuse those automatic retries rather than guessing the durable clear behavior.
+
+- [ ] **Step 4: Replace every enabled replication opening.** Besides `doWake`/`execLease.Replicate`, inspect `lease.Replicate`, `ReplicateWithLease`, move checkpoint in `armMovesPass`, root/box-wide Litestream startup, seed helpers and recovery/probe opens. `movespass.go` currently derives the host from a DB basename and opens `instances/<host>` replication without claim admission; neither is usable under the flag. Pass explicit host/session identity. Disable/refuse the legacy move worker when enabled until the moves owner provides its claim-phase coordinator. Do not run old and new move protocols against the same host. Background box-wide replication must not independently open claim-managed DBs.
+
+- [ ] **Step 5: Test the full session contract.** Required witnesses: stale serving admission after an operation starts; paused generation A upload arriving after B's cold upload; same-box restart; same-agent child restart with live replication; new-agent inherited unit; failed purge; restore corruption; unfinished admissions chain; prepared generation open-once and restarted probe; empty bootstrap; refused warm without certificate; replayed/late certificate; compaction or retention failure at close; marker-success/publication-crash recovery; foreign-region predecessor preservation; five-attempt failure and probe budget; strict cgroup refusal and co-spawn refusal. Use `leasetest.VersionedBucket` paging/fault seams and the Plan 7b witness cases rather than inventing a second storage model.
+
+```bash
+go test ./internal/activator ./internal/lease ./internal/host ./internal/genselect ./internal/hostclaim -run 'Claim|Generation|Admission|Restore|Certificate|Close|Strict' -count=1 -race
+```
+
+A skipped container/systemd witness is a limitation to report. It does not establish containment or certificate eligibility.
+
+### Task 10: Run at-rest sweeps and resume owned chores
+
+**Files:** `internal/host/claimpark.go`, `agent.go`, regional ownership/enumeration providers and tests. **Decisions:** D1/D2/D3/D5/D6.
+
+- [ ] **Step 1: Write worker tests with a fake clock and real Plan 4 engine.** Start from a serving host, a free host, an active operation, a foreign authoritative region, a late staging object and residue older than the capped history. Assert correct owned chores only, and zero storage/claim mutations when any provider, region binding, listing page, marker read or local authority check fails.
+
+- [ ] **Step 2: Add one agent-owned cancellable worker.** Start only when the startup flag is enabled and all required providers exist. Run at startup and periodically (one-minute scan is a scheduling choice, not an evidence timeout), with serial-triggered work for already-known chores. Serialize this worker's scans, use bounded per-host work, stop/join it with the agent, and retry `park.ErrPending` on later passes instead of sleeping inside a host operation. No package-global controller. Regional assignment must remain checked inside `Engine.Authorize`, not only when the worker was constructed.
+
+Enumerate hosts from a complete regional namespace census, including both replica and staging namespaces and free-host residue. Registry rows alone miss deleted hosts. For each host, discover all pages through `Engine.Discover`, read the claim directly, and supply moves' `View` under that same observation. A host namespace with no claim requires D2's legacy authority; do not synthesize a free claim or delete it. Ignore only lock objects exactly as Plan 4 specifies.
+
+Use `Regional.Sweep` to create scoped chores only for serving/free states. Active operations suppress **new** sweeps; existing owned chores may still run when their real authorization permits. `parking` with a stopped installation is not permission inferred from the word parking. Every chore retains its original evidence time, scope and retirement ID across retries. New residue after the horizon rotates to a new retirement event; do not reset its original evidence time to the retry clock.
+
+Preserve the authoritative region's installed generation, exact pinned versions, marker versions and entire unfinished predecessor run. A matching unfinished marker lag is normal. Any unexplained disagreement alerts and suppresses that live location. The same holder location in another region is residue. `@root` is the root-generation chore sentinel, not `g-@root/`. Complete the scoped holderless free-host sweep with the library's last-ack/free CAS and retained `quiet_after`; never delete a claim object.
+
+- [ ] **Step 3: Prove lifecycle work and sweep work do not race into authority.** Pause after discovery, change claim/session/marker, then resume. Pause after copy/manifest/delete and change regional assignment. Assert refusal/no acknowledgement at the next authorization point. Test one page failing after earlier pages succeeded, an exact pinned noncurrent object, a current delete marker, remote residue in `moves/<host>/`, late residue after `H`, unknown legacy archive incarnation, no evidence, and request-limit zero. Assert all free/serving successor installs wait for persisted `quiet_after`.
+
+```bash
+go test ./internal/host ./internal/hostbox ./internal/park -run 'Claim|Sweep|Remote|Regional|Horizon' -count=1 -race
+```
+
+### Task 11: Required integration review and repository gate
+
+- [ ] **Step 1: Review all enabled refusals and remaining decisions.** Each decision needs an approved contract, concrete production provider and integration tests before its dependent task is complete. A branch containing only Tasks 2–5 may land inert as partial work, but must be described as partial. Completion of this Plan 6 requires every mutation/spawn row in Tasks 6–10 to be wired or deliberately refused for a named unsupported shape. Broadly refusing all work because a provider was forgotten is not completed integration.
+
+- [ ] **Step 2: Re-run the mutation/open inventory.** Search the tree, not only the files originally listed. Require a concrete caller test for each mutation under the flag. Verify that no lifecycle environment reads moved into libraries and that no globals were introduced. Confirm no recursion through the same hostguard, no registry transaction held across admission, and no root command bypass.
+
+```bash
+rg -n 'CARLOS_HOST_CLAIM' --glob '*.go'
+rg -n 'PointLive\(|EnsureAdminToken|PurgeLocalDBArtifacts|ReplicateWithLease|\.Replicate\(' internal
+rg -n 'UpsertTimer|DeleteTimer|MarkTimerFired|FireTimerNow|SetTimerStatus|PruneTimers|DeleteTimersExcept' internal
+rg -n 'cmd.Start\(|Cgroups.Start|startUnit|seedUnit|startSidecarUnit|PrepareStrict' internal/activator internal/host internal/instancectl
+```
+
+Expected: explicit flag-off legacy branches and enabled guarded paths, including rollback and failure cleanup. Review shared functions reached by both roots and agent; guarding one caller is insufficient.
+
+- [ ] **Step 3: Run the repository's required checks with the normal cache.**
+
+```bash
+go test ./internal/hostwrite ./internal/hostbox ./internal/hostguard ./internal/stopevidence ./internal/park ./internal/genselect -count=1 -race
+go test ./internal/host ./internal/provision ./internal/activator ./internal/appconfig ./internal/release ./internal/schedule ./internal/registry -count=1
+go build ./...
+go vet ./...
+go test ./... -count=1
+gofmt -l .
+GOOS=darwin GOARCH=amd64 go build ./...
+GOOS=windows GOARCH=amd64 go build ./...
+GOOS=linux GOARCH=arm64 go build ./...
+```
+
+Expected: all pass; `gofmt -l .` is empty. Use the existing shared on-disk cache only when default cache permissions require it. Binary-invoking tests use `carlosTestEnv` and scratch `cmd.Dir`, never inherited production credentials/config. No live AWS, production processes, root services or flag changes are part of this implementation gate.
+
+- [ ] **Step 4: Obtain the repository-required Opus authority/production-path review.** Review stale captures, activation validation, registry/retirement acknowledgement order, certificate evidence, exact restore, containment, root-process deadlines and all D1–D8 resolutions. Fix findings before landing. Mechanical implementation can be delegated to explicitly named Sonnet/Haiku as the repository policy directs; security/authority decisions require the reviewer. A missing review verdict is not approval.
+
+Push the implementation branch to amadan, describe final changes and actual evidence, squash to one change commit, wait for CI on the exact tip, then use `amadan branch merge carlos/platform feat/hostclaim-box -expect <tip> -message "..."` under the repository's reviewed-branch policy. Read main's CI afterward. These are later implementation/landing steps, not actions performed while writing this file. Keep activation, the floor and production rollout in Plan 8.
+
+## Authoring verification
+
+On 2026-10-05, the 13 complete Go file blocks above were checked in a disposable on-disk source export outside this repository. The export used `origin/main` at `562f3dfc`, the real `hostclaim`/`hostguard`/`stopevidence`/`cgroup` packages from `origin/feat/hostclaim-boxguard` at `8c40aca6`, and `genselect` from `origin/feat/hostclaim-genselect` at `574d9469`. Since Plan 4 was not committed, its published rev 3 production blocks and exact additive claim-schema patch supplied `park` and the guard retirement extension. This validates the published interfaces; it is not evidence that a future merge of the unfinished park branch is already green.
+
+Verification results:
+
+- With the new adapter implementations withheld, the test build failed on the missing symbols. Restoring the supplied implementations passed the focused tests for the flag, missing providers, stale selections, writer CAS, regional refusal, strict spawn and timer control.
+- The exact `.parked` tmpfiles test failed before the bootstrap edit and passed afterward.
+- `go test -buildvcs=false ./internal/hostwrite ./internal/hostbox ./internal/hostguard ./internal/stopevidence ./internal/genselect -count=1 -race` passed. `go vet ./internal/hostwrite ./internal/hostbox` passed.
+- `go build -buildvcs=false ./...` passed for Linux/amd64, Darwin/amd64, Windows/amd64 and Linux/arm64, including the final code and bootstrap edit. `-buildvcs=false` is needed because the disposable export is not a Git checkout.
+- Every complete Go block was compared byte-for-byte with its tested file and checked with `gofmt`. Markdown fences and trailing whitespace were checked.
+- The default Go cache was attempted and failed as read-only in this sandbox. Verification then used the pre-existing shared `/home/paulca/.cache/tmp/gocache`; no cache was created under `/tmp` or per task.
+- Orchestra and the read-only amadan #234 lookup were blocked by sandbox networking. Explicitly named Sonnet source-audit and Opus authority-review attempts each timed out after 45 seconds without a result. **No Opus review verdict was obtained.** The implementation/landing review remains required.
+
+The production integrations in Tasks 6–10 are specified, not executed by this authoring check. The repository-wide behavioral test gate remains an implementation requirement; the checks above do not claim it passed for code that has not been implemented. No production resource, flag, service, branch, index or commit was changed. The disposable source/scratch files were removed after verification; only this requested Markdown file remains changed.