package permissions

import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"slices"
	"sort"
	"strings"

	"github.com/nexuscrm/kernel/pkg/schemacatalog"
	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

const assignmentPolicySetTargetDomain = "permission_set_assignment_policy/set/utf8mb4_unicode_ci-v1"

type assignmentPolicyPlan struct {
	Scope           cp.ComponentManagedScope       `json:"scope"`
	OwnerPack       string                         `json:"ownerPack"`
	PolicyKey       string                         `json:"policyKey,omitempty"`
	Policy          *PermissionSetAssignmentPolicy `json:"policy,omitempty"`
	TargetID        string                         `json:"targetId,omitempty"`
	TargetOwnerPack string                         `json:"targetOwnerPack,omitempty"`
	Resolution      string                         `json:"resolution,omitempty"`
	Profiles        []string                       `json:"profiles,omitempty"`
	Eligible        []string                       `json:"eligible,omitempty"`
	Previous        *assignmentPolicyStaleClaim    `json:"previous,omitempty"`
	StaleClaims     []assignmentPolicyStaleClaim   `json:"staleClaims,omitempty"`
}

type assignmentPolicyStaleClaim struct {
	ID                  string `json:"id"`
	PermissionSetID     string `json:"permissionSetId"`
	PermissionSet       string `json:"permissionSet"`
	DefinitionOwnerPack string `json:"definitionOwnerPack"`
	PolicyKey           string `json:"policyKey"`
}

type assignmentPolicyLiveProjection struct {
	Present           bool     `json:"present"`
	PolicyKey         string   `json:"policyKey,omitempty"`
	OwnerPack         string   `json:"ownerPack,omitempty"`
	PermissionSet     string   `json:"permissionSet,omitempty"`
	ProfilesAnyOf     []string `json:"profiles_any_of"`
	EligibleAssignees []string `json:"eligibleAssignees"`
	ActiveAssignments []string `json:"activeAssignments"`
	Suspended         bool     `json:"suspended"`
	WorkGeneration    uint64   `json:"workGeneration"`
	AppliedGeneration uint64   `json:"appliedGeneration"`
	ResolutionState   string   `json:"resolutionState"`
}

type assignmentPolicySetProjection struct {
	OwnerPack  string   `json:"ownerPack"`
	PolicyKeys []string `json:"policyKeys"`
}

func planPermissionSetAssignmentPolicy(
	ctx context.Context,
	scope cp.ComponentManagedScope,
	request cp.ComponentManagedLifecycleRequest,
	store cp.ComponentManagedReadStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
	eligibilityBudget *assignmentPolicyEligibilityReadBudget,
) (cp.ComponentManagedPlan, error) {
	switch scope {
	case cp.ComponentManagedScopeItem:
		return planPermissionSetAssignmentPolicyItem(
			ctx, request, store, eligibility, eligibilityBudget,
		)
	case cp.ComponentManagedScopeSet:
		return planPermissionSetAssignmentPolicySet(ctx, request, store)
	default:
		return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy scope %q is unsupported", scope)
	}
}

func planPermissionSetAssignmentPolicyItem(
	ctx context.Context,
	request cp.ComponentManagedLifecycleRequest,
	store cp.ComponentManagedReadStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
	eligibilityBudget *assignmentPolicyEligibilityReadBudget,
) (cp.ComponentManagedPlan, error) {
	if err := request.Validate(cp.ComponentManagedScopeItem); err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	policy, source, _, err := assignmentPolicyExpectedRequest(*request.Item)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	snapshot, err := readAssignmentPolicyTargetForPlan(ctx, store, *request.Item, policy.PermissionSet)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	resolution, profiles, eligible, eligibilityItems, err := projectAssignmentPolicyEligibility(
		ctx,
		store,
		snapshot.PermissionSetID,
		policy.ProfilesAnyOf,
		eligibility,
		eligibilityBudget,
	)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	plan := assignmentPolicyPlan{
		Scope: cp.ComponentManagedScopeItem, OwnerPack: request.Item.PackName,
		PolicyKey: request.Item.Component.BusinessKey, Policy: &policy,
		TargetID: snapshot.PermissionSetID, TargetOwnerPack: snapshot.DefinitionOwnerPack,
		Resolution: resolution,
		Profiles:   profiles, Eligible: eligible,
	}
	selectorGroups := [][]string{policy.ProfilesAnyOf, snapshot.Profiles}
	var previousReleaseUsage cp.ComponentManagedUsage
	sourceClaims, err := store.ReadRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyClaimTable,
		[]string{"Id", "PermissionSetId", "OwnerPack", "PolicyKey"},
		cp.ComponentRow{"OwnerPack": request.Item.PackName, "PolicyKey": request.Item.Component.BusinessKey},
		1, nil,
	))
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	if len(sourceClaims) == 1 {
		previousID, rowErr := assignmentPolicyRequiredString(sourceClaims[0], "PermissionSetId")
		if rowErr != nil {
			return cp.ComponentManagedPlan{}, rowErr
		}
		if previousID != snapshot.PermissionSetID {
			previousName, nameErr := readAssignmentPolicyTargetNameByID(ctx, store, previousID)
			if nameErr != nil {
				return cp.ComponentManagedPlan{}, nameErr
			}
			claimID, _ := assignmentPolicyRequiredString(sourceClaims[0], "Id")
			plan.Previous = &assignmentPolicyStaleClaim{
				ID: claimID, PermissionSetID: previousID, PermissionSet: previousName,
				PolicyKey: request.Item.Component.BusinessKey,
			}
			previousSnapshot, snapshotErr := readAssignmentPolicyTarget(ctx, store, previousName)
			if snapshotErr != nil {
				return cp.ComponentManagedPlan{}, snapshotErr
			}
			if previousSnapshot.ClaimID != claimID || !assignmentPolicySourceIdentityEqual(
				previousSnapshot.OwnerPack, previousSnapshot.PolicyKey,
				request.Item.PackName, request.Item.Component.BusinessKey,
			) {
				return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy previous claim identity is inconsistent")
			}
			plan.Previous.DefinitionOwnerPack = previousSnapshot.DefinitionOwnerPack
			previousReleaseUsage = assignmentPolicyReleaseUsage(previousSnapshot)
			selectorGroups = append(selectorGroups, previousSnapshot.Profiles)
		}
	}
	opaque, err := json.Marshal(plan)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	targets, err := source.ManagedTargets(policy)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	targets = append(
		targets,
		PermissionSetAssignmentPolicySerializationTarget(),
		assignmentPolicySetTarget(request.Item.PackName),
	)
	selectorTargets, err := assignmentPolicySelectorManagedTargets(selectorGroups...)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	targets = append(targets, selectorTargets...)
	if plan.Previous != nil {
		oldTarget, targetErr := PermissionSetDefinitionManagedTarget(plan.Previous.PermissionSet)
		if targetErr != nil {
			return cp.ComponentManagedPlan{}, targetErr
		}
		targets = append(targets, oldTarget)
	}
	desired := len(eligible) + len(profiles) + 3
	current := len(snapshot.Assignments) + len(snapshot.Profiles) + eligibilityItems + 3
	deltaRows := len(snapshot.Profiles) + len(profiles) +
		2*len(snapshot.Assignments) + len(eligible) + 4
	mutationStatements := deltaRows
	if plan.Previous != nil {
		current += previousReleaseUsage.CurrentItems
		deltaRows += previousReleaseUsage.DeltaRows
		mutationStatements += previousReleaseUsage.MutationStatements
	}
	return cp.NewComponentManagedPlan(cp.ComponentManagedPlanSpec{
		Targets:              targets,
		RequiredCapabilities: assignmentPolicyCapabilities(),
		Estimate: cp.ComponentManagedUsage{
			CurrentItems: current, DesiredItems: desired,
			DeltaRows: deltaRows, MutationStatements: mutationStatements,
			MutationBytes: deltaRows * assignmentPolicyMutationBytesPerRow,
			BatchRows:     min(deltaRows, assignmentPolicyMaximumRows),
		},
		Effects:            assignmentPolicyEffects(),
		ProjectionIdentity: assignmentPolicyItemProjectionIdentity(*request.Item),
		OpaquePlan:         opaque,
	})
}

