// Package catalogsnapshot builds immutable, content-addressed metadata
// artifacts. It deliberately owns no serving selector: callers must name an
// exact artifact digest and projection scope.
package catalogsnapshot

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/nexuscrm/kernel/pkg/formula"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	consumerv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	connector "github.com/pingcap-inc/nexuscrm-contract/pkg/connector"
	commonv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	outboundintentv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/outboundintentv1"
)

const (
	// EffectiveMetadataSchemaV1 is the closed, immutable input grammar owned by
	// the Catalog snapshot compiler. Operator jobs may transport these bytes,
	// but must not define a parallel object/field DTO or metadata authority.
	EffectiveMetadataSchemaV1 = "nexuscrm.catalog-effective-metadata/v1"
	EffectiveMetadataSchemaV2 = "nexuscrm.catalog-effective-metadata/v2"
	EffectiveMetadataSchemaV3 = "nexuscrm.catalog-effective-metadata/v3"
	EffectiveMetadataSchemaV4 = "nexuscrm.catalog-effective-metadata/v4"
	EffectiveMetadataSchemaV5 = "nexuscrm.catalog-effective-metadata/v5"
	EffectiveMetadataSchemaV7 = "nexuscrm.catalog-effective-metadata/v7"
	EffectiveMetadataSchemaV8 = "nexuscrm.catalog-effective-metadata/v8"
	// EffectiveMetadataSchemaV9 carries workload-scoped command execution
	// bindings derived from the same Catalog publication as the command
	// registration.
	EffectiveMetadataSchemaV9 = "nexuscrm.catalog-effective-metadata/v9"
	// EffectiveMetadataSchemaV10 carries generic inbound connector mapping and
	// authorship facts required by independent Runtime Flow execution.
	EffectiveMetadataSchemaV10 = "nexuscrm.catalog-effective-metadata/v10"
	// EffectiveMetadataSchemaV11 carries the complete immutable authority used
	// to finalize an inbound remote identity inside the owning record-mutation
	// transaction. Credential references are identities only; secret values and
	// provider effects remain outside Catalog and Runtime.
	EffectiveMetadataSchemaV11 = "nexuscrm.catalog-effective-metadata/v11"
	// EffectiveMetadataSchemaV12 adds the optional source-record recovery
	// eligibility sidecar to an inbound finalization authority.
	EffectiveMetadataSchemaV12 = "nexuscrm.catalog-effective-metadata/v12"
	// EffectiveMetadataSchemaV13 adds immutable, neutral approval definitions.
	// Product source grammars remain outside Catalog and Runtime.
	EffectiveMetadataSchemaV13 = "nexuscrm.catalog-effective-metadata/v13"
	// EffectiveMetadataSchemaV14 carries the exact executable formula metadata
	// selected by the same immutable Catalog revision as Runtime serving.
	EffectiveMetadataSchemaV14 = "nexuscrm.catalog-effective-metadata/v14"
	// EffectiveMetadataSchemaV15 carries the operation-typed outbound mail
	// completion authority introduced by Catalog Snapshot V16.
	EffectiveMetadataSchemaV15 = "nexuscrm.catalog-effective-metadata/v15"
	// EffectiveMetadataSchemaV16 carries the complete live PageLayout routing
	// closure selected in the same transaction as the rest of Catalog.
	EffectiveMetadataSchemaV16 = "nexuscrm.catalog-effective-metadata/v16"
	// EffectiveMetadataSchemaV17 carries executable field-mapping value policies.
	EffectiveMetadataSchemaV17 = "nexuscrm.catalog-effective-metadata/v17"
	// EffectiveMetadataSchemaV18 carries provider-neutral outbound-mail V2
	// completion field identities in addition to the prior grammar.
	EffectiveMetadataSchemaV18 = "nexuscrm.catalog-effective-metadata/v18"
	// EffectiveMetadataSchemaV19 carries the complete stored Layout authoring
	// aggregate and its dedicated least-privilege Runtime projection.
	EffectiveMetadataSchemaV19 = "nexuscrm.catalog-effective-metadata/v19"
	// EffectiveMetadataSchemaV20 includes snapshot-bound Layout create context.
	EffectiveMetadataSchemaV20 = "nexuscrm.catalog-effective-metadata/v20"
	// V1 names the historical non-serving P7b artifacts. Open rejects them now
	// that every projection must declare an explicit profile.
	CatalogSnapshotSchemaV1     = "nexuscrm.catalog-snapshot/v1"
	RuntimeMetadataViewSchemaV1 = "nexuscrm.runtime-metadata-view/v1"
	CatalogSnapshotSchemaV2     = "nexuscrm.catalog-snapshot/v2"
	RuntimeMetadataViewSchemaV2 = "nexuscrm.runtime-metadata-view/v2"
	CatalogSnapshotSchemaV3     = "nexuscrm.catalog-snapshot/v3"
	RuntimeMetadataViewSchemaV3 = "nexuscrm.runtime-metadata-view/v3"
	CatalogSnapshotSchemaV4     = "nexuscrm.catalog-snapshot/v4"
	RuntimeMetadataViewSchemaV4 = "nexuscrm.runtime-metadata-view/v4"
	CatalogSnapshotSchemaV5     = "nexuscrm.catalog-snapshot/v5"
	RuntimeMetadataViewSchemaV5 = "nexuscrm.runtime-metadata-view/v5"
	CatalogSnapshotSchemaV6     = "nexuscrm.catalog-snapshot/v6"
	// CatalogSnapshotSchemaV8 adds AppRelease-owned neutral report
	// definitions. Runtime never reopens a live Report row or installs an L1
	// report dialect.
	CatalogSnapshotSchemaV8 = "nexuscrm.catalog-snapshot/v8"
	// CatalogSnapshotSchemaV9 adds AppRelease-owned Runtime command
	// registrations. They authorize only exact command kind/version pairs and
	// never name a handler, parser, transport, or L1 business operation.
	CatalogSnapshotSchemaV9 = "nexuscrm.catalog-snapshot/v9"
	// CatalogSnapshotSchemaV10 adds workload-scoped immutable definition and
	// context bindings for commands whose dynamic payload selects executable
	// metadata.
	CatalogSnapshotSchemaV10 = "nexuscrm.catalog-snapshot/v10"
	// CatalogSnapshotSchemaV11 adds immutable generic inbound connector
	// mapping and authorship facts. Catalog remains their only publication
	// authority; Runtime never reopens an installed pack or mapping repository.
	CatalogSnapshotSchemaV11 = "nexuscrm.catalog-snapshot/v11"
	// CatalogSnapshotSchemaV12 adds the exact contract, outbound-mapping and
	// callout-profile identity needed to publish inbound remote identity in the
	// same Runtime transaction as the record mutation. It does not authorize a
	// provider callout.
	CatalogSnapshotSchemaV12 = "nexuscrm.catalog-snapshot/v12"
	// CatalogSnapshotSchemaV13 carries recovery eligibility from the same
	// immutable connector contract publication as finalization authority.
	CatalogSnapshotSchemaV13 = "nexuscrm.catalog-snapshot/v13"
	// CatalogSnapshotSchemaV14 carries neutral approval definitions compiled by
	// L1 and revision-stamped by Catalog.
	CatalogSnapshotSchemaV14 = "nexuscrm.catalog-snapshot/v14"
	CatalogSnapshotSchemaV15 = "nexuscrm.catalog-snapshot/v15"
	// CatalogSnapshotSchemaV16 adds operation-typed outbound routes and the
	// neutral completion projection for SEND_MAIL. Legacy UPSERT routes retain
	// the v15 wire grammar.
	CatalogSnapshotSchemaV16 = "nexuscrm.catalog-snapshot/v16"
	// CatalogSnapshotSchemaV17 adds caller-effective PageLayout documents,
	// assignments, and neutral virtual related-list resolutions.
	CatalogSnapshotSchemaV17 = "nexuscrm.catalog-snapshot/v17"
	// CatalogSnapshotSchemaV18 adds executable ValueMap and OnUnmappedValue
	// semantics to generic record-mutation field mappings.
	CatalogSnapshotSchemaV18 = "nexuscrm.catalog-snapshot/v18"
	// CatalogSnapshotSchemaV19 adds optional Cc/Bcc/HTML completion field
	// identities for provider-neutral outbound mail V2.
	CatalogSnapshotSchemaV19 = "nexuscrm.catalog-snapshot/v19"
	// CatalogSnapshotSchemaV20 adds the stored Layout authoring aggregate. It
	// remains separate from caller-effective page-layout resolution.
	CatalogSnapshotSchemaV20 = "nexuscrm.catalog-snapshot/v20"
	// CatalogSnapshotSchemaV21 adds derived, read-only Layout create context.
	CatalogSnapshotSchemaV21    = "nexuscrm.catalog-snapshot/v21"
	RuntimeMetadataViewSchemaV6 = "nexuscrm.runtime-metadata-view/v6"
	// RuntimeMetadataViewSchemaV7 adds the record-view-only IsNameField
	// projection. Catalog Snapshot V6 already owns the source metadata fact;
	// this version boundary is solely for the independently serialized Runtime
	// view grammar.
	RuntimeMetadataViewSchemaV7 = "nexuscrm.runtime-metadata-view/v7"
	// RuntimeMetadataViewSchemaV8 adds the record-access-only KeyPrefix object
	// identity projection. The Catalog snapshot grammar already owns KeyPrefix;
	// the version bump prevents an older record-access Runtime from silently
	// accepting a view whose identity closure it cannot use.
	RuntimeMetadataViewSchemaV8 = "nexuscrm.runtime-metadata-view/v8"
	// RuntimeMetadataViewSchemaV10 is the report-execution-only projection of
	// immutable, versioned neutral report definitions.
	RuntimeMetadataViewSchemaV10 = "nexuscrm.runtime-metadata-view/v10"
	// RuntimeMetadataViewSchemaV11 carries the exact AppInstallation-scoped
	// command kind/version registrations selected by Catalog. A command-only
	// view contains no object metadata.
	RuntimeMetadataViewSchemaV11 = "nexuscrm.runtime-metadata-view/v11"
	// RuntimeMetadataViewSchemaV12 carries workload-scoped immutable
	// definition bindings for definition-selecting commands.
	RuntimeMetadataViewSchemaV12 = "nexuscrm.runtime-metadata-view/v12"
	// RuntimeMetadataViewSchemaV13 is the record-mutation projection of the
	// connector execution facts introduced by Catalog Snapshot V11.
	RuntimeMetadataViewSchemaV13 = "nexuscrm.runtime-metadata-view/v13"
	// RuntimeMetadataViewSchemaV14 adds the closed inbound-identity
	// finalization authority introduced by Catalog Snapshot V12.
	RuntimeMetadataViewSchemaV14 = "nexuscrm.runtime-metadata-view/v14"
	// RuntimeMetadataViewSchemaV15 adds the closed source-record eligibility
	// predicate used by the command-owned recovery transition.
	RuntimeMetadataViewSchemaV15 = "nexuscrm.runtime-metadata-view/v15"
	// RuntimeMetadataViewSchemaV16 carries immutable neutral approval definitions.
	// The explicit profile determines whether the view also carries mutation
	// authority; approval reads never inherit the execution closure.
	RuntimeMetadataViewSchemaV16 = "nexuscrm.runtime-metadata-view/v16"
	RuntimeMetadataViewSchemaV17 = "nexuscrm.runtime-metadata-view/v17"
	// RuntimeMetadataViewSchemaV18 is the least-privilege metadata half of
	// effective-permission serving: scoped object/field identities and active
	// record-type identities only. It carries no record mutation authority.
	RuntimeMetadataViewSchemaV18 = "nexuscrm.runtime-metadata-view/v18"
	// RuntimeMetadataViewSchemaV19 carries the exact revision-local formula
	// vocabulary required by approval-execution mutation validation. Approval
	// read remains v16 and never inherits executable formula authority.
	RuntimeMetadataViewSchemaV19 = "nexuscrm.runtime-metadata-view/v19"
	// RuntimeMetadataViewSchemaV20 adds the record-query-only identity and
	// display projection for immutable logical reference targets. It never
	// carries executable Approval definitions, criteria, metadata, or actions.
	RuntimeMetadataViewSchemaV20 = "nexuscrm.runtime-metadata-view/v20"
	// RuntimeMetadataViewSchemaV21 closes the metadata facts required to
	// compute effective object and field permissions. It carries only generic
	// permission-decision object facts and sharing-parent edges; record/query
	// physical identity and executable mutation authority remain absent.
	RuntimeMetadataViewSchemaV21 = "nexuscrm.runtime-metadata-view/v21"
	// RuntimeMetadataViewSchemaV22 is the record-mutation projection of the
	// operation-typed SEND_MAIL route and its neutral completion authority.
	RuntimeMetadataViewSchemaV22 = "nexuscrm.runtime-metadata-view/v22"
	// RuntimeMetadataViewSchemaV23 is the layout-resolution-only projection. It
	// contains presentation metadata and routing facts, never record data,
	// physical storage identity, or permission decisions.
	RuntimeMetadataViewSchemaV23 = "nexuscrm.runtime-metadata-view/v23"
	// RuntimeMetadataViewSchemaV24 closes the generic access-decision facts
	// required by the record-view response. V7 could return Read/Update/Delete/
	// Locked but omitted RequiredWritePermission and LockRule from its object
	// projection, so the response could overstate mutation access.
	RuntimeMetadataViewSchemaV24 = "nexuscrm.runtime-metadata-view/v24"
	// RuntimeMetadataViewSchemaV25 carries executable field-mapping value
	// policies in a mutation-capable projection.
	RuntimeMetadataViewSchemaV25 = "nexuscrm.runtime-metadata-view/v25"
	// RuntimeMetadataViewSchemaV26 projects the V19 outbound-mail completion
	// authority while preserving V22 and V25 for already published views.
	RuntimeMetadataViewSchemaV26 = "nexuscrm.runtime-metadata-view/v26"
	// RuntimeMetadataViewSchemaV27 is the stored Layout authoring projection.
	// It contains no rendering resolver or record/query authority.
	RuntimeMetadataViewSchemaV27 = "nexuscrm.runtime-metadata-view/v27"
	// RuntimeMetadataViewSchemaV28 carries same-snapshot Layout create context.
	RuntimeMetadataViewSchemaV28        = "nexuscrm.runtime-metadata-view/v28"
	ServingCompatibilityReceiptSchemaV1 = "nexuscrm.runtime-serving-compatibility-receipt/v1"
	ServingCompatibilityReceiptSchemaV2 = "nexuscrm.runtime-serving-compatibility-receipt/v2"
)

