plan: claim Plan 6 rev 4, answers the rev 3 review (two P2)
Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+145
−37
docs/superpowers/plans/2026-10-05-host-lifecycle-claim-6-box-wiring.md+145 −37
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| index 45010a53c..3dab81cda 100644 |
| --- 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 |
| @@ -1,8 +1,8 @@ |
| # Host lifecycle claim, Plan 6: box wiring |
| -Rev 3 answers the rev 2 review (two P1, ten P2). |
| +Rev 4 answers the rev 3 review (two P2). |
| -**Authoring status:** this revision addresses the twelve rev 2 findings. The earlier completeness requirement remains unmet. The code below compiles against the pinned base and has focused tests; production composition, the complete root collector/launch journal, registry ownership and several final caller bindings remain unfinished. Enabled production startup refuses. The missing implementation is listed at Tasks 9 and 11; it must not be mistaken for an unresolved ruling or a completed integration. |
| +**Authoring status:** this revision addresses both rev 3 findings. The earlier completeness requirement remains unmet. The code below compiles against the pinned base and has focused tests; production composition, the complete root collector/launch journal, registry ownership and several final caller bindings remain unfinished. Enabled production startup refuses. The missing implementation is listed at Tasks 9 and 11; it must not be mistaken for an unresolved ruling or a completed integration. |
| > **For agentic workers:** Tasks 1-5 are built on `feat/hostclaim-box` at `2bd3ea1f`. Do not rerun their branch-creation commands. Execute Tasks 6-11 in order, with the failing test first, on that implementation branch. Keep `CARLOS_HOST_CLAIM` unset. This document is a plan, not authorization to enable the feature or change production. Missing required providers return an error before dependent effects. |
| @@ -1535,7 +1535,7 @@ func loadPinned(ctx context.Context, reader genselect.Reader, bucket string, pla |
| var last ltx.Checksum |
| var previous uint64 |
| for i, selected := range plan.Files { |
| - if i != 0 && selected.MinTXID != previous+1 { |
| + if i != 0 && (previous == ^uint64(0) || !ltx.IsContiguous(ltx.TXID(previous), ltx.TXID(selected.MinTXID), ltx.TXID(selected.MaxTXID))) { |
| return nil, 0, genselect.ErrGap |
| } |
| rc, err := reader.OpenVersion(ctx, bucket, selected.Key, selected.VersionID) |
| @@ -1638,6 +1638,7 @@ import ( |
| "database/sql" |
| "encoding/binary" |
| "errors" |
| + "fmt" |
| "io" |
| "os" |
| "path/filepath" |
| @@ -1645,8 +1646,10 @@ import ( |
| "testing" |
| "github.com/carlosframework/platform/internal/genselect" |
| + "github.com/carlosframework/platform/internal/hostclaim" |
| "github.com/carlosframework/platform/internal/hostwrite" |
| "github.com/carlosframework/platform/internal/lease" |
| + "github.com/carlosframework/platform/internal/lease/leasetest" |
| "github.com/superfly/ltx" |
| _ "modernc.org/sqlite" |
| ) |
| @@ -1834,7 +1837,70 @@ func TestColdRestoreInstallEmptyRequiresProofAndWritesOnlyGeneration(t *testing. |
| } |
| } |
| +func TestColdRestoreAcceptsSelectorOverlappingOutput(t *testing.T) { |
| + for _, min := range []ltx.TXID{10, 12} { |
| + t.Run(fmt.Sprintf("continuation-%d-13", min), func(t *testing.T) { |
| + ctx := t.Context() |
| + bucket := leasetest.NewVersionedBucket() |
| + bucket.AddBucket("data") |
| + bucket.PageSize = 1 |
| + key, snapshot, crc := restoreLTXFixture(t, "snapshot-at-11", 9, 1, 11) |
| + version := bucket.Put("data", key, snapshot) |
| + continuation, data, _ := restoreLTXFixture(t, "compacted-at-13", 1, min, 13) |
| + bucket.Put("data", continuation, data) |
| + plan, err := genselect.SelectPrepared(ctx, bucket, genselect.Request{ |
| + Bucket: "data", Region: "ie", Host: "shop", |
| + Holder: hostclaim.Holder{Incarnation: "inc", Location: "instances/shop"}, |
| + }, genselect.PreparedPin{Generation: "one", SnapshotKey: key, SnapshotVersion: version, SnapshotTXID: 11, SnapshotCRC64: crc}) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if len(plan.Files) != 2 || plan.Files[0].MinTXID != 1 || plan.Files[0].MaxTXID != 11 || plan.Files[1].MinTXID != uint64(min) || plan.Files[1].MaxTXID != 13 || plan.MaxTXID != 13 { |
| + t.Fatalf("selector output = %+v", plan) |
| + } |
| + path := filepath.Join(t.TempDir(), "restored.db") |
| + if err := (ColdRestore{Reader: bucket, Bucket: "data", Generation: "new", Work: &restoreWork{}}).Install(ctx, path, plan); err != nil { |
| + t.Fatalf("restore selector output: %v", err) |
| + } |
| + db, err := sql.Open("sqlite", path) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + defer db.Close() |
| + var got string |
| + if err := db.QueryRow(`SELECT value FROM fixture`).Scan(&got); err != nil || got != "compacted-at-13" { |
| + t.Fatalf("restored value = %q, err = %v", got, err) |
| + } |
| + if string(mustRead(t, path+".gen")) != "new\n" { |
| + t.Fatal("admitted generation marker missing") |
| + } |
| + }) |
| + } |
| +} |
| + |
| +func TestLoadPinnedRejectsGapAndNonadvancingRange(t *testing.T) { |
| + for _, bounds := range [][2]ltx.TXID{{13, 13}, {10, 11}} { |
| + t.Run(fmt.Sprint(bounds), func(t *testing.T) { |
| + key, snapshot, _ := restoreLTXFixture(t, "snapshot", 9, 1, 11) |
| + continuation, data, _ := restoreLTXFixture(t, "invalid", 1, bounds[0], bounds[1]) |
| + reader := &restoreReader{data: map[string][]byte{key + "@v1": snapshot, continuation + "@v2": data}} |
| + plan := &genselect.Plan{Generation: "one", MaxTXID: uint64(bounds[1]), Files: []genselect.File{ |
| + {Key: key, VersionID: "v1", Level: 9, MinTXID: 1, MaxTXID: 11, Size: int64(len(snapshot))}, |
| + {Key: continuation, VersionID: "v2", Level: 1, MinTXID: uint64(bounds[0]), MaxTXID: uint64(bounds[1]), Size: int64(len(data))}, |
| + }} |
| + if _, _, err := loadPinned(t.Context(), reader, "data", plan); !errors.Is(err, genselect.ErrGap) { |
| + t.Fatalf("invalid continuation accepted: %v", err) |
| + } |
| + }) |
| + } |
| +} |
| + |
| func snapshotFixture(t *testing.T, value string) (string, []byte, uint64) { |
| + t.Helper() |
| + return restoreLTXFixture(t, value, 9, 1, 1) |
| +} |
| + |
| +func restoreLTXFixture(t *testing.T, value string, level int, min, max ltx.TXID) (string, []byte, uint64) { |
| t.Helper() |
| path := filepath.Join(t.TempDir(), "fixture.db") |
| db, err := sql.Open("sqlite", path) |
| @@ -1855,7 +1921,7 @@ func snapshotFixture(t *testing.T, value string) (string, []byte, uint64) { |
| if len(raw)%pageSize != 0 { |
| t.Fatalf("database size %d not page aligned", len(raw)) |
| } |
| - spec := ltx.FileSpec{Header: ltx.Header{Version: ltx.Version, Flags: ltx.HeaderFlagNoChecksum, PageSize: uint32(pageSize), Commit: uint32(len(raw) / pageSize), MinTXID: 1, MaxTXID: 1}} |
| + spec := ltx.FileSpec{Header: ltx.Header{Version: ltx.Version, Flags: ltx.HeaderFlagNoChecksum, PageSize: uint32(pageSize), Commit: uint32(len(raw) / pageSize), MinTXID: min, MaxTXID: max}} |
| for off := 0; off < len(raw); off += pageSize { |
| pgno := uint32(off/pageSize + 1) |
| if pgno == ltx.LockPgno(uint32(pageSize)) { |
| @@ -1867,7 +1933,7 @@ func snapshotFixture(t *testing.T, value string) (string, []byte, uint64) { |
| if _, err := spec.WriteTo(&out); err != nil { |
| t.Fatal(err) |
| } |
| - return "instances/shop/g-one/0009/0000000000000001-0000000000000001.ltx", out.Bytes(), uint64(spec.Trailer.FileChecksum) |
| + return fmt.Sprintf("instances/shop/g-one/%04x/%s", level, ltx.FormatFilename(min, max)), out.Bytes(), uint64(spec.Trailer.FileChecksum) |
| } |
| func mustRead(t *testing.T, path string) []byte { |
| @@ -8056,7 +8122,7 @@ func TestClaimWiringRegionalContractBeforeTask10(t *testing.T) { |
| ### Task 10: Run regional obligations and serving/free sweeps |
| - [ ] Assemble `Regional.Engine` with the real versioned bucket wrapped in `RequestStore`, current roster assignment, immutable evidence resolver, moves live view and aggregate renewing leases. `Owner` and every `Authorize` call revalidate enrollment, region, bucket, chore operation/phase and evidence. A construction-time check is insufficient. |
| -- [ ] `RegionalWorker.Census` drains both `instances/` and `moves/` listings and also reads the regional claim work queue, so an empty data namespace does not hide an unacknowledged chore. Reject malformed or partial listings. A claimless namespace needs #232/Plan 5 backfill disposition; it is not automatically free. |
| +- [ ] `RegionalWorker.Census` drains both `instances/` and `moves/` listings and also reads direct `control/hosts/<host>.json` claim objects, so an empty data namespace does not hide an unacknowledged chore. Skip nested namespaces, including `control/hosts/<host>/evidence/` and `control/hosts/<host>/exec/`, before validating direct claim keys. Reject malformed or partial listings. A claimless namespace needs #232/Plan 5 backfill disposition; it is not automatically free. |
| - [ ] Run existing owned chores in every permitted claim state. Re-read before binding each unbound chore; the evidence resolver must cover every possible producer and return its original time. Persist exactly `RequestLimit = 120*time.Second`. The immutable `ParkScope` is never rebound on retry. The active moves staging scope is `moves/<host>/<op>` on kind `park-replica`; unknown kinds remain errors. |
| - [ ] Only serving/free claims create new at-rest sweeps. Full discovery includes noncurrent versions, delete markers, old incarnations outside the 32-entry history and staging residue. Engine classification owns the exact lock exclusions. Preserve the current authoritative-region view, its marker versions/pins and unfinished run; foreign-region residue uses that region's evidence. Unknown generation classification or unexplained marker disagreement suppresses the affected retirement. |
| - [ ] Acquire the replica-location and all relevant staging-work leases in lexical order; partial acquisition releases only this worker's acquisitions. Each storage request rechecks fresh authority and every lease. Constituent loss cancels further requests and prevents acknowledgement. The underlying providers must cancel in-flight operations on loss and enforce the 120-second budget; the aggregate handle alone is not a watchdog. Staging retains signature-at-check and no-resigning behavior. |
| @@ -8524,10 +8590,18 @@ func (w RegionalWorker) Census(ctx context.Context) ([]string, error) { |
| return nil, err |
| } |
| for _, key := range claimKeys { |
| - if !strings.HasPrefix(key, "control/hosts/") || !strings.HasSuffix(key, ".json") { |
| + tail, ok := strings.CutPrefix(key, "control/hosts/") |
| + if !ok { |
| return nil, ErrUnsupported |
| } |
| - host := strings.TrimSuffix(strings.TrimPrefix(key, "control/hosts/"), ".json") |
| + // List is recursive; evidence and exec objects are not claim records. |
| + if strings.Contains(tail, "/") { |
| + continue |
| + } |
| + if !strings.HasSuffix(tail, ".json") { |
| + return nil, ErrUnsupported |
| + } |
| + host := strings.TrimSuffix(tail, ".json") |
| want, keyErr := hostclaim.Key(host) |
| if keyErr != nil || want != key { |
| return nil, ErrUnsupported |
| @@ -8862,35 +8936,56 @@ func TestRegionalWorkerRefusesMissingAuthorityEvidenceAndUnknownKinds(t *testing |
| } |
| func TestRegionalWorkerCensusIncludesQueuedClaimWithoutResidue(t *testing.T) { |
| - claims := release.NewDirStore(t.TempDir()) |
| - host := "queued.example" |
| - created := time.Unix(1, 0).UTC() |
| - inc, err := hostclaim.Incarnation("bab", "app", host, created) |
| - if err != nil { |
| - t.Fatal(err) |
| - } |
| - _, err = hostclaim.Update(t.Context(), claims, hostclaim.Observed{Host: host, Absent: true}, func(c *hostclaim.Claim) error { |
| - c.Holder = &hostclaim.Holder{Family: "instance", Key: "apps/bab/app/instances/" + host + ".json", Account: "bab", App: "app", Incarnation: inc, CreatedAt: created, Location: "instances/" + host + "/" + inc, Stamp: 1} |
| - c.Op = hostclaim.Op{Kind: hostclaim.KindParking, ID: "op"} |
| - c.Obligations = []hostclaim.Obligation{{ID: "id", Op: "op", Kind: "park-replica", Region: "ie", Owner: "region:ie", Retirement: "retire", Park: &hostclaim.ParkScope{Location: c.Holder.Location, Incarnation: inc, EvidenceAt: time.Unix(1, 0).UTC(), RequestLimit: RequestLimit}}} |
| - c.Touched = hostclaim.Touched{Complete: true, Regions: []string{"ie"}} |
| - return nil |
| - }) |
| - if err != nil { |
| - t.Fatal(err) |
| - } |
| - bucket := leasetest.NewVersionedBucket() |
| - bucket.AddBucket("data") |
| - w := RegionalWorker{ |
| - Regional: Regional{Engine: park.Engine{Claims: claims, Store: bucket, Bucket: "data", Region: "ie"}}, |
| - Enrollment: enrollmentFunc(func(context.Context, string, string, time.Duration) error { return nil }), |
| - Evidence: evidenceFunc(func(context.Context, hostclaim.Observed, []lease.ObjectVersion) (string, time.Time, error) { |
| - return "", time.Time{}, errors.New("unused") |
| - }), |
| - } |
| - hosts, err := w.Census(t.Context()) |
| - if err != nil || len(hosts) != 1 || hosts[0] != host { |
| - t.Fatalf("census = %v, %v", hosts, err) |
| + for name, namespaces := range map[string][]string{ |
| + "direct-only": nil, |
| + "evidence": {"evidence/fence/receipt.json"}, |
| + "exec": {"exec/controller.json"}, |
| + "both": {"evidence/fence/receipt.json", "exec/controller.json"}, |
| + } { |
| + t.Run(name, func(t *testing.T) { |
| + claims := release.NewDirStore(t.TempDir()) |
| + host := "queued.example" |
| + created := time.Unix(1, 0).UTC() |
| + inc, err := hostclaim.Incarnation("bab", "app", host, created) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + _, err = hostclaim.Update(t.Context(), claims, hostclaim.Observed{Host: host, Absent: true}, func(c *hostclaim.Claim) error { |
| + c.Holder = &hostclaim.Holder{Family: "instance", Key: "apps/bab/app/instances/" + host + ".json", Account: "bab", App: "app", Incarnation: inc, CreatedAt: created, Location: "instances/" + host + "/" + inc, Stamp: 1} |
| + c.Op = hostclaim.Op{Kind: hostclaim.KindParking, ID: "op"} |
| + c.Obligations = []hostclaim.Obligation{{ID: "id", Op: "op", Kind: "park-replica", Region: "ie", Owner: "region:ie", Retirement: "retire", Park: &hostclaim.ParkScope{Location: c.Holder.Location, Incarnation: inc, EvidenceAt: time.Unix(1, 0).UTC(), RequestLimit: RequestLimit}}} |
| + c.Touched = hostclaim.Touched{Complete: true, Regions: []string{"ie"}} |
| + return nil |
| + }) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + for _, namespace := range namespaces { |
| + for _, nestedHost := range []string{host, "nested-only.example"} { |
| + key := "control/hosts/" + nestedHost + "/" + namespace |
| + if _, err := claims.Put(t.Context(), key, []byte(`{"not_a_claim":true}`), ""); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + } |
| + keys, err := claims.List(t.Context(), "control/hosts/") |
| + if err != nil || len(keys) != 1+2*len(namespaces) { |
| + t.Fatalf("recursive claim-store listing = %v, %v", keys, err) |
| + } |
| + bucket := leasetest.NewVersionedBucket() |
| + bucket.AddBucket("data") |
| + w := RegionalWorker{ |
| + Regional: Regional{Engine: park.Engine{Claims: claims, Store: bucket, Bucket: "data", Region: "ie"}}, |
| + Enrollment: enrollmentFunc(func(context.Context, string, string, time.Duration) error { return nil }), |
| + Evidence: evidenceFunc(func(context.Context, hostclaim.Observed, []lease.ObjectVersion) (string, time.Time, error) { |
| + return "", time.Time{}, errors.New("unused") |
| + }), |
| + } |
| + hosts, err := w.Census(t.Context()) |
| + if err != nil || len(hosts) != 1 || hosts[0] != host { |
| + t.Fatalf("census = %v, %v", hosts, err) |
| + } |
| + }) |
| } |
| } |
| @@ -9221,3 +9316,16 @@ go test ./internal/activator ./internal/host ./internal/lease ./internal/release |
| The actual Task 6 gate passed with only Task 6 applied, and Task 9's prescribed `go test ./internal/host -run '^TestClaimWiring' -count=1` passed before Task 10. Tests used the default on-disk scratch location. The sandbox again rejected the default Go cache as read-only; subsequent commands used the existing shared `/home/paulca/.cache/tmp/gocache` with `GOPROXY=off`, as in rev 2. No new per-task cache was created. |
| **Limits:** the full repository test suite and privileged cgroup witness remain unverified; this revision does not convert the fixture tests into a kernel proof. The required Opus review was attempted explicitly through the CLI, but timed out without a verdict. No Opus approval is claimed. No production resources, AWS services or feature flags were changed. Temporary exports and review/test scratch were removed. Only this plan was edited in the repository, with no staging or commit; concurrent files belonging to other work were left alone. The production-composition gaps recorded above remain, and `park-superseded` remains the sole unresolved design item identified by the brief, with unknown kinds refused. |
| + |
| + |
| +## Rev 4 authoring verification |
| + |
| +Reconstructed all **72** source/test blocks from Tasks 6-10 into a disposable export of **feat/hostclaim-box 2bd3ea1f**. Every zero-context patch applied. Tasks 1-5 remain byte-identical to rev 3. Checked the requested revision heading, fenced blocks, trailing whitespace, absence of em dashes and equality between the new-file blocks and tested source. |
| + |
| +`loadPinned` now uses `ltx.IsContiguous` with the selector's overflow guard. `TestColdRestoreAcceptsSelectorOverlappingOutput` passes real `genselect.SelectPrepared` output through `ColdRestore.Install`: snapshot `[1,11]` followed by compacted `[10,13]`, plus adjacent `[12,13]`. It checks the restored SQLite value from TXID 13 and the admitted generation marker. `TestLoadPinnedRejectsGapAndNonadvancingRange` keeps gaps and ranges that do not advance refused. Restoring exact adjacency made the overlapping restore regression fail with `genselect.ErrGap`. |
| + |
| +`RegionalWorker.Census` skips nested keys before validating direct `control/hosts/<host>.json` claim objects. `TestRegionalWorkerCensusIncludesQueuedClaimWithoutResidue` uses the real recursive `release.DirStore` with evidence-only, exec-only and combined nested objects, alongside its direct-only case. Each nested namespace appears under both the queued host and a host with no direct claim. The test checks that the recursive listing contains every object and the census returns only the queued host. Removing the nested-key skip made all three nested cases fail. Both fixes were restored before the final checks. |
| + |
| +The final source passed whole-tree `go build -buildvcs=false ./...`, `go vet ./...` and `gofmt -l .`, plus builds for Darwin/amd64, Windows/amd64 and Linux/arm64. All package tests compiled with `go test ./... -run '^$'`. Focused restore/census tests passed, followed by the complete `internal/hostbox` and `internal/genselect` suites with `-count=1 -race`. The sandbox refused writes to the default Go cache; checks used the existing shared on-disk `/home/paulca/.cache/tmp/gocache` with `GOPROXY=off`. |
| + |
| +**Limits:** the full repository test suite and privileged kernel witness were not rerun. The required Opus review was requested explicitly but timed out without a verdict. Existing production-composition gaps remain. Only this plan was edited for this revision; no staging, commit, production changes or feature activation occurred. Temporary exports and review scratch were removed. |