func readAssignmentPolicyTargetForPlan(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	request cp.ComponentManagedRequest,
	name string,
) (assignmentPolicyTargetSnapshot, error) {
	// DependsOn proves candidate ordering only for this Plan pass. Mutate and
	// Project deliberately use the strict live resolver and cannot consume this
	// declaration as a Permission Set Definition or authorization fact.
	allowDeclaredUnavailable := false
	for _, dependency := range request.Component.DependsOn {
		if dependency.Kind == permissionSetDefinitionComponentKind &&
			dependency.BusinessKey == name {
			allowDeclaredUnavailable = true
			break
		}
	}
	return readAssignmentPolicyTargetAllowingDeclaredUnavailable(ctx, store, name, allowDeclaredUnavailable)
}

func planPermissionSetAssignmentPolicySet(
	ctx context.Context,
	request cp.ComponentManagedLifecycleRequest,
	store cp.ComponentManagedReadStore,
) (cp.ComponentManagedPlan, error) {
	if err := request.Validate(cp.ComponentManagedScopeSet); err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	if request.Set.Kind != PermissionSetAssignmentPolicyComponentKind ||
		request.Set.SourceOwner != "" || request.Set.PackName == "" ||
		strings.TrimSpace(request.Set.PackName) != request.Set.PackName {
		return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy set request is not canonical")
	}
	desired, err := assignmentPolicyDesiredSet(request.Set.PackName, request.DesiredBusinessKeys)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	claims, err := readAssignmentPolicyRows(ctx, store, cp.ComponentManagedRowQuery{
		Table:   schemacatalog.AssignmentPolicyClaimTable,
		Columns: []string{"Id", "PermissionSetId", "OwnerPack", "PolicyKey"},
		Equal:   cp.ComponentRow{"OwnerPack": request.Set.PackName},
		OrderBy: []cp.ComponentManagedOrder{
			{Column: "PermissionSetId", Direction: cp.ComponentManagedOrderAscending},
		},
		LogicalKeyColumns: []string{"PermissionSetId"},
		MaximumRows:       assignmentPolicyMaximumRows,
	})
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	plan := assignmentPolicyPlan{Scope: cp.ComponentManagedScopeSet, OwnerPack: request.Set.PackName}
	targets := []cp.ComponentManagedTarget{
		PermissionSetAssignmentPolicySerializationTarget(),
		assignmentPolicySetTarget(request.Set.PackName),
	}
	for _, key := range desired {
		source, sourceErr := NewPermissionSetAssignmentPolicySource(request.Set.PackName, key)
		if sourceErr != nil {
			return cp.ComponentManagedPlan{}, sourceErr
		}
		targets = append(targets, source.ManagedTarget())
	}
	currentItems := len(claims)
	deltaRows := 0
	mutationStatements := 0
	for _, row := range claims {
		key, err := assignmentPolicyRequiredString(row, "PolicyKey")
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		ownerPack, err := assignmentPolicyRequiredString(row, "OwnerPack")
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		if !assignmentPolicySourceIdentityEqual(ownerPack, key, request.Set.PackName, key) {
			return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy claim owner differs from exact-set owner")
		}
		source, sourceErr := NewPermissionSetAssignmentPolicySource(request.Set.PackName, key)
		if sourceErr != nil {
			return cp.ComponentManagedPlan{}, sourceErr
		}
		targets = append(targets, source.ManagedTarget())
		targetID, err := assignmentPolicyRequiredString(row, "PermissionSetId")
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		name, err := readAssignmentPolicyTargetNameByID(ctx, store, targetID)
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		target, err := PermissionSetDefinitionManagedTarget(name)
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		targets = append(targets, target)
		if _, keep := desired[assignmentPolicyDatabaseIdentity(key)]; keep {
			continue
		}
		id, err := assignmentPolicyRequiredString(row, "Id")
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		snapshot, err := readAssignmentPolicyTarget(ctx, store, name)
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
		if snapshot.ClaimID != id || snapshot.PermissionSetID != targetID ||
			!assignmentPolicySourceIdentityEqual(
				snapshot.OwnerPack, snapshot.PolicyKey, request.Set.PackName, key,
			) {
			return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy stale claim identity is inconsistent")
		}
		releaseUsage := assignmentPolicyReleaseUsage(snapshot)
		currentItems += releaseUsage.CurrentItems
		deltaRows += releaseUsage.DeltaRows
		mutationStatements += releaseUsage.MutationStatements
		plan.StaleClaims = append(plan.StaleClaims, assignmentPolicyStaleClaim{
			ID: id, PermissionSetID: targetID, PermissionSet: name,
			DefinitionOwnerPack: snapshot.DefinitionOwnerPack, PolicyKey: key,
		})
	}
	opaque, err := json.Marshal(plan)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	return cp.NewComponentManagedPlan(cp.ComponentManagedPlanSpec{
		Targets: targets, RequiredCapabilities: assignmentPolicyCapabilities(),
		Estimate: cp.ComponentManagedUsage{
			CurrentItems: currentItems, DesiredItems: len(request.DesiredBusinessKeys),
			DeltaRows:          deltaRows,
			MutationStatements: mutationStatements,
			MutationBytes:      deltaRows * assignmentPolicyMutationBytesPerRow,
			BatchRows:          assignmentPolicyMaximumRows,
		},
		Effects:            assignmentPolicyEffects(),
		ProjectionIdentity: assignmentPolicySetProjectionIdentity(*request.Set),
		OpaquePlan:         opaque,
	})
}