type CatalogRevision uint64
type SchemaGeneration uint64
type EngineGeneration uint64
type DefinitionVersion string
type Digest string

// ProjectionProfile is an internal Catalog compiler profile. It selects a
// closed metadata fact set; it is not an L1 API capability or a wire contract.
type ProjectionProfile string

const (
	ProjectionSelectedRootReadV1     ProjectionProfile = "selected-root-read/v1"
	ProjectionRecordAccessV1         ProjectionProfile = "record-access/v1"
	ProjectionRecordQueryV1          ProjectionProfile = "record-query/v1"
	ProjectionRecordMutationV1       ProjectionProfile = "record-mutation/v1"
	ProjectionRecordViewV1           ProjectionProfile = "record-view/v1"
	ProjectionReportExecutionV1      ProjectionProfile = "report-execution/v1"
	ProjectionCommandAcceptanceV1    ProjectionProfile = "command-acceptance/v1"
	ProjectionApprovalExecutionV1    ProjectionProfile = "approval-execution/v1"
	ProjectionApprovalReadV1         ProjectionProfile = "approval-read/v1"
	ProjectionEffectivePermissionsV1 ProjectionProfile = "effective-permissions/v1"
	ProjectionPageLayoutResolutionV1 ProjectionProfile = "page-layout-resolution/v1"
	ProjectionLayoutAuthoringV1      ProjectionProfile = "layout-authoring/v1"
)

