package mapping

import (
	"context"
	"errors"
	"regexp"
	"strings"

	commonsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	identitysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/identityv1"
	querysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
	accesssemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordaccessv1"
	attachmentsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordattachmentsv1"
	defaultsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recorddefaultsv1"
	mutationsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordmutationv1"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordsv1"
	viewsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordviewv1"
	recyclemutationsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recyclebinmutationv1"
	recyclesemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recyclebinv1"
	relatedsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/relatedcountsv1"
	commonv1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/common/v1"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type capabilitySpec struct {
	name          string
	protocolMajor uint32
	protocolMinor uint32
	major         uint32
	minor         uint32
	// conflict is opt-in because ABORTED/CONFLICT is mutation state and must
	// not become part of every older capability merely because status encoding
	// is shared. Capabilities that do not declare it fail closed in both
	// directions at this common boundary.
	conflict bool
	// undetailedTransport contains categories that gRPC or the trusted host can
	// originate before the capability handler has a chance to attach typed
	// details. Only unambiguous, non-disclosing outcomes belong here.
	undetailedTransport map[commonsemantic.FailureCategory]bool
}

var (
	selectedRootCapability = capabilitySpec{
		name: semantic.CapabilityName, protocolMajor: semantic.ProtocolMajor, protocolMinor: semantic.ProtocolMinor, major: 1, minor: 0,
	}
	recordAccessCapability = capabilitySpec{
		name: accesssemantic.CapabilityName, protocolMajor: accesssemantic.ProtocolMajor, protocolMinor: accesssemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	createDefaultPreviewCapability = capabilitySpec{
		name: defaultsemantic.CapabilityName, protocolMajor: defaultsemantic.ProtocolMajor,
		protocolMinor: defaultsemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	recordMutationCapability = capabilitySpec{
		name: mutationsemantic.CapabilityName, protocolMajor: mutationsemantic.ProtocolMajor, protocolMinor: mutationsemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	queryCapability = capabilitySpec{
		name: querysemantic.CapabilityName, protocolMajor: querysemantic.ProtocolMajor, protocolMinor: querysemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	relatedCountCapability = capabilitySpec{
		name: relatedsemantic.CapabilityName, protocolMajor: relatedsemantic.ProtocolMajor, protocolMinor: relatedsemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	recycleBinCapability = capabilitySpec{
		name: recyclesemantic.CapabilityName, protocolMajor: recyclesemantic.ProtocolMajor, protocolMinor: recyclesemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	recycleBinMutationCapability = capabilitySpec{
		name: recyclemutationsemantic.CapabilityName, protocolMajor: recyclemutationsemantic.ProtocolMajor,
		protocolMinor: recyclemutationsemantic.ProtocolMinor, major: 1, minor: 0, conflict: true,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	recordViewCapability = capabilitySpec{
		name: viewsemantic.CapabilityName, protocolMajor: viewsemantic.ProtocolMajor, protocolMinor: viewsemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	recordAttachmentSourceCapability = capabilitySpec{
		name: attachmentsemantic.CapabilityName, protocolMajor: attachmentsemantic.ProtocolMajor, protocolMinor: attachmentsemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
	identityCapability = capabilitySpec{
		name: identitysemantic.CapabilityName, protocolMajor: identitysemantic.ProtocolMajor, protocolMinor: identitysemantic.ProtocolMinor, major: 1, minor: 0,
		undetailedTransport: map[commonsemantic.FailureCategory]bool{
			commonsemantic.FailureUnauthenticated:   true,
			commonsemantic.FailureForbidden:         true,
			commonsemantic.FailureCanceled:          true,
			commonsemantic.FailureDeadlineExceeded:  true,
			commonsemantic.FailureResourceExhausted: true,
			commonsemantic.FailureUnavailable:       true,
		},
	}
)

func ToStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validSelectedRootFailureCategory(failure.Category) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, selectedRootCapability)
}

// ToRecordAccessStatusError projects a neutral record-access semantic failure
// without allowing selected-root capability facts to leak into its receipts or
// compatibility detail.
func ToRecordAccessStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecordAccessFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recordAccessCapability)
}

func ToCreateDefaultPreviewStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validCreateDefaultPreviewFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, createDefaultPreviewCapability)
}

func ToRecordMutationStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecordMutationFailure(failure, false, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recordMutationCapability)
}

// ToRecordMutationReconciliationStatusError is the status-query counterpart
// to ToRecordMutationStatusError. Only reconciliation may expose top-level
// MISSING for an unknown, expired, or digest-mismatched command.
func ToRecordMutationReconciliationStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecordMutationFailure(failure, false, true) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recordMutationCapability)
}

func ToQueryStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validQueryFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, queryCapability)
}

func ToRelatedCountStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRelatedCountFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, relatedCountCapability)
}

func ToRecycleBinStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecycleBinFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recycleBinCapability)
}

func ToRecycleBinMutationStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecycleBinMutationFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recycleBinMutationCapability)
}

func ToRecordViewStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecordViewFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recordViewCapability)
}

// ToRecordAttachmentSourceStatusError preserves only failures admitted by the
// attachment-source contract and binds all typed details to its capability.
func ToRecordAttachmentSourceStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validRecordAttachmentSourceFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, recordAttachmentSourceCapability)
}

