package hostops import ( "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/park" "strconv" "strings" ) const MoveLossReplicaBaseline = "replica:" const MoveLossSealBaseline = "seal:" // ParseMoveLossBaseline is shared by the frozen-source writer and validators. func ParseMoveLossBaseline(value string) (kind, region, identity string, err error) { if strings.HasPrefix(value, MoveLossReplicaBaseline) { r, g, ok := strings.Cut(strings.TrimPrefix(value, MoveLossReplicaBaseline), "/") if ok && r != "" && g != "" && !strings.Contains(g, "/") { return "replica", r, g, nil } } if strings.HasPrefix(value, MoveLossSealBaseline) { id := strings.TrimPrefix(value, MoveLossSealBaseline) if id != "" && !strings.Contains(id, "/") { return "seal", "", id, nil } } return "", "", "", hostclaim.ErrLossRecord } // MoveLossRecoveryOwner shares the resolve owner's signed-intent policy with boxes. // This policy is pure; it exposes neither the console store nor mutation grants. func MoveLossRecoveryOwner() hostclaim.LossRecoveryOwner { return &moveLossOwner{} } func (m *moveLossOwner) ValidateLossRecovery(c hostclaim.Claim, loss hostclaim.LossRecord, a hostclaim.Admission) error { in, _, err := lossIntentOf(loss) if err != nil { return err } stamp, err := strconv.ParseUint(c.Op.Journal[hostclaim.JournalSourceStamp], 10, 64) if err != nil || stamp == 0 || c.Holder == nil || c.Holder.Stamp != stamp || c.Holder.Incarnation != in.Incarnation || c.Holder.Key != in.RecordKey || c.Op.ID != in.Move || c.Op.Kind != hostclaim.KindRestoring || c.Op.Phase != hostclaim.PhaseProbing || c.Op.Intent["rollback"] != in.Rollback || c.Op.Exec != in.Source || c.Op.Intent["source"] != in.Source || c.Op.Intent["target"] != in.Target || c.Op.Intent["to"] != in.TargetRegion || !hostclaim.LostTargetReleased(&c, loss.ID) || a.Box != in.Source || !park.SameRegion(c.Op.Intent["home_region"], a.Region, in.SourceRegion) || a.Mode != "cold" || a.Coverage != "" || a.KeepStamp || a.PredecessorCertified { return hostclaim.ErrLossRecord } return nil }