type Lineage struct {
	CatalogRevision  CatalogRevision  `json:"catalogRevision"`
	SchemaGeneration SchemaGeneration `json:"schemaGeneration"`
	EngineGeneration EngineGeneration `json:"engineGeneration"`
}

// Compatibility is the local Runtime state checked before a view can be used.
// SchemaGeneration is monotonic physical readiness; EngineGeneration is an
// exact semantic implementation generation for the v2 artifact.
type Compatibility struct {
	SchemaGeneration SchemaGeneration
	EngineGeneration EngineGeneration
}

type ObjectInput struct {
	CatalogRevision CatalogRevision
	Metadata        *models.ObjectMetadata
}

type RelationshipInput struct {
	CatalogRevision CatalogRevision
	Metadata        *models.Relationship
}

type SharingRuleInput struct {
	CatalogRevision CatalogRevision
	Metadata        *models.SharingRule
}

// DefinitionInput carries only identity/version lineage. Definition payloads
// belong to their owning capability and enter a view only when its profile
// explicitly selects them.
type DefinitionInput struct {
	CatalogRevision   CatalogRevision
	ComponentID       string
	DefinitionVersion DefinitionVersion
	ContentDigest     Digest
}

// ReportDefinitionInput is one neutral report IR already normalized by the L1
// release compiler. Catalog validates and scopes it but does not parse a
// product report dialect or read a mutable Report repository.
type ReportDefinitionInput struct {
	CatalogRevision   CatalogRevision
	ComponentID       string
	DefinitionVersion DefinitionVersion
	ContentDigest     Digest
	Definition        *models.ReportDefinition
}

// CommandRegistrationInput is one AppRelease-owned authorization for an exact
// neutral Runtime command kind and payload format version. It deliberately
// carries no handler/parser identity: execution ownership remains outside the
// durable acceptance boundary.
type CommandRegistrationInput struct {
	CatalogRevision      CatalogRevision
	ComponentID          string
	DefinitionVersion    DefinitionVersion
	ContentDigest        Digest
	CommandKind          string
	PayloadFormatVersion uint32
	ExecutionBindings    []CommandExecutionBinding
}

// CommandExecutionBinding narrows one registered neutral command to the exact
// immutable definition and context namespace an authorized workload may
// execute. Dynamic inputs remain outside Catalog.
type CommandExecutionBinding struct {
	AuthorizedWorkloadID string `json:"authorizedWorkloadId"`
	DefinitionRef        string `json:"definitionRef"`
	DefinitionVersion    string `json:"definitionVersion"`
	ContextNamespace     string `json:"contextNamespace"`
}

// IntegrationBindingReference is one exact Catalog-authorized component used
// by a neutral outbound intent route. It contains identity only: endpoint,
// credential value, provider request and delivery state remain outside
// Runtime.
type IntegrationBindingReference struct {
	Kind               consumerv1.IntegrationBindingKind `json:"kind"`
	OwnerPack          string                            `json:"ownerPack"`
	PackInstallationID string                            `json:"packInstallationId"`
	PackPayloadDigest  string                            `json:"packPayloadDigest"`
	BusinessKey        string                            `json:"businessKey"`
	DefinitionVersion  uint64                            `json:"definitionVersion"`
}

// OutboundMailCompletionProjection is the product-neutral record projection
// Runtime may apply after Integration proves delivery of a SEND_MAIL intent.
// Every object and field identity is Catalog-owned; provider endpoints,
// credentials, and transport responses are deliberately absent.
type OutboundMailCompletionProjection struct {
	RecipientAddressField string                         `json:"recipientAddressField"`
	RecipientOptOutField  string                         `json:"recipientOptOutField"`
	Activity              OutboundMailActivityProjection `json:"activity"`
	Message               OutboundMailMessageProjection  `json:"message"`
}

type OutboundMailActivityProjection struct {
	ObjectAPIName     string `json:"objectApiName"`
	SourceRecordField string `json:"sourceRecordField"`
	SubjectField      string `json:"subjectField"`
	ActivityDateField string `json:"activityDateField"`
	StatusField       string `json:"statusField"`
	PriorityField     string `json:"priorityField"`
	BodyField         string `json:"bodyField"`
	OwnerField        string `json:"ownerField"`
	TypeField         string `json:"typeField"`
	SubtypeField      string `json:"subtypeField"`
	FixedSubject      string `json:"fixedSubject"`
	FixedStatus       string `json:"fixedStatus"`
	FixedPriority     string `json:"fixedPriority"`
	FixedType         string `json:"fixedType"`
	FixedSubtype      string `json:"fixedSubtype"`
}

type OutboundMailMessageProjection struct {
	ObjectAPIName      string `json:"objectApiName"`
	ActivityIDField    string `json:"activityIdField"`
	FromAddressField   string `json:"fromAddressField"`
	ToAddressField     string `json:"toAddressField"`
	CcAddressField     string `json:"ccAddressField,omitempty"`
	BccAddressField    string `json:"bccAddressField,omitempty"`
	SubjectField       string `json:"subjectField"`
	TextBodyField      string `json:"textBodyField"`
	HTMLBodyField      string `json:"htmlBodyField,omitempty"`
	AttachmentIDsField string `json:"attachmentIdsField,omitempty"`
	IncomingField      string `json:"incomingField"`
	StatusField        string `json:"statusField"`
	MessageDateField   string `json:"messageDateField"`
	FixedIncoming      bool   `json:"fixedIncoming"`
	FixedStatus        string `json:"fixedStatus"`
}

// OutboundIntentRoute binds one pack-owned Flow action to the exact
// Integration workload and immutable binding references allowed to accept its
// provider-neutral intent. Catalog derives this value from an
// IntegrationBindingView publication; Runtime cannot author or widen it.
type OutboundIntentRoute struct {
	AuthorizedWorkloadID string                            `json:"authorizedWorkloadId"`
	ConnectorOwnerKey    string                            `json:"connectorOwnerKey"`
	FlowDeveloperName    string                            `json:"flowDeveloperName"`
	FlowActionName       string                            `json:"flowActionName"`
	SourceObject         string                            `json:"sourceObject"`
	ActionSlotID         string                            `json:"actionSlotId"`
	DestinationSlotID    string                            `json:"destinationSlotId"`
	Operation            outboundintentv1.Operation        `json:"operation,omitempty"`
	Bindings             []IntegrationBindingReference     `json:"bindings"`
	MailCompletion       *OutboundMailCompletionProjection `json:"mailCompletion,omitempty"`
}

type OutboundIntentRouteInput struct {
	CatalogRevision CatalogRevision
	Route           OutboundIntentRoute
}

// MutationDefinitionInput is the Catalog-owned, revision-stamped metadata
// closure required by the generic record mutation engine. Each row remains a
// normal Catalog fact; this input does not create a second authoring surface.
// Runtime projection selects the complete effective behavior reachable from
// its object closure and never consults the live metadata repository. App
// component provenance is intentionally separate: the initiating App must not
// be able to omit another App's or an administrator's active rule for the same
// effective object.
type MutationDefinitionInput struct {
	CatalogRevision                  CatalogRevision
	ValidationRule                   *models.ValidationRule
	RecordType                       *models.RecordType
	TriggerSubscription              *TriggerSubscription
	FlowDefinition                   *models.FlowDefinition
	FlowVersion                      *models.FlowVersion
	AutoNumberRule                   *AutoNumberRule
	FieldMappingRule                 *FieldMappingRule
	ConnectorInboundFieldMappingRule *ConnectorInboundFieldMappingRule
	ConnectorInboundAuthorship       *ConnectorInboundAuthorshipBinding
	ConnectorInboundFinalization     *ConnectorInboundFinalizationAuthority
	CreateSourceGuard                *CreateFromSourceGuardRule
	OAuthPublicScope                 *OAuthPublicScopeRule
}

