package hostfence import ( "context" "github.com/carlosframework/platform/internal/hostclaim" "slices" ) // CheckOneBoxRegion uses the same signed roster as fence authority. A fenced // source still counts; neither a missing heartbeat nor a second fenced box // turns a two-box placement into a one-box region. func (a ClaimFenceAuthority) CheckOneBoxRegion(ctx context.Context, source, region string) error { o, err := a.Directory.Read(ctx) if err != nil { return err } b, ok := o.Roster.Boxes[source] if !ok || b.Region != region { return hostclaim.ErrFence } placement, ok := o.Roster.Regions[region] if !ok || placement.Account != b.Cloud.Account || placement.AWSRegion != b.Cloud.Region || !slices.Contains(placement.Namespaces, b.Namespace) || !slices.Contains(placement.Pools, b.Pool) { return hostclaim.ErrFence } count := 0 for _, candidate := range o.Roster.Boxes { if candidate.Region == region && candidate.Namespace == b.Namespace && candidate.Pool == b.Pool && candidate.State != "retired" { count++ } } if b.State == "retired" || count != 1 { return hostclaim.ErrFence } return nil }