// Package catalogreconcile composes one immutable Catalog serving selection
// from the existing Catalog App authority and metadata compiler owners.
//
// It is deployment orchestration only. It owns no metadata facts, serving
// lookup, App semantics, or Runtime fallback path.
package catalogreconcile

import (
	"context"
	"fmt"
	"reflect"
	"slices"
	"sort"
	"strings"

	"github.com/nexuscrm/kernel/pkg/formula"
	"github.com/nexuscrm/metadata/catalogsnapshot"
	"github.com/nexuscrm/shared/pkg/fieldprovenance"
	"github.com/nexuscrm/shared/pkg/metadatarel"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/appauthority"
	consumerv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/recordsguard"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/approvalv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/auditlogv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/bulkingestv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commandv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/effectivepermissionsv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/filesv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/flowv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/listviewv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/outboundintentv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/pagelayoutresolutionv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/permissionauthoringv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordaccessv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordattachmentsv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recorddefaultsv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordmutationv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordviewv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recyclebinmutationv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recyclebinv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/relatedcountsv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/reportv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/searchv1"
	"github.com/pingcap-inc/nexuscrm-controlplane/catalogapp"
)

// MetadataReader is the existing metadata repository surface required to
// compile the record-access Runtime closure. Implementations must honor the
// transaction carried by ctx.
type MetadataReader interface {
	GetAllSchemas(context.Context) ([]*models.ObjectMetadata, error)
	GetAllRelationships(context.Context) ([]*models.Relationship, error)
	GetSharingRules(context.Context, string) ([]*models.SharingRule, error)
}

// BulkSharingRuleMetadataReader is an optional publication optimization. It
// returns the same authoritative rows as GetSharingRules, but avoids one
// remote database round trip per installed object.
type BulkSharingRuleMetadataReader interface {
	GetAllSharingRules(context.Context) ([]*models.SharingRule, error)
}

// MutationMetadataReader is the additional generic Catalog closure required
// only when the release grants the neutral record-mutation capability. Every
// fact is read under the same transaction as object, relationship, and sharing
// metadata; reconcile remains a compiler/consumer and never becomes another
// metadata authoring surface.
type MutationMetadataReader interface {
	GetAllValidationRules(context.Context) ([]*models.ValidationRule, error)
	RecordTypeMetadataReader
	EffectiveFlowMetadataReader
	FieldMappingMetadataReader
	GetActiveTriggerSubscriptions(context.Context) ([]catalogsnapshot.TriggerSubscription, error)
	AutoNumberMetadataReader
}

// AutoNumberMetadataReader supplies the server-default facts needed by both
// mutation and read-only create requirements, in the same source transaction.
type AutoNumberMetadataReader interface {
	GetAutoNumberRules(context.Context) ([]catalogsnapshot.AutoNumberRule, error)
}

// RecordTypeMetadataReader is the least-privilege metadata source shared by
// record mutation and effective-permission publication. Permission-only
// reconcile must not require validation, Flow, trigger, or other mutation
// authority merely to publish active record-type identities.
type RecordTypeMetadataReader interface {
	GetRecordTypes(context.Context, string) ([]*models.RecordType, error)
}

// EffectiveFlowMetadataReader is shared by mutation projection and
// AppMetadataView V2 publication. Effective Flow authority is not owned by the
// mutation capability: a V2 consumer must observe the same active override
// even when its selected Runtime capability does not include mutation.
type EffectiveFlowMetadataReader interface {
	GetAllFlowDefinitions(context.Context) ([]*models.FlowDefinition, error)
	GetFlowVersions(context.Context, string) ([]*models.FlowVersion, error)
}

// FieldMappingMetadataReader supplies the lookup projections used to seal an
// effective Flow. Flow publication and mutation projection must consume the
// same sealed behavior even when only AppMetadata is selected.
type FieldMappingMetadataReader interface {
	GetFieldMappingRules(context.Context) ([]catalogsnapshot.FieldMappingRule, error)
}

// BulkRecordTypeMetadataReader is the shared bulk optimization for mutation
// and effective-permission publication. Readers that do not implement it
// retain the existing per-object path, keeping the compiler compatible with
// N-1 adapters.
type BulkRecordTypeMetadataReader interface {
	GetAllRecordTypes(context.Context) ([]*models.RecordType, error)
}

type CreateSourceGuardMetadataReader interface {
	GetCreateFromSourceGuardEntries(context.Context, string) ([]recordsguard.CreateFromSourceGuardEntry, error)
}

type EffectiveObjectSearchMetadataReader interface {
	GetRuntimeSearchAllDefaultFields(
		context.Context,
	) ([]searchAllDefaultFieldsDeclaration, error)
}

// EffectiveFormulaFunctionMetadataReader resolves executable formula
// declarations from the immutable pack generations selected by the same
// transaction as the Catalog revision being compiled.
type EffectiveFormulaFunctionMetadataReader interface {
	GetRuntimeFormulaFunctionBundles(context.Context) ([]formula.FunctionBundle, error)
}

type EffectiveApplicationNavigationMetadataReader interface {
	GetApplicationDefinitions(context.Context) ([]*models.AppConfig, error)
}

// InTransaction runs fn in one database snapshot and commits only when fn
// succeeds. The production adapter is persistence.TransactionManager.WithTransaction.
type InTransaction func(context.Context, func(context.Context) error) error

// MetadataSelection names the Catalog-owned immutable lineage and projection
// scope. Object names are derived from the effective repository snapshot; a
// deployer cannot supply a competing object allowlist. Capability identity
// selects a projection profile. Any capability-owned App facts enter through
// the separately verified AppRelease argument, never a source checkout.
type MetadataSelection struct {
	OrgID                string
	AppInstallationID    string
	RuntimeCapabilityID  string
	RuntimeCapabilityIDs []string
	IntegrationBindings  []catalogapp.IntegrationBindingSelection
	OutboundMailRoutes   []OutboundMailRouteConfig
	CatalogRevision      uint64
	SchemaGeneration     uint64
	EngineGeneration     uint64
	ApprovalDefinitions  []catalogsnapshot.ApprovalDefinitionInput
}

// ReadEffectiveMetadata reads the complete effective object and sharing-rule
// closure from exactly one database transaction. It preserves explicit
// relationship authority and derives the sharing-parent edges required by the
// record-access projection and folds the verified AppRelease's closed
// capability facts into the same compiler input. It emits no source-backed
// serving handle.
func ReadEffectiveMetadata(
	ctx context.Context,
	withinTransaction InTransaction,
	reader MetadataReader,
	selection MetadataSelection,
	release *appauthority.VerifiedPackage,
) (catalogsnapshot.EffectiveMetadata, error) {
	result, err := readEffectiveMetadata(
		ctx, withinTransaction, reader, selection, release, "",
	)
	return result.metadata, err
}