type TriggerSubscription struct {
	ID                string `json:"id"`
	KeyPrefix         string `json:"keyPrefix"`
	EventType         string `json:"eventType"`
	RecordTriggerType string `json:"recordTriggerType"`
	FlowDefinitionID  string `json:"flowDefinitionId"`
	FlowVersionID     string `json:"flowVersionId"`
	IsActive          bool   `json:"isActive"`
}

// AutoNumberRule is the immutable Catalog representation of the generic
// autonumber engine input. Counter values remain Runtime record state and are
// intentionally absent.
type AutoNumberRule struct {
	FieldID       string               `json:"fieldId"`
	ObjectAPIName string               `json:"objectApiName"`
	FieldAPIName  string               `json:"fieldApiName"`
	Format        string               `json:"format"`
	Start         int64                `json:"start"`
	Scope         string               `json:"scope"`
	DateSource    string               `json:"dateSource"`
	OnChange      string               `json:"onChange"`
	TokenRefs     []AutoNumberTokenRef `json:"tokenRefs,omitempty"`
}

type AutoNumberTokenRef struct {
	DirectField  string                   `json:"directField,omitempty"`
	FKChains     [][]AutoNumberLookupStep `json:"fkChains"`
	ReadStrategy string                   `json:"readStrategy"`
	TargetField  string                   `json:"targetField"`
	TargetObject string                   `json:"targetObject"`
	TokenLiteral string                   `json:"tokenLiteral"`
}

type AutoNumberLookupStep struct {
	FK           string `json:"fk"`
	TargetField  string `json:"targetField"`
	TargetObject string `json:"targetObject"`
}

// FieldMappingRule is one effective generic source-to-target mapping row used
// by record mutation and Flow record operations. Catalog remains the author
// and conflict resolver; Runtime receives only the effective row for one
// revision and never reads _System_ObjectFieldMapping directly.
type FieldMappingRule struct {
	SourceObject      string `json:"sourceObject"`
	TargetObject      string `json:"targetObject"`
	ActionType        string `json:"actionType"`
	SourceField       string `json:"sourceField,omitempty"`
	TargetField       string `json:"targetField"`
	DefaultValue      string `json:"defaultValue,omitempty"`
	ValueMap          string `json:"valueMap,omitempty"`
	OnUnmappedValue   string `json:"onUnmappedValue,omitempty"`
	SourceLookupField string `json:"sourceLookupField,omitempty"`
}

// ConnectorInboundFieldMappingRule is one immutable connector execution fact.
// It is intentionally distinct from FieldMappingRule: the latter is consumed
// by legacy Flow/Records copy adapters, while this type carries transform,
// conflict, value-map and owner semantics for the connector executor.
type ConnectorInboundFieldMappingRule struct {
	Source              string `json:"source"`
	PackAuthored        bool   `json:"packAuthored,omitempty"`
	SourceObject        string `json:"sourceObject"`
	TargetObject        string `json:"targetObject"`
	ActionType          string `json:"actionType"`
	SourceField         string `json:"sourceField"`
	TargetField         string `json:"targetField"`
	Direction           string `json:"direction"`
	TransformExpression string `json:"transformExpression,omitempty"`
	ConflictPolicy      string `json:"conflictPolicy,omitempty"`
	DefaultValue        string `json:"defaultValue,omitempty"`
	ValueMap            string `json:"valueMap,omitempty"`
	OnUnmappedValue     string `json:"onUnmappedValue,omitempty"`
	SortOrder           int    `json:"sortOrder,omitempty"`
}

// ConnectorInboundAuthorshipBinding is the minimum immutable installed
// connector contract projection required to bind inbound remote-id evidence.
// It contains no credential value, provider payload, or external effect.
type ConnectorInboundAuthorshipBinding struct {
	ConnectorOwnerKey string `json:"connectorOwnerKey"`
	Generation        string `json:"generation"`
	ActionSlotID      string `json:"actionSlotId"`
	ActionType        string `json:"actionType"`
	SourceObject      string `json:"sourceObject"`
	DestinationSlotID string `json:"destinationSlotId"`
	TargetObject      string `json:"targetObject"`
	ProfileOwnerPack  string `json:"profileOwnerPack,omitempty"`
	ProfileName       string `json:"profileName"`
	RemoteIDField     string `json:"remoteIdField"`
}

// ConnectorInboundFinalizationAuthority is the complete least-privilege
// metadata closure needed to publish an inbound remote identity atomically
// with its owning record mutation. Catalog derives every field from exact
// installed pack generations. Runtime may use it to build durable identity
// state, but it contains no credential value and authorizes no external I/O.
type ConnectorInboundFinalizationAuthority struct {
	ContractGeneration        string                                                    `json:"contractGeneration"`
	Contract                  connector.ConnectorPushDurableMetadataContract            `json:"contract"`
	Profile                   ConnectorInboundFinalizationProfile                       `json:"profile"`
	OutboundMappings          []connector.ConnectorFieldMappingInput                    `json:"outboundMappings"`
	RecoverySourceEligibility *connector.ConnectorPushRecoverySourceEligibilityContract `json:"recoverySourceEligibility,omitempty"`
}

// ConnectorInboundFinalizationProfile is the exact installed profile subset
// hashed into durable remote-link state. Pagination, batch-read and provider
// payload behavior are intentionally absent because finalization performs no
// provider effect.
type ConnectorInboundFinalizationProfile struct {
	Generation           string  `json:"generation"`
	OwnerPack            string  `json:"ownerPack"`
	ProfileName          string  `json:"profileName"`
	CredentialRef        string  `json:"credentialRef"`
	EndpointClass        string  `json:"endpointClass"`
	MaxAttempts          int     `json:"maxAttempts"`
	BaseDelayNanos       int64   `json:"baseDelayNanos"`
	Multiplier           float64 `json:"multiplier"`
	MaxDelayNanos        int64   `json:"maxDelayNanos"`
	RetryableStatusCodes []int   `json:"retryableStatusCodes,omitempty"`
}

// CreateFromSourceGuardRule is the effective ownership fact that prevents a
// generic target-record create from bypassing the Standard Action/Flow that
// owns that source relationship. Catalog derives it from the existing field
// mapping, object/field, StandardAction, and active Flow authorities inside one
// revision; Runtime never re-reads those registries behind the bound view.
type CreateFromSourceGuardRule struct {
	TargetObject           string `json:"targetObject"`
	SourceFKField          string `json:"sourceFkField"`
	OwningStandardActionID string `json:"owningStandardActionId"`
	ActionName             string `json:"actionName"`
}

// OAuthPublicScopeRule is the least-privilege, effective decision needed when
// the generic record engine validates an OAuth-client metadata write.
// ObjectAPIName explicitly binds the decision to the metadata object that owns
// the write policy; the app-blind compiler never infers that role from a known
// product or system object name. Runtime receives neither HTTP route patterns
// nor product route-family vocabulary; those facts have already been validated
// by the owning L1 release compiler before this decision is published.
type OAuthPublicScopeRule struct {
	ObjectAPIName string `json:"objectApiName"`
	Name          string `json:"name"`
	OwnerPack     string `json:"ownerPack,omitempty"`
}

// RuntimeProjectionInput is an effective scope supplied by Catalog. The
// compiler consumes the opaque AppInstallation identifier; it neither creates
// nor validates AppInstallation lifecycle authority.
type RuntimeProjectionInput struct {
	CatalogRevision        CatalogRevision
	AppInstallationID      string
	CapabilityID           string
	Profile                ProjectionProfile
	ObjectAPINames         []string
	DefinitionComponentIDs []string
}