func ToIdentityStatusError(err error) error {
	var failure *commonsemantic.Failure
	if errors.As(err, &failure) && !validIdentityFailure(failure, false) {
		err = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return toStatusError(err, identityCapability)
}

func toStatusError(err error, capability capabilitySpec) error {
	if err == nil {
		return nil
	}
	if errors.Is(err, context.Canceled) {
		return status.Error(codes.Canceled, "runtime request canceled")
	}
	if errors.Is(err, context.DeadlineExceeded) {
		return status.Error(codes.DeadlineExceeded, "runtime request deadline exceeded")
	}
	var failure *commonsemantic.Failure
	if !errors.As(err, &failure) {
		failure = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	if failure.Category == commonsemantic.FailureConflict && !capability.conflict {
		failure = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	if codeForCategory(failure.Category) == codes.OK {
		failure = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	if failure.Receipts != nil && !validSemanticReceipts(*failure.Receipts, capability) {
		failure = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	if !commonsemantic.ValidFailureRetryAfter(failure) || !commonsemantic.ValidFailureConflictReason(failure) {
		failure = &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	detail := &commonv1.RuntimeErrorDetail{Category: toWireCategory(failure.Category)}
	if failure.Receipts != nil {
		detail.Receipts = toWireReceipts(*failure.Receipts, capability)
	}
	switch failure.Category {
	case commonsemantic.FailureConflict:
		if failure.ConflictReason != "" {
			detail.Detail = &commonv1.RuntimeErrorDetail_Conflict{Conflict: &commonv1.ConflictDetail{Reason: toWireConflictReason(failure.ConflictReason)}}
		}
	case semantic.FailureInvalidRequest:
		detail.Detail = &commonv1.RuntimeErrorDetail_InvalidRequest{InvalidRequest: &commonv1.InvalidRequestDetail{
			Component: toWireInvalidComponent(failure.InvalidComponent), CanonicalFieldName: safeFieldName(failure.CanonicalField),
		}}
	case semantic.FailureResourceExhausted:
		detail.Detail = &commonv1.RuntimeErrorDetail_LimitViolation{LimitViolation: &commonv1.LimitViolationDetail{
			Kind: toWireLimitKind(failure.LimitKind), ApprovedMaximum: failure.Maximum,
			RetryAfterMilliseconds: failure.RetryAfterMillis,
		}}
	case semantic.FailureIncompatible:
		detail.Detail = &commonv1.RuntimeErrorDetail_Compatibility{Compatibility: &commonv1.CompatibilityDetail{
			RequiredCapability:        capability.name,
			SupportedProtocolMajor:    capability.protocolMajor,
			SupportedProtocolMinorMin: capability.protocolMinor,
			SupportedProtocolMinorMax: capability.protocolMinor,
		}}
	case semantic.FailureStaleState:
		detail.Detail = &commonv1.RuntimeErrorDetail_StaleState{StaleState: &commonv1.StaleStateDetail{
			Axis: toWireStaleAxis(failure.StaleAxis), RequiredRevision: failure.RequiredRevision, ServedRevision: failure.ServedRevision,
		}}
	case semantic.FailureUnavailable:
		detail.Detail = &commonv1.RuntimeErrorDetail_Unavailable{Unavailable: &commonv1.UnavailableDetail{RetryAfterMilliseconds: failure.RetryAfterMillis}}
	case semantic.FailureInternal:
		detail.Detail = &commonv1.RuntimeErrorDetail_InternalFailure{InternalFailure: &commonv1.InternalFailureDetail{RequestId: safeRequestID(failure.RequestID)}}
	}
	withDetail, detailErr := status.New(codeForCategory(failure.Category), "runtime request failed").WithDetails(detail)
	if detailErr != nil {
		return status.Error(codes.Internal, "runtime request failed")
	}
	return withDetail.Err()
}

func FromStatusError(err error) error {
	decoded := fromStatusError(err, selectedRootCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validSelectedRootFailureCategory(failure.Category) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func validSelectedRootFailureCategory(category commonsemantic.FailureCategory) bool {
	switch category {
	case semantic.FailureInvalidRequest, semantic.FailureUnauthenticated,
		semantic.FailureForbidden, semantic.FailureMissing, semantic.FailureCanceled,
		semantic.FailureDeadlineExceeded, semantic.FailureResourceExhausted,
		semantic.FailureIncompatible, semantic.FailureStaleState,
		semantic.FailureUnavailable, semantic.FailureInternal:
		return true
	default:
		return false
	}
}

// FromRecordAccessStatusError decodes only details bound to the record-access
// capability. A well-formed receipt for a different Runtime capability fails
// closed as INCOMPATIBLE/INTERNAL rather than being silently reinterpreted.
func FromRecordAccessStatusError(err error) error {
	decoded := fromStatusError(err, recordAccessCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecordAccessFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromCreateDefaultPreviewStatusError(err error) error {
	decoded := fromStatusError(err, createDefaultPreviewCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validCreateDefaultPreviewFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRecordMutationStatusError(err error) error {
	decoded := fromStatusError(err, recordMutationCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecordMutationFailure(failure, true, false) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRecordMutationReconciliationStatusError(err error) error {
	decoded := fromStatusError(err, recordMutationCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecordMutationFailure(failure, true, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromQueryStatusError(err error) error {
	decoded := fromStatusError(err, queryCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validQueryFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRelatedCountStatusError(err error) error {
	decoded := fromStatusError(err, relatedCountCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRelatedCountFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRecycleBinStatusError(err error) error {
	decoded := fromStatusError(err, recycleBinCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecycleBinFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRecycleBinMutationStatusError(err error) error {
	decoded := fromStatusError(err, recycleBinMutationCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecycleBinMutationFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRecordViewStatusError(err error) error {
	decoded := fromStatusError(err, recordViewCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecordViewFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromRecordAttachmentSourceStatusError(err error) error {
	decoded := fromStatusError(err, recordAttachmentSourceCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validRecordAttachmentSourceFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func FromIdentityStatusError(err error) error {
	decoded := fromStatusError(err, identityCapability)
	var failure *commonsemantic.Failure
	if errors.As(decoded, &failure) && !validIdentityFailure(failure, true) {
		return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
	}
	return decoded
}

func fromStatusError(err error, capability capabilitySpec) error {
	if err == nil {
		return nil
	}
	grpcStatus, ok := status.FromError(err)
	if !ok {
		return &semantic.Failure{Category: semantic.FailureInternal}
	}
	category := categoryForCode(grpcStatus.Code())
	for _, raw := range grpcStatus.Details() {
		detail, ok := raw.(*commonv1.RuntimeErrorDetail)
		if !ok {
			continue
		}
		decoded := fromWireCategory(detail.GetCategory())
		if codeForCategory(decoded) != grpcStatus.Code() {
			return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
		}
		if decoded == commonsemantic.FailureConflict && !capability.conflict {
			return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
		}
		category = decoded
		failure := &commonsemantic.Failure{Category: category}
		if detail.GetReceipts() != nil {
			receipts, err := fromWireReceipts(detail.GetReceipts(), capability)
			if err != nil {
				return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
			}
			failure.Receipts = &receipts
		}
		if !decodeSafeDetail(failure, detail) || !commonsemantic.ValidFailureRetryAfter(failure) {
			return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
		}
		return failure
	}
	// Canceled and deadline are generated by gRPC itself for every capability.
	// A capability may additionally review a finite set of unambiguous host or
	// transport outcomes. Every other category requires typed detail so an
	// intermediary cannot reinterpret an arbitrary status as semantic truth.
	if category == semantic.FailureCanceled || category == semantic.FailureDeadlineExceeded || capability.undetailedTransport[category] {
		return &commonsemantic.Failure{Category: category}
	}
	return &commonsemantic.Failure{Category: commonsemantic.FailureInternal}
}

func decodeSafeDetail(failure *semantic.Failure, detail *commonv1.RuntimeErrorDetail) bool {
	switch failure.Category {
	case semantic.FailureInvalidRequest:
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_InvalidRequest)
		if !ok || value.InvalidRequest == nil {
			return false
		}
		failure.InvalidComponent = fromWireInvalidComponent(value.InvalidRequest.GetComponent())
		failure.CanonicalField = value.InvalidRequest.GetCanonicalFieldName()
		return failure.InvalidComponent != semantic.InvalidComponentUnspecified &&
			(failure.CanonicalField == "" || safeFieldName(failure.CanonicalField) == failure.CanonicalField)
	case semantic.FailureResourceExhausted:
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_LimitViolation)
		if !ok || value.LimitViolation == nil {
			return false
		}
		failure.LimitKind = fromWireLimitKind(value.LimitViolation.GetKind())
		failure.Maximum = value.LimitViolation.GetApprovedMaximum()
		failure.RetryAfterMillis = value.LimitViolation.GetRetryAfterMilliseconds()
		return failure.LimitKind != ""
	case semantic.FailureIncompatible:
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_Compatibility)
		if !ok || value.Compatibility == nil {
			return false
		}
		failure.RequiredCapability = value.Compatibility.GetRequiredCapability()
		failure.SupportedMajor = value.Compatibility.GetSupportedProtocolMajor()
		failure.SupportedMinorMin = value.Compatibility.GetSupportedProtocolMinorMin()
		failure.SupportedMinorMax = value.Compatibility.GetSupportedProtocolMinorMax()
		return safeCapabilityName(failure.RequiredCapability) &&
			failure.SupportedMajor != 0 &&
			failure.SupportedMinorMin <= failure.SupportedMinorMax
	case semantic.FailureStaleState:
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_StaleState)
		if !ok || value.StaleState == nil {
			return false
		}
		failure.StaleAxis = fromWireStaleAxis(value.StaleState.GetAxis())
		failure.RequiredRevision = value.StaleState.GetRequiredRevision()
		failure.ServedRevision = value.StaleState.GetServedRevision()
		return failure.StaleAxis != ""
	case semantic.FailureUnavailable:
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_Unavailable)
		if !ok || value.Unavailable == nil {
			return false
		}
		failure.RetryAfterMillis = value.Unavailable.GetRetryAfterMilliseconds()
		return true
	case semantic.FailureInternal:
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_InternalFailure)
		if !ok || value.InternalFailure == nil {
			return false
		}
		failure.RequestID = value.InternalFailure.GetRequestId()
		return failure.RequestID == "" || safeRequestID(failure.RequestID) == failure.RequestID
	case commonsemantic.FailureConflict:
		if detail.GetDetail() == nil {
			return true
		}
		value, ok := detail.GetDetail().(*commonv1.RuntimeErrorDetail_Conflict)
		if !ok || value.Conflict == nil {
			return false
		}
		switch value.Conflict.GetReason() {
		case commonv1.ConflictReason_CONFLICT_REASON_REVISION_MISMATCH:
			failure.ConflictReason = commonsemantic.ConflictRevisionMismatch
		case commonv1.ConflictReason_CONFLICT_REASON_REFERENCED:
			failure.ConflictReason = commonsemantic.ConflictReferenced
		case commonv1.ConflictReason_CONFLICT_REASON_DEFAULT_REQUIRED:
			failure.ConflictReason = commonsemantic.ConflictDefaultRequired
		default:
			return false
		}
		return true
	case semantic.FailureUnauthenticated, semantic.FailureForbidden, semantic.FailureMissing,
		semantic.FailureCanceled, semantic.FailureDeadlineExceeded:
		return detail.GetDetail() == nil
	default:
		return false
	}
}

func toWireConflictReason(reason commonsemantic.ConflictReason) commonv1.ConflictReason {
	switch reason {
	case commonsemantic.ConflictRevisionMismatch:
		return commonv1.ConflictReason_CONFLICT_REASON_REVISION_MISMATCH
	case commonsemantic.ConflictReferenced:
		return commonv1.ConflictReason_CONFLICT_REASON_REFERENCED
	case commonsemantic.ConflictDefaultRequired:
		return commonv1.ConflictReason_CONFLICT_REASON_DEFAULT_REQUIRED
	default:
		return commonv1.ConflictReason_CONFLICT_REASON_UNSPECIFIED
	}
}

func codeForCategory(category semantic.FailureCategory) codes.Code {
	return map[semantic.FailureCategory]codes.Code{
		semantic.FailureInvalidRequest:    codes.InvalidArgument,
		semantic.FailureUnauthenticated:   codes.Unauthenticated,
		semantic.FailureForbidden:         codes.PermissionDenied,
		semantic.FailureMissing:           codes.NotFound,
		commonsemantic.FailureConflict:    codes.Aborted,
		semantic.FailureCanceled:          codes.Canceled,
		semantic.FailureDeadlineExceeded:  codes.DeadlineExceeded,
		semantic.FailureResourceExhausted: codes.ResourceExhausted,
		semantic.FailureIncompatible:      codes.FailedPrecondition,
		semantic.FailureStaleState:        codes.FailedPrecondition,
		semantic.FailureUnavailable:       codes.Unavailable,
		semantic.FailureInternal:          codes.Internal,
	}[category]
}

func categoryForCode(code codes.Code) semantic.FailureCategory {
	return map[codes.Code]semantic.FailureCategory{
		codes.InvalidArgument:   semantic.FailureInvalidRequest,
		codes.Unauthenticated:   semantic.FailureUnauthenticated,
		codes.PermissionDenied:  semantic.FailureForbidden,
		codes.NotFound:          semantic.FailureMissing,
		codes.Aborted:           commonsemantic.FailureConflict,
		codes.Canceled:          semantic.FailureCanceled,
		codes.DeadlineExceeded:  semantic.FailureDeadlineExceeded,
		codes.ResourceExhausted: semantic.FailureResourceExhausted,
		codes.Unavailable:       semantic.FailureUnavailable,
		codes.Internal:          semantic.FailureInternal,
	}[code]
}

func toWireCategory(category semantic.FailureCategory) commonv1.ErrorCategory {
	return map[semantic.FailureCategory]commonv1.ErrorCategory{
		semantic.FailureInvalidRequest:    commonv1.ErrorCategory_ERROR_CATEGORY_INVALID_REQUEST,
		semantic.FailureUnauthenticated:   commonv1.ErrorCategory_ERROR_CATEGORY_UNAUTHENTICATED,
		semantic.FailureForbidden:         commonv1.ErrorCategory_ERROR_CATEGORY_FORBIDDEN,
		semantic.FailureMissing:           commonv1.ErrorCategory_ERROR_CATEGORY_MISSING,
		commonsemantic.FailureConflict:    commonv1.ErrorCategory_ERROR_CATEGORY_CONFLICT,
		semantic.FailureCanceled:          commonv1.ErrorCategory_ERROR_CATEGORY_CANCELED,
		semantic.FailureDeadlineExceeded:  commonv1.ErrorCategory_ERROR_CATEGORY_DEADLINE_EXCEEDED,
		semantic.FailureResourceExhausted: commonv1.ErrorCategory_ERROR_CATEGORY_RESOURCE_EXHAUSTED,
		semantic.FailureIncompatible:      commonv1.ErrorCategory_ERROR_CATEGORY_INCOMPATIBLE,
		semantic.FailureStaleState:        commonv1.ErrorCategory_ERROR_CATEGORY_STALE_STATE,
		semantic.FailureUnavailable:       commonv1.ErrorCategory_ERROR_CATEGORY_UNAVAILABLE,
		semantic.FailureInternal:          commonv1.ErrorCategory_ERROR_CATEGORY_INTERNAL_FAILURE,
	}[category]
}

func fromWireCategory(category commonv1.ErrorCategory) semantic.FailureCategory {
	for semanticCategory, wireCategory := range map[semantic.FailureCategory]commonv1.ErrorCategory{
		semantic.FailureInvalidRequest:    commonv1.ErrorCategory_ERROR_CATEGORY_INVALID_REQUEST,
		semantic.FailureUnauthenticated:   commonv1.ErrorCategory_ERROR_CATEGORY_UNAUTHENTICATED,
		semantic.FailureForbidden:         commonv1.ErrorCategory_ERROR_CATEGORY_FORBIDDEN,
		semantic.FailureMissing:           commonv1.ErrorCategory_ERROR_CATEGORY_MISSING,
		commonsemantic.FailureConflict:    commonv1.ErrorCategory_ERROR_CATEGORY_CONFLICT,
		semantic.FailureCanceled:          commonv1.ErrorCategory_ERROR_CATEGORY_CANCELED,
		semantic.FailureDeadlineExceeded:  commonv1.ErrorCategory_ERROR_CATEGORY_DEADLINE_EXCEEDED,
		semantic.FailureResourceExhausted: commonv1.ErrorCategory_ERROR_CATEGORY_RESOURCE_EXHAUSTED,
		semantic.FailureIncompatible:      commonv1.ErrorCategory_ERROR_CATEGORY_INCOMPATIBLE,
		semantic.FailureStaleState:        commonv1.ErrorCategory_ERROR_CATEGORY_STALE_STATE,
		semantic.FailureUnavailable:       commonv1.ErrorCategory_ERROR_CATEGORY_UNAVAILABLE,
		semantic.FailureInternal:          commonv1.ErrorCategory_ERROR_CATEGORY_INTERNAL_FAILURE,
	} {
		if wireCategory == category {
			return semanticCategory
		}
	}
	return semantic.FailureInternal
}

func toWireInvalidComponent(component semantic.InvalidComponent) commonv1.InvalidComponent {
	return map[semantic.InvalidComponent]commonv1.InvalidComponent{
		semantic.InvalidComponentObjectID:                commonv1.InvalidComponent_INVALID_COMPONENT_OBJECT_ID,
		semantic.InvalidComponentRecordID:                commonv1.InvalidComponent_INVALID_COMPONENT_RECORD_ID,
		semantic.InvalidComponentField:                   commonv1.InvalidComponent_INVALID_COMPONENT_SELECTED_ROOT_FIELD,
		semantic.InvalidComponentDeadline:                commonv1.InvalidComponent_INVALID_COMPONENT_DEADLINE,
		semantic.InvalidComponentResponse:                commonv1.InvalidComponent_INVALID_COMPONENT_RESPONSE,
		commonsemantic.InvalidComponentAppInstallationID: commonv1.InvalidComponent_INVALID_COMPONENT_APP_INSTALLATION_ID,
		commonsemantic.InvalidComponentCapability:        commonv1.InvalidComponent_INVALID_COMPONENT_RUNTIME_CAPABILITY,
		commonsemantic.InvalidComponentCommandID:         commonv1.InvalidComponent_INVALID_COMPONENT_COMMAND_ID,
		commonsemantic.InvalidComponentOperation:         commonv1.InvalidComponent_INVALID_COMPONENT_OPERATION,
		commonsemantic.InvalidComponentFieldValue:        commonv1.InvalidComponent_INVALID_COMPONENT_FIELD_VALUE,
		commonsemantic.InvalidComponentBatchMode:         commonv1.InvalidComponent_INVALID_COMPONENT_BATCH_MODE,
		commonsemantic.InvalidComponentCommandData:       commonv1.InvalidComponent_INVALID_COMPONENT_COMMAND_DATA,
		commonsemantic.InvalidComponentQueryPlan:         commonv1.InvalidComponent_INVALID_COMPONENT_QUERY_PLAN,
		commonsemantic.InvalidComponentPredicate:         commonv1.InvalidComponent_INVALID_COMPONENT_QUERY_PREDICATE,
		commonsemantic.InvalidComponentQuerySelection:    commonv1.InvalidComponent_INVALID_COMPONENT_QUERY_SELECTION,
		commonsemantic.InvalidComponentRelationshipField: commonv1.InvalidComponent_INVALID_COMPONENT_RELATIONSHIP_FIELD,
		commonsemantic.InvalidComponentSavedViewID:       commonv1.InvalidComponent_INVALID_COMPONENT_SAVED_VIEW_ID,
	}[component]
}

func fromWireInvalidComponent(component commonv1.InvalidComponent) semantic.InvalidComponent {
	return map[commonv1.InvalidComponent]semantic.InvalidComponent{
		commonv1.InvalidComponent_INVALID_COMPONENT_OBJECT_ID:           semantic.InvalidComponentObjectID,
		commonv1.InvalidComponent_INVALID_COMPONENT_RECORD_ID:           semantic.InvalidComponentRecordID,
		commonv1.InvalidComponent_INVALID_COMPONENT_SELECTED_ROOT_FIELD: semantic.InvalidComponentField,
		commonv1.InvalidComponent_INVALID_COMPONENT_DEADLINE:            semantic.InvalidComponentDeadline,
		commonv1.InvalidComponent_INVALID_COMPONENT_RESPONSE:            semantic.InvalidComponentResponse,
		commonv1.InvalidComponent_INVALID_COMPONENT_APP_INSTALLATION_ID: commonsemantic.InvalidComponentAppInstallationID,
		commonv1.InvalidComponent_INVALID_COMPONENT_RUNTIME_CAPABILITY:  commonsemantic.InvalidComponentCapability,
		commonv1.InvalidComponent_INVALID_COMPONENT_COMMAND_ID:          commonsemantic.InvalidComponentCommandID,
		commonv1.InvalidComponent_INVALID_COMPONENT_OPERATION:           commonsemantic.InvalidComponentOperation,
		commonv1.InvalidComponent_INVALID_COMPONENT_FIELD_VALUE:         commonsemantic.InvalidComponentFieldValue,
		commonv1.InvalidComponent_INVALID_COMPONENT_BATCH_MODE:          commonsemantic.InvalidComponentBatchMode,
		commonv1.InvalidComponent_INVALID_COMPONENT_COMMAND_DATA:        commonsemantic.InvalidComponentCommandData,
		commonv1.InvalidComponent_INVALID_COMPONENT_QUERY_PLAN:          commonsemantic.InvalidComponentQueryPlan,
		commonv1.InvalidComponent_INVALID_COMPONENT_QUERY_PREDICATE:     commonsemantic.InvalidComponentPredicate,
		commonv1.InvalidComponent_INVALID_COMPONENT_QUERY_SELECTION:     commonsemantic.InvalidComponentQuerySelection,
		commonv1.InvalidComponent_INVALID_COMPONENT_RELATIONSHIP_FIELD:  commonsemantic.InvalidComponentRelationshipField,
		commonv1.InvalidComponent_INVALID_COMPONENT_SAVED_VIEW_ID:       commonsemantic.InvalidComponentSavedViewID,
	}[component]
}

func toWireLimitKind(kind semantic.LimitKind) commonv1.LimitKind {
	return map[semantic.LimitKind]commonv1.LimitKind{
		semantic.LimitSelectedFields:          commonv1.LimitKind_LIMIT_KIND_SELECTED_FIELDS,
		semantic.LimitSemanticRequest:         commonv1.LimitKind_LIMIT_KIND_SEMANTIC_REQUEST_BYTES,
		semantic.LimitSemanticResponse:        commonv1.LimitKind_LIMIT_KIND_SEMANTIC_RESPONSE_BYTES,
		semantic.LimitObjectID:                commonv1.LimitKind_LIMIT_KIND_OBJECT_IDENTIFIER_BYTES,
		semantic.LimitFieldID:                 commonv1.LimitKind_LIMIT_KIND_FIELD_IDENTIFIER_BYTES,
		semantic.LimitRecordID:                commonv1.LimitKind_LIMIT_KIND_RECORD_IDENTIFIER_BYTES,
		commonsemantic.LimitRecordCount:       commonv1.LimitKind_LIMIT_KIND_RECORD_COUNT,
		commonsemantic.LimitAppInstallationID: commonv1.LimitKind_LIMIT_KIND_APP_INSTALLATION_IDENTIFIER_BYTES,
		commonsemantic.LimitCapabilityCount:   commonv1.LimitKind_LIMIT_KIND_CAPABILITY_COUNT,
		commonsemantic.LimitCapabilityID:      commonv1.LimitKind_LIMIT_KIND_CAPABILITY_IDENTIFIER_BYTES,
		commonsemantic.LimitQueryPredicate:    commonv1.LimitKind_LIMIT_KIND_QUERY_PREDICATE_NODES,
		commonsemantic.LimitQueryDepth:        commonv1.LimitKind_LIMIT_KIND_QUERY_NESTING_DEPTH,
		commonsemantic.LimitQueryOrderBy:      commonv1.LimitKind_LIMIT_KIND_QUERY_ORDER_BY_COUNT,
		commonsemantic.LimitQuerySubqueries:   commonv1.LimitKind_LIMIT_KIND_QUERY_SUBQUERY_COUNT,
		commonsemantic.LimitQueryOffset:       commonv1.LimitKind_LIMIT_KIND_QUERY_OFFSET,
		semantic.LimitAdmission:               commonv1.LimitKind_LIMIT_KIND_ADMISSION,
		commonsemantic.LimitOperationCount:    commonv1.LimitKind_LIMIT_KIND_OPERATION_COUNT,
		commonsemantic.LimitFieldCount:        commonv1.LimitKind_LIMIT_KIND_FIELD_COUNT,
		commonsemantic.LimitCommandID:         commonv1.LimitKind_LIMIT_KIND_COMMAND_IDENTIFIER_BYTES,
		commonsemantic.LimitWireFrame:         commonv1.LimitKind_LIMIT_KIND_WIRE_FRAME_BYTES,
		commonsemantic.LimitUploadBytes:       commonv1.LimitKind_LIMIT_KIND_UPLOAD_BYTES,
	}[kind]
}

func fromWireLimitKind(kind commonv1.LimitKind) semantic.LimitKind {
	for semanticKind, wireKind := range map[semantic.LimitKind]commonv1.LimitKind{
		semantic.LimitSelectedFields:          commonv1.LimitKind_LIMIT_KIND_SELECTED_FIELDS,
		semantic.LimitSemanticRequest:         commonv1.LimitKind_LIMIT_KIND_SEMANTIC_REQUEST_BYTES,
		semantic.LimitSemanticResponse:        commonv1.LimitKind_LIMIT_KIND_SEMANTIC_RESPONSE_BYTES,
		semantic.LimitObjectID:                commonv1.LimitKind_LIMIT_KIND_OBJECT_IDENTIFIER_BYTES,
		semantic.LimitFieldID:                 commonv1.LimitKind_LIMIT_KIND_FIELD_IDENTIFIER_BYTES,
		semantic.LimitRecordID:                commonv1.LimitKind_LIMIT_KIND_RECORD_IDENTIFIER_BYTES,
		commonsemantic.LimitRecordCount:       commonv1.LimitKind_LIMIT_KIND_RECORD_COUNT,
		commonsemantic.LimitAppInstallationID: commonv1.LimitKind_LIMIT_KIND_APP_INSTALLATION_IDENTIFIER_BYTES,
		commonsemantic.LimitCapabilityCount:   commonv1.LimitKind_LIMIT_KIND_CAPABILITY_COUNT,
		commonsemantic.LimitCapabilityID:      commonv1.LimitKind_LIMIT_KIND_CAPABILITY_IDENTIFIER_BYTES,
		commonsemantic.LimitQueryPredicate:    commonv1.LimitKind_LIMIT_KIND_QUERY_PREDICATE_NODES,
		commonsemantic.LimitQueryDepth:        commonv1.LimitKind_LIMIT_KIND_QUERY_NESTING_DEPTH,
		commonsemantic.LimitQueryOrderBy:      commonv1.LimitKind_LIMIT_KIND_QUERY_ORDER_BY_COUNT,
		commonsemantic.LimitQuerySubqueries:   commonv1.LimitKind_LIMIT_KIND_QUERY_SUBQUERY_COUNT,
		commonsemantic.LimitQueryOffset:       commonv1.LimitKind_LIMIT_KIND_QUERY_OFFSET,
		semantic.LimitAdmission:               commonv1.LimitKind_LIMIT_KIND_ADMISSION,
		commonsemantic.LimitOperationCount:    commonv1.LimitKind_LIMIT_KIND_OPERATION_COUNT,
		commonsemantic.LimitFieldCount:        commonv1.LimitKind_LIMIT_KIND_FIELD_COUNT,
		commonsemantic.LimitCommandID:         commonv1.LimitKind_LIMIT_KIND_COMMAND_IDENTIFIER_BYTES,
		commonsemantic.LimitWireFrame:         commonv1.LimitKind_LIMIT_KIND_WIRE_FRAME_BYTES,
		commonsemantic.LimitUploadBytes:       commonv1.LimitKind_LIMIT_KIND_UPLOAD_BYTES,
	} {
		if wireKind == kind {
			return semanticKind
		}
	}
	return ""
}

func toWireStaleAxis(axis semantic.StaleAxis) commonv1.StaleAxis {
	return map[semantic.StaleAxis]commonv1.StaleAxis{
		semantic.StaleAxisCatalog:  commonv1.StaleAxis_STALE_AXIS_CATALOG_REVISION,
		semantic.StaleAxisSecurity: commonv1.StaleAxis_STALE_AXIS_SECURITY_EPOCH,
	}[axis]
}

func fromWireStaleAxis(axis commonv1.StaleAxis) semantic.StaleAxis {
	return map[commonv1.StaleAxis]semantic.StaleAxis{
		commonv1.StaleAxis_STALE_AXIS_CATALOG_REVISION: semantic.StaleAxisCatalog,
		commonv1.StaleAxis_STALE_AXIS_SECURITY_EPOCH:   semantic.StaleAxisSecurity,
	}[axis]
}

func safeFieldName(name string) string {
	if name == "" || len(name) > semantic.MaxFieldIdentifierBytes || !safeFieldPattern.MatchString(name) {
		return ""
	}
	return name
}

var (
	safeFieldPattern      = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)
	safeRequestIDPattern  = regexp.MustCompile(`^[A-Za-z0-9._:-]+$`)
	safeCapabilityPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9.-]*$`)
)

func safeCapabilityName(name string) bool {
	return len(name) <= 128 && safeCapabilityPattern.MatchString(name)
}

func safeRequestID(requestID string) string {
	requestID = strings.TrimSpace(requestID)
	if len(requestID) > 128 || !safeRequestIDPattern.MatchString(requestID) {
		return ""
	}
	return requestID
}

func toWireReceipts(receipts commonsemantic.Receipts, capability capabilitySpec) *commonv1.ConsistencyReceipts {
	return &commonv1.ConsistencyReceipts{
		ProtocolVersion:   &commonv1.ProtocolVersion{Major: capability.protocolMajor, Minor: capability.protocolMinor},
		CatalogRevision:   receipts.CatalogRevision,
		SchemaGeneration:  receipts.SchemaGeneration,
		EngineGeneration:  receipts.EngineGeneration,
		SecurityEpoch:     receipts.SecurityEpoch,
		CapabilityVersion: &commonv1.CapabilityVersion{Name: capability.name, Major: capability.major, Minor: capability.minor},
	}
}

func validSemanticReceipts(receipts commonsemantic.Receipts, capability capabilitySpec) bool {
	return commonsemantic.ValidReceipts(receipts, capability.name)
}

func validIdentityFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !identitysemantic.ValidTopLevelFailure(failure.Category) || failure.Receipts != nil {
		return false
	}
	switch failure.Category {
	case identitysemantic.FailureInvalidRequest:
		return failure.CanonicalField == "" && (failure.InvalidComponent == identitysemantic.InvalidComponentAppInstallationID ||
			failure.InvalidComponent == identitysemantic.InvalidComponentCapability || failure.InvalidComponent == identitysemantic.InvalidComponentDeadline ||
			failure.InvalidComponent == identitysemantic.InvalidComponentResponse)
	case identitysemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case identitysemantic.LimitAppInstallationID:
			return failure.Maximum == identitysemantic.MaxAppInstallationIdentifierBytes
		case identitysemantic.LimitCapabilityCount:
			return failure.Maximum == identitysemantic.MaxRequestedCapabilities
		case identitysemantic.LimitCapabilityID:
			return failure.Maximum == identitysemantic.MaxCapabilityIdentifierBytes
		case identitysemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case identitysemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == identitysemantic.CapabilityName && failure.SupportedMajor == identitysemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= identitysemantic.ProtocolMinor && failure.SupportedMinorMax >= identitysemantic.ProtocolMinor
	case identitysemantic.FailureStaleState:
		return failure.StaleAxis == identitysemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validRecordMutationFailure(failure *commonsemantic.Failure, decoded, reconciliation bool) bool {
	if failure == nil || (!reconciliation && !mutationsemantic.ValidMutateTopLevelFailure(failure.Category)) ||
		(reconciliation && !mutationsemantic.ValidStatusTopLevelFailure(failure.Category)) {
		return false
	}
	switch failure.Category {
	case mutationsemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" {
			return false
		}
		switch failure.InvalidComponent {
		case mutationsemantic.InvalidComponentObjectID, mutationsemantic.InvalidComponentRecordID,
			mutationsemantic.InvalidComponentDeadline, mutationsemantic.InvalidComponentResponse,
			mutationsemantic.InvalidComponentCommandID, mutationsemantic.InvalidComponentOperation,
			mutationsemantic.InvalidComponentFieldValue, mutationsemantic.InvalidComponentBatchMode,
			mutationsemantic.InvalidComponentCommandData:
			return true
		default:
			return false
		}
	case mutationsemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case mutationsemantic.LimitObjectID:
			return failure.Maximum == mutationsemantic.MaxObjectIdentifierBytes
		case mutationsemantic.LimitFieldID:
			return failure.Maximum == mutationsemantic.MaxFieldIdentifierBytes
		case mutationsemantic.LimitRecordID:
			return failure.Maximum == mutationsemantic.MaxRecordIdentifierBytes
		case mutationsemantic.LimitOperationCount:
			return failure.Maximum == mutationsemantic.MaxOperations
		case mutationsemantic.LimitFieldCount:
			return failure.Maximum == mutationsemantic.MaxFieldsPerOperation
		case mutationsemantic.LimitCommandID:
			return failure.Maximum == mutationsemantic.MaxCommandIdentifierBytes
		case mutationsemantic.LimitSemanticRequest:
			return failure.Maximum == mutationsemantic.MaxSemanticRequestBytes
		case mutationsemantic.LimitSemanticResponse:
			return failure.Maximum == mutationsemantic.MaxSemanticResponseBytes
		case mutationsemantic.LimitWireFrame:
			return failure.Maximum > 0
		case mutationsemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case mutationsemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == mutationsemantic.CapabilityName &&
			failure.SupportedMajor == mutationsemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= mutationsemantic.ProtocolMinor &&
			failure.SupportedMinorMax >= mutationsemantic.ProtocolMinor
	case mutationsemantic.FailureStaleState:
		return failure.StaleAxis == mutationsemantic.StaleAxisCatalog || failure.StaleAxis == mutationsemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validQueryFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !querysemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil && !commonsemantic.ValidReceipts(*failure.Receipts, querysemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case querysemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" && safeFieldName(failure.CanonicalField) != failure.CanonicalField {
			return false
		}
		switch failure.InvalidComponent {
		case querysemantic.InvalidComponentObjectID, querysemantic.InvalidComponentSelection,
			querysemantic.InvalidComponentDeadline, querysemantic.InvalidComponentQueryPlan,
			querysemantic.InvalidComponentPredicate, querysemantic.InvalidComponentResponse:
			return true
		default:
			return false
		}
	case querysemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case querysemantic.LimitSelectedFields:
			return failure.Maximum == querysemantic.MaxSelectedFields
		case querysemantic.LimitSemanticRequest:
			return failure.Maximum == querysemantic.MaxSemanticRequestBytes
		case querysemantic.LimitSemanticResponse:
			// New readers must preserve the former peer's 1 MiB rejection
			// during a readers-first rollout. New writers still emit only
			// the current approved maximum; unrelated maxima stay invalid.
			return failure.Maximum == querysemantic.MaxSemanticResponseBytes || (decoded && failure.Maximum == 1024*1024)
		case querysemantic.LimitObjectID:
			return failure.Maximum == querysemantic.MaxObjectIdentifierBytes
		case querysemantic.LimitFieldID:
			return failure.Maximum == querysemantic.MaxFieldIdentifierBytes
		case querysemantic.LimitRecordID:
			return failure.Maximum == querysemantic.MaxRecordIdentifierBytes
		case querysemantic.LimitRecordCount:
			return failure.Maximum == querysemantic.MaxRows || failure.Maximum == querysemantic.MaxRows+1
		case querysemantic.LimitQueryPredicate:
			return failure.Maximum == querysemantic.MaxPredicateNodes
		case querysemantic.LimitQueryDepth:
			return failure.Maximum == querysemantic.MaxNestingDepth
		case querysemantic.LimitQueryOrderBy:
			return failure.Maximum == querysemantic.MaxOrderBy
		case querysemantic.LimitQuerySubqueries:
			return failure.Maximum == querysemantic.MaxSubqueries
		case querysemantic.LimitQueryOffset:
			return failure.Maximum == querysemantic.MaxOffset
		case querysemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case querysemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == querysemantic.CapabilityName && failure.SupportedMajor == querysemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= querysemantic.ProtocolMinor && failure.SupportedMinorMax >= querysemantic.ProtocolMinor
	case querysemantic.FailureStaleState:
		return failure.StaleAxis == querysemantic.StaleAxisCatalog || failure.StaleAxis == querysemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validCreateDefaultPreviewFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !defaultsemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil &&
		!commonsemantic.ValidReceipts(*failure.Receipts, defaultsemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case defaultsemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" {
			return false
		}
		switch failure.InvalidComponent {
		case defaultsemantic.InvalidComponentObjectID,
			defaultsemantic.InvalidComponentRecordID,
			defaultsemantic.InvalidComponentRelationshipField,
			defaultsemantic.InvalidComponentFieldValue,
			defaultsemantic.InvalidComponentOperation,
			defaultsemantic.InvalidComponentDeadline,
			defaultsemantic.InvalidComponentResponse:
			return true
		default:
			return false
		}
	case defaultsemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case defaultsemantic.LimitObjectID:
			return failure.Maximum == defaultsemantic.MaxObjectIdentifierBytes
		case defaultsemantic.LimitFieldID:
			return failure.Maximum == defaultsemantic.MaxFieldIdentifierBytes
		case defaultsemantic.LimitRecordID:
			return failure.Maximum == defaultsemantic.MaxRecordIdentifierBytes
		case defaultsemantic.LimitFieldCount:
			return failure.Maximum == defaultsemantic.MaxDefaultFields
		case defaultsemantic.LimitSemanticRequest:
			return failure.Maximum == defaultsemantic.MaxSemanticRequestBytes
		case defaultsemantic.LimitSemanticResponse:
			return failure.Maximum == defaultsemantic.MaxSemanticResponseBytes
		case defaultsemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case defaultsemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == defaultsemantic.CapabilityName &&
			failure.SupportedMajor == defaultsemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= defaultsemantic.ProtocolMinor &&
			failure.SupportedMinorMax >= defaultsemantic.ProtocolMinor
	case defaultsemantic.FailureStaleState:
		return failure.StaleAxis == defaultsemantic.StaleAxisCatalog ||
			failure.StaleAxis == defaultsemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validRelatedCountFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !relatedsemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil && !commonsemantic.ValidReceipts(*failure.Receipts, relatedsemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case relatedsemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" {
			return false
		}
		switch failure.InvalidComponent {
		case relatedsemantic.InvalidComponentObjectID, relatedsemantic.InvalidComponentRecordID,
			relatedsemantic.InvalidComponentRelationshipField, relatedsemantic.InvalidComponentFieldValue,
			relatedsemantic.InvalidComponentDeadline, relatedsemantic.InvalidComponentResponse:
			return true
		default:
			return false
		}
	case relatedsemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case relatedsemantic.LimitObjectID:
			return failure.Maximum == relatedsemantic.MaxObjectIdentifierBytes
		case relatedsemantic.LimitFieldID:
			return failure.Maximum == relatedsemantic.MaxFieldIdentifierBytes
		case relatedsemantic.LimitRecordID:
			return failure.Maximum == relatedsemantic.MaxRecordIdentifierBytes
		case relatedsemantic.LimitOperationCount:
			return failure.Maximum == relatedsemantic.MaxCounts
		case relatedsemantic.LimitSemanticRequest:
			return failure.Maximum == relatedsemantic.MaxSemanticRequestBytes
		case relatedsemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case relatedsemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == relatedsemantic.CapabilityName && failure.SupportedMajor == relatedsemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= relatedsemantic.ProtocolMinor && failure.SupportedMinorMax >= relatedsemantic.ProtocolMinor
	case relatedsemantic.FailureStaleState:
		return failure.StaleAxis == relatedsemantic.StaleAxisCatalog || failure.StaleAxis == relatedsemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validRecordViewFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !viewsemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil && !commonsemantic.ValidReceipts(*failure.Receipts, viewsemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case viewsemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" {
			return false
		}
		switch failure.InvalidComponent {
		case viewsemantic.InvalidComponentObjectID, viewsemantic.InvalidComponentRecordID,
			viewsemantic.InvalidComponentField, viewsemantic.InvalidComponentFieldValue,
			viewsemantic.InvalidComponentOperation, viewsemantic.InvalidComponentDeadline,
			viewsemantic.InvalidComponentResponse:
			return true
		default:
			return false
		}
	case viewsemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case viewsemantic.LimitObjectID:
			return failure.Maximum == viewsemantic.MaxObjectIdentifierBytes
		case viewsemantic.LimitFieldID:
			return failure.Maximum == viewsemantic.MaxFieldIdentifierBytes || failure.Maximum == viewsemantic.MaxResolverIdentifierBytes
		case viewsemantic.LimitRecordID:
			return failure.Maximum == viewsemantic.MaxRecordIdentifierBytes
		case viewsemantic.LimitFieldCount:
			return failure.Maximum == viewsemantic.MaxRootFields || failure.Maximum == viewsemantic.MaxReferenceDisplays
		case viewsemantic.LimitOperationCount:
			return failure.Maximum == viewsemantic.MaxAttachmentSources
		case viewsemantic.LimitSemanticRequest:
			return failure.Maximum == viewsemantic.MaxSemanticRequestBytes
		case viewsemantic.LimitSemanticResponse:
			return failure.Maximum == viewsemantic.MaxSemanticResponseBytes
		case querysemantic.LimitSelectedFields:
			return failure.Maximum == querysemantic.MaxSelectedFields
		case querysemantic.LimitQueryDepth:
			return failure.Maximum == querysemantic.MaxNestingDepth
		case viewsemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case viewsemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == viewsemantic.CapabilityName && failure.SupportedMajor == viewsemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= viewsemantic.ProtocolMinor && failure.SupportedMinorMax >= viewsemantic.ProtocolMinor
	case viewsemantic.FailureStaleState:
		return failure.StaleAxis == viewsemantic.StaleAxisCatalog || failure.StaleAxis == viewsemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validRecordAttachmentSourceFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !attachmentsemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil && !commonsemantic.ValidReceipts(*failure.Receipts, attachmentsemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case attachmentsemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" {
			return false
		}
		switch failure.InvalidComponent {
		case attachmentsemantic.InvalidComponentObjectID, attachmentsemantic.InvalidComponentRecordID,
			attachmentsemantic.InvalidComponentField, attachmentsemantic.InvalidComponentFieldValue,
			attachmentsemantic.InvalidComponentOperation, attachmentsemantic.InvalidComponentDeadline,
			attachmentsemantic.InvalidComponentResponse:
			return true
		default:
			return false
		}
	case attachmentsemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case attachmentsemantic.LimitObjectID:
			return failure.Maximum == attachmentsemantic.MaxObjectIdentifierBytes
		case attachmentsemantic.LimitFieldID:
			return failure.Maximum == attachmentsemantic.MaxFieldIdentifierBytes || failure.Maximum == attachmentsemantic.MaxResolverIdentifierBytes
		case attachmentsemantic.LimitRecordID:
			return failure.Maximum == attachmentsemantic.MaxRecordIdentifierBytes
		case attachmentsemantic.LimitOperationCount:
			return failure.Maximum == attachmentsemantic.MaxSources
		case attachmentsemantic.LimitSemanticRequest:
			return failure.Maximum == attachmentsemantic.MaxSemanticRequestBytes
		case attachmentsemantic.LimitSemanticResponse:
			return failure.Maximum == attachmentsemantic.MaxSemanticResponseBytes
		case attachmentsemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case attachmentsemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == attachmentsemantic.CapabilityName &&
			failure.SupportedMajor == attachmentsemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= attachmentsemantic.ProtocolMinor &&
			failure.SupportedMinorMax >= attachmentsemantic.ProtocolMinor
	case attachmentsemantic.FailureStaleState:
		return failure.StaleAxis == attachmentsemantic.StaleAxisCatalog || failure.StaleAxis == attachmentsemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validRecycleBinFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !recyclesemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil && !commonsemantic.ValidReceipts(*failure.Receipts, recyclesemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case recyclesemantic.FailureInvalidRequest:
		if failure.CanonicalField != "" {
			return false
		}
		switch failure.InvalidComponent {
		case recyclesemantic.InvalidComponentOperation, recyclesemantic.InvalidComponentDeadline,
			recyclesemantic.InvalidComponentResponse:
			return true
		default:
			return false
		}
	case recyclesemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case recyclesemantic.LimitRecordCount:
			return failure.Maximum == recyclesemantic.MaxItems || failure.Maximum == recyclesemantic.MaxFailedObjects
		case recyclesemantic.LimitSemanticResponse:
			return failure.Maximum == recyclesemantic.MaxSemanticResponseBytes
		case recyclesemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case recyclesemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == recyclesemantic.CapabilityName && failure.SupportedMajor == recyclesemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= recyclesemantic.ProtocolMinor && failure.SupportedMinorMax >= recyclesemantic.ProtocolMinor
	case recyclesemantic.FailureStaleState:
		return failure.StaleAxis == recyclesemantic.StaleAxisCatalog || failure.StaleAxis == recyclesemantic.StaleAxisSecurity
	default:
		return true
	}
}

func validRecycleBinMutationFailure(failure *commonsemantic.Failure, decoded bool) bool {
	if failure == nil || !recyclemutationsemantic.ValidTopLevelFailure(failure.Category) {
		return false
	}
	if failure.Receipts != nil && !commonsemantic.ValidReceipts(*failure.Receipts, recyclemutationsemantic.CapabilityName) {
		return false
	}
	switch failure.Category {
	case recyclemutationsemantic.FailureInvalidRequest:
		return failure.CanonicalField == "" && (failure.InvalidComponent == recyclemutationsemantic.InvalidComponentRecordID ||
			failure.InvalidComponent == recyclemutationsemantic.InvalidComponentOperation ||
			failure.InvalidComponent == recyclemutationsemantic.InvalidComponentDeadline ||
			failure.InvalidComponent == recyclemutationsemantic.InvalidComponentResponse)
	case recyclemutationsemantic.FailureResourceExhausted:
		if decoded && failure.LimitKind == "" {
			return true
		}
		switch failure.LimitKind {
		case recyclemutationsemantic.LimitRecordID:
			return failure.Maximum == recyclemutationsemantic.MaxRecordIdentifierBytes
		case recyclemutationsemantic.LimitSemanticRequest:
			return failure.Maximum == recyclemutationsemantic.MaxSemanticRequestBytes
		case recyclemutationsemantic.LimitAdmission:
			return true
		default:
			return false
		}
	case recyclemutationsemantic.FailureIncompatible:
		if !decoded {
			return true
		}
		return failure.RequiredCapability == recyclemutationsemantic.CapabilityName &&
			failure.SupportedMajor == recyclemutationsemantic.ProtocolMajor &&
			failure.SupportedMinorMin <= recyclemutationsemantic.ProtocolMinor &&
			failure.SupportedMinorMax >= recyclemutationsemantic.ProtocolMinor
	case recyclemutationsemantic.FailureStaleState:
		return failure.StaleAxis == recyclemutationsemantic.StaleAxisCatalog || failure.StaleAxis == recyclemutationsemantic.StaleAxisSecurity
	default:
		return true
	}
}

func fromWireReceipts(receipts *commonv1.ConsistencyReceipts, capability capabilitySpec) (commonsemantic.Receipts, error) {
	if receipts == nil || receipts.GetProtocolVersion() == nil || receipts.GetCapabilityVersion() == nil ||
		receipts.GetProtocolVersion().GetMajor() != capability.protocolMajor ||
		receipts.GetProtocolVersion().GetMinor() != capability.protocolMinor ||
		receipts.GetCapabilityVersion().GetName() != capability.name ||
		receipts.GetCapabilityVersion().GetMajor() != capability.major || receipts.GetCapabilityVersion().GetMinor() != capability.minor {
		return commonsemantic.Receipts{}, incompatibleFailureFor(capability)
	}
	return commonsemantic.Receipts{
		ProtocolVersion:   "1.0",
		CatalogRevision:   receipts.GetCatalogRevision(),
		SchemaGeneration:  receipts.GetSchemaGeneration(),
		EngineGeneration:  receipts.GetEngineGeneration(),
		SecurityEpoch:     receipts.GetSecurityEpoch(),
		CapabilityVersion: capability.name,
	}, nil
}