type effectiveMetadataRead struct {
	metadata                     catalogsnapshot.EffectiveMetadata
	components                   []catalogapp.EffectiveMetadataComponent
	historicalRetryComponentSets [][]catalogapp.EffectiveMetadataComponent
}

func readEffectiveMetadata(
	ctx context.Context,
	withinTransaction InTransaction,
	reader MetadataReader,
	selection MetadataSelection,
	release *appauthority.VerifiedPackage,
	effectiveMetadataCapability string,
) (effectiveMetadataRead, error) {
	if withinTransaction == nil {
		return effectiveMetadataRead{}, fmt.Errorf("Catalog reconcile transaction runner is required")
	}
	if reader == nil {
		return effectiveMetadataRead{}, fmt.Errorf("Catalog reconcile metadata reader is required")
	}
	if err := validateSelection(selection); err != nil {
		return effectiveMetadataRead{}, err
	}
	var recordViewRelease recordViewReleaseDocument
	if selectionIncludesRecordViewAttachmentFacts(selection) {
		var err error
		recordViewRelease, err = readRecordViewReleaseDocument(release)
		if err != nil {
			return effectiveMetadataRead{}, err
		}
	}
	includeCompleteRelationships :=
		selectionIncludesCapability(selection, queryv1.CapabilityName) ||
			selectionIncludesCapability(selection, recyclebinv1.CapabilityName) ||
			selectionIncludesCapability(selection, relatedcountsv1.CapabilityName) ||
			selectionIncludesCapability(selection, searchv1.CapabilityName) ||
			selectionIncludesMutationFacts(selection) ||
			selectionIncludesRecordViewAttachmentFacts(selection)

	var result effectiveMetadataRead
	err := withinTransaction(ctx, func(txCtx context.Context) error {
		var effectiveFlows []effectiveActiveFlow
		var fieldMappings []catalogsnapshot.FieldMappingRule
		objects, err := reader.GetAllSchemas(txCtx)
		if err != nil {
			return fmt.Errorf("read effective object metadata: %w", err)
		}
		if len(objects) == 0 {
			return fmt.Errorf("effective metadata contains no objects")
		}
		objects, err = decorateEffectiveCompoundFields(txCtx, objects, release)
		if err != nil {
			return fmt.Errorf("bind effective compound metadata: %w", err)
		}
		compoundRoles, err := compoundComponentRolesFromRelease(release)
		if err != nil {
			return fmt.Errorf("bind effective compound component roles: %w", err)
		}
		objects = materializeEffectiveFieldProvenance(objects)
		explicitRelationships, err := reader.GetAllRelationships(txCtx)
		if err != nil {
			return fmt.Errorf("read effective relationship metadata: %w", err)
		}
		explicitByChild := make(map[string][]*models.Relationship)
		for i, relationship := range explicitRelationships {
			if relationship == nil {
				return fmt.Errorf("explicit relationship metadata[%d] is nil", i)
			}
			childKey := strings.ToLower(strings.TrimSpace(relationship.ChildObjectAPIName))
			explicitByChild[childKey] = append(explicitByChild[childKey], relationship)
		}
		installedObjects := make(map[string]struct{}, len(objects))
		for _, object := range objects {
			if object == nil {
				continue
			}
			name := strings.TrimSpace(object.APIName)
			if name != "" {
				installedObjects[strings.ToLower(name)] = struct{}{}
			}
		}
		var sharingRulesByObject map[string][]*models.SharingRule
		if bulkReader, ok := reader.(BulkSharingRuleMetadataReader); ok {
			allRules, err := bulkReader.GetAllSharingRules(txCtx)
			if err != nil {
				return fmt.Errorf("read effective sharing rules: %w", err)
			}
			sharingRulesByObject = make(map[string][]*models.SharingRule)
			for i, rule := range allRules {
				if rule == nil {
					return fmt.Errorf("effective sharing rule[%d] is nil", i)
				}
				key := strings.ToLower(strings.TrimSpace(rule.ObjectAPIName))
				sharingRulesByObject[key] = append(sharingRulesByObject[key], rule)
			}
		}

		input := catalogsnapshot.CompileInput{
			OrgID: selection.OrgID,
			Lineage: catalogsnapshot.Lineage{
				CatalogRevision:  catalogsnapshot.CatalogRevision(selection.CatalogRevision),
				SchemaGeneration: catalogsnapshot.SchemaGeneration(selection.SchemaGeneration),
				EngineGeneration: catalogsnapshot.EngineGeneration(selection.EngineGeneration),
			},
			Objects:       make([]catalogsnapshot.ObjectInput, 0, len(objects)),
			Relationships: make([]catalogsnapshot.RelationshipInput, 0, len(explicitRelationships)),
			SharingRules:  []catalogsnapshot.SharingRuleInput{},
		}
		objectNames := make([]string, 0, len(objects))
		for i, object := range objects {
			if object == nil {
				return fmt.Errorf("effective object metadata[%d] is nil", i)
			}
			name := strings.TrimSpace(object.APIName)
			if name == "" {
				return fmt.Errorf("effective object metadata[%d] has no API name", i)
			}
			input.Objects = append(input.Objects, catalogsnapshot.ObjectInput{
				CatalogRevision: input.Lineage.CatalogRevision,
				Metadata:        object,
			})
			childKey := strings.ToLower(name)
			overlays, rejected, err := partitionRelationshipOverlays(object, explicitByChild[childKey])
			if err != nil {
				return err
			}
			explicitEdges := make(map[string]struct{}, len(overlays))
			for _, relationship := range overlays {
				explicitEdges[relationshipIdentityKey(relationship)] = struct{}{}
			}
			for _, relationship := range metadatarel.ResolveEffectiveRelationships(object, overlays) {
				_, explicitlyMaterialized := explicitEdges[relationshipIdentityKey(relationship)]
				_, parentInstalled := installedObjects[strings.ToLower(strings.TrimSpace(relationship.ParentObjectAPIName))]
				// Record-access consumes only sharing-parent relationships. Query
				// consumes the complete field-owned topology already resolved by the
				// metadata authority. An ordinary field-derived lookup whose target is
				// not installed is an opaque ID, not a navigable graph edge. Explicit
				// rows and sharing parents remain compiler-validated and fail closed.
				if canonicalRelationshipIdentity(relationship.ParentObjectAPIName) &&
					!parentInstalled && !explicitlyMaterialized && !relationship.IsSharingParent {
					continue
				}
				// Keep the narrower D1 snapshot behavior when neither query nor
				// mutation is selected.
				if !includeCompleteRelationships && !relationship.IsSharingParent && !explicitlyMaterialized {
					continue
				}
				input.Relationships = append(input.Relationships, catalogsnapshot.RelationshipInput{
					CatalogRevision: input.Lineage.CatalogRevision,
					Metadata:        relationship,
				})
			}
			// The effective resolver is intentionally overlay-only. Preserve
			// malformed identities so the Catalog compiler remains their canonical
			// validator; stale or retargeted field edges already failed above.
			for _, relationship := range rejected {
				input.Relationships = append(input.Relationships, catalogsnapshot.RelationshipInput{
					CatalogRevision: input.Lineage.CatalogRevision,
					Metadata:        relationship,
				})
			}
			delete(explicitByChild, childKey)
			objectNames = append(objectNames, name)
			var rules []*models.SharingRule
			if sharingRulesByObject != nil {
				rules = sharingRulesByObject[strings.ToLower(name)]
			} else {
				rules, err = reader.GetSharingRules(txCtx, name)
				if err != nil {
					return fmt.Errorf("read effective sharing rules for %q: %w", name, err)
				}
			}
			for j, rule := range rules {
				if rule == nil {
					return fmt.Errorf("effective sharing rule %q[%d] is nil", name, j)
				}
				input.SharingRules = append(input.SharingRules, catalogsnapshot.SharingRuleInput{
					CatalogRevision: input.Lineage.CatalogRevision,
					Metadata:        rule,
				})
			}
		}
		// Preserve explicit rows for unknown children so the compiler remains the
		// fail-closed owner for dangling object references.
		for _, relationship := range explicitRelationships {
			childKey := strings.ToLower(strings.TrimSpace(relationship.ChildObjectAPIName))
			if _, unknownChild := explicitByChild[childKey]; !unknownChild {
				continue
			}
			input.Relationships = append(input.Relationships, catalogsnapshot.RelationshipInput{
				CatalogRevision: input.Lineage.CatalogRevision,
				Metadata:        relationship,
			})
		}
		mutationSelected := selectionIncludesMutationFacts(selection)
		pageLayoutResolutionSelected := selectionIncludesCapability(
			selection, pagelayoutresolutionv1.CapabilityName,
		)
		layoutAuthoringSelected := selectionIncludesCapability(
			selection, layoutauthoringv1.CapabilityName,
		)
		recordTypePermissionsSelected := selectionIncludesCapability(
			selection, effectivepermissionsv1.CapabilityName,
		)
		if mutationSelected || effectiveMetadataCapability != "" {
			flowReader, ok := reader.(EffectiveFlowMetadataReader)
			if !ok {
				return fmt.Errorf("effective Flow publication requires the effective Flow metadata reader")
			}
			effectiveFlows, err = readEffectiveActiveFlows(txCtx, flowReader)
			if err != nil {
				return err
			}
			fieldMappingReader, ok := reader.(FieldMappingMetadataReader)
			if !ok {
				return fmt.Errorf("effective Flow publication requires the field-mapping metadata reader")
			}
			fieldMappings, err = fieldMappingReader.GetFieldMappingRules(txCtx)
			if err != nil {
				return fmt.Errorf("read effective field mappings: %w", err)
			}
			effectiveFlows, err = sealEffectiveFlowRecordLookupFieldClosures(
				effectiveFlows, fieldMappings,
			)
			if err != nil {
				return err
			}
		}
		if mutationSelected {
			mutationReader, ok := reader.(MutationMetadataReader)
			if !ok {
				return fmt.Errorf("mutation-backed projection requires the complete mutation metadata reader")
			}
			if err := appendMutationDefinitions(
				txCtx, mutationReader, input.Lineage.CatalogRevision, objects,
				effectiveFlows, fieldMappings, &input,
			); err != nil {
				return err
			}
			if err := appendConnectorExecutionDefinitions(
				txCtx,
				reader,
				input.Lineage.CatalogRevision,
				selection.IntegrationBindings,
				&input,
			); err != nil {
				return err
			}
			if err := appendOutboundMailRoutes(
				txCtx,
				reader,
				input.Lineage.CatalogRevision,
				selection.OutboundMailRoutes,
				selection.IntegrationBindings,
				&input,
			); err != nil {
				return err
			}
			formulaReader, ok := reader.(EffectiveFormulaFunctionMetadataReader)
			if !ok {
				return fmt.Errorf("mutation-backed projection requires the effective formula-function metadata reader")
			}
			formulaBundles, err := formulaReader.GetRuntimeFormulaFunctionBundles(txCtx)
			if err != nil {
				return fmt.Errorf("read effective formula function bundles: %w", err)
			}
			input.FormulaFunctionBundles = make(
				[]catalogsnapshot.FormulaFunctionBundleInput,
				0,
				len(formulaBundles),
			)
			for _, bundle := range formulaBundles {
				input.FormulaFunctionBundles = append(input.FormulaFunctionBundles, catalogsnapshot.FormulaFunctionBundleInput{
					CatalogRevision: input.Lineage.CatalogRevision,
					Bundle:          bundle,
				})
			}
		} else if recordTypePermissionsSelected ||
			effectiveMetadataCapability == consumerv1.AppMetadataV3CapabilityName {
			recordTypeReader, ok := reader.(RecordTypeMetadataReader)
			if !ok {
				return fmt.Errorf(
					"effective-permissions or App metadata V3 projection requires the record-type metadata reader",
				)
			}
			if err := appendRecordTypeDefinitions(
				txCtx,
				recordTypeReader,
				input.Lineage.CatalogRevision,
				objects,
				&input,
			); err != nil {
				return err
			}
		}
		// A read-only publication still needs the current server-default facts.
		// The mutation path above already read them once in this transaction.
		if !mutationSelected && (layoutAuthoringSelected || effectiveMetadataCapability == consumerv1.AppMetadataV3CapabilityName) {
			autoNumberReader, ok := reader.(AutoNumberMetadataReader)
			if !ok {
				return fmt.Errorf("create requirement publication requires the autonumber metadata reader")
			}
			if err := appendAutoNumberDefinitions(txCtx, autoNumberReader, input.Lineage.CatalogRevision, &input); err != nil {
				return err
			}
		}
		if pageLayoutResolutionSelected {
			pageLayoutReader, ok := reader.(PageLayoutResolutionMetadataReader)
			if !ok {
				return fmt.Errorf("page-layout resolution projection requires the complete page-layout metadata reader")
			}
			if err := appendPageLayoutResolutionDefinitions(
				txCtx,
				pageLayoutReader,
				input.Lineage.CatalogRevision,
				objects,
				&input,
				layoutAuthoringSelected,
			); err != nil {
				return err
			}
		} else if layoutAuthoringSelected {
			layoutReader, ok := reader.(LayoutAuthoringMetadataReader)
			if !ok {
				return fmt.Errorf("Layout authoring projection requires the complete stored Layout metadata reader")
			}
			if err := appendLayoutAuthoringDefinitions(
				txCtx,
				layoutReader,
				input.Lineage.CatalogRevision,
				objects,
				&input,
			); err != nil {
				return err
			}
		}
		releaseDefinitions, err := readPlatformReleaseDefinitions(release, selection)
		if err != nil {
			return err
		}
		if err := mergeReleaseFormulaFunctionBundles(
			&input,
			releaseDefinitions.formulaFunctionBundles,
		); err != nil {
			return err
		}
		commandBindings, err := commandExecutionBindings(
			releaseDefinitions.commands,
			selection.IntegrationBindings,
		)
		if err != nil {
			return err
		}
		for _, report := range releaseDefinitions.reports {
			input.ReportDefinitions = append(input.ReportDefinitions, catalogsnapshot.ReportDefinitionInput{
				CatalogRevision: input.Lineage.CatalogRevision, ComponentID: report.componentID,
				DefinitionVersion: catalogsnapshot.DefinitionVersion(report.definitionVersion),
				ContentDigest:     catalogsnapshot.Digest(report.contentDigest),
				Definition:        report.definition,
			})
		}
		for _, command := range releaseDefinitions.commands {
			input.CommandRegistrations = append(input.CommandRegistrations, catalogsnapshot.CommandRegistrationInput{
				CatalogRevision: input.Lineage.CatalogRevision, ComponentID: command.componentID,
				DefinitionVersion: catalogsnapshot.DefinitionVersion(command.definitionVersion),
				ContentDigest:     catalogsnapshot.Digest(command.contentDigest),
				CommandKind:       command.commandKind, PayloadFormatVersion: command.payloadFormatVersion,
				ExecutionBindings: commandBindings[command.key()],
			})
		}
		for _, approval := range releaseDefinitions.approvals {
			input.ApprovalDefinitions = append(input.ApprovalDefinitions, catalogsnapshot.ApprovalDefinitionInput{
				CatalogRevision: input.Lineage.CatalogRevision,
				DefinitionID:    approval.componentID,
				ObjectAPIName:   approval.objectAPIName,
				DeveloperName:   approval.developerName,
				Envelope:        append([]byte(nil), approval.envelope...),
			})
		}
		input.ApprovalDefinitions = append(
			input.ApprovalDefinitions,
			selection.ApprovalDefinitions...,
		)
		approvalDefinitionIDs := releaseDefinitions.approvalComponentIDs()
		for _, definition := range selection.ApprovalDefinitions {
			approvalDefinitionIDs = append(approvalDefinitionIDs, definition.DefinitionID)
		}
		sort.Strings(approvalDefinitionIDs)
		approvalDefinitionIDs = slices.Compact(approvalDefinitionIDs)
		if selectionIncludesCapability(selection, approvalv1.ExecuteCapabilityName) &&
			len(approvalDefinitionIDs) == 0 {
			return fmt.Errorf("Approval execution requires at least one immutable definition")
		}
		if selectionIncludesRecordViewAttachmentFacts(selection) {
			for _, resolver := range recordViewRelease.Resolvers {
				input.AttachmentSourceResolvers = append(input.AttachmentSourceResolvers, catalogsnapshot.RecordAttachmentSourceResolverInput{
					CatalogRevision:                 input.Lineage.CatalogRevision,
					ResolverID:                      resolver.ResolverID,
					Kind:                            catalogsnapshot.RecordAttachmentSourceResolverKind(resolver.Kind),
					SourceObjectAPIName:             resolver.SourceObjectAPIName,
					SourceFileReferenceFieldAPIName: resolver.SourceFileReferenceFieldAPIName,
					SourceDeletedFieldAPIName:       resolver.SourceDeletedFieldAPIName,
					SourceRecordMatcher: &catalogsnapshot.RecordAttachmentSourceRecordMatcher{
						Kind:             catalogsnapshot.RecordAttachmentSourceRecordMatcherKind(resolver.SourceRecordMatcher.Kind),
						StartOffsetBytes: resolver.SourceRecordMatcher.StartOffsetBytes,
						LengthBytes:      resolver.SourceRecordMatcher.LengthBytes,
					},
				})
			}
			for _, field := range recordViewRelease.Fields {
				input.AttachmentSourceFields = append(input.AttachmentSourceFields, catalogsnapshot.RecordAttachmentSourceFieldInput{
					CatalogRevision: input.Lineage.CatalogRevision,
					ObjectAPIName:   field.ParentAPIName,
					FieldAPIName:    field.FieldAPIName,
					ResolverID:      field.ResolverID,
				})
			}
		}
		sort.Strings(objectNames)
		for _, capabilityID := range metadataCapabilityIDs(selection) {
			profile, err := projectionProfile(capabilityID)
			if err != nil {
				return err
			}
			var definitionComponentIDs []string
			switch profile {
			case catalogsnapshot.ProjectionReportExecutionV1:
				definitionComponentIDs = releaseDefinitions.reportComponentIDs()
			case catalogsnapshot.ProjectionCommandAcceptanceV1:
				definitionComponentIDs = releaseDefinitions.commandComponentIDs()
			case catalogsnapshot.ProjectionApprovalExecutionV1, catalogsnapshot.ProjectionApprovalReadV1:
				definitionComponentIDs = append([]string(nil), approvalDefinitionIDs...)
			}
			projectionObjectNames := objectNames
			if profile == catalogsnapshot.ProjectionCommandAcceptanceV1 {
				projectionObjectNames = nil
			}
			input.Projections = append(input.Projections, catalogsnapshot.RuntimeProjectionInput{
				CatalogRevision:        input.Lineage.CatalogRevision,
				AppInstallationID:      selection.AppInstallationID,
				CapabilityID:           capabilityID,
				Profile:                profile,
				ObjectAPINames:         projectionObjectNames,
				DefinitionComponentIDs: definitionComponentIDs,
			})
		}
		result.metadata, err = catalogsnapshot.BuildEffectiveMetadata(input)
		if err != nil {
			return fmt.Errorf("compile effective metadata: %w", err)
		}
		if effectiveMetadataCapability != "" {
			searchReader, ok := reader.(EffectiveObjectSearchMetadataReader)
			if !ok {
				return fmt.Errorf(
					"complete App metadata requires the effective object-search metadata reader",
				)
			}
			declarations, err := searchReader.GetRuntimeSearchAllDefaultFields(txCtx)
			if err != nil {
				return fmt.Errorf(
					"read effective search-all field declarations: %w",
					err,
				)
			}
			var createRequiredFields map[string][]string
			if effectiveMetadataCapability == consumerv1.AppMetadataV3CapabilityName {
				createRequiredFields, err = result.metadata.CreateRequiredInputFields()
				if err != nil {
					return fmt.Errorf("derive effective create requirements: %w", err)
				}
			}
			component, err := buildEffectiveObjectSearchComponent(
				objects, declarations, effectiveMetadataCapability, createRequiredFields, compoundRoles,
			)
			if err != nil {
				return err
			}
			var historicalObjectSearches []catalogapp.EffectiveMetadataComponent
			if effectiveMetadataCapability == consumerv1.AppMetadataV3CapabilityName {
				for _, format := range []uint32{
					effectiveObjectSearchComponentFormatV5,
					effectiveObjectSearchComponentFormatV4,
					effectiveObjectSearchComponentFormatV3,
					effectiveObjectSearchComponentFormatV2,
				} {
					historicalObjectSearch, buildErr :=
						buildEffectiveObjectSearchComponentForFormat(
							objects, declarations, format, nil, compoundRoles,
						)
					if buildErr != nil {
						return buildErr
					}
					historicalObjectSearches = append(
						historicalObjectSearches, historicalObjectSearch,
					)
				}
			}
			applicationReader, ok := reader.(EffectiveApplicationNavigationMetadataReader)
			if !ok {
				return fmt.Errorf(
					"complete App metadata requires the effective application-navigation metadata reader",
				)
			}
			applications, err := applicationReader.GetApplicationDefinitions(txCtx)
			if err != nil {
				return fmt.Errorf("read effective application navigation: %w", err)
			}
			applicationComponent, err :=
				buildEffectiveApplicationNavigationComponent(applications, objects)
			if err != nil {
				return err
			}
			result.components = []catalogapp.EffectiveMetadataComponent{
				applicationComponent,
				component,
			}
			flowComponents, err := buildEffectiveStandardFlowComponents(
				release, effectiveFlows,
			)
			if err != nil {
				return err
			}
			result.components = append(result.components, flowComponents...)
			if effectiveMetadataCapability == consumerv1.AppMetadataV3CapabilityName {
				scopeReader, ok := reader.(EffectiveSearchScopeMetadataReader)
				if !ok {
					return fmt.Errorf("complete App metadata requires the effective search-scope metadata reader")
				}
				scopeComponent, err := buildEffectiveSearchScopeComponent(txCtx, scopeReader, objectNames)
				if err != nil {
					return err
				}
				result.components = append(result.components, scopeComponent)
				recordTypeDefinitions := make(
					[]*models.RecordType, 0, len(input.MutationDefinitions),
				)
				for _, definition := range input.MutationDefinitions {
					if definition.RecordType != nil {
						recordTypeDefinitions = append(
							recordTypeDefinitions, definition.RecordType,
						)
					}
				}
				recordTypeComponents, err := buildEffectiveRecordTypeComponents(
					recordTypeDefinitions,
				)
				if err != nil {
					return err
				}
				result.components = append(
					result.components, recordTypeComponents...,
				)
				oauthReader, ok := reader.(EffectiveOAuthAuthorityMetadataReader)
				if !ok {
					return fmt.Errorf(
						"complete App metadata V3 requires the effective OAuth authority metadata reader",
					)
				}
				oauthComponents, err := buildEffectiveOAuthAuthorityComponents(
					txCtx, oauthReader,
				)
				if err != nil {
					return err
				}
				result.components = append(result.components, oauthComponents...)
				layoutReader, ok := reader.(EffectivePageLayoutMetadataReader)
				if !ok {
					return fmt.Errorf(
						"complete App metadata V3 requires the effective page-layout metadata reader",
					)
				}
				layoutComponents, err := buildEffectivePageLayoutComponents(
					txCtx, layoutReader, release, objectNames,
				)
				if err != nil {
					return err
				}
				result.components = append(result.components, layoutComponents...)
				relatedListReader, ok := reader.(EffectiveRelatedListRuleMetadataReader)
				if !ok {
					return fmt.Errorf("complete App metadata V3 requires the effective related-list rule metadata reader")
				}
				relatedListComponent, err := buildEffectiveRelatedListPresentationComponent(txCtx, relatedListReader, objectNames, explicitRelationships)
				if err != nil {
					return err
				}
				result.components = append(result.components, relatedListComponent)
				actionMetadataReader, ok := reader.(EffectiveObjectActionMetadataReader)
				if !ok {
					return fmt.Errorf(
						"complete App metadata V3 requires the effective object-action metadata reader",
					)
				}
				objectActionComponents, err := buildEffectiveObjectActionComponents(
					txCtx, actionMetadataReader, objectNames,
				)
				if err != nil {
					return err
				}
				result.components = append(result.components, objectActionComponents...)
				actionReader, ok := reader.(EffectiveStandardActionMetadataReader)
				if !ok {
					return fmt.Errorf(
						"complete App metadata V3 requires the effective standard-action metadata reader",
					)
				}
				actionComponents, err := buildEffectiveStandardActionComponents(
					txCtx, actionReader, release,
				)
				if err != nil {
					return err
				}
				result.components = append(result.components, actionComponents...)
				reportTypeReader, ok := reader.(EffectiveReportTypeMetadataReader)
				if !ok {
					return fmt.Errorf(
						"complete App metadata V3 requires the effective report-type metadata reader",
					)
				}
				reportTypes, err := reportTypeReader.GetEffectiveReportTypes(txCtx)
				if err != nil {
					return fmt.Errorf("read effective report types: %w", err)
				}
				reportTypeComponents, err := buildEffectiveReportTypeComponents(reportTypes)
				if err != nil {
					return err
				}
				result.components = append(result.components, reportTypeComponents...)
			}
			for _, historicalObjectSearch := range historicalObjectSearches {
				historicalComponents := slices.Clone(result.components)
				replaced := false
				for index, value := range historicalComponents {
					if value.ComponentKind == consumerv1.EffectiveObjectSearchComponentKind &&
						value.BusinessKey == consumerv1.EffectiveObjectSearchComponentBusinessKey {
						historicalComponents[index] = historicalObjectSearch
						replaced = true
						break
					}
				}
				if !replaced {
					return fmt.Errorf(
						"complete App metadata V3 omitted the effective object-search component",
					)
				}
				result.historicalRetryComponentSets = append(
					result.historicalRetryComponentSets,
					historicalComponents,
				)
			}
			for index, value := range result.components {
				if err := consumerv1.ValidateEffectiveMetadataComponentForCapability(
					value, effectiveMetadataCapability,
				); err != nil {
					return fmt.Errorf("effective metadata component[%d] is invalid: %w", index, err)
				}
			}
		}
		return nil
	})
	if err != nil {
		return effectiveMetadataRead{}, err
	}
	return result, nil
}