// RecordAttachmentSourceResolverInput is one closed, AppRelease-owned source
// lookup plan. It can select a source row and its file-reference field, but it
// cannot carry SQL, joins, target tables, output columns, or authorization
// policy. Runtime always resolves to its own protected file model and applies
// parent/file authorization before returning any file fact.
type RecordAttachmentSourceResolverInput struct {
	CatalogRevision                 CatalogRevision
	ResolverID                      string
	Kind                            RecordAttachmentSourceResolverKind
	SourceObjectAPIName             string
	SourceFileReferenceFieldAPIName string
	SourceDeletedFieldAPIName       string
	SourceRecordMatcher             *RecordAttachmentSourceRecordMatcher
}

// RecordAttachmentSourceFieldInput binds one effective root string field to a
// resolver from the same immutable AppRelease closure. L1 receives only this
// binding after FLS; it never reads or copies the AppRelease component.
type RecordAttachmentSourceFieldInput struct {
	CatalogRevision CatalogRevision
	ObjectAPIName   string
	FieldAPIName    string
	ResolverID      string
}

type RecordAttachmentSourceResolverKind string

const (
	// RecordAttachmentSourceByRecordV1 is the historical non-serving closure.
	// It only described a whole source-record identifier and must never be
	// selected by the serving attachment-source operation.
	RecordAttachmentSourceByRecordV1 RecordAttachmentSourceResolverKind = "record-attachment-by-source-record/v1"
	// RecordAttachmentSourceByRecordV2 requires a separately validated,
	// metadata-declared record-identifier matcher. It is the only resolver
	// grammar that a future serving attachment-source operation may select.
	RecordAttachmentSourceByRecordV2 RecordAttachmentSourceResolverKind = "record-attachment-by-source-record/v2"
)

// RecordAttachmentSourceRecordMatcherKind is intentionally a tiny closed
// vocabulary. It names whether an already authorized, proof-bound source
// value is a complete record identifier or one bounded identifier segment. It
// is not a product URL grammar, SQL expression, or query plan.
type RecordAttachmentSourceRecordMatcherKind string

const (
	RecordAttachmentSourceMatchRecordIDV1 RecordAttachmentSourceRecordMatcherKind = "record-identifier-exact/v1"
	// RecordAttachmentSourceMatchRecordIDSegmentV1 remains readable only for
	// historical artifacts. It declared a length but not where the segment
	// occurs in the source record identifier, so it cannot authorize a serving
	// lookup.
	RecordAttachmentSourceMatchRecordIDSegmentV1 RecordAttachmentSourceRecordMatcherKind = "record-identifier-segment/v1"
	// RecordAttachmentSourceMatchRecordIDSegmentV2 declares the complete,
	// bounded source-record identifier segment relation. It is the only segment
	// matcher that a serving resolver may select.
	RecordAttachmentSourceMatchRecordIDSegmentV2 RecordAttachmentSourceRecordMatcherKind = "record-identifier-segment/v2"
)

// RecordAttachmentSourceRecordMatcher is the Catalog-owned source-row key
// relation. The request-scoped byte offset belongs to the caller's proof of
// the current parent-field value; it cannot be Catalog metadata because an
// identifier's position in a product value varies per record. In contrast,
// StartOffsetBytes and LengthBytes are static facts about the source record
// identifier itself. A segment matcher must declare both. The bounds reuse the
// published Runtime record-identifier ceiling rather than inventing a second
// metadata limit.
type RecordAttachmentSourceRecordMatcher struct {
	Kind             RecordAttachmentSourceRecordMatcherKind
	StartOffsetBytes *uint16
	LengthBytes      uint16
}

const maxAttachmentSourceRecordIdentifierBytes = commonv1.MaxRecordIdentifierBytes

// RecordAttachmentSourceResolver is the immutable neutral plan exposed by a
// bound RuntimeMetadataView. Its closed matcher determines whether the
// authorized source value is the source object's complete record identifier or
// contains one bounded identifier segment. Product-specific URL parsing stays
// in L1.
type RecordAttachmentSourceResolver struct {
	ResolverID                      string
	Kind                            RecordAttachmentSourceResolverKind
	SourceObjectAPIName             string
	SourceFileReferenceFieldAPIName string
	SourceDeletedFieldAPIName       string
	SourceRecordMatcher             *RecordAttachmentSourceRecordMatcher
}

type RecordAttachmentSourceField struct {
	ObjectAPIName string
	FieldAPIName  string
	ResolverID    string
}

type CompileInput struct {
	OrgID                     string
	Lineage                   Lineage
	Objects                   []ObjectInput
	Relationships             []RelationshipInput
	SharingRules              []SharingRuleInput
	Definitions               []DefinitionInput
	ReportDefinitions         []ReportDefinitionInput
	CommandRegistrations      []CommandRegistrationInput
	ApprovalDefinitions       []ApprovalDefinitionInput
	FormulaFunctionBundles    []FormulaFunctionBundleInput
	OutboundIntentRoutes      []OutboundIntentRouteInput
	MutationDefinitions       []MutationDefinitionInput
	AttachmentSourceResolvers []RecordAttachmentSourceResolverInput
	AttachmentSourceFields    []RecordAttachmentSourceFieldInput
	PageLayouts               []PageLayoutInput
	LayoutAssignments         []LayoutAssignmentInput
	PageLayoutRecordTypes     []PageLayoutRecordTypeInput
	RelatedListResolutions    []RelatedListResolutionInput
	LayoutAuthoringAggregates []LayoutAuthoringAggregateInput
	Projections               []RuntimeProjectionInput
}

// LayoutAuthoringAggregateInput binds one complete stored-authoring workspace
// to the Catalog revision that observed it. It is deliberately separate from
// PageLayouts and LayoutAssignments: those inputs own caller-effective
// resolution facts and may exclude stored Layout kinds that authoring must
// preserve losslessly.
type LayoutAuthoringAggregateInput struct {
	CatalogRevision CatalogRevision
	Aggregate       *models.LayoutAuthoringAggregate
}

// FormulaFunctionBundleInput binds one executable formula declaration bundle
// to the Catalog revision that selected it. Like every other source-backed
// compiler input, the revision stamp is checked before the canonical snapshot
// drops source provenance into its single immutable Lineage.
type FormulaFunctionBundleInput struct {
	CatalogRevision CatalogRevision
	Bundle          formula.FunctionBundle
}

// EffectiveMetadata is canonical, content-addressed compiler input. Its
// representation is intentionally opaque so callers cannot construct a second
// metadata model or bypass strict decoding and validation.
type EffectiveMetadata struct {
	digest Digest
	bytes  []byte
}

func (m EffectiveMetadata) Digest() Digest { return m.digest }
func (m EffectiveMetadata) Bytes() []byte  { return append([]byte(nil), m.bytes...) }

type ProjectionKey struct {
	AppInstallationID string
	CapabilityID      string
}

type ArtifactKind string

const (
	ArtifactCatalogSnapshot             ArtifactKind = "catalog-snapshot"
	ArtifactRuntimeMetadataView         ArtifactKind = "runtime-metadata-view"
	ArtifactServingCompatibilityReceipt ArtifactKind = "serving-compatibility-receipt"
)

type Artifact struct {
	kind   ArtifactKind
	digest Digest
	bytes  []byte
}

func (a Artifact) Kind() ArtifactKind { return a.kind }
func (a Artifact) Digest() Digest     { return a.digest }
func (a Artifact) Bytes() []byte      { return append([]byte(nil), a.bytes...) }

var (
	ErrArtifactNotFound  = errors.New("catalog snapshot artifact not found")
	ErrArtifactCorrupt   = errors.New("catalog snapshot artifact is corrupt")
	ErrUnsupportedSchema = errors.New("catalog snapshot schema version is unsupported")
	ErrIncompatible      = errors.New("catalog snapshot artifact is incompatible with this Runtime")
)

