package ownership import ( "context" "errors" "time" ) var ( ErrInvalidOwnership = errors.New("invalid proxy ownership request") ErrOwnershipUnavailable = errors.New("proxy is unavailable for ownership") ErrAlreadyOwned = errors.New("proxy is already owned") ErrStaleAssignment = errors.New("proxy ownership assignment is stale") ErrNotDraining = errors.New("proxy ownership is not draining") ErrDrainNotReady = errors.New("proxy still has active or reserved runtime") ErrInvalidDrainTicket = errors.New("invalid drain ticket request") ) type Assignment struct { ProxyID string WorkerID string Epoch uint64 Version uint64 ExpiresAt time.Time Draining bool } // DrainTicket records a pending removal after an ownership assignment enters // draining. RequiredSnapshotEpoch fences the first complete Worker snapshot // that may prove the proxy was excluded. type DrainTicket struct { ProxyID string WorkerID string AssignmentEpoch uint64 RequiredSnapshotEpoch uint64 } // DrainTicketStore exposes bounded, Worker-local pending drain tickets. It // deliberately does not finalize ownership: a later runtime transaction must // prove both an acknowledged exclusion snapshot and zero live counters. type DrainTicketStore interface { PendingDrains(context.Context, string, int) ([]DrainTicket, error) } // Repository is the shared authority for ownership changes. Implementations // that also support extraction must serialize both operations transactionally. type Repository interface { Assign(context.Context, time.Time, string, string, time.Duration) (Assignment, error) Renew(context.Context, time.Time, string, string, uint64, time.Duration) (Assignment, error) BeginDrain(context.Context, string, string, uint64) (Assignment, error) AcknowledgeDrain(context.Context, string, string, uint64, int64, int64) error Get(context.Context, string) (Assignment, bool, error) Expire(context.Context, time.Time, int) ([]Assignment, error) }