// mergeReleaseFormulaFunctionBundles composes the verified AppRelease with
// formula authority already selected from immutable pack generations. A
// release may carry the same bundle that its source pack published; that is
// one definition with two verified delivery paths, not two registrations.
// Exact duplicates collapse, while any overlapping definition disagreement
// fails closed instead of silently choosing an authority.
func mergeReleaseFormulaFunctionBundles(
	input *catalogsnapshot.CompileInput,
	releaseBundles []formula.FunctionBundle,
) error {
	if input == nil || len(releaseBundles) == 0 {
		return nil
	}
	existingBundles := make([]formula.FunctionBundle, 0, len(input.FormulaFunctionBundles))
	definitionsByName := make(map[string]formula.FunctionDefinition)
	for _, bundleInput := range input.FormulaFunctionBundles {
		existingBundles = append(existingBundles, bundleInput.Bundle)
		for _, definition := range bundleInput.Bundle.Functions {
			definitionsByName[strings.TrimSpace(definition.Name)] = definition
		}
	}
	if err := formula.ValidateFunctionBundles(existingBundles); err != nil {
		return fmt.Errorf("validate immutable-generation formula functions: %w", err)
	}

	for _, releaseBundle := range formula.CloneFunctionBundles(releaseBundles) {
		missing := formula.FunctionBundle{}
		for _, definition := range releaseBundle.Functions {
			name := strings.TrimSpace(definition.Name)
			if existing, ok := definitionsByName[name]; ok {
				if !reflect.DeepEqual(existing, definition) {
					return fmt.Errorf(
						"formula function %q disagrees between immutable pack generation and verified AppRelease",
						name,
					)
				}
				continue
			}
			definitionsByName[name] = definition
			missing.Functions = append(missing.Functions, definition)
		}
		if len(missing.Functions) != 0 {
			input.FormulaFunctionBundles = append(
				input.FormulaFunctionBundles,
				catalogsnapshot.FormulaFunctionBundleInput{
					CatalogRevision: input.Lineage.CatalogRevision,
					Bundle:          missing,
				},
			)
			existingBundles = append(existingBundles, missing)
		}
	}
	if err := formula.ValidateFunctionBundles(existingBundles); err != nil {
		return fmt.Errorf("validate composed formula functions: %w", err)
	}
	return nil
}