type ConflictKind string

const (
	ConflictMissingRevision         ConflictKind = "missing_revision"
	ConflictMixedRevision           ConflictKind = "mixed_revision"
	ConflictInvalidIdentity         ConflictKind = "invalid_identity"
	ConflictDuplicateObject         ConflictKind = "duplicate_object"
	ConflictDuplicateField          ConflictKind = "duplicate_field"
	ConflictDuplicateRelationship   ConflictKind = "duplicate_relationship"
	ConflictAmbiguousSharingParent  ConflictKind = "ambiguous_sharing_parent"
	ConflictInvalidReadSource       ConflictKind = "invalid_read_source"
	ConflictInvalidRelationship     ConflictKind = "invalid_relationship"
	ConflictInvalidSharingRule      ConflictKind = "invalid_sharing_rule"
	ConflictInvalidAccessPolicy     ConflictKind = "invalid_access_policy"
	ConflictInvalidLockRule         ConflictKind = "invalid_lock_rule"
	ConflictInvalidDefinition       ConflictKind = "invalid_definition"
	ConflictInvalidProjection       ConflictKind = "invalid_projection"
	ConflictInvalidAttachmentSource ConflictKind = "invalid_attachment_source"
	ConflictEncoding                ConflictKind = "encoding_failure"
)

type ConflictError struct {
	Kind ConflictKind
	Path string
	Err  error
}

func (e *ConflictError) Error() string {
	if e == nil {
		return "<nil>"
	}
	if e.Path == "" {
		return fmt.Sprintf("catalog snapshot %s: %v", e.Kind, e.Err)
	}
	return fmt.Sprintf("catalog snapshot %s at %s: %v", e.Kind, e.Path, e.Err)
}

func (e *ConflictError) Unwrap() error { return e.Err }

func conflict(kind ConflictKind, path, format string, args ...any) error {
	return &ConflictError{Kind: kind, Path: path, Err: fmt.Errorf(format, args...)}
}

type catalogDocument struct {
	Schema                 string                        `json:"schema"`
	OrgID                  string                        `json:"orgId"`
	Lineage                Lineage                       `json:"lineage"`
	Objects                []catalogObject               `json:"objects"`
	Relationships          []relationshipRecord          `json:"relationships"`
	SharingRules           []sharingRuleRecord           `json:"sharingRules"`
	Definitions            []definitionRecord            `json:"definitions"`
	Reports                []reportDefinitionRecord      `json:"reports,omitempty"`
	CommandRegistrations   []commandRegistrationRecord   `json:"commandRegistrations,omitempty"`
	ApprovalDefinitions    []approvalDefinitionRecord    `json:"approvalDefinitions,omitempty"`
	FormulaFunctionBundles []formula.FunctionBundle      `json:"formulaFunctionBundles,omitempty"`
	OutboundIntentRoutes   []OutboundIntentRoute         `json:"outboundIntentRoutes,omitempty"`
	Mutation               *mutationDefinitionDocument   `json:"mutation,omitempty"`
	RecordView             *recordViewDefinitionDocument `json:"recordView,omitempty"`
	PageLayoutResolution   *pageLayoutResolutionDocument `json:"pageLayoutResolution,omitempty"`
	LayoutAuthoring        *layoutAuthoringDocument      `json:"layoutAuthoring,omitempty"`
	Projections            []projectionRecord            `json:"runtimeProjections"`
}

type recordViewDefinitionDocument struct {
	Resolvers []recordAttachmentSourceResolverRecord `json:"attachmentSourceResolvers"`
	Fields    []recordAttachmentSourceFieldRecord    `json:"attachmentSourceFields"`
}

type recordAttachmentSourceResolverRecord struct {
	ResolverID                      string                               `json:"resolverId"`
	Kind                            RecordAttachmentSourceResolverKind   `json:"kind"`
	SourceObjectAPIName             string                               `json:"sourceObjectApiName"`
	SourceFileReferenceFieldAPIName string                               `json:"sourceFileReferenceFieldApiName"`
	SourceDeletedFieldAPIName       string                               `json:"sourceDeletedFieldApiName,omitempty"`
	SourceRecordMatcher             *recordAttachmentSourceMatcherRecord `json:"sourceRecordMatcher,omitempty"`
}

type recordAttachmentSourceMatcherRecord struct {
	Kind             RecordAttachmentSourceRecordMatcherKind `json:"kind,omitempty"`
	StartOffsetBytes *uint16                                 `json:"startOffsetBytes,omitempty"`
	LengthBytes      uint16                                  `json:"lengthBytes,omitempty"`
}

type recordAttachmentSourceFieldRecord struct {
	ObjectAPIName string `json:"objectApiName"`
	FieldAPIName  string `json:"fieldApiName"`
	ResolverID    string `json:"resolverId"`
}

type mutationDefinitionDocument struct {
	ValidationRules                   []models.ValidationRule                 `json:"validationRules"`
	RecordTypes                       []models.RecordType                     `json:"recordTypes"`
	TriggerSubscriptions              []TriggerSubscription                   `json:"triggerSubscriptions"`
	FlowDefinitions                   []runtimeFlowDefinitionRecord           `json:"flowDefinitions"`
	FlowVersions                      []runtimeFlowVersionRecord              `json:"flowVersions"`
	AutoNumberRules                   []AutoNumberRule                        `json:"autoNumberRules"`
	FieldMappingRules                 []FieldMappingRule                      `json:"fieldMappingRules"`
	ConnectorInboundFieldMappingRules []ConnectorInboundFieldMappingRule      `json:"connectorInboundFieldMappingRules,omitempty"`
	ConnectorInboundAuthorship        []ConnectorInboundAuthorshipBinding     `json:"connectorInboundAuthorship,omitempty"`
	ConnectorInboundFinalization      []ConnectorInboundFinalizationAuthority `json:"connectorInboundFinalization,omitempty"`
	CreateSourceGuards                []CreateFromSourceGuardRule             `json:"createSourceGuards"`
	OAuthPublicScopes                 []OAuthPublicScopeRule                  `json:"oauthPublicScopes"`
	LegacyScopes                      []legacyMutationDefinitionScope         `json:"scopes,omitempty"`
}

// legacyMutationDefinitionScope exists only to decode and validate v3 Catalog
// artifacts during the v3 -> v4 rollout. New compilers never emit it and
// Runtime projection never uses it as behavior-selection authority.
type legacyMutationDefinitionScope struct {
	ComponentID string `json:"componentId"`
	Kind        string `json:"kind"`
	FactKey     string `json:"factKey"`
}

type runtimeFlowDefinitionRecord struct {
	ID                   string `json:"id"`
	DeveloperName        string `json:"developerName"`
	ProcessType          string `json:"processType"`
	TriggerType          string `json:"triggerType,omitempty"`
	TriggerObjectOrEvent string `json:"triggerObjectOrEvent,omitempty"`
	ActiveVersionID      string `json:"activeVersionId"`
	IsDeleted            bool   `json:"isDeleted,omitempty"`
	IsCustomized         bool   `json:"isCustomized,omitempty"`
	OwnerPack            string `json:"ownerPack,omitempty"`
}

type runtimeFlowVersionRecord struct {
	ID                     string          `json:"id"`
	DefinitionID           string          `json:"definitionId"`
	VersionNumber          int             `json:"versionNumber"`
	Status                 string          `json:"status"`
	ProcessType            string          `json:"processType"`
	Source                 string          `json:"source,omitempty"`
	DefinitionIsCustomized bool            `json:"definitionIsCustomized,omitempty"`
	DefinitionOwnerPack    string          `json:"definitionOwnerPack,omitempty"`
	IsDeleted              bool            `json:"isDeleted,omitempty"`
	Metadata               json.RawMessage `json:"metadata"`
}