func mutatePermissionSetAssignmentPolicy(
	ctx context.Context,
	scope cp.ComponentManagedScope,
	request cp.ComponentManagedLifecycleRequest,
	plan cp.ComponentManagedPlan,
	store cp.ComponentManagedMutationStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (cp.ComponentManagedMutationResult, error) {
	if store == nil {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy lifecycle mutation store is required")
	}
	if err := request.Validate(scope); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if err := plan.Validate(); err != nil {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy lifecycle plan: %w", err)
	}
	var decoded assignmentPolicyPlan
	if err := json.Unmarshal(plan.OpaquePlan(), &decoded); err != nil {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("decode assignment policy lifecycle plan: %w", err)
	}
	if decoded.Scope != scope {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy opaque plan scope changed")
	}
	switch scope {
	case cp.ComponentManagedScopeItem:
		return mutatePermissionSetAssignmentPolicyItem(
			ctx, *request.Item, request, decoded, plan, store, eligibility,
		)
	case cp.ComponentManagedScopeSet:
		return mutatePermissionSetAssignmentPolicySet(
			ctx, *request.Set, request, request.DesiredBusinessKeys, decoded, plan, store,
		)
	default:
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy scope %q is unsupported", scope)
	}
}

func validateAssignmentPolicyPlanFresh(
	ctx context.Context,
	scope cp.ComponentManagedScope,
	request cp.ComponentManagedLifecycleRequest,
	planned cp.ComponentManagedPlan,
	store cp.ComponentManagedReadStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
	eligibilityBudget *assignmentPolicyEligibilityReadBudget,
) error {
	fresh, err := planPermissionSetAssignmentPolicy(
		ctx, scope, request, store, eligibility, eligibilityBudget,
	)
	if err != nil {
		return fmt.Errorf("replan assignment policy after root locking: %w", err)
	}
	if !bytes.Equal(fresh.Fingerprint(), planned.Fingerprint()) {
		return fmt.Errorf("assignment policy plan became stale after root locking")
	}
	return nil
}

func mutatePermissionSetAssignmentPolicyItem(
	ctx context.Context,
	request cp.ComponentManagedRequest,
	lifecycleRequest cp.ComponentManagedLifecycleRequest,
	plan assignmentPolicyPlan,
	planEnvelope cp.ComponentManagedPlan,
	store cp.ComponentManagedMutationStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (cp.ComponentManagedMutationResult, error) {
	policy, _, _, err := assignmentPolicyExpectedRequest(request)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	roots := []assignmentPolicyRootLock{{
		PermissionSetID: plan.TargetID,
		PermissionSet:   policy.PermissionSet,
		OwnerPack:       plan.TargetOwnerPack,
	}}
	if plan.Previous != nil {
		roots = append(roots, assignmentPolicyRootLock{
			PermissionSetID: plan.Previous.PermissionSetID,
			PermissionSet:   plan.Previous.PermissionSet,
			OwnerPack:       plan.Previous.DefinitionOwnerPack,
		})
	}
	if err := lockAssignmentPolicyRoots(ctx, store, roots); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	eligibilityBudget := newAssignmentPolicyEligibilityReadBudget(
		assignmentPolicyManagedBudget().MaxCurrentItems,
	)
	lockedResolution, lockedProfiles, lockedEligible, _, err := projectAssignmentPolicyEligibility(
		ctx,
		store,
		plan.TargetID,
		policy.ProfilesAnyOf,
		eligibility,
		eligibilityBudget,
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if lockedResolution != plan.Resolution || !slices.Equal(lockedProfiles, plan.Profiles) ||
		!slices.Equal(lockedEligible, plan.Eligible) {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy plan became stale after eligibility locking")
	}
	if err := validateAssignmentPolicyPlanFresh(
		ctx, cp.ComponentManagedScopeItem, lifecycleRequest, planEnvelope, store, eligibility,
		eligibilityBudget,
	); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	targetID := plan.TargetID
	changed := 0
	if plan.Previous != nil {
		removed, removeErr := clearAndReleaseAssignmentPolicyClaim(
			ctx, store, request.PackName, request.Component.BusinessKey, *plan.Previous,
		)
		if removeErr != nil {
			return cp.ComponentManagedMutationResult{}, removeErr
		}
		changed += removed
	}
	claimRows, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyClaimTable,
		[]string{"Id", "PermissionSetId", "OwnerPack", "PolicyKey", "PayloadHash"},
		cp.ComponentRow{"PermissionSetId": targetID}, 1, []string{"PermissionSetId"},
	))
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if len(claimRows) == 1 {
		owner, _ := assignmentPolicyRequiredString(claimRows[0], "OwnerPack")
		key, _ := assignmentPolicyRequiredString(claimRows[0], "PolicyKey")
		if !assignmentPolicySourceIdentityEqual(
			owner, key, request.PackName, request.Component.BusinessKey,
		) {
			return cp.ComponentManagedMutationResult{}, fmt.Errorf(
				"Permission Set %s is already claimed by %s/%s", policy.PermissionSet, owner, key,
			)
		}
	}
	claimWasAbsent := len(claimRows) == 0
	if len(claimRows) == 0 {
		id, idErr := store.NewID()
		if idErr != nil {
			return cp.ComponentManagedMutationResult{}, idErr
		}
		affected, insertErr := store.InsertRows(ctx, cp.ComponentManagedInsertBatch{
			Table: schemacatalog.AssignmentPolicyClaimTable,
			Rows: []cp.ComponentManagedInsertRow{{
				LogicalKey: cp.ComponentRow{"PermissionSetId": targetID},
				Values: cp.ComponentRow{
					"Id": id, "PermissionSetId": targetID, "OwnerPack": request.PackName,
					"PolicyKey": request.Component.BusinessKey, "PayloadHash": assignmentPolicyPayloadHash(request.Payload),
				},
			}},
			CurrentTimestampColumns: []string{"CreatedDate", "LastModifiedDate"},
		})
		if err := assignmentPolicyRequireExactWrite(
			"insert", schemacatalog.AssignmentPolicyClaimTable, affected, insertErr,
		); err != nil {
			return cp.ComponentManagedMutationResult{}, err
		}
		changed++
	} else {
		owner, _ := assignmentPolicyRequiredString(claimRows[0], "OwnerPack")
		key, _ := assignmentPolicyRequiredString(claimRows[0], "PolicyKey")
		if owner != request.PackName || key != request.Component.BusinessKey ||
			!bytes.Equal(assignmentPolicyBytes(claimRows[0]["PayloadHash"]), assignmentPolicyPayloadHash(request.Payload)) {
			id, _ := assignmentPolicyRequiredString(claimRows[0], "Id")
			affected, updateErr := store.UpdateRows(ctx, cp.ComponentManagedUpdate{
				Table: schemacatalog.AssignmentPolicyClaimTable, Match: cp.ComponentRow{"Id": id},
				Values: cp.ComponentRow{
					"OwnerPack": request.PackName, "PolicyKey": request.Component.BusinessKey,
					"PayloadHash": assignmentPolicyPayloadHash(request.Payload),
				},
				CurrentTimestampColumns: []string{"LastModifiedDate"}, MaximumAffectedRows: 1,
			})
			if err := assignmentPolicyRequireExactWrite(
				"update", schemacatalog.AssignmentPolicyClaimTable, affected, updateErr,
			); err != nil {
				return cp.ComponentManagedMutationResult{}, err
			}
			changed++
		}
	}
	releaseChanged, releaseProof, err := consumeAssignmentPolicyReleaseReceiptForTarget(
		ctx, store, request.PackName, request.Component.BusinessKey, targetID,
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	changed += releaseChanged
	selectorChanged, err := reconcileAssignmentPolicySelectors(ctx, store, targetID, plan.Profiles)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	changed += selectorChanged
	state, stateChanged, err := ensureAssignmentPolicyState(ctx, store, targetID, policy.PermissionSet, plan.Resolution)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	changed += stateChanged
	desired := plan.Eligible
	if state.Suspended || plan.Resolution != assignmentPolicyResolutionResolved {
		desired = nil
	}
	mutationGeneration := state.WorkGeneration
	if stateChanged == 0 {
		mutationGeneration, err = nextAssignmentPolicyGeneration(state.WorkGeneration)
		if err != nil {
			return cp.ComponentManagedMutationResult{}, err
		}
	}
	assignmentChanged, err := reconcileAssignmentPolicyAssignments(
		ctx,
		store,
		request.PackName,
		request.Component.BusinessKey,
		targetID,
		mutationGeneration,
		claimWasAbsent && state.ResolutionState == assignmentPolicyResolutionRemoved,
		releaseProof,
		false,
		desired,
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	changed += assignmentChanged
	if state.WorkGeneration != state.AppliedGeneration || state.ResolutionState != plan.Resolution || changed > 0 {
		nextGeneration := state.WorkGeneration
		if stateChanged == 0 && changed > 0 {
			nextGeneration, err = nextAssignmentPolicyGeneration(state.WorkGeneration)
			if err != nil {
				return cp.ComponentManagedMutationResult{}, err
			}
		}
		affected, updateErr := store.UpdateRows(ctx, cp.ComponentManagedUpdate{
			Table: schemacatalog.AssignmentPolicyTargetStateTable, Match: cp.ComponentRow{"Id": state.ID},
			Values: cp.ComponentRow{
				"WorkGeneration": nextGeneration, "AppliedGeneration": nextGeneration,
				"ResolutionState":  plan.Resolution,
				"ResolutionDigest": assignmentPolicyDigest(plan.Resolution), "RetryCount": 0,
				"LastFailureCode": nil, "LastFailureDigest": nil, "NextAttemptAt": nil,
			},
			CurrentTimestampColumns: []string{"LastModifiedDate"}, MaximumAffectedRows: 1,
		})
		if err := assignmentPolicyRequireExactWrite(
			"update", schemacatalog.AssignmentPolicyTargetStateTable, affected, updateErr,
		); err != nil {
			return cp.ComponentManagedMutationResult{}, err
		}
		changed++
	}
	if changed == 0 {
		return cp.ComponentManagedMutationResult{Disposition: cp.ComponentManagedMutationNoChange}, nil
	}
	disposition := cp.ComponentManagedMutationDesiredProjectionStaged
	if plan.Resolution != assignmentPolicyResolutionResolved || state.Suspended {
		disposition = cp.ComponentManagedMutationSafeProjectionStaged
	}
	return cp.ComponentManagedMutationResult{Disposition: disposition}, nil
}

func mutatePermissionSetAssignmentPolicySet(
	ctx context.Context,
	request cp.ComponentManagedSetRequest,
	lifecycleRequest cp.ComponentManagedLifecycleRequest,
	desired []string,
	plan assignmentPolicyPlan,
	planEnvelope cp.ComponentManagedPlan,
	store cp.ComponentManagedMutationStore,
) (cp.ComponentManagedMutationResult, error) {
	if request.PackName != plan.OwnerPack {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy set owner changed")
	}
	desiredSet, err := assignmentPolicyDesiredSet(request.PackName, desired)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	roots := make([]assignmentPolicyRootLock, 0, len(plan.StaleClaims))
	for _, stale := range plan.StaleClaims {
		roots = append(roots, assignmentPolicyRootLock{
			PermissionSetID: stale.PermissionSetID,
			PermissionSet:   stale.PermissionSet,
			OwnerPack:       stale.DefinitionOwnerPack,
		})
	}
	if err := lockAssignmentPolicyRoots(ctx, store, roots); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if err := validateAssignmentPolicyPlanFresh(
		ctx, cp.ComponentManagedScopeSet, lifecycleRequest, planEnvelope, store, nil, nil,
	); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	changed := 0
	for _, stale := range plan.StaleClaims {
		if _, keep := desiredSet[assignmentPolicyDatabaseIdentity(stale.PolicyKey)]; keep {
			continue
		}
		cleared, err := clearAndReleaseAssignmentPolicyClaim(ctx, store, request.PackName, stale.PolicyKey, stale)
		if err != nil {
			return cp.ComponentManagedMutationResult{}, err
		}
		changed += cleared
	}
	if changed == 0 {
		return cp.ComponentManagedMutationResult{Disposition: cp.ComponentManagedMutationNoChange}, nil
	}
	return cp.ComponentManagedMutationResult{Disposition: cp.ComponentManagedMutationSafeProjectionStaged}, nil
}

func clearAndReleaseAssignmentPolicyClaim(
	ctx context.Context,
	store cp.ComponentManagedMutationStore,
	ownerPack, policyKey string,
	stale assignmentPolicyStaleClaim,
) (int, error) {
	claimRows, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyClaimTable,
		[]string{"Id", "PermissionSetId", "OwnerPack", "PolicyKey"},
		cp.ComponentRow{"PermissionSetId": stale.PermissionSetID}, 1, []string{"PermissionSetId"},
	))
	if err != nil {
		return 0, err
	}
	if len(claimRows) == 0 {
		return 0, nil
	}
	owner, _ := assignmentPolicyRequiredString(claimRows[0], "OwnerPack")
	key, _ := assignmentPolicyRequiredString(claimRows[0], "PolicyKey")
	if !assignmentPolicySourceIdentityEqual(owner, key, ownerPack, policyKey) {
		return 0, fmt.Errorf("assignment policy claim owner changed during clear-and-release")
	}
	changed := 0
	deleted, err := store.DeleteRows(ctx, cp.ComponentManagedDelete{
		Table:               schemacatalog.AssignmentPolicySelectorTable,
		Match:               cp.ComponentRow{"PermissionSetId": stale.PermissionSetID},
		MaximumAffectedRows: assignmentPolicyMaximumRows,
	})
	if err != nil {
		return 0, err
	}
	changed += int(deleted)
	stateRows, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyTargetStateTable,
		[]string{"Id", "PermissionSetId", "Suspended", "WorkGeneration", "AppliedGeneration", "ResolutionState"},
		cp.ComponentRow{"PermissionSetId": stale.PermissionSetID}, 1, []string{"PermissionSetId"},
	))
	if err != nil {
		return 0, err
	}
	if len(stateRows) != 1 {
		return 0, fmt.Errorf("assignment policy claim has no durable target state")
	}
	state, err := assignmentPolicyStateFromRow(stateRows[0])
	if err != nil {
		return 0, err
	}
	generation, err := nextAssignmentPolicyGeneration(state.WorkGeneration)
	if err != nil {
		return 0, err
	}
	assignmentChanged, err := reconcileAssignmentPolicyAssignments(
		ctx,
		store,
		ownerPack,
		policyKey,
		stale.PermissionSetID,
		generation,
		false,
		nil,
		true,
		nil,
	)
	if err != nil {
		return 0, err
	}
	changed += assignmentChanged
	finalized, err := finalizeReleasedAssignmentPolicyTombstones(
		ctx, store, ownerPack, policyKey, stale.PermissionSetID, generation,
	)
	if err != nil {
		return 0, err
	}
	changed += finalized
	updated, err := store.UpdateRows(ctx, cp.ComponentManagedUpdate{
		Table: schemacatalog.AssignmentPolicyTargetStateTable,
		Match: cp.ComponentRow{"Id": state.ID},
		Values: cp.ComponentRow{
			"WorkGeneration": generation, "AppliedGeneration": generation,
			"ResolutionState":  assignmentPolicyResolutionRemoved,
			"ResolutionDigest": assignmentPolicyDigest(assignmentPolicyResolutionRemoved),
			"NextAttemptAt":    nil, "RetryCount": uint64(0),
			"LastFailureCode": nil, "LastFailureDigest": nil,
		},
		CurrentTimestampColumns: []string{"LastModifiedDate"}, MaximumAffectedRows: 1,
	})
	if err := assignmentPolicyRequireExactWrite(
		"update", schemacatalog.AssignmentPolicyTargetStateTable, updated, err,
	); err != nil {
		return 0, err
	}
	changed++
	target, err := PermissionSetDefinitionManagedTarget(stale.PermissionSet)
	if err != nil {
		return 0, err
	}
	receiptChanged, err := upsertAssignmentPolicyReleaseReceipt(
		ctx, store, ownerPack, policyKey, stale.PermissionSetID, generation, target,
	)
	if err != nil {
		return 0, err
	}
	changed += receiptChanged
	deleted, err = store.DeleteRows(ctx, cp.ComponentManagedDelete{
		Table: schemacatalog.AssignmentPolicyClaimTable,
		Match: cp.ComponentRow{"Id": stale.ID}, MaximumAffectedRows: 1,
	})
	if err := assignmentPolicyRequireExactWrite(
		"delete", schemacatalog.AssignmentPolicyClaimTable, deleted, err,
	); err != nil {
		return 0, err
	}
	return changed + 1, nil
}