// materializeEffectiveFieldProvenance closes the read-time metadata contract
// before the immutable Catalog compiler observes repository rows. _System_Field
// intentionally does not persist Source, IsCompound, or ComposedFrom; those
// facts are derived from the runtime object-spec declarations installed for
// this process. Catalog artifacts must carry the derived values because their
// consumers cannot consult that process-local classifier after publication.
//
// CloneWithAdditionalFields keeps the repository-owned metadata detached from
// the publication copy. This matters for cached readers and also prevents one
// capability projection from changing another reader's source snapshot.
func materializeEffectiveFieldProvenance(objects []*models.ObjectMetadata) []*models.ObjectMetadata {
	result := make([]*models.ObjectMetadata, len(objects))
	for objectIndex, object := range objects {
		if object == nil {
			continue
		}
		fields := make([]models.FieldMetadata, len(object.Fields))
		for fieldIndex := range object.Fields {
			field := object.Fields[fieldIndex]
			field.Source = fieldprovenance.ClassifySource(object.APIName, field.APIName)
			if isCompound, composedFrom := fieldprovenance.ClassifyCompound(object.APIName, field.APIName); isCompound {
				field.IsCompound = true
				field.ComposedFrom = composedFrom
			}
			fields[fieldIndex] = field
		}
		result[objectIndex] = models.CloneWithAdditionalFields(object, fields)
	}
	return result
}