type catalogObject struct {
	Metadata models.ObjectMetadata `json:"metadata"`
	Fields   []catalogField        `json:"fields"`
}

type catalogField struct {
	Metadata                         models.FieldMetadata `json:"metadata"`
	PhysicalName                     string               `json:"physicalName,omitempty"`
	GeneratedForPolymorphicReference string               `json:"generatedForPolymorphicReference,omitempty"`
}

type relationshipRecord struct {
	ID                  string  `json:"id,omitempty"`
	ChildObjectAPIName  string  `json:"childObjectApiName"`
	ParentObjectAPIName string  `json:"parentObjectApiName"`
	FieldAPIName        string  `json:"fieldApiName"`
	RelationshipName    string  `json:"relationshipName,omitempty"`
	RelationshipType    string  `json:"relationshipType,omitempty"`
	IsSharingParent     bool    `json:"isSharingParent,omitempty"`
	CascadeDelete       bool    `json:"cascadeDelete,omitempty"`
	RestrictedDelete    bool    `json:"restrictedDelete,omitempty"`
	RelatedListLabel    *string `json:"relatedListLabel,omitempty"`
	RelatedListFields   *string `json:"relatedListFields,omitempty"`
}

type sharingRuleRecord struct {
	ID                string  `json:"id"`
	ObjectAPIName     string  `json:"objectApiName"`
	Name              string  `json:"name"`
	Criteria          string  `json:"criteria,omitempty"`
	AccessLevel       string  `json:"accessLevel"`
	SharedFromRoleID  *string `json:"sharedFromRoleId,omitempty"`
	SharedFromGroupID *string `json:"sharedFromGroupId,omitempty"`
	ShareWithRoleID   *string `json:"shareWithRoleId,omitempty"`
	ShareWithGroupID  *string `json:"shareWithGroupId,omitempty"`
}

type definitionRecord struct {
	ComponentID       string            `json:"componentId"`
	DefinitionVersion DefinitionVersion `json:"definitionVersion"`
	ContentDigest     Digest            `json:"contentDigest"`
}

type projectionRecord struct {
	AppInstallationID      string            `json:"appInstallationId"`
	CapabilityID           string            `json:"capabilityId"`
	Profile                ProjectionProfile `json:"profile"`
	ObjectAPINames         []string          `json:"objectApiNames"`
	DefinitionComponentIDs []string          `json:"definitionComponentIds"`
}

type runtimeViewDocument struct {
	Schema                 string                                 `json:"schema"`
	SourceSnapshotDigest   Digest                                 `json:"sourceSnapshotDigest"`
	OrgID                  string                                 `json:"orgId"`
	AppInstallationID      string                                 `json:"appInstallationId"`
	CapabilityID           string                                 `json:"capabilityId"`
	Profile                ProjectionProfile                      `json:"profile"`
	Lineage                Lineage                                `json:"lineage"`
	Objects                []runtimeObjectRecord                  `json:"objects"`
	Relationships          []runtimeRelationshipRecord            `json:"relationships"`
	SharingRules           []runtimeSharingRuleRecord             `json:"sharingRules"`
	Definitions            []definitionRecord                     `json:"definitions"`
	Reports                []reportDefinitionRecord               `json:"reports,omitempty"`
	CommandRegistrations   []commandRegistrationRecord            `json:"commandRegistrations,omitempty"`
	ApprovalDefinitions    []approvalDefinitionRecord             `json:"approvalDefinitions,omitempty"`
	ReferenceIdentities    []runtimeReferenceIdentityRecord       `json:"referenceIdentities,omitempty"`
	FormulaFunctionBundles []formula.FunctionBundle               `json:"formulaFunctionBundles,omitempty"`
	OutboundIntentRoutes   []OutboundIntentRoute                  `json:"outboundIntentRoutes,omitempty"`
	Mutation               *mutationDefinitionDocument            `json:"mutation,omitempty"`
	RecordView             *recordViewDefinitionDocument          `json:"recordView,omitempty"`
	EffectivePermissions   *effectivePermissionDefinitionDocument `json:"effectivePermissions,omitempty"`
	PageLayoutResolution   *pageLayoutResolutionDocument          `json:"pageLayoutResolution,omitempty"`
	LayoutAuthoring        *layoutAuthoringDocument               `json:"layoutAuthoring,omitempty"`
}

// runtimeReferenceIdentityRecord is deliberately a closed display projection,
// not a generic map. Adding executable fields requires a new artifact grammar.
type runtimeReferenceIdentityRecord struct {
	ObjectAPIName       string `json:"objectApiName"`
	ID                  string `json:"id"`
	Name                string `json:"name"`
	DeveloperName       string `json:"developerName"`
	ProcessDefinitionID string `json:"processDefinitionId,omitempty"`
	StepOrder           int    `json:"stepOrder,omitempty"`
}

type effectivePermissionDefinitionDocument struct {
	Objects []EffectivePermissionObject `json:"objects"`
}

// EffectivePermissionObject is the immutable Catalog half of one scoped
// permission projection. Object and field identities are owned by the v21
// Runtime object closure; FieldNames remains only to decode historical v18
// artifacts, which are never admitted for effective-permission serving.
type EffectivePermissionObject struct {
	ResourceType string                          `json:"resourceType"`
	FieldNames   []string                        `json:"fieldNames,omitempty"`
	RecordTypes  []EffectivePermissionRecordType `json:"recordTypes"`
}

type EffectivePermissionRecordType struct {
	RecordTypeID  string `json:"recordTypeId"`
	DeveloperName string `json:"developerName"`
	Name          string `json:"name"`
}

// runtimeRelationshipRecord omits Catalog identity, presentation and mutation
// facts. Record-query views additionally carry the neutral relationship name
// needed to resolve already-parsed parent and child paths without consulting a
// Catalog repository.
type runtimeRelationshipRecord struct {
	ChildObjectAPIName  string                             `json:"childObjectApiName"`
	ParentObjectAPIName string                             `json:"parentObjectApiName"`
	FieldAPIName        string                             `json:"fieldApiName"`
	RelationshipName    string                             `json:"relationshipName,omitempty"`
	RelationshipType    string                             `json:"relationshipType,omitempty"`
	IsSharingParent     bool                               `json:"isSharingParent,omitempty"`
	Mutation            *runtimeMutationRelationshipRecord `json:"mutation,omitempty"`
}

// runtimeMutationRelationshipRecord contains relationship policies consumed
// only by record deletion. Keeping the complete write-only relationship shape
// under one profile-owned closure prevents read/access/query artifacts from
// acquiring delete semantics as the relationship model evolves.
type runtimeMutationRelationshipRecord struct {
	CascadeDelete    bool `json:"cascadeDelete,omitempty"`
	RestrictedDelete bool `json:"restrictedDelete,omitempty"`
}

// runtimeSharingRuleRecord carries the policy expression and its role/group
// references, but not the Catalog row identity or human presentation name.
// Role/group entities, memberships, grants and generated shares remain outside
// this metadata view.
type runtimeSharingRuleRecord struct {
	ObjectAPIName     string  `json:"objectApiName"`
	Criteria          string  `json:"criteria,omitempty"`
	AccessLevel       string  `json:"accessLevel"`
	SharedFromRoleID  *string `json:"sharedFromRoleId,omitempty"`
	SharedFromGroupID *string `json:"sharedFromGroupId,omitempty"`
	ShareWithRoleID   *string `json:"shareWithRoleId,omitempty"`
	ShareWithGroupID  *string `json:"shareWithGroupId,omitempty"`
}

