carlos / platform Public

hostclaim: publication walks every entry, warm entries born covered, warm-region check restored (claim rev 6.22, joint round 13)

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 f0127321eb97acae7b529eb993910873a720d14d parent b0d6563
3 files changed, +136 −53
  • internal/hostclaim/generation.go +10 −5
  • internal/hostclaim/generation_test.go +21 −13
  • internal/hostclaim/rev713_test.go +105 −35

CI passed — run details

diff --git a/internal/hostclaim/generation.go b/internal/hostclaim/generation.go
index 99abc974b..5491b62f0 100644
--- a/internal/hostclaim/generation.go
+++ b/internal/hostclaim/generation.go
@@ -68,6 +68,9 @@ func AdmitWriter(in Admission) func(*Claim) error {
if len(h.Admissions) > 0 {
predecessor = h.Admissions[len(h.Admissions)-1]
}
+ if in.Mode == "warm" && in.Region != predecessor.Region {
+ return fmt.Errorf("%w: a warm admission stays in its predecessor's region", ErrWrongState)
+ }
type writerSession struct {
box string
session uint64
@@ -87,6 +90,7 @@ func AdmitWriter(in Admission) func(*Claim) error {
Session: c.Gen + 1, Box: in.Box, Generation: h.Generation,
Predecessor: predecessor.Generation, Mode: in.Mode, Coverage: in.Coverage,
Region: in.Region, PredecessorRegion: predecessor.Region,
+ Covered: in.Mode == "warm",
AdditionalWritesLost: append([]WritesLost(nil), in.AdditionalWritesLost...),
}
for _, ob := range c.Obligations {
@@ -124,13 +128,14 @@ func PublishGeneration(observedOpID, observedPhase string, observedSession uint6
return ErrWrongState
}
h := c.Holder
- last := -1
- for i, record := range h.Admissions {
+ admitted := false
+ for _, record := range h.Admissions {
if record.Generation == publishedGeneration {
- last = i
+ admitted = true
+ break
}
}
- if last == -1 {
+ if !admitted {
return ErrWrongState
}
activeGeneration := publishedGeneration
@@ -141,7 +146,7 @@ func PublishGeneration(observedOpID, observedPhase string, observedSession uint6
if op == "" {
op = fmt.Sprintf("session:%d", h.Session)
}
- for i := 0; i <= last; i++ {
+ for i := range h.Admissions {
record := &h.Admissions[i]
if record.Covered {
continue
diff --git a/internal/hostclaim/generation_test.go b/internal/hostclaim/generation_test.go
index 51a7d7448..ae486d4a7 100644
--- a/internal/hostclaim/generation_test.go
+++ b/internal/hostclaim/generation_test.go
@@ -58,7 +58,7 @@ func TestAdmitWriterWarmColdAdmissions(t *testing.T) {
if o.Claim.Holder.WriterBox != "boxT" || o.Claim.Holder.Session != warm || warm <= cold || o.Claim.Holder.Generation != "gen_a" || o.Claim.Holder.Stamp != cold {
t.Fatalf("warm holder = %+v, gen = %d", o.Claim.Holder, warm)
}
- second := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: warm, Box: "boxT", Generation: "gen_a", Mode: "warm", Predecessor: "gen_a"}
+ second := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: warm, Box: "boxT", Generation: "gen_a", Mode: "warm", Predecessor: "gen_a", Covered: true}
assertAdmissions(t, o.Claim, []AdmissionRecord{first, second})
o, err = Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: warm, ObservedGeneration: "gen_a", Box: "boxT", Mode: "cold", NewGeneration: "gen_b", PredecessorCertified: true}))
if err != nil {
@@ -123,7 +123,7 @@ func TestAdmitWriterPreservesOperation(t *testing.T) {
want.Holder.Generation = generation
want.Holder.Stamp = want.Gen
}
- want.Holder.Admissions = []AdmissionRecord{{Region: "ie", PredecessorRegion: "ie", Session: want.Gen, Box: "boxT", Generation: generation, Mode: mode}}
+ want.Holder.Admissions = []AdmissionRecord{{Region: "ie", PredecessorRegion: "ie", Session: want.Gen, Box: "boxT", Generation: generation, Mode: mode, Covered: mode == "warm"}}
if !reflect.DeepEqual(next.Claim, &want) {
t.Fatalf("admission changed fields outside holder writer fields and admissions: got %+v, want %+v", next.Claim, &want)
}
@@ -422,7 +422,7 @@ func TestAdmitWriterCoverage(t *testing.T) {
in.NewGeneration, generation = "gen_b", "gen_b"
}
o = updateGenerationTest(t, ctx, s, o, AdmitWriter(in))
- last := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: o.Claim.Gen, Box: "adi-knitting", Generation: generation, Predecessor: "gen_a", Mode: mode, Coverage: coverage}
+ last := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: o.Claim.Gen, Box: "adi-knitting", Generation: generation, Predecessor: "gen_a", Mode: mode, Coverage: coverage, Covered: mode == "warm"}
if mode == "cold" && !certified && coverage == "" {
last.WritesLost = &WritesLost{Box: "adi-knitting", Generation: "gen_a", Session: before.Session, RemoteMaxTXID: 42}
}
@@ -619,7 +619,7 @@ func TestPublishGenerationRefusals(t *testing.T) {
}
}
-func TestPublishGenerationCoverageBoundary(t *testing.T) {
+func TestPublishGenerationAllAdmissionsInOrder(t *testing.T) {
ctx := context.Background()
s := release.NewDirStore(t.TempDir())
o := servingClaim(t, ctx, s)
@@ -630,8 +630,14 @@ func TestPublishGenerationCoverageBoundary(t *testing.T) {
{Region: "ie", PredecessorRegion: "ie", Generation: "G1", Predecessor: ""},
{Region: "ie", PredecessorRegion: "ie", Generation: "G1", Predecessor: RootGeneration},
{Region: "ie", PredecessorRegion: "ie", Generation: "G2", Predecessor: "G1"},
- {Region: "ie", PredecessorRegion: "ie", Generation: "G2", Predecessor: "G2", Mode: "warm"},
- {Region: "ie", PredecessorRegion: "ie", Generation: "later", Predecessor: "G2"},
+ {Region: "ie", PredecessorRegion: "ie", Generation: "G2", Predecessor: "G2", Mode: "warm", Covered: true},
+ {Region: "ie", PredecessorRegion: "ie", Generation: "later", Predecessor: "G2", Mode: "cold"},
+ {Region: "ie", PredecessorRegion: "ie", Generation: "after-last-match", Predecessor: "later", Mode: "cold"},
+ {Region: "ie", PredecessorRegion: "uk", Generation: "foreign", Predecessor: "foreign-predecessor", Mode: "cold"},
+ {Region: "ie", Generation: "empty", Predecessor: "no-objects", Mode: "cold"},
+ {Region: "ie", PredecessorRegion: "ie", Generation: "duplicate", Predecessor: "later", Mode: "cold"},
+ {Region: "ie", PredecessorRegion: "ie", Generation: "warm-only", Predecessor: "warm-only", Mode: "warm", Covered: true},
+ {Region: "ie", PredecessorRegion: "ie", Generation: "last", Predecessor: "final-predecessor", Mode: "cold"},
}
c.Obligations = []Obligation{
{ID: "existing", Op: "old-op", Kind: "park-generation", Region: "ie", Generation: "G1", Retirement: "ret1", Owner: "region:ie"},
@@ -643,14 +649,16 @@ func TestPublishGenerationCoverageBoundary(t *testing.T) {
calls := 0
newID := func() string { calls++; return fmt.Sprintf("id%d", calls) }
o = updateGenerationTest(t, ctx, s, o, PublishGeneration("", "", 0, "G2", "ie", newID))
- want := append(append([]Obligation(nil), before.Claim.Obligations...), Obligation{
- ID: "id1", Op: "session:0", Kind: "park-generation", Region: "ie", Generation: RootGeneration, Retirement: "id2", Owner: "region:ie",
- })
- if calls != 2 || !reflect.DeepEqual(o.Claim.Obligations, want) {
+ want := append(append([]Obligation(nil), before.Claim.Obligations...),
+ Obligation{ID: "id1", Op: "session:0", Kind: "park-generation", Region: "ie", Generation: RootGeneration, Retirement: "id2", Owner: "region:ie"},
+ Obligation{ID: "id3", Op: "session:0", Kind: "park-generation", Region: "ie", Generation: "later", Retirement: "id4", Owner: "region:ie"},
+ Obligation{ID: "id5", Op: "session:0", Kind: "park-generation", Region: "ie", Generation: "final-predecessor", Retirement: "id6", Owner: "region:ie"},
+ )
+ if calls != 6 || !reflect.DeepEqual(o.Claim.Obligations, want) {
t.Fatalf("deduplicated chores = %+v, want %+v; calls %d", o.Claim.Obligations, want, calls)
}
for i, record := range o.Claim.Holder.Admissions {
- if record.Covered != (i < 4) {
+ if record.Covered != (i != 5 && i != 7) {
t.Fatalf("record %d covered = %t", i, record.Covered)
}
}
@@ -665,7 +673,7 @@ func TestPublishGenerationActiveRoot(t *testing.T) {
t.Fatal("active root must not be retired")
return ""
}))
- if o.Claim.Holder.Admissions[0].Covered || len(o.Claim.Obligations) != 0 {
+ if !o.Claim.Holder.Admissions[0].Covered || len(o.Claim.Obligations) != 0 {
t.Fatalf("active root publication = %+v", o.Claim)
}
}
@@ -830,7 +838,7 @@ func TestAdmitWriterRegionRules(t *testing.T) {
}
}
next, err := Update(ctx, s, o, AdmitWriter(in))
- if name == "empty region" {
+ if name == "empty region" || name == "warm other region" || name == "first warm other region" {
if !errors.Is(err, ErrWrongState) {
t.Fatalf("admission = %v, want ErrWrongState", err)
}
diff --git a/internal/hostclaim/rev713_test.go b/internal/hostclaim/rev713_test.go
index 0a2359bc3..b14aa245f 100644
--- a/internal/hostclaim/rev713_test.go
+++ b/internal/hostclaim/rev713_test.go
@@ -11,40 +11,45 @@ import (
"github.com/carlosframework/platform/internal/release"
)
-func TestAdmitWriterWarmReturnRegion(t *testing.T) {
- for _, region := range []string{"ie", ""} {
- t.Run("region="+region, func(t *testing.T) {
- ctx := context.Background()
- s := release.NewDirStore(t.TempDir())
- o := servingClaim(t, ctx, s)
- o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "uk", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "GT"}))
- target := o.Claim.Holder.Admissions[0]
- o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error {
- c.Holder.Generation = "GS"
- c.Op = Op{Kind: KindReverting, ID: "move", Phase: "return", Exec: "boxS"}
- return nil
- })
- next, err := Update(ctx, s, o, AdmitWriter(Admission{
- ObservedOpID: "move", ObservedPhase: "return", ObservedSession: target.Session, ObservedGeneration: "GS",
- Box: "boxS", Mode: "warm", Region: region, PredecessorRegion: "ignored",
- PredecessorCertified: true, Coverage: "clean-return",
- }))
- if region == "" {
- if !errors.Is(err, ErrWrongState) {
- t.Fatalf("empty region admission = %v", err)
+func TestAdmitWriterReturnRegion(t *testing.T) {
+ for _, mode := range []string{"warm", "cold"} {
+ for _, region := range []string{"ie", ""} {
+ t.Run(mode+"/region="+region, func(t *testing.T) {
+ ctx := context.Background()
+ s := release.NewDirStore(t.TempDir())
+ o := servingClaim(t, ctx, s)
+ o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "uk", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "GT"}))
+ target := o.Claim.Holder.Admissions[0]
+ o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error {
+ c.Op = Op{Kind: KindReverting, ID: "move", Phase: "return", Exec: "boxS"}
+ return nil
+ })
+ in := Admission{
+ ObservedOpID: "move", ObservedPhase: "return", ObservedSession: target.Session, ObservedGeneration: "GT",
+ Box: "boxS", Mode: mode, Region: region, PredecessorRegion: "ignored",
+ PredecessorCertified: true, Coverage: "clean-return",
}
- assertAdmissionStored(t, ctx, s, o)
- return
- }
- if err != nil {
- t.Fatal(err)
- }
- last := next.Claim.Holder.Admissions[1]
- if last.Region != "ie" || last.PredecessorRegion != "uk" || last.Predecessor != "GT" || last.Generation != "GS" || last.Covered {
- t.Fatalf("warm return = %+v", last)
- }
- assertAdmissionStored(t, ctx, s, next)
- })
+ if mode == "cold" {
+ in.NewGeneration = "GS2"
+ }
+ next, err := Update(ctx, s, o, AdmitWriter(in))
+ if mode == "warm" || region == "" {
+ if !errors.Is(err, ErrWrongState) {
+ t.Fatalf("return admission = %v, want ErrWrongState", err)
+ }
+ assertAdmissionStored(t, ctx, s, o)
+ return
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ last := next.Claim.Holder.Admissions[1]
+ if last.Region != "ie" || last.PredecessorRegion != "uk" || last.Predecessor != "GT" || last.Generation != "GS2" || last.Mode != "cold" || last.Covered {
+ t.Fatalf("cold return = %+v", last)
+ }
+ assertAdmissionStored(t, ctx, s, next)
+ })
+ }
}
}
@@ -130,8 +135,8 @@ func TestPublishGenerationServingCyclesBoundAdmissions(t *testing.T) {
}))
o = updateGenerationTest(t, ctx, s, o, PublishGeneration("", "", o.Claim.Holder.Session, generation, "ie", newID))
records := o.Claim.Holder.Admissions
- if records[len(records)-1].Covered || len(o.Claim.Obligations) != 0 {
- t.Fatalf("cycle %d covered or retired live predecessor", cycle)
+ if !records[len(records)-1].Covered || len(o.Claim.Obligations) != 0 {
+ t.Fatalf("cycle %d left warm entry uncovered or retired live predecessor", cycle)
}
if len(records) > 8 {
t.Fatalf("cycle %d admissions grew to %d", cycle, len(records))
@@ -364,6 +369,7 @@ func TestAdmitWriterAdditionalWritesLostValidation(t *testing.T) {
loss.Generation = RootGeneration
case "warm":
in.Mode, in.NewGeneration, in.PredecessorCertified = "warm", "", true
+ in.Region = "uk"
case "sealed":
in.Coverage = "sealed"
}
@@ -400,3 +406,67 @@ func TestAdmitWriterAdditionalWritesLostValidation(t *testing.T) {
})
}
}
+
+func TestAdmitWriterWarmBornCovered(t *testing.T) {
+ for _, generation := range []string{"", "G1"} {
+ t.Run("generation="+generation, func(t *testing.T) {
+ ctx := context.Background()
+ s := release.NewDirStore(t.TempDir())
+ o := servingClaim(t, ctx, s)
+ if generation != "" {
+ o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{
+ Region: "ie", PredecessorRegion: "ie", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: generation,
+ }))
+ }
+ o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{
+ Region: "ie", PredecessorRegion: "ie", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: generation,
+ Box: o.Claim.Op.Exec, Mode: "warm", PredecessorCertified: true,
+ }))
+ records := o.Claim.Holder.Admissions
+ last := records[len(records)-1]
+ if !last.Covered || last.Mode != "warm" || last.Generation != generation || last.Predecessor != generation || last.WritesLost != nil || len(o.Claim.Obligations) != 0 {
+ t.Fatalf("warm birth = %+v; chores = %+v", last, o.Claim.Obligations)
+ }
+ if len(records) > 1 && records[0].Covered {
+ t.Fatal("warm birth covered an earlier cold entry")
+ }
+ assertAdmissionStored(t, ctx, s, o)
+ })
+ }
+}
+
+func TestCompleteObligationDoesNotCoverAdmissions(t *testing.T) {
+ for _, kind := range []string{"park-replica", "park-generation"} {
+ t.Run(kind, func(t *testing.T) {
+ ctx := context.Background()
+ s := release.NewDirStore(t.TempDir())
+ o := servingClaim(t, ctx, s)
+ o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{
+ Region: "ie", PredecessorRegion: "ie", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G1",
+ }))
+ o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error {
+ ob := Obligation{ID: "park", Op: "cleanup", Kind: kind, Region: "ie", Owner: "region:ie", Retirement: "ret"}
+ if kind == "park-generation" {
+ ob.Generation = RootGeneration
+ }
+ c.Obligations = append(c.Obligations, ob)
+ return nil
+ })
+ before := o.Claim.Holder.Admissions
+ if before[0].Covered {
+ t.Fatal("queueing a park alone covered its predecessor")
+ }
+ next, err := Update(ctx, s, o, CompleteObligation("cleanup", "park"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ stored, err := Read(ctx, s, testHost)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if stored.ETag != next.ETag || len(stored.Claim.Obligations) != 0 || !reflect.DeepEqual(stored.Claim.Holder.Admissions, before) {
+ t.Fatalf("acknowledgement changed admissions: %+v", stored.Claim)
+ }
+ })
+ }
+}