func appendAutoNumberDefinitions(ctx context.Context, reader AutoNumberMetadataReader, revision catalogsnapshot.CatalogRevision, input *catalogsnapshot.CompileInput) error {
	rules, err := reader.GetAutoNumberRules(ctx)
	if err != nil {
		return fmt.Errorf("read effective autonumber rules: %w", err)
	}
	for i := range rules {
		value := rules[i]
		input.MutationDefinitions = append(input.MutationDefinitions, catalogsnapshot.MutationDefinitionInput{
			CatalogRevision: revision, AutoNumberRule: &value,
		})
	}
	return nil
}

func appendMutationDefinitions(
	ctx context.Context,
	reader MutationMetadataReader,
	revision catalogsnapshot.CatalogRevision,
	objects []*models.ObjectMetadata,
	effectiveFlows []effectiveActiveFlow,
	fieldMappings []catalogsnapshot.FieldMappingRule,
	input *catalogsnapshot.CompileInput,
) error {
	// Product HTTP/OAuth route policy is not Runtime mutation metadata. An L1
	// compiler may later publish a neutral decision artifact through an explicit
	// contract, but this app-blind Catalog compiler must not infer that decision
	// from product component kinds or live route rows. The record engine already
	// fails closed when no public-scope policy decision is present.
	appendDefinition := func(value catalogsnapshot.MutationDefinitionInput) {
		value.CatalogRevision = revision
		input.MutationDefinitions = append(input.MutationDefinitions, value)
	}
	validationRules, err := reader.GetAllValidationRules(ctx)
	if err != nil {
		return fmt.Errorf("read effective validation rules: %w", err)
	}
	for i, rule := range validationRules {
		if rule == nil {
			return fmt.Errorf("effective validation rule[%d] is nil", i)
		}
		appendDefinition(catalogsnapshot.MutationDefinitionInput{ValidationRule: rule})
	}
	if err := appendRecordTypeDefinitions(
		ctx, reader, revision, objects, input,
	); err != nil {
		return err
	}
	for _, flow := range effectiveFlows {
		definition, active := flow.definition, flow.version
		appendDefinition(catalogsnapshot.MutationDefinitionInput{FlowDefinition: definition})
		appendDefinition(catalogsnapshot.MutationDefinitionInput{FlowVersion: active})
	}
	subscriptions, err := reader.GetActiveTriggerSubscriptions(ctx)
	if err != nil {
		return fmt.Errorf("read effective trigger subscriptions: %w", err)
	}
	for i := range subscriptions {
		value := subscriptions[i]
		appendDefinition(catalogsnapshot.MutationDefinitionInput{TriggerSubscription: &value})
	}
	if err := appendAutoNumberDefinitions(ctx, reader, revision, input); err != nil {
		return err
	}
	for i := range fieldMappings {
		value := fieldMappings[i]
		appendDefinition(catalogsnapshot.MutationDefinitionInput{FieldMappingRule: &value})
	}
	guardTargets := map[string]string{}
	for _, mapping := range fieldMappings {
		if strings.EqualFold(strings.TrimSpace(mapping.ActionType), "insertInheritFromLookup") {
			continue
		}
		name := strings.TrimSpace(mapping.TargetObject)
		if name != "" {
			guardTargets[strings.ToLower(name)] = name
		}
	}
	guardTargetNames := make([]string, 0, len(guardTargets))
	for _, name := range guardTargets {
		guardTargetNames = append(guardTargetNames, name)
	}
	sort.Slice(guardTargetNames, func(i, j int) bool {
		return strings.ToLower(guardTargetNames[i]) < strings.ToLower(guardTargetNames[j])
	})
	var guardReader CreateSourceGuardMetadataReader
	if len(guardTargetNames) != 0 {
		var ok bool
		guardReader, ok = reader.(CreateSourceGuardMetadataReader)
		if !ok {
			return fmt.Errorf("record-mutation projection with action-owned field mappings requires the create-from-source guard metadata reader")
		}
	}
	for _, targetObject := range guardTargetNames {
		entries, err := guardReader.GetCreateFromSourceGuardEntries(ctx, targetObject)
		if err != nil {
			return fmt.Errorf("read effective create-from-source guards for %q: %w", targetObject, err)
		}
		for _, entry := range entries {
			value := catalogsnapshot.CreateFromSourceGuardRule{
				TargetObject: targetObject, SourceFKField: entry.SourceFKField,
				OwningStandardActionID: entry.OwningStandardActionId, ActionName: entry.ActionName,
			}
			appendDefinition(catalogsnapshot.MutationDefinitionInput{CreateSourceGuard: &value})
		}
	}
	return nil
}