// runtimeObjectRecord is the least-privilege object projection needed by the
// independently composed read or record-access path. Mutation hooks, defaults, layouts,
// navigation, secrets, Integration payloads, and record data are absent.
type runtimeObjectRecord struct {
	APIName                 string                         `json:"apiName"`
	KeyPrefix               *string                        `json:"keyPrefix,omitempty"`
	RequiredReadPermission  string                         `json:"requiredReadPermission,omitempty"`
	RequiredWritePermission string                         `json:"requiredWritePermission,omitempty"`
	TableType               constants.TableType            `json:"tableType,omitempty"`
	AccessPolicy            *models.ObjectAccessPolicy     `json:"accessPolicy,omitempty"`
	LockRule                *string                        `json:"lockRule,omitempty"`
	SharingModel            models.SharingModel            `json:"sharingModel"`
	EnableHierarchySharing  bool                           `json:"enableHierarchySharing"`
	ReadSource              *models.ObjectReadSourceConfig `json:"readSource,omitempty"`
	ResolvedBaseReadTable   string                         `json:"resolvedBaseReadTable,omitempty"`
	Fields                  []runtimeFieldRecord           `json:"fields"`
	Mutation                *runtimeMutationObjectRecord   `json:"mutation,omitempty"`
}

// runtimeMutationObjectRecord contains only write-engine facts. Presentation,
// navigation, layouts, secrets and unrelated App/Integration metadata remain
// absent. Physical field identity remains explicit because database mapping is
// part of Runtime execution, not an L1 fact.
type runtimeMutationObjectRecord struct {
	KeyPrefix              *string                        `json:"keyPrefix,omitempty"`
	IsSystem               bool                           `json:"isSystem,omitempty"`
	IsCustom               bool                           `json:"isCustom,omitempty"`
	CustomSetting          bool                           `json:"customSetting,omitempty"`
	TableType              constants.TableType            `json:"tableType,omitempty"`
	DeleteMode             string                         `json:"deleteMode,omitempty"`
	SharingParentObject    *string                        `json:"sharingParentObject,omitempty"`
	SharingParentField     *string                        `json:"sharingParentField,omitempty"`
	ChildCloneRules        []models.ChildCloneRule        `json:"childCloneRules,omitempty"`
	ExclusiveSiblingFields []models.ExclusiveSiblingField `json:"exclusiveSiblingFields,omitempty"`
	DefaultChildRows       []models.DefaultChildRow       `json:"defaultChildRows,omitempty"`
}

type runtimeFieldRecord struct {
	APIName                          string                        `json:"apiName"`
	PhysicalName                     string                        `json:"physicalName,omitempty"`
	Type                             models.FieldType              `json:"type"`
	LogicalType                      *models.FieldType             `json:"logicalType,omitempty"`
	Required                         bool                          `json:"required,omitempty"`
	IsCompound                       bool                          `json:"isCompound,omitempty"`
	ComposedFrom                     []string                      `json:"composedFrom,omitempty"`
	ReferenceTo                      []string                      `json:"referenceTo,omitempty"`
	IsPolymorphic                    bool                          `json:"isPolymorphic,omitempty"`
	Formula                          *string                       `json:"formula,omitempty"`
	ReturnType                       *models.FieldType             `json:"returnType,omitempty"`
	FormulaMode                      *string                       `json:"formulaMode,omitempty"`
	FormulaStorageMode               *string                       `json:"formulaStorageMode,omitempty"`
	ProjectionConfig                 *models.FieldProjectionConfig `json:"projection,omitempty"`
	IsMasterDetail                   bool                          `json:"isMasterDetail,omitempty"`
	RelationshipName                 *string                       `json:"relationshipName,omitempty"`
	ChildRelationshipName            *string                       `json:"childRelationshipName,omitempty"`
	Precision                        *int                          `json:"precision,omitempty"`
	Scale                            *int                          `json:"scale,omitempty"`
	IsVirtual                        bool                          `json:"isVirtual,omitempty"`
	VirtualKind                      string                        `json:"virtualKind,omitempty"`
	VirtualSourceAPIName             string                        `json:"virtualSourceApiName,omitempty"`
	ReadProtectionPolicy             string                        `json:"readProtectionPolicy,omitempty"`
	GeneratedForPolymorphicReference string                        `json:"generatedForPolymorphicReference,omitempty"`
	// IsNameField is a record-view presentation fact. It is emitted only for
	// the record-view projection, where Runtime needs the Catalog-declared
	// display field to enrich an already-authorized reference without a second
	// metadata read path.
	IsNameField bool                        `json:"isNameField,omitempty"`
	Mutation    *runtimeMutationFieldRecord `json:"mutation,omitempty"`
}

// runtimeMutationFieldRecord contains the field facts required only by the
// write engine. Keeping them in one profile-owned closure means read/access/
// query views cannot acquire write semantics one field at a time as this shape
// evolves.
type runtimeMutationFieldRecord struct {
	ID                    string                 `json:"id,omitempty"`
	DefaultedOnCreate     bool                   `json:"defaultedOnCreate,omitempty"`
	IsUnique              bool                   `json:"isUnique,omitempty"`
	IsNameField           bool                   `json:"isNameField,omitempty"`
	Source                string                 `json:"source,omitempty"`
	Options               models.PicklistOptions `json:"options,omitempty"`
	WritableReferenceTo   []string               `json:"writableReferenceTo,omitempty"`
	DeleteRule            *models.DeleteRule     `json:"deleteRule,omitempty"`
	IsSystem              bool                   `json:"isSystem,omitempty"`
	Createable            bool                   `json:"createable,omitempty"`
	Updateable            bool                   `json:"updateable,omitempty"`
	DefaultValue          *string                `json:"defaultValue,omitempty"`
	TrackHistory          bool                   `json:"trackHistory,omitempty"`
	MinValue              *float64               `json:"minValue,omitempty"`
	MaxValue              *float64               `json:"maxValue,omitempty"`
	MinLength             *int                   `json:"minLength,omitempty"`
	MaxLength             *int                   `json:"maxLength,omitempty"`
	Regex                 *string                `json:"regex,omitempty"`
	RegexMessage          *string                `json:"regexMessage,omitempty"`
	Validator             *string                `json:"validator,omitempty"`
	ValidatorConfig       *string                `json:"validatorConfig,omitempty"`
	ControllingField      *string                `json:"controllingField,omitempty"`
	PicklistDependency    map[string][]string    `json:"picklistDependency,omitempty"`
	RollupConfig          *models.RollupConfig   `json:"rollupConfig,omitempty"`
	WriteProtectionPolicy string                 `json:"writeProtectionPolicy,omitempty"`
	SiblingMaxParentField *string                `json:"siblingMaxParentField,omitempty"`
}

type CatalogSnapshot struct {
	digest Digest
	doc    catalogDocument
}

type runtimeRollupDependencyIndex struct {
	parentObjectIndex int
	rollupFieldIndex  int
}

type RuntimeMetadataView struct {
	digest                           Digest
	doc                              runtimeViewDocument
	objectsByName                    map[string]int
	relsByChild                      map[string][]int
	relsByParent                     map[string][]int
	rulesByObject                    map[string][]int
	definitionsByID                  map[string]int
	reportDefinitionsByID            map[string]int
	commandRegistrations             map[string]struct{}
	commandExecutionBindings         map[string]string
	approvalDefinitionsByID          map[string]int
	approvalDefinitionsByObject      map[string][]int
	referenceIdentitiesByObject      map[string]map[string]int
	attachmentResolversByID          map[string]int
	attachmentFieldsByObject         map[string][]int
	effectivePermissionObjectsByName map[string]int
	rollupDependenciesByChild        map[string][]runtimeRollupDependencyIndex
	hasAnySiblingMaxDefaults         bool
}

type ParityInput struct {
	Objects       []*models.ObjectMetadata
	Relationships []*models.Relationship
	SharingRules  []*models.SharingRule
}

type ParityDifference struct {
	Path     string `json:"path"`
	Kind     string `json:"kind"`
	Expected string `json:"expected,omitempty"`
	Actual   string `json:"actual,omitempty"`
}

type ParityReport struct {
	Differences []ParityDifference `json:"differences"`
}

func (r ParityReport) Equivalent() bool { return len(r.Differences) == 0 }
