carlos / platform Public

zdd plan 2 task 12: claimed spawns pin a generation child under the entry's parent

The spawnClaimedGen helper is built closed until main's isolated root launcher
can carry claim reservations. On this branch, main (commit a4cd3003) deliberately
closed the in-process claimed spawn path: spawnClaimedBefore returns
ErrClaimIsolationUnavailable when enabled. The generation child shape must stay
closed for the same reason. A later plan will route claims-on generation spawns
through the isolated root launcher rather than reopen an in-process path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev dd3cba85be074a69ebe7b1096af0544c4fd816a8 parent 8e4d876
2 files changed, +49 −0
  • internal/activator/claimspawn.go +13 −0
  • internal/activator/claimspawn_test.go +36 −0
diff --git a/internal/activator/claimspawn.go b/internal/activator/claimspawn.go
index 60b5cc0c8..578260f65 100644
--- a/internal/activator/claimspawn.go
+++ b/internal/activator/claimspawn.go
@@ -21,3 +21,16 @@ func spawnClaimedBefore(ctx context.Context, enabled bool, manager *cgroup.Manag
// Keep this old helper closed even if a future caller reintroduces it.
return nil, nil, ErrClaimIsolationUnavailable
}
+
+// spawnClaimedGen pins and reserves a generation child under the entry's
+// parent for the generation layout under claims (zero-downtime spec section
+// 7.3). It stays closed until main's isolated root launcher can carry claim
+// reservations, like spawnClaimedBefore. A later plan must route claims-on
+// generation spawns through that launcher rather than reopen an in-process
+// path.
+func spawnClaimedGen(ctx context.Context, parent *cgroup.Prepared, n uint64, tier cgroup.Limit, selected hostwrite.Work, identity hostwrite.Identity, build func() *exec.Cmd, before func() error) (*exec.Cmd, *cgroup.Prepared, error) {
+ if parent == nil || selected == nil || build == nil || n == 0 {
+ return nil, nil, hostwrite.ErrUnavailable
+ }
+ return nil, nil, ErrClaimIsolationUnavailable
+}
diff --git a/internal/activator/claimspawn_test.go b/internal/activator/claimspawn_test.go
index a6933ccca..5c5d45236 100644
--- a/internal/activator/claimspawn_test.go
+++ b/internal/activator/claimspawn_test.go
@@ -39,3 +39,39 @@ func TestClaimSpawnNeverFallsBack(t *testing.T) {
t.Fatal(builds, calls)
}
}
+
+// spawnClaimedGen never falls back to an ordinary start: an invalid
+// argument refuses before the host write is entered, and a refused work or
+// a parent that cannot pin a child never builds the command.
+func TestClaimSpawnGenNeverFallsBack(t *testing.T) {
+ calls, builds := 0, 0
+ beforeCalled := false
+ build := func() *exec.Cmd { builds++; return exec.Command("must-not-execute") }
+ before := func() error { beforeCalled = true; return nil }
+
+ if _, _, err := spawnClaimedGen(context.Background(), nil, 1, cgroup.TierDefault, claimSpawnWork{false, &calls}, hostwrite.Identity{}, build, before); !errors.Is(err, hostwrite.ErrUnavailable) {
+ t.Fatalf("nil parent: %v", err)
+ }
+ if _, _, err := spawnClaimedGen(context.Background(), &cgroup.Prepared{}, 0, cgroup.TierDefault, claimSpawnWork{false, &calls}, hostwrite.Identity{}, build, before); !errors.Is(err, hostwrite.ErrUnavailable) {
+ t.Fatalf("generation 0: %v", err)
+ }
+ if calls != 0 {
+ t.Fatalf("host write entered %d times for invalid arguments", calls)
+ }
+ for _, deny := range []bool{true, false} {
+ beforeCalled = false
+ cmd, child, err := spawnClaimedGen(context.Background(), &cgroup.Prepared{}, 7, cgroup.TierDefault, claimSpawnWork{deny, &calls}, hostwrite.Identity{}, build, before)
+ if cmd != nil || child != nil {
+ t.Fatalf("deny=%v: cmd=%v child=%v", deny, cmd, child)
+ }
+ if !errors.Is(err, ErrClaimIsolationUnavailable) {
+ t.Fatalf("deny=%v: err=%v, want ErrClaimIsolationUnavailable", deny, err)
+ }
+ if beforeCalled {
+ t.Fatalf("deny=%v: before was called", deny)
+ }
+ }
+ if builds != 0 || calls != 0 {
+ t.Fatalf("builds=%d calls=%d, want 0 and 0", builds, calls)
+ }
+}