func appendRecordTypeDefinitions(
	ctx context.Context,
	reader RecordTypeMetadataReader,
	revision catalogsnapshot.CatalogRevision,
	objects []*models.ObjectMetadata,
	input *catalogsnapshot.CompileInput,
) error {
	appendRecordType := func(recordType *models.RecordType) {
		input.MutationDefinitions = append(
			input.MutationDefinitions,
			catalogsnapshot.MutationDefinitionInput{
				CatalogRevision: revision,
				RecordType:      recordType,
			},
		)
	}
	var recordTypesByObject map[string][]*models.RecordType
	if bulkReader, ok := reader.(BulkRecordTypeMetadataReader); ok {
		allRecordTypes, err := bulkReader.GetAllRecordTypes(ctx)
		if err != nil {
			return fmt.Errorf("read effective record types: %w", err)
		}
		recordTypesByObject = make(map[string][]*models.RecordType)
		for i, recordType := range allRecordTypes {
			if recordType == nil {
				return fmt.Errorf("effective record type[%d] is nil", i)
			}
			key := strings.ToLower(strings.TrimSpace(recordType.ObjectAPIName))
			recordTypesByObject[key] = append(recordTypesByObject[key], recordType)
		}
	}
	for _, object := range objects {
		var recordTypes []*models.RecordType
		if recordTypesByObject != nil {
			recordTypes = recordTypesByObject[strings.ToLower(object.APIName)]
		} else {
			var err error
			recordTypes, err = reader.GetRecordTypes(ctx, object.APIName)
			if err != nil {
				return fmt.Errorf("read effective record types for %q: %w", object.APIName, err)
			}
		}
		for i, recordType := range recordTypes {
			if recordType == nil {
				return fmt.Errorf("effective record type %q[%d] is nil", object.APIName, i)
			}
			appendRecordType(recordType)
		}
	}
	return nil
}

