carlos / platform Public

feat: claim converge preserves Wildcard + CreatedAt (#151, woodstar coordination)

The woodstar-carloku branch adds an additive wildcard field to domain
claims (its spec §4-5). Declare it here so this binary's converge
rewrite round-trips it, and narrow converge to repoint Route only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell fa5dc0be9a90054fd4214935abd16a4b6f805871 parent 4e3941f
2 files changed, +29 −4
  • internal/domains/claims.go +19 −1
  • internal/domains/claims_test.go +10 −3
diff --git a/internal/domains/claims.go b/internal/domains/claims.go
index cf0823f80..51c5abae3 100644
--- a/internal/domains/claims.go
+++ b/internal/domains/claims.go
@@ -39,6 +39,14 @@ type Claim struct {
Route string `json:"route,omitempty"`
CreatedAt string `json:"created_at"`
CreatedBy string `json:"created_by,omitempty"`
+ // Wildcard marks a claim whose *.<host> labels also resolve to the
+ // primary route, with delegated DNS-01 issuance for the wildcard cert
+ // (woodstar-carloku migration spec §4-5 — that branch gives it meaning;
+ // nothing in this package acts on it). Declared here so a converge
+ // rewrite by this binary round-trips the value instead of stripping a
+ // field it doesn't know — the additive-wire rule applied to writers,
+ // not just readers.
+ Wildcard bool `json:"wildcard,omitempty"`
}
// ErrHostUnavailable is returned by AttachClaim when host is already claimed
@@ -101,7 +109,17 @@ func AttachClaim(ctx context.Context, s release.Store, c Claim) (bool, error) {
if cur.Route == c.Route {
return false, nil
}
- if _, err := s.Put(ctx, ClaimKey(c.Host), body, etag); err == nil {
+ // Converge repoints Route and nothing else: the stored claim keeps
+ // its CreatedAt (the claim's age) and Wildcard (TLS opt-in state a
+ // route repoint has no business clearing). Writing the caller's
+ // whole claim here would strip both.
+ next := *cur
+ next.Route = c.Route
+ nbody, err := json.Marshal(next)
+ if err != nil {
+ return false, err
+ }
+ if _, err := s.Put(ctx, ClaimKey(c.Host), nbody, etag); err == nil {
return false, nil
} else if errors.Is(err, release.ErrCASConflict) && attempt == 0 {
continue // converge race — one retry, then surface
diff --git a/internal/domains/claims_test.go b/internal/domains/claims_test.go
index 697cfc36c..f542ace87 100644
--- a/internal/domains/claims_test.go
+++ b/internal/domains/claims_test.go
@@ -58,12 +58,16 @@ func TestAttachClaimIdempotent(t *testing.T) {
func TestAttachClaimConvergesRoute(t *testing.T) {
s := release.NewDirStore(t.TempDir())
ctx := context.Background()
- claim := Claim{Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live"}
+ claim := Claim{Host: "tickets.example.com", Account: "bab", App: "kass", Route: "canary/live",
+ CreatedAt: "2026-08-12T00:00:00Z", Wildcard: true}
if _, err := AttachClaim(ctx, s, claim); err != nil {
t.Fatal(err)
}
- claim.Route = "canary/next"
- created, err := AttachClaim(ctx, s, claim)
+ // A converge repoints Route and nothing else: the caller's claim here
+ // deliberately carries no CreatedAt and no Wildcard, and both stored
+ // values must survive — a route repoint must never strip another
+ // branch's TLS opt-in or restamp the claim's age.
+ created, err := AttachClaim(ctx, s, Claim{Host: claim.Host, Account: "bab", App: "kass", Route: "canary/next"})
if err != nil || created {
t.Fatalf("AttachClaim route change: created=%v err=%v, want false nil", created, err)
}
@@ -74,6 +78,9 @@ func TestAttachClaimConvergesRoute(t *testing.T) {
if got.Route != "canary/next" {
t.Fatalf("Route = %q, want canary/next", got.Route)
}
+ if !got.Wildcard || got.CreatedAt != "2026-08-12T00:00:00Z" {
+ t.Fatalf("converge must preserve Wildcard+CreatedAt, got wildcard=%v created_at=%q", got.Wildcard, got.CreatedAt)
+ }
}
func TestAttachClaimOtherOwnerRefused(t *testing.T) {