func upsertAssignmentPolicyReleaseReceipt(
	ctx context.Context,
	store cp.ComponentManagedMutationStore,
	ownerPack, policyKey, permissionSetID string,
	generation uint64,
	target cp.ComponentManagedTarget,
) (int, error) {
	receipts, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyReleaseReceiptTable,
		[]string{"Id", "OwnerPack", "PolicyKey", "PermissionSetId"},
		cp.ComponentRow{
			"OwnerPack": ownerPack, "PolicyKey": policyKey, "PermissionSetId": permissionSetID,
		},
		1,
		[]string{"OwnerPack", "PolicyKey", "PermissionSetId"},
	))
	if err != nil {
		return 0, err
	}
	digest := assignmentPolicyExactEmptyDigest(target, permissionSetID, generation)
	values := cp.ComponentRow{
		"TargetDomain":       target.TargetDomain,
		"PhysicalKey":        append([]byte(nil), target.PhysicalKeyBytes...),
		"PermissionSetId":    permissionSetID,
		"ReleasedGeneration": generation,
		"ExactEmptyDigest":   digest,
	}
	if len(receipts) == 1 {
		actualOwner, rowErr := assignmentPolicyRequiredString(receipts[0], "OwnerPack")
		if rowErr != nil {
			return 0, rowErr
		}
		actualKey, rowErr := assignmentPolicyRequiredString(receipts[0], "PolicyKey")
		if rowErr != nil {
			return 0, rowErr
		}
		if !assignmentPolicySourceIdentityEqual(actualOwner, actualKey, ownerPack, policyKey) {
			return 0, fmt.Errorf("assignment policy release receipt belongs to another source")
		}
		actualPermissionSetID, rowErr := assignmentPolicyRequiredString(receipts[0], "PermissionSetId")
		if rowErr != nil {
			return 0, rowErr
		}
		if actualPermissionSetID != permissionSetID {
			return 0, fmt.Errorf("assignment policy release receipt belongs to another target")
		}
		id, rowErr := assignmentPolicyRequiredString(receipts[0], "Id")
		if rowErr != nil {
			return 0, rowErr
		}
		affected, updateErr := store.UpdateRows(ctx, cp.ComponentManagedUpdate{
			Table:  schemacatalog.AssignmentPolicyReleaseReceiptTable,
			Match:  cp.ComponentRow{"Id": id},
			Values: values,
			CurrentTimestampColumns: []string{
				"ReleasedAt", "LastModifiedDate",
			},
			MaximumAffectedRows: 1,
		})
		if err := assignmentPolicyRequireExactWrite(
			"update", schemacatalog.AssignmentPolicyReleaseReceiptTable, affected, updateErr,
		); err != nil {
			return 0, err
		}
		return 1, nil
	}
	id, err := store.NewID()
	if err != nil {
		return 0, err
	}
	values["Id"] = id
	values["OwnerPack"] = ownerPack
	values["PolicyKey"] = policyKey
	affected, err := store.InsertRows(ctx, cp.ComponentManagedInsertBatch{
		Table: schemacatalog.AssignmentPolicyReleaseReceiptTable,
		Rows: []cp.ComponentManagedInsertRow{{
			LogicalKey: cp.ComponentRow{
				"OwnerPack": ownerPack, "PolicyKey": policyKey, "PermissionSetId": permissionSetID,
			},
			Values: values,
		}},
		CurrentTimestampColumns: []string{"ReleasedAt", "CreatedDate", "LastModifiedDate"},
	})
	if err := assignmentPolicyRequireExactWrite(
		"insert", schemacatalog.AssignmentPolicyReleaseReceiptTable, affected, err,
	); err != nil {
		return 0, err
	}
	return 1, nil
}

func consumeAssignmentPolicyReleaseReceiptForTarget(
	ctx context.Context,
	store cp.ComponentManagedMutationStore,
	ownerPack, policyKey, permissionSetID string,
) (int, *assignmentPolicyReleaseProof, error) {
	rows, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyReleaseReceiptTable,
		[]string{
			"Id", "OwnerPack", "PolicyKey", "TargetDomain", "PhysicalKey",
			"PermissionSetId", "ReleasedGeneration", "ExactEmptyDigest",
		},
		cp.ComponentRow{
			"OwnerPack": ownerPack, "PolicyKey": policyKey, "PermissionSetId": permissionSetID,
		},
		1,
		[]string{"OwnerPack", "PolicyKey", "PermissionSetId"},
	))
	if err != nil {
		return 0, nil, err
	}
	if len(rows) == 0 {
		return 0, nil, nil
	}
	actualOwner, err := assignmentPolicyRequiredString(rows[0], "OwnerPack")
	if err != nil {
		return 0, nil, err
	}
	actualKey, err := assignmentPolicyRequiredString(rows[0], "PolicyKey")
	if err != nil {
		return 0, nil, err
	}
	if !assignmentPolicySourceIdentityEqual(actualOwner, actualKey, ownerPack, policyKey) {
		return 0, nil, fmt.Errorf("assignment policy release receipt belongs to another source")
	}
	actualPermissionSetID, err := assignmentPolicyRequiredString(rows[0], "PermissionSetId")
	if err != nil {
		return 0, nil, err
	}
	if actualPermissionSetID != permissionSetID {
		return 0, nil, fmt.Errorf("assignment policy release receipt belongs to another target")
	}
	releasedGeneration, err := assignmentPolicyRequiredUint64(rows[0], "ReleasedGeneration")
	if err != nil {
		return 0, nil, err
	}
	if err := validateAssignmentPolicyReleasedTombstoneTransfer(
		ctx, store, actualOwner, actualKey, actualPermissionSetID, releasedGeneration,
	); err != nil {
		return 0, nil, err
	}
	receiptID, err := assignmentPolicyRequiredString(rows[0], "Id")
	if err != nil {
		return 0, nil, err
	}
	deleted, err := store.DeleteRows(ctx, cp.ComponentManagedDelete{
		Table: schemacatalog.AssignmentPolicyReleaseReceiptTable,
		Match: cp.ComponentRow{"Id": receiptID}, MaximumAffectedRows: 1,
	})
	if err := assignmentPolicyRequireExactWrite(
		"delete", schemacatalog.AssignmentPolicyReleaseReceiptTable, deleted, err,
	); err != nil {
		return 0, nil, err
	}
	return 1, &assignmentPolicyReleaseProof{
		OwnerPack: actualOwner, PolicyKey: actualKey,
		PermissionSetID: actualPermissionSetID, ReleasedGeneration: releasedGeneration,
	}, nil
}

func assignmentPolicyExactEmptyDigest(
	target cp.ComponentManagedTarget,
	permissionSetID string,
	generation uint64,
) []byte {
	canonical := []byte(fmt.Sprintf(
		"nexuscrm.permission-set-assignment-policy/exact-empty/v1\x00%s\x00%x\x00%s\x00%d",
		target.TargetDomain,
		target.PhysicalKeyBytes,
		permissionSetID,
		generation,
	))
	digest := sha256.Sum256(canonical)
	return append([]byte(nil), digest[:]...)
}

func projectPermissionSetAssignmentPolicy(
	ctx context.Context,
	scope cp.ComponentManagedScope,
	request cp.ComponentManagedLifecycleRequest,
	store cp.ComponentManagedReadStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (cp.ComponentManagedProjection, error) {
	if err := request.Validate(scope); err != nil {
		return cp.ComponentManagedProjection{}, err
	}
	eligibilityBudget := newAssignmentPolicyEligibilityReadBudget(
		assignmentPolicyManagedBudget().MaxCurrentItems,
	)
	switch scope {
	case cp.ComponentManagedScopeItem:
		policy, _, _, err := assignmentPolicyExpectedRequest(*request.Item)
		if err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		snapshot, err := readAssignmentPolicyTarget(ctx, store, policy.PermissionSet)
		if err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		resolution, profiles, eligible, _, err := projectAssignmentPolicyEligibility(
			ctx,
			store,
			snapshot.PermissionSetID,
			policy.ProfilesAnyOf,
			eligibility,
			eligibilityBudget,
		)
		if err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		_, _, liveEligible, _, err := projectAssignmentPolicyEligibility(
			ctx,
			store,
			snapshot.PermissionSetID,
			snapshot.Profiles,
			eligibility,
			eligibilityBudget,
		)
		if err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		snapshot.Eligible = liveEligible
		expected := assignmentPolicyProjectionFromSnapshot(
			snapshot, true, request.Item.PackName, request.Item.Component.BusinessKey,
			profiles, eligible, resolution,
		)
		expected.ActiveAssignments = assignmentPolicyRetainedSubjectIDs(
			expected.EligibleAssignees,
			snapshot.Assignments,
		)
		live := assignmentPolicyProjectionFromSnapshot(
			snapshot, snapshot.ClaimID != "", snapshot.OwnerPack, snapshot.PolicyKey,
			snapshot.Profiles, snapshot.Eligible, snapshot.Resolution,
		)
		if snapshot.State != nil &&
			snapshot.State.WorkGeneration > snapshot.State.AppliedGeneration &&
			!snapshot.State.Suspended &&
			resolution == assignmentPolicyResolutionResolved {
			desired := make(map[string]struct{}, len(expected.ActiveAssignments))
			for _, assignee := range expected.ActiveAssignments {
				desired[assignmentPolicyDatabaseIdentity(assignee)] = struct{}{}
			}
			onlyMissingGrants := true
			for _, assignee := range live.ActiveAssignments {
				if _, present := desired[assignmentPolicyDatabaseIdentity(assignee)]; !present {
					onlyMissingGrants = false
					break
				}
			}
			if onlyMissingGrants {
				expected.ActiveAssignments = append([]string{}, live.ActiveAssignments...)
			}
		}
		expectedBytes, _ := json.Marshal(expected)
		liveBytes, _ := json.Marshal(live)
		return cp.ComponentManagedProjection{
			Identity: assignmentPolicyItemProjectionIdentity(*request.Item),
			Expected: expectedBytes, Live: liveBytes,
		}, nil
	case cp.ComponentManagedScopeSet:
		desired, err := assignmentPolicyDesiredSet(request.Set.PackName, request.DesiredBusinessKeys)
		if err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		if err := verifyAssignmentPolicyReleasedTargets(ctx, store, request.Set.PackName); err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		rows, err := readAssignmentPolicyRows(ctx, store, cp.ComponentManagedRowQuery{
			Table: schemacatalog.AssignmentPolicyClaimTable, Columns: []string{"PermissionSetId", "PolicyKey"},
			Equal:             cp.ComponentRow{"OwnerPack": request.Set.PackName},
			OrderBy:           []cp.ComponentManagedOrder{{Column: "PermissionSetId", Direction: cp.ComponentManagedOrderAscending}},
			LogicalKeyColumns: []string{"PermissionSetId"},
			MaximumRows:       assignmentPolicyMaximumRows,
		})
		if err != nil {
			return cp.ComponentManagedProjection{}, err
		}
		liveKeys := make([]string, 0, len(rows))
		for _, row := range rows {
			key, rowErr := assignmentPolicyRequiredString(row, "PolicyKey")
			if rowErr != nil {
				return cp.ComponentManagedProjection{}, rowErr
			}
			liveKeys = append(liveKeys, assignmentPolicyProjectionIdentityKey(key))
		}
		sort.Strings(liveKeys)
		desiredKeys := make([]string, 0, len(desired))
		for identity := range desired {
			desiredKeys = append(desiredKeys, hex.EncodeToString([]byte(identity)))
		}
		sort.Strings(desiredKeys)
		expectedBytes, _ := json.Marshal(assignmentPolicySetProjection{OwnerPack: request.Set.PackName, PolicyKeys: desiredKeys})
		liveBytes, _ := json.Marshal(assignmentPolicySetProjection{OwnerPack: request.Set.PackName, PolicyKeys: liveKeys})
		return cp.ComponentManagedProjection{
			Identity: assignmentPolicySetProjectionIdentity(*request.Set),
			Expected: expectedBytes, Live: liveBytes,
		}, nil
	default:
		return cp.ComponentManagedProjection{}, fmt.Errorf("assignment policy scope %q is unsupported", scope)
	}
}

func verifyAssignmentPolicyReleasedTargets(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	ownerPack string,
) error {
	receipts, err := readAssignmentPolicyRows(ctx, store, cp.ComponentManagedRowQuery{
		Table: schemacatalog.AssignmentPolicyReleaseReceiptTable,
		Columns: []string{
			"Id", "OwnerPack", "PolicyKey", "TargetDomain", "PhysicalKey",
			"PermissionSetId", "ReleasedGeneration", "ExactEmptyDigest",
		},
		Equal: cp.ComponentRow{"OwnerPack": ownerPack},
		OrderBy: []cp.ComponentManagedOrder{
			{Column: "PolicyKey", Direction: cp.ComponentManagedOrderAscending},
			{Column: "PermissionSetId", Direction: cp.ComponentManagedOrderAscending},
		},
		LogicalKeyColumns: []string{"PolicyKey", "PermissionSetId"},
		MaximumRows:       assignmentPolicyMaximumRows,
	})
	if err != nil {
		return err
	}
	for _, receipt := range receipts {
		policyKey, err := assignmentPolicyRequiredString(receipt, "PolicyKey")
		if err != nil {
			return err
		}
		targetDomain, err := assignmentPolicyRequiredString(receipt, "TargetDomain")
		if err != nil {
			return err
		}
		if targetDomain != permissionSetDefinitionManagedTargetDomain {
			return fmt.Errorf("assignment policy release receipt %s has target domain %q", policyKey, targetDomain)
		}
		physicalKey := append([]byte(nil), assignmentPolicyBytes(receipt["PhysicalKey"])...)
		if len(physicalKey) == 0 {
			return fmt.Errorf("assignment policy release receipt %s has no physical key", policyKey)
		}
		permissionSetID, err := assignmentPolicyRequiredString(receipt, "PermissionSetId")
		if err != nil {
			return err
		}
		generation, err := assignmentPolicyRequiredUint64(receipt, "ReleasedGeneration")
		if err != nil {
			return err
		}
		target := cp.ComponentManagedTarget{
			TargetDomain: targetDomain, PhysicalKeyBytes: physicalKey,
		}
		wantDigest := assignmentPolicyExactEmptyDigest(target, permissionSetID, generation)
		if !bytes.Equal(assignmentPolicyBytes(receipt["ExactEmptyDigest"]), wantDigest) {
			return fmt.Errorf("assignment policy release receipt %s exact-empty digest is invalid", policyKey)
		}

		claims, err := store.ReadRows(ctx, assignmentPolicyQuery(
			schemacatalog.AssignmentPolicyClaimTable,
			[]string{"Id", "OwnerPack", "PolicyKey"},
			cp.ComponentRow{"PermissionSetId": permissionSetID}, 1, nil,
		))
		if err != nil {
			return err
		}
		if len(claims) != 0 {
			claimOwner, ownerErr := assignmentPolicyRequiredString(claims[0], "OwnerPack")
			if ownerErr != nil {
				return ownerErr
			}
			claimKey, keyErr := assignmentPolicyRequiredString(claims[0], "PolicyKey")
			if keyErr != nil {
				return keyErr
			}
			if assignmentPolicySourceIdentityEqual(claimOwner, claimKey, ownerPack, policyKey) {
				return fmt.Errorf("active assignment policy %s/%s retains a release receipt", ownerPack, policyKey)
			}
			// A later policy may legitimately claim and change the same target;
			// the receipt remains bounded historical evidence for this source.
			continue
		}

		stateRows, err := store.ReadRows(ctx, assignmentPolicyQuery(
			schemacatalog.AssignmentPolicyTargetStateTable,
			[]string{
				"Id", "TargetDomain", "PhysicalKey", "PermissionSetId", "Suspended",
				"WorkGeneration", "AppliedGeneration", "ResolutionState",
			},
			cp.ComponentRow{"PermissionSetId": permissionSetID}, 1, nil,
		))
		if err != nil {
			return err
		}
		if len(stateRows) != 1 {
			return fmt.Errorf("released assignment policy %s/%s has no durable target state", ownerPack, policyKey)
		}
		state, err := assignmentPolicyStateFromRow(stateRows[0])
		if err != nil {
			return err
		}
		if state.ResolutionState != assignmentPolicyResolutionRemoved ||
			state.WorkGeneration != state.AppliedGeneration || state.WorkGeneration < generation {
			return fmt.Errorf("released assignment policy %s/%s has unconverged target state", ownerPack, policyKey)
		}
		stateTargetID, err := assignmentPolicyRequiredString(stateRows[0], "PermissionSetId")
		if err != nil {
			return err
		}
		stateTargetDomain, err := assignmentPolicyRequiredString(stateRows[0], "TargetDomain")
		if err != nil {
			return err
		}
		if stateTargetID != permissionSetID || stateTargetDomain != targetDomain ||
			!bytes.Equal(assignmentPolicyBytes(stateRows[0]["PhysicalKey"]), physicalKey) {
			return fmt.Errorf("released assignment policy %s/%s target-state identity differs from its receipt", ownerPack, policyKey)
		}
		selectors, err := store.ReadRows(ctx, assignmentPolicyQuery(
			schemacatalog.AssignmentPolicySelectorTable,
			[]string{"Id"}, cp.ComponentRow{"PermissionSetId": permissionSetID}, 1, nil,
		))
		if err != nil {
			return err
		}
		if len(selectors) != 0 {
			return fmt.Errorf("released assignment policy %s/%s retains selectors", ownerPack, policyKey)
		}
		assignments, err := store.ReadRows(ctx, assignmentPolicyQuery(
			"PermissionSetAssignment", []string{"Id"},
			cp.ComponentRow{"PermissionSetId": permissionSetID, "IsDeleted": false}, 1, nil,
		))
		if err != nil {
			return err
		}
		if len(assignments) != 0 {
			return fmt.Errorf("released assignment policy %s/%s retains an active assignment", ownerPack, policyKey)
		}
	}
	return nil
}

func assignmentPolicyProjectionFromSnapshot(
	snapshot assignmentPolicyTargetSnapshot,
	present bool,
	owner, key string,
	profiles, eligible []string,
	resolution string,
) assignmentPolicyLiveProjection {
	active := make([]string, 0, len(snapshot.Assignments))
	for _, row := range snapshot.Assignments {
		if !row.IsDeleted {
			active = append(active, row.Assignee)
		}
	}
	sortAssignmentPolicySubjectIDs(active)
	suspended := snapshot.State != nil && snapshot.State.Suspended
	if suspended || resolution != assignmentPolicyResolutionResolved {
		eligible = []string{}
	}
	projection := assignmentPolicyLiveProjection{
		Present: present, PolicyKey: key, OwnerPack: owner,
		PermissionSet: snapshot.PermissionSet, ProfilesAnyOf: append([]string(nil), profiles...),
		EligibleAssignees: append([]string(nil), eligible...), ActiveAssignments: active,
		Suspended: suspended, ResolutionState: resolution,
	}
	if snapshot.State != nil {
		projection.WorkGeneration = snapshot.State.WorkGeneration
		projection.AppliedGeneration = snapshot.State.AppliedGeneration
	}
	if !projection.Present {
		projection.PolicyKey, projection.OwnerPack = "", ""
	}
	return projection
}

func assignmentPolicyRetainedSubjectIDs(
	desired []string,
	assignments map[string]assignmentPolicyAssignmentRow,
) []string {
	retained := make([]string, 0, len(desired))
	for _, subjectID := range desired {
		if assignment, present := assignments[assignmentPolicyDatabaseIdentity(subjectID)]; present {
			retained = append(retained, assignment.Assignee)
			continue
		}
		retained = append(retained, subjectID)
	}
	sortAssignmentPolicySubjectIDs(retained)
	return retained
}

func assignmentPolicySetTarget(ownerPack string) cp.ComponentManagedTarget {
	return cp.ComponentManagedTarget{
		TargetDomain:     assignmentPolicySetTargetDomain,
		PhysicalKeyBytes: []byte(assignmentPolicyDatabaseIdentity(ownerPack)),
	}
}

func assignmentPolicyDesiredSet(ownerPack string, keys []string) (map[string]string, error) {
	if len(keys) > assignmentPolicyMaximumRows {
		return nil, fmt.Errorf(
			"desired assignment policy set contains %d entries; maximum is %d",
			len(keys), assignmentPolicyMaximumRows,
		)
	}
	desired := make(map[string]string, len(keys))
	for _, key := range keys {
		if _, err := NewPermissionSetAssignmentPolicySource(ownerPack, key); err != nil {
			return nil, err
		}
		identity := assignmentPolicyDatabaseIdentity(key)
		if previous, duplicate := desired[identity]; duplicate {
			return nil, fmt.Errorf(
				"desired assignment policy keys %q and %q collide under database collation",
				previous, key,
			)
		}
		desired[identity] = key
	}
	return desired, nil
}

func assignmentPolicySourceIdentityEqual(ownerPack, policyKey, otherOwnerPack, otherPolicyKey string) bool {
	return assignmentPolicyDatabaseIdentityEqual(ownerPack, otherOwnerPack) &&
		assignmentPolicyDatabaseIdentityEqual(policyKey, otherPolicyKey)
}

func assignmentPolicyCapabilities() []cp.ComponentManagedCapability {
	return []cp.ComponentManagedCapability{
		cp.ComponentManagedCapabilityExactSet,
		cp.ComponentManagedCapabilityTargetSerialization,
		cp.ComponentManagedCapabilityStructuredMutation,
		cp.ComponentManagedCapabilityEffects,
		cp.ComponentManagedCapabilityEvidence,
		cp.ComponentManagedCapabilityFreshProjection,
	}
}

func assignmentPolicyEffects() []cp.ComponentManagedEffectRequirement {
	return []cp.ComponentManagedEffectRequirement{{
		Class: PermissionSetDefinitionPermissionStateEffectClass,
		Triggers: []cp.ComponentManagedMutationDisposition{
			cp.ComponentManagedMutationDesiredProjectionStaged,
			cp.ComponentManagedMutationSafeProjectionStaged,
		},
	}}
}

func assignmentPolicyItemProjectionIdentity(request cp.ComponentManagedRequest) []byte {
	identity := []byte(string(PermissionSetAssignmentPolicyComponentKind) + "\x00item\x00")
	return append(identity, assignmentPolicySourceIdentityBytes(request.PackName, request.Component.BusinessKey)...)
}

func assignmentPolicySetProjectionIdentity(request cp.ComponentManagedSetRequest) []byte {
	identity := []byte(string(PermissionSetAssignmentPolicyComponentKind) + "\x00set\x00")
	return append(identity, []byte(assignmentPolicyDatabaseIdentity(request.PackName))...)
}

func assignmentPolicyProjectionIdentityKey(value string) string {
	return hex.EncodeToString([]byte(assignmentPolicyDatabaseIdentity(value)))
}

func permissionSetAssignmentPolicyLifecycleProvider(
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) cp.ComponentManagedLifecycleProvider {
	return cp.ComponentManagedLifecycleProvider{
		Plan: func(
			ctx context.Context,
			scope cp.ComponentManagedScope,
			request cp.ComponentManagedLifecycleRequest,
			store cp.ComponentManagedReadStore,
		) (cp.ComponentManagedPlan, error) {
			return planPermissionSetAssignmentPolicy(
				ctx,
				scope,
				request,
				store,
				eligibility,
				newAssignmentPolicyEligibilityReadBudget(
					assignmentPolicyManagedBudget().MaxCurrentItems,
				),
			)
		},
		Mutate: func(
			ctx context.Context,
			scope cp.ComponentManagedScope,
			request cp.ComponentManagedLifecycleRequest,
			plan cp.ComponentManagedPlan,
			store cp.ComponentManagedMutationStore,
		) (cp.ComponentManagedMutationResult, error) {
			return mutatePermissionSetAssignmentPolicy(
				ctx, scope, request, plan, store, eligibility,
			)
		},
		Project: func(
			ctx context.Context,
			scope cp.ComponentManagedScope,
			request cp.ComponentManagedLifecycleRequest,
			store cp.ComponentManagedReadStore,
		) (cp.ComponentManagedProjection, error) {
			return projectPermissionSetAssignmentPolicy(
				ctx, scope, request, store, eligibility,
			)
		},
	}
}