func partitionRelationshipOverlays(
	object *models.ObjectMetadata,
	rows []*models.Relationship,
) (overlays, rejected []*models.Relationship, err error) {
	seen := make(map[string]struct{}, len(rows))
	for _, relationship := range rows {
		if !canonicalRelationshipIdentity(relationship.ChildObjectAPIName) ||
			!canonicalRelationshipIdentity(relationship.ParentObjectAPIName) ||
			!canonicalRelationshipIdentity(relationship.FieldAPIName) {
			rejected = append(rejected, relationship)
			continue
		}
		field := models.FindField(object, relationship.FieldAPIName)
		if field == nil || !metadatarel.FieldReferencesParent(*field, relationship.ParentObjectAPIName) {
			return nil, nil, fmt.Errorf(
				"explicit relationship overlay %s.%s -> %s has no field-owned edge",
				relationship.ChildObjectAPIName,
				relationship.FieldAPIName,
				relationship.ParentObjectAPIName,
			)
		}
		key := relationshipIdentityKey(relationship)
		if _, duplicate := seen[key]; duplicate {
			return nil, nil, fmt.Errorf(
				"duplicate explicit relationship overlay for %s.%s -> %s",
				relationship.ChildObjectAPIName,
				relationship.FieldAPIName,
				relationship.ParentObjectAPIName,
			)
		}
		seen[key] = struct{}{}
		overlays = append(overlays, relationship)
	}
	return overlays, rejected, nil
}

func relationshipIdentityKey(relationship *models.Relationship) string {
	if relationship == nil {
		return ""
	}
	return strings.ToLower(strings.Join([]string{
		relationship.ChildObjectAPIName,
		relationship.FieldAPIName,
		relationship.ParentObjectAPIName,
	}, "\x00"))
}

func canonicalRelationshipIdentity(value string) bool {
	return value != "" && strings.TrimSpace(value) == value
}

func validateSelection(selection MetadataSelection) error {
	for name, value := range map[string]string{
		"OrgID":             selection.OrgID,
		"AppInstallationID": selection.AppInstallationID,
	} {
		if strings.TrimSpace(value) == "" {
			return fmt.Errorf("%s is required", name)
		}
	}
	if selection.CatalogRevision == 0 || selection.SchemaGeneration == 0 || selection.EngineGeneration == 0 {
		return fmt.Errorf("Catalog, schema, and engine generations must be explicit and non-zero")
	}
	capabilityIDs := metadataCapabilityIDs(selection)
	if len(capabilityIDs) == 0 {
		return fmt.Errorf("RuntimeCapabilityID is required")
	}
	seen := make(map[string]struct{}, len(capabilityIDs))
	for _, capabilityID := range capabilityIDs {
		if _, duplicate := seen[capabilityID]; duplicate {
			return fmt.Errorf("duplicate Runtime capability %q", capabilityID)
		}
		seen[capabilityID] = struct{}{}
		if _, err := projectionProfile(capabilityID); err != nil {
			return err
		}
	}
	mappingOwners, pushBindings := connectorExecutionSelections(selection.IntegrationBindings)
	if (len(mappingOwners) != 0 || len(pushBindings) != 0) && !selectionIncludesMutationFacts(selection) {
		return fmt.Errorf(
			"connector execution IntegrationBinding requires a record-mutation, Files, or Flow projection capability",
		)
	}
	return nil
}

func metadataCapabilityIDs(selection MetadataSelection) []string {
	var result []string
	if len(selection.RuntimeCapabilityIDs) != 0 {
		result = append(result, selection.RuntimeCapabilityIDs...)
	} else if selection.RuntimeCapabilityID != "" {
		result = append(result, selection.RuntimeCapabilityID)
	}
	// A RuntimeCommand is a consumer-only L0 requirement, not an L1 handler
	// selection. It still needs the command registration and projection in the
	// same immutable Catalog snapshot so the independent Integration workload
	// can be admitted without inventing an sfcrm handler.
	for _, binding := range selection.IntegrationBindings {
		if binding.Binding.RuntimeCommand != nil &&
			!slices.Contains(result, commandv1.CapabilityName) {
			result = append(result, commandv1.CapabilityName)
		}
		// A connector-push contract authorizes only a neutral transactional
		// intent handoff. Provider dispatch, credentials, retry and reconciliation
		// remain owned by the separately deployed Integration workload.
		if binding.Binding.Kind == consumerv1.BindingConnectorPushContract &&
			!slices.Contains(result, outboundintentv1.CapabilityName) {
			result = append(result, outboundintentv1.CapabilityName)
		}
	}
	if len(selection.OutboundMailRoutes) != 0 &&
		!slices.Contains(result, outboundintentv1.CapabilityName) {
		result = append(result, outboundintentv1.CapabilityName)
	}
	return result
}

func selectionIncludesCapability(selection MetadataSelection, capabilityID string) bool {
	for _, selected := range metadataCapabilityIDs(selection) {
		if selected == capabilityID {
			return true
		}
	}
	return false
}

// selectionIncludesRecordViewAttachmentFacts identifies the two Runtime
// capabilities that consume the same AppRelease-owned attachment resolver
// closure. They receive separate HandlerBindings and trusted capability
// grants, but their views must be derived from one immutable Catalog snapshot.
func selectionIncludesRecordViewAttachmentFacts(selection MetadataSelection) bool {
	return selectionIncludesCapability(selection, recordviewv1.CapabilityName) ||
		selectionIncludesCapability(selection, recordattachmentsv1.CapabilityName)
}

func selectionIncludesMutationFacts(selection MetadataSelection) bool {
	return selectionIncludesCapability(selection, recordmutationv1.CapabilityName) ||
		selectionIncludesCapability(selection, recyclebinmutationv1.CapabilityName) ||
		selectionIncludesCapability(selection, bulkingestv1.CapabilityName) ||
		selectionIncludesCapability(selection, recorddefaultsv1.CapabilityName) ||
		selectionIncludesCapability(selection, listviewv1.CapabilityName) ||
		selectionIncludesCapability(selection, filesv1.CapabilityName) ||
		selectionIncludesCapability(selection, flowv1.CapabilityName) ||
		selectionIncludesCapability(selection, permissionauthoringv1.CapabilityName) ||
		selectionIncludesCapability(selection, outboundintentv1.CapabilityName) ||
		selectionIncludesCapability(selection, approvalv1.ExecuteCapabilityName)
}

func projectionProfile(runtimeCapabilityID string) (catalogsnapshot.ProjectionProfile, error) {
	switch runtimeCapabilityID {
	case recordaccessv1.CapabilityName:
		return catalogsnapshot.ProjectionRecordAccessV1, nil
	case effectivepermissionsv1.CapabilityName, auditlogv1.CapabilityName:
		// Permission and audit admission views need no query or record-mutation
		// execution metadata.
		return catalogsnapshot.ProjectionEffectivePermissionsV1, nil
	case queryv1.CapabilityName, recyclebinv1.CapabilityName, relatedcountsv1.CapabilityName,
		consumerv1.AppMetadataCapabilityName, consumerv1.AppMetadataV2CapabilityName,
		consumerv1.AppMetadataV3CapabilityName,
		consumerv1.IntegrationBindingCapabilityName,
		searchv1.CapabilityName:
		return catalogsnapshot.ProjectionRecordQueryV1, nil
	case recordmutationv1.CapabilityName, recyclebinmutationv1.CapabilityName,
		bulkingestv1.CapabilityName,
		recorddefaultsv1.CapabilityName,
		listviewv1.CapabilityName,
		filesv1.CapabilityName, flowv1.CapabilityName,
		permissionauthoringv1.CapabilityName,
		outboundintentv1.CapabilityName:
		return catalogsnapshot.ProjectionRecordMutationV1, nil
	case reportv1.CapabilityName:
		return catalogsnapshot.ProjectionReportExecutionV1, nil
	case commandv1.CapabilityName:
		return catalogsnapshot.ProjectionCommandAcceptanceV1, nil
	case approvalv1.ExecuteCapabilityName:
		return catalogsnapshot.ProjectionApprovalExecutionV1, nil
	case approvalv1.ReadCapabilityName:
		return catalogsnapshot.ProjectionApprovalReadV1, nil
	case recordviewv1.CapabilityName:
		return catalogsnapshot.ProjectionRecordViewV1, nil
	case recordattachmentsv1.CapabilityName:
		return catalogsnapshot.ProjectionRecordViewV1, nil
	case pagelayoutresolutionv1.CapabilityName:
		return catalogsnapshot.ProjectionPageLayoutResolutionV1, nil
	case layoutauthoringv1.CapabilityName:
		return catalogsnapshot.ProjectionLayoutAuthoringV1, nil
	default:
		return "", fmt.Errorf("Catalog reconcile metadata compiler does not support Runtime capability %q", runtimeCapabilityID)
	}
}
