from __future__ import annotations

from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field, replace
from datetime import datetime
import re
from typing import Literal, Protocol, cast, runtime_checkable
from urllib.parse import urlsplit

from govoplan_core.core.external_references import (
    ExternalObjectReference,
    IntegrationMaturity,
    SourceAuthorityMode,
)


INSTITUTIONAL_CONTEXT_CONTRACT_VERSION = "1"
CAPABILITY_MANDATE_RESOLVER = "mandates.resolver"
CAPABILITY_SERVICE_DEFINITIONS = "services.definitions"
CAPABILITY_SERVICE_AVAILABILITY = "services.availability"
CAPABILITY_FORM_DEFINITIONS = "forms.definitions"
CAPABILITY_PARTY_RESOLVER = "parties.resolver"
CAPABILITY_DECISION_REGISTRY = "decisions.registry"

InstitutionalReferenceKind = Literal[
    "institution",
    "organization_unit",
    "function",
    "function_assignment",
    "task",
    "mandate",
    "jurisdiction",
    "service",
    "form",
    "form_submission",
    "case",
    "party",
    "decision",
    "work_item",
    "workflow",
    "approval",
    "record",
]
LegalBasisKind = Literal[
    "law",
    "regulation",
    "statute",
    "policy",
    "contract",
    "delegation",
    "mandate",
    "organizational_rule",
    "exception",
    "other",
]
EvidenceKind = Literal[
    "document",
    "record",
    "event",
    "snapshot",
    "materialization",
    "decision",
    "signature",
    "external",
    "other",
]
PartySubjectKind = Literal["identity", "organization", "group", "external"]
MandateStatus = Literal["draft", "active", "suspended", "replaced", "retired"]
ServicePublicationState = Literal["draft", "published", "suspended", "retired"]
ServiceAvailabilityRequirementKind = Literal[
    "module",
    "capability",
    "mandate",
    "policy",
    "connector",
    "maintenance",
    "audience",
    "configuration",
]
ServiceAvailabilityFailureState = Literal["unavailable", "hidden"]
ServiceLaunchState = Literal["started", "redirect"]
FormPublicationState = Literal["draft", "published", "retired"]
FormValueType = Literal[
    "text",
    "multiline_text",
    "integer",
    "number",
    "boolean",
    "date",
    "datetime",
    "email",
    "choice",
    "multi_choice",
    "object",
    "list",
]
FormSignatureRequirement = Literal["none", "optional", "required"]
FormConditionKind = Literal["predicate", "all", "any", "not"]
FormConditionOperator = Literal[
    "eq",
    "neq",
    "lt",
    "lte",
    "gt",
    "gte",
    "in",
    "not_in",
    "contains",
    "is_empty",
    "is_not_empty",
]
ProcedurePartyStatus = Literal["active", "revoked", "expired", "superseded"]
DecisionState = Literal[
    "draft",
    "proposed",
    "approved",
    "decided",
    "effective",
    "corrected",
    "revoked",
    "superseded",
]
DecisionAssuranceLevel = Literal[
    "human",
    "human_reviewed_automation",
    "automated_under_mandate",
]
DisclosureState = Literal[
    "not_assessed",
    "restricted",
    "partly_disclosable",
    "disclosable",
    "published",
]

_LEGAL_BASIS_KINDS = frozenset(
    {
        "law",
        "regulation",
        "statute",
        "policy",
        "contract",
        "delegation",
        "mandate",
        "organizational_rule",
        "exception",
        "other",
    }
)
_EVIDENCE_KINDS = frozenset(
    {
        "document",
        "record",
        "event",
        "snapshot",
        "materialization",
        "decision",
        "signature",
        "external",
        "other",
    }
)
_PARTY_SUBJECT_KINDS = frozenset({"identity", "organization", "group", "external"})
_MANDATE_STATUSES = frozenset({"draft", "active", "suspended", "replaced", "retired"})
_MANDATE_TRANSITIONS: Mapping[MandateStatus, frozenset[MandateStatus]] = {
    "draft": frozenset({"active", "retired"}),
    "active": frozenset({"suspended", "replaced", "retired"}),
    "suspended": frozenset({"active", "replaced", "retired"}),
    "replaced": frozenset(),
    "retired": frozenset(),
}
_SERVICE_PUBLICATION_STATES = frozenset({"draft", "published", "suspended", "retired"})
_FORM_PUBLICATION_STATES = frozenset({"draft", "published", "retired"})
_FORM_VALUE_TYPES = frozenset(
    {
        "text",
        "multiline_text",
        "integer",
        "number",
        "boolean",
        "date",
        "datetime",
        "email",
        "choice",
        "multi_choice",
        "object",
        "list",
    }
)
_FORM_SIGNATURE_REQUIREMENTS = frozenset({"none", "optional", "required"})
_FORM_CONDITION_KINDS = frozenset({"predicate", "all", "any", "not"})
_FORM_CONDITION_OPERATORS = frozenset(
    {
        "eq",
        "neq",
        "lt",
        "lte",
        "gt",
        "gte",
        "in",
        "not_in",
        "contains",
        "is_empty",
        "is_not_empty",
    }
)
_SERVICE_AVAILABILITY_REQUIREMENT_KINDS = frozenset(
    {
        "module",
        "capability",
        "mandate",
        "policy",
        "connector",
        "maintenance",
        "audience",
        "configuration",
    }
)
_PROCEDURE_PARTY_STATUSES = frozenset({"active", "revoked", "expired", "superseded"})
_PROCEDURE_PARTY_TRANSITIONS: Mapping[
    ProcedurePartyStatus, frozenset[ProcedurePartyStatus]
] = {
    "active": frozenset({"active", "revoked", "expired", "superseded"}),
    "revoked": frozenset(),
    "expired": frozenset(),
    "superseded": frozenset(),
}
_DECISION_STATES = frozenset(
    {
        "draft",
        "proposed",
        "approved",
        "decided",
        "effective",
        "corrected",
        "revoked",
        "superseded",
    }
)
_DECISION_ASSURANCE_LEVELS = frozenset(
    {"human", "human_reviewed_automation", "automated_under_mandate"}
)
_DISCLOSURE_STATES = frozenset(
    {
        "not_assessed",
        "restricted",
        "partly_disclosable",
        "disclosable",
        "published",
    }
)
_DECISION_TRANSITIONS: Mapping[DecisionState, frozenset[DecisionState]] = {
    "draft": frozenset({"proposed", "revoked"}),
    "proposed": frozenset({"approved", "decided", "revoked"}),
    "approved": frozenset({"decided", "revoked"}),
    "decided": frozenset({"effective", "corrected", "revoked", "superseded"}),
    "effective": frozenset({"corrected", "revoked", "superseded"}),
    "corrected": frozenset({"effective", "corrected", "revoked", "superseded"}),
    "revoked": frozenset(),
    "superseded": frozenset(),
}

_REFERENCE_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,254}$")
_MODULE_ID_RE = re.compile(r"^[a-z][a-z0-9_]*$")


class InstitutionalContextError(ValueError):
    pass


@dataclass(frozen=True, slots=True)
class TemporalRevision:
    revision: str
    valid_from: datetime | None = None
    valid_to: datetime | None = None
    recorded_at: datetime | None = None
    superseded_at: datetime | None = None
    change_reason: str | None = None

    def __post_init__(self) -> None:
        _require_identifier(self.revision, "Temporal revision")
        for field_name in (
            "valid_from",
            "valid_to",
            "recorded_at",
            "superseded_at",
        ):
            _require_aware_datetime(getattr(self, field_name), field_name)
        if (
            self.valid_from is not None
            and self.valid_to is not None
            and self.valid_to <= self.valid_from
        ):
            raise InstitutionalContextError(
                "Temporal valid_to must be later than valid_from."
            )
        if (
            self.recorded_at is not None
            and self.superseded_at is not None
            and self.superseded_at < self.recorded_at
        ):
            raise InstitutionalContextError(
                "Temporal superseded_at cannot precede recorded_at."
            )

    def effective_at(self, instant: datetime) -> bool:
        _require_aware_datetime(instant, "effective instant")
        return (self.valid_from is None or instant >= self.valid_from) and (
            self.valid_to is None or instant < self.valid_to
        )

    def to_dict(self) -> dict[str, object]:
        return {
            "revision": self.revision,
            "valid_from": _datetime_value(self.valid_from),
            "valid_to": _datetime_value(self.valid_to),
            "recorded_at": _datetime_value(self.recorded_at),
            "superseded_at": _datetime_value(self.superseded_at),
            "change_reason": self.change_reason,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "TemporalRevision":
        return cls(
            revision=_required_text(value, "revision"),
            valid_from=_optional_datetime(value.get("valid_from")),
            valid_to=_optional_datetime(value.get("valid_to")),
            recorded_at=_optional_datetime(value.get("recorded_at")),
            superseded_at=_optional_datetime(value.get("superseded_at")),
            change_reason=_optional_text(value.get("change_reason")),
        )


@dataclass(frozen=True, slots=True)
class InstitutionalReference:
    kind: InstitutionalReferenceKind
    owner_module: str
    object_id: str
    tenant_id: str
    version: str | None = None
    valid_at: datetime | None = None
    label: str | None = None

    def __post_init__(self) -> None:
        if self.kind not in {
            "institution",
            "organization_unit",
            "function",
            "function_assignment",
            "task",
            "mandate",
            "jurisdiction",
            "service",
            "form",
            "form_submission",
            "case",
            "party",
            "decision",
            "work_item",
            "workflow",
            "approval",
            "record",
        }:
            raise InstitutionalContextError(
                f"Unsupported institutional reference kind: {self.kind!r}."
            )
        if not _MODULE_ID_RE.fullmatch(self.owner_module):
            raise InstitutionalContextError(
                f"Invalid institutional reference owner module: {self.owner_module!r}."
            )
        _require_identifier(self.object_id, "Institutional object id")
        _require_identifier(self.tenant_id, "Institutional tenant id")
        _require_aware_datetime(self.valid_at, "institutional valid_at")

    def to_dict(self, *, disclose_label: bool = False) -> dict[str, object]:
        return {
            "kind": self.kind,
            "owner_module": self.owner_module,
            "object_id": self.object_id,
            "tenant_id": self.tenant_id,
            "version": self.version,
            "valid_at": _datetime_value(self.valid_at),
            "label": self.label if disclose_label else None,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "InstitutionalReference":
        return cls(
            kind=cast(InstitutionalReferenceKind, _required_text(value, "kind")),
            owner_module=_required_text(value, "owner_module"),
            object_id=_required_text(value, "object_id"),
            tenant_id=_required_text(value, "tenant_id"),
            version=_optional_text(value.get("version")),
            valid_at=_optional_datetime(value.get("valid_at")),
            label=_optional_text(value.get("label")),
        )


@dataclass(frozen=True, slots=True)
class LegalBasisReference:
    kind: LegalBasisKind
    authority: str
    reference: str
    version: str
    effective_from: datetime | None = None
    effective_to: datetime | None = None
    title: str | None = None
    inspection_url: str | None = None

    def __post_init__(self) -> None:
        if self.kind not in _LEGAL_BASIS_KINDS:
            raise InstitutionalContextError(
                f"Unsupported legal basis kind: {self.kind!r}."
            )
        _require_text(self.authority, "Legal basis authority")
        _require_identifier(self.reference, "Legal basis reference")
        _require_identifier(self.version, "Legal basis version")
        _require_aware_datetime(self.effective_from, "legal basis effective_from")
        _require_aware_datetime(self.effective_to, "legal basis effective_to")
        if (
            self.effective_from is not None
            and self.effective_to is not None
            and self.effective_to <= self.effective_from
        ):
            raise InstitutionalContextError(
                "Legal basis effective_to must be later than effective_from."
            )
        _validate_inspection_url(self.inspection_url)

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "kind": self.kind,
            "authority": self.authority,
            "reference": self.reference,
            "version": self.version,
            "effective_from": _datetime_value(self.effective_from),
            "effective_to": _datetime_value(self.effective_to),
            "title": self.title if include_inspection else None,
            "inspection_url": self.inspection_url if include_inspection else None,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "LegalBasisReference":
        return cls(
            kind=cast(LegalBasisKind, _required_text(value, "kind")),
            authority=_required_text(value, "authority"),
            reference=_required_text(value, "reference"),
            version=_required_text(value, "version"),
            effective_from=_optional_datetime(value.get("effective_from")),
            effective_to=_optional_datetime(value.get("effective_to")),
            title=_optional_text(value.get("title")),
            inspection_url=_optional_text(value.get("inspection_url")),
        )


@dataclass(frozen=True, slots=True)
class EvidenceReference:
    kind: EvidenceKind
    owner_module: str
    evidence_id: str
    tenant_id: str
    version: str | None = None
    checksum: str | None = None
    source_ref: str | None = None
    derived_from: tuple[str, ...] = ()
    responsible_actor_ref: str | None = None
    captured_at: datetime | None = None
    inspection_url: str | None = None

    def __post_init__(self) -> None:
        if self.kind not in _EVIDENCE_KINDS:
            raise InstitutionalContextError(
                f"Unsupported evidence kind: {self.kind!r}."
            )
        if not _MODULE_ID_RE.fullmatch(self.owner_module):
            raise InstitutionalContextError(
                f"Invalid evidence owner module: {self.owner_module!r}."
            )
        _require_identifier(self.evidence_id, "Evidence id")
        _require_identifier(self.tenant_id, "Evidence tenant id")
        _require_aware_datetime(self.captured_at, "evidence captured_at")
        _validate_text_tuple(self.derived_from, "Evidence derivation references")
        _validate_inspection_url(self.inspection_url)

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "kind": self.kind,
            "owner_module": self.owner_module,
            "evidence_id": self.evidence_id,
            "tenant_id": self.tenant_id,
            "version": self.version,
            "checksum": self.checksum,
            "source_ref": self.source_ref,
            "derived_from": list(self.derived_from),
            "responsible_actor_ref": self.responsible_actor_ref,
            "captured_at": _datetime_value(self.captured_at),
            "inspection_url": self.inspection_url if include_inspection else None,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "EvidenceReference":
        return cls(
            kind=cast(EvidenceKind, _required_text(value, "kind")),
            owner_module=_required_text(value, "owner_module"),
            evidence_id=_required_text(value, "evidence_id"),
            tenant_id=_required_text(value, "tenant_id"),
            version=_optional_text(value.get("version")),
            checksum=_optional_text(value.get("checksum")),
            source_ref=_optional_text(value.get("source_ref")),
            derived_from=_text_tuple(value.get("derived_from")),
            responsible_actor_ref=_optional_text(value.get("responsible_actor_ref")),
            captured_at=_optional_datetime(value.get("captured_at")),
            inspection_url=_optional_text(value.get("inspection_url")),
        )


@dataclass(frozen=True, slots=True)
class InformationGovernanceReference:
    classification: str
    purposes: tuple[str, ...]
    legal_basis_refs: tuple[str, ...] = ()
    retention_policy_ref: str | None = None
    hold_refs: tuple[str, ...] = ()
    minimization_profile: str | None = None
    disclosure_state: DisclosureState = "not_assessed"

    def __post_init__(self) -> None:
        if self.disclosure_state not in _DISCLOSURE_STATES:
            raise InstitutionalContextError(
                f"Unsupported disclosure state: {self.disclosure_state!r}."
            )
        _require_text(self.classification, "Information classification")
        _validate_text_tuple(self.purposes, "Information purposes", require=True)
        _validate_text_tuple(self.legal_basis_refs, "Information legal basis refs")
        _validate_text_tuple(self.hold_refs, "Information hold refs")

    def to_dict(self) -> dict[str, object]:
        return {
            "classification": self.classification,
            "purposes": list(self.purposes),
            "legal_basis_refs": list(self.legal_basis_refs),
            "retention_policy_ref": self.retention_policy_ref,
            "hold_refs": list(self.hold_refs),
            "minimization_profile": self.minimization_profile,
            "disclosure_state": self.disclosure_state,
        }

    @classmethod
    def from_mapping(
        cls, value: Mapping[str, object]
    ) -> "InformationGovernanceReference":
        return cls(
            classification=_required_text(value, "classification"),
            purposes=_text_tuple(value.get("purposes")),
            legal_basis_refs=_text_tuple(value.get("legal_basis_refs")),
            retention_policy_ref=_optional_text(value.get("retention_policy_ref")),
            hold_refs=_text_tuple(value.get("hold_refs")),
            minimization_profile=_optional_text(value.get("minimization_profile")),
            disclosure_state=cast(
                DisclosureState,
                str(value.get("disclosure_state") or "not_assessed"),
            ),
        )


@dataclass(frozen=True, slots=True)
class GeoReference:
    reference_id: str
    crs: str
    latitude: float | None = None
    longitude: float | None = None
    geometry_ref: str | None = None
    administrative_area_ref: str | None = None
    address_ref: str | None = None
    location_ref: str | None = None
    source: str | None = None
    accuracy_meters: float | None = None
    valid_from: datetime | None = None
    valid_to: datetime | None = None
    external_gis: ExternalObjectReference | None = None

    def __post_init__(self) -> None:
        _require_identifier(self.reference_id, "Geo reference id")
        _require_text(self.crs, "Geo CRS")
        if (self.latitude is None) != (self.longitude is None):
            raise InstitutionalContextError(
                "Geo latitude and longitude must be supplied together."
            )
        if self.latitude is not None and not -90 <= self.latitude <= 90:
            raise InstitutionalContextError("Geo latitude is outside -90..90.")
        if self.longitude is not None and not -180 <= self.longitude <= 180:
            raise InstitutionalContextError("Geo longitude is outside -180..180.")
        if self.accuracy_meters is not None and self.accuracy_meters < 0:
            raise InstitutionalContextError("Geo accuracy cannot be negative.")
        _require_aware_datetime(self.valid_from, "geo valid_from")
        _require_aware_datetime(self.valid_to, "geo valid_to")
        if (
            self.valid_from is not None
            and self.valid_to is not None
            and self.valid_to <= self.valid_from
        ):
            raise InstitutionalContextError(
                "Geo valid_to must be later than valid_from."
            )

    def to_dict(self) -> dict[str, object]:
        return {
            "reference_id": self.reference_id,
            "crs": self.crs,
            "latitude": self.latitude,
            "longitude": self.longitude,
            "geometry_ref": self.geometry_ref,
            "administrative_area_ref": self.administrative_area_ref,
            "address_ref": self.address_ref,
            "location_ref": self.location_ref,
            "source": self.source,
            "accuracy_meters": self.accuracy_meters,
            "valid_from": _datetime_value(self.valid_from),
            "valid_to": _datetime_value(self.valid_to),
            "external_gis": (
                self.external_gis.to_dict() if self.external_gis is not None else None
            ),
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "GeoReference":
        external = value.get("external_gis")
        return cls(
            reference_id=_required_text(value, "reference_id"),
            crs=_required_text(value, "crs"),
            latitude=_optional_float(value.get("latitude")),
            longitude=_optional_float(value.get("longitude")),
            geometry_ref=_optional_text(value.get("geometry_ref")),
            administrative_area_ref=_optional_text(
                value.get("administrative_area_ref")
            ),
            address_ref=_optional_text(value.get("address_ref")),
            location_ref=_optional_text(value.get("location_ref")),
            source=_optional_text(value.get("source")),
            accuracy_meters=_optional_float(value.get("accuracy_meters")),
            valid_from=_optional_datetime(value.get("valid_from")),
            valid_to=_optional_datetime(value.get("valid_to")),
            external_gis=(
                _external_reference_from_mapping(external)
                if isinstance(external, Mapping)
                else None
            ),
        )


@dataclass(frozen=True, slots=True)
class ActorRepresentationReference:
    tenant_id: str
    account_id: str | None = None
    identity_id: str | None = None
    service_account_id: str | None = None
    represented_account_id: str | None = None
    represented_function_ref: InstitutionalReference | None = None
    represented_party_ref: InstitutionalReference | None = None
    function_assignment_ref: InstitutionalReference | None = None
    delegation_ref: str | None = None
    power_ref: str | None = None
    mandate_ref: InstitutionalReference | None = None

    def __post_init__(self) -> None:
        _require_identifier(self.tenant_id, "Actor tenant id")
        if bool(self.account_id) == bool(self.service_account_id):
            raise InstitutionalContextError(
                "Actor representation requires exactly one real account or service account."
            )
        _validate_reference_kind(
            self.represented_function_ref, "function", "represented function"
        )
        _validate_reference_kind(
            self.represented_party_ref, "party", "represented party"
        )
        _validate_reference_kind(
            self.function_assignment_ref,
            "function_assignment",
            "function assignment",
        )
        _validate_reference_kind(self.mandate_ref, "mandate", "actor mandate")
        _validate_reference_tenants(
            self.tenant_id,
            (
                self.represented_function_ref,
                self.represented_party_ref,
                self.function_assignment_ref,
                self.mandate_ref,
            ),
        )

    def to_dict(self) -> dict[str, object]:
        return {
            "tenant_id": self.tenant_id,
            "account_id": self.account_id,
            "identity_id": self.identity_id,
            "service_account_id": self.service_account_id,
            "represented_account_id": self.represented_account_id,
            "represented_function_ref": _reference_value(self.represented_function_ref),
            "represented_party_ref": _reference_value(self.represented_party_ref),
            "function_assignment_ref": _reference_value(self.function_assignment_ref),
            "delegation_ref": self.delegation_ref,
            "power_ref": self.power_ref,
            "mandate_ref": _reference_value(self.mandate_ref),
        }

    @classmethod
    def from_mapping(
        cls, value: Mapping[str, object]
    ) -> "ActorRepresentationReference":
        return cls(
            tenant_id=_required_text(value, "tenant_id"),
            account_id=_optional_text(value.get("account_id")),
            identity_id=_optional_text(value.get("identity_id")),
            service_account_id=_optional_text(value.get("service_account_id")),
            represented_account_id=_optional_text(value.get("represented_account_id")),
            represented_function_ref=_optional_institutional_reference(
                value.get("represented_function_ref")
            ),
            represented_party_ref=_optional_institutional_reference(
                value.get("represented_party_ref")
            ),
            function_assignment_ref=_optional_institutional_reference(
                value.get("function_assignment_ref")
            ),
            delegation_ref=_optional_text(value.get("delegation_ref")),
            power_ref=_optional_text(value.get("power_ref")),
            mandate_ref=_optional_institutional_reference(value.get("mandate_ref")),
        )


@dataclass(frozen=True, slots=True)
class ExternalSourceReference:
    reference: ExternalObjectReference
    authority_mode: SourceAuthorityMode
    maturity: IntegrationMaturity
    freshness_state: str
    health_state: str
    conflict_state: str = "none"

    def __post_init__(self) -> None:
        if self.reference.authority_mode != self.authority_mode:
            raise InstitutionalContextError(
                "External source authority mode must match its object reference."
            )
        if self.reference.maturity != self.maturity:
            raise InstitutionalContextError(
                "External source maturity must match its object reference."
            )
        _require_text(self.freshness_state, "External source freshness state")
        _require_text(self.health_state, "External source health state")
        _require_text(self.conflict_state, "External source conflict state")

    def to_dict(self) -> dict[str, object]:
        return {
            "reference": self.reference.to_dict(),
            "authority_mode": self.authority_mode,
            "maturity": self.maturity,
            "freshness_state": self.freshness_state,
            "health_state": self.health_state,
            "conflict_state": self.conflict_state,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "ExternalSourceReference":
        reference = value.get("reference")
        if not isinstance(reference, Mapping):
            raise InstitutionalContextError(
                "External source reference payload is required."
            )
        return cls(
            reference=_external_reference_from_mapping(reference),
            authority_mode=cast(
                SourceAuthorityMode, _required_text(value, "authority_mode")
            ),
            maturity=cast(IntegrationMaturity, _required_text(value, "maturity")),
            freshness_state=_required_text(value, "freshness_state"),
            health_state=_required_text(value, "health_state"),
            conflict_state=str(value.get("conflict_state") or "none"),
        )


@dataclass(frozen=True, slots=True)
class PresentationReference:
    language: str | None = None
    accessibility_profile: str | None = None
    channel: str | None = None
    explanation_ref: str | None = None
    availability_ref: str | None = None

    def to_dict(self) -> dict[str, object]:
        return {
            "language": self.language,
            "accessibility_profile": self.accessibility_profile,
            "channel": self.channel,
            "explanation_ref": self.explanation_ref,
            "availability_ref": self.availability_ref,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "PresentationReference":
        return cls(
            language=_optional_text(value.get("language")),
            accessibility_profile=_optional_text(value.get("accessibility_profile")),
            channel=_optional_text(value.get("channel")),
            explanation_ref=_optional_text(value.get("explanation_ref")),
            availability_ref=_optional_text(value.get("availability_ref")),
        )


@dataclass(frozen=True, slots=True)
class GovernedContextEnvelope:
    tenant_id: str
    temporal: TemporalRevision
    actor: ActorRepresentationReference | None = None
    institution_ref: InstitutionalReference | None = None
    organization_unit_ref: InstitutionalReference | None = None
    function_ref: InstitutionalReference | None = None
    task_ref: InstitutionalReference | None = None
    mandate_ref: InstitutionalReference | None = None
    jurisdiction_refs: tuple[InstitutionalReference, ...] = ()
    service_ref: InstitutionalReference | None = None
    case_ref: InstitutionalReference | None = None
    party_refs: tuple[InstitutionalReference, ...] = ()
    work_item_ref: InstitutionalReference | None = None
    workflow_ref: InstitutionalReference | None = None
    approval_refs: tuple[InstitutionalReference, ...] = ()
    decision_ref: InstitutionalReference | None = None
    record_refs: tuple[InstitutionalReference, ...] = ()
    legal_bases: tuple[LegalBasisReference, ...] = ()
    evidence: tuple[EvidenceReference, ...] = ()
    information_governance: InformationGovernanceReference | None = None
    external_sources: tuple[ExternalSourceReference, ...] = ()
    presentation: PresentationReference | None = None
    contract_version: str = INSTITUTIONAL_CONTEXT_CONTRACT_VERSION

    def __post_init__(self) -> None:
        if self.contract_version != INSTITUTIONAL_CONTEXT_CONTRACT_VERSION:
            raise InstitutionalContextError(
                "Unsupported institutional context contract version."
            )
        _require_identifier(self.tenant_id, "Institutional context tenant id")
        _validate_reference_kind(
            self.institution_ref, "institution", "institution reference"
        )
        _validate_reference_kind(
            self.organization_unit_ref,
            "organization_unit",
            "organization unit reference",
        )
        _validate_reference_kind(self.function_ref, "function", "function reference")
        _validate_reference_kind(self.task_ref, "task", "task reference")
        _validate_reference_kind(self.mandate_ref, "mandate", "mandate reference")
        _validate_reference_kind(self.service_ref, "service", "service reference")
        _validate_reference_kind(self.case_ref, "case", "case reference")
        _validate_reference_kind(self.decision_ref, "decision", "decision reference")
        for item in self.jurisdiction_refs:
            _validate_reference_kind(item, "jurisdiction", "jurisdiction reference")
        for item in self.party_refs:
            _validate_reference_kind(item, "party", "party reference")
        _validate_reference_kind(self.work_item_ref, "work_item", "work item reference")
        _validate_reference_kind(self.workflow_ref, "workflow", "workflow reference")
        for item in self.approval_refs:
            _validate_reference_kind(item, "approval", "approval reference")
        for item in self.record_refs:
            _validate_reference_kind(item, "record", "record reference")
        references = (
            self.institution_ref,
            self.organization_unit_ref,
            self.function_ref,
            self.task_ref,
            self.mandate_ref,
            *self.jurisdiction_refs,
            self.service_ref,
            self.case_ref,
            *self.party_refs,
            self.work_item_ref,
            self.workflow_ref,
            *self.approval_refs,
            self.decision_ref,
            *self.record_refs,
        )
        _validate_reference_tenants(self.tenant_id, references)
        if self.actor is not None and self.actor.tenant_id != self.tenant_id:
            raise InstitutionalContextError(
                "Actor representation belongs to a different tenant."
            )
        for item in self.evidence:
            if item.tenant_id != self.tenant_id:
                raise InstitutionalContextError(
                    "Evidence reference belongs to a different tenant."
                )

    def effective_at(self, instant: datetime) -> bool:
        if not self.temporal.effective_at(instant):
            return False
        return all(
            item.valid_at is None or item.valid_at == instant
            for item in (
                self.mandate_ref,
                self.service_ref,
                self.case_ref,
                self.decision_ref,
            )
            if item is not None
        )

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "contract_version": self.contract_version,
            "tenant_id": self.tenant_id,
            "temporal": self.temporal.to_dict(),
            "actor": self.actor.to_dict() if self.actor else None,
            "institution_ref": _reference_value(self.institution_ref),
            "organization_unit_ref": _reference_value(self.organization_unit_ref),
            "function_ref": _reference_value(self.function_ref),
            "task_ref": _reference_value(self.task_ref),
            "mandate_ref": _reference_value(self.mandate_ref),
            "jurisdiction_refs": [item.to_dict() for item in self.jurisdiction_refs],
            "service_ref": _reference_value(self.service_ref),
            "case_ref": _reference_value(self.case_ref),
            "party_refs": [item.to_dict() for item in self.party_refs],
            "work_item_ref": _reference_value(self.work_item_ref),
            "workflow_ref": _reference_value(self.workflow_ref),
            "approval_refs": [item.to_dict() for item in self.approval_refs],
            "decision_ref": _reference_value(self.decision_ref),
            "record_refs": [item.to_dict() for item in self.record_refs],
            "legal_bases": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.legal_bases
            ],
            "evidence": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.evidence
            ],
            "information_governance": (
                self.information_governance.to_dict()
                if self.information_governance
                else None
            ),
            "external_sources": [item.to_dict() for item in self.external_sources],
            "presentation": self.presentation.to_dict() if self.presentation else None,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "GovernedContextEnvelope":
        temporal = value.get("temporal")
        if not isinstance(temporal, Mapping):
            raise InstitutionalContextError(
                "Institutional context temporal revision is required."
            )
        return cls(
            contract_version=str(
                value.get("contract_version") or INSTITUTIONAL_CONTEXT_CONTRACT_VERSION
            ),
            tenant_id=_required_text(value, "tenant_id"),
            temporal=TemporalRevision.from_mapping(temporal),
            actor=_optional_actor(value.get("actor")),
            institution_ref=_optional_institutional_reference(
                value.get("institution_ref")
            ),
            organization_unit_ref=_optional_institutional_reference(
                value.get("organization_unit_ref")
            ),
            function_ref=_optional_institutional_reference(value.get("function_ref")),
            task_ref=_optional_institutional_reference(value.get("task_ref")),
            mandate_ref=_optional_institutional_reference(value.get("mandate_ref")),
            jurisdiction_refs=_institutional_references(value.get("jurisdiction_refs")),
            service_ref=_optional_institutional_reference(value.get("service_ref")),
            case_ref=_optional_institutional_reference(value.get("case_ref")),
            party_refs=_institutional_references(value.get("party_refs")),
            work_item_ref=_optional_institutional_reference(value.get("work_item_ref")),
            workflow_ref=_optional_institutional_reference(value.get("workflow_ref")),
            approval_refs=_institutional_references(value.get("approval_refs")),
            decision_ref=_optional_institutional_reference(value.get("decision_ref")),
            record_refs=_institutional_references(value.get("record_refs")),
            legal_bases=tuple(
                LegalBasisReference.from_mapping(item)
                for item in _mapping_sequence(value.get("legal_bases"))
            ),
            evidence=tuple(
                EvidenceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("evidence"))
            ),
            information_governance=_optional_governance(
                value.get("information_governance")
            ),
            external_sources=tuple(
                ExternalSourceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("external_sources"))
            ),
            presentation=_optional_presentation(value.get("presentation")),
        )


@dataclass(frozen=True, slots=True)
class MandateDefinition:
    reference: InstitutionalReference
    temporal: TemporalRevision
    task_types: tuple[str, ...]
    authority_types: tuple[str, ...]
    organization_unit_refs: tuple[InstitutionalReference, ...] = ()
    function_refs: tuple[InstitutionalReference, ...] = ()
    jurisdiction_refs: tuple[InstitutionalReference, ...] = ()
    subject_types: tuple[str, ...] = ()
    authority_ceiling: str | None = None
    legal_bases: tuple[LegalBasisReference, ...] = ()
    evidence: tuple[EvidenceReference, ...] = ()
    status: MandateStatus = "active"
    replacement_ref: InstitutionalReference | None = None
    suspension_reason: str | None = None
    conflict_refs: tuple[str, ...] = ()

    def __post_init__(self) -> None:
        _validate_reference_kind(self.reference, "mandate", "mandate definition")
        if self.status not in _MANDATE_STATUSES:
            raise InstitutionalContextError(
                f"Unsupported mandate status: {self.status!r}."
            )
        _validate_text_tuple(self.task_types, "Mandate task types", require=True)
        _validate_text_tuple(
            self.authority_types, "Mandate authority types", require=True
        )
        for item in self.organization_unit_refs:
            _validate_reference_kind(item, "organization_unit", "mandate unit")
        for item in self.function_refs:
            _validate_reference_kind(item, "function", "mandate function")
        for item in self.jurisdiction_refs:
            _validate_reference_kind(item, "jurisdiction", "mandate jurisdiction")
        _validate_reference_kind(
            self.replacement_ref,
            "mandate",
            "replaced mandate reference",
        )
        _validate_text_tuple(self.conflict_refs, "Mandate conflict references")
        if self.status == "suspended" and not str(self.suspension_reason or "").strip():
            raise InstitutionalContextError(
                "Suspended mandates require a suspension reason."
            )
        if self.status == "replaced" and self.replacement_ref is None:
            raise InstitutionalContextError(
                "Replaced mandates require the prior mandate reference."
            )
        _validate_reference_tenants(
            self.reference.tenant_id,
            (
                *self.organization_unit_refs,
                *self.function_refs,
                *self.jurisdiction_refs,
                self.replacement_ref,
            ),
        )
        for item in self.evidence:
            if item.tenant_id != self.reference.tenant_id:
                raise InstitutionalContextError(
                    "Mandate evidence belongs to a different tenant."
                )

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "reference": self.reference.to_dict(),
            "temporal": self.temporal.to_dict(),
            "task_types": list(self.task_types),
            "authority_types": list(self.authority_types),
            "organization_unit_refs": [
                item.to_dict() for item in self.organization_unit_refs
            ],
            "function_refs": [item.to_dict() for item in self.function_refs],
            "jurisdiction_refs": [item.to_dict() for item in self.jurisdiction_refs],
            "subject_types": list(self.subject_types),
            "authority_ceiling": self.authority_ceiling,
            "legal_bases": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.legal_bases
            ],
            "evidence": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.evidence
            ],
            "status": self.status,
            "replacement_ref": _reference_value(self.replacement_ref),
            "suspension_reason": self.suspension_reason,
            "conflict_refs": list(self.conflict_refs),
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "MandateDefinition":
        reference = _required_mapping(value, "reference")
        temporal = _required_mapping(value, "temporal")
        return cls(
            reference=InstitutionalReference.from_mapping(reference),
            temporal=TemporalRevision.from_mapping(temporal),
            task_types=_text_tuple(value.get("task_types")),
            authority_types=_text_tuple(value.get("authority_types")),
            organization_unit_refs=_institutional_references(
                value.get("organization_unit_refs")
            ),
            function_refs=_institutional_references(value.get("function_refs")),
            jurisdiction_refs=_institutional_references(value.get("jurisdiction_refs")),
            subject_types=_text_tuple(value.get("subject_types")),
            authority_ceiling=_optional_text(value.get("authority_ceiling")),
            legal_bases=tuple(
                LegalBasisReference.from_mapping(item)
                for item in _mapping_sequence(value.get("legal_bases"))
            ),
            evidence=tuple(
                EvidenceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("evidence"))
            ),
            status=cast(MandateStatus, str(value.get("status") or "active")),
            replacement_ref=_optional_institutional_reference(
                value.get("replacement_ref")
            ),
            suspension_reason=_optional_text(value.get("suspension_reason")),
            conflict_refs=_text_tuple(value.get("conflict_refs")),
        )


def revise_mandate_definition(
    current: MandateDefinition,
    *,
    expected_revision: str,
    temporal: TemporalRevision,
    status: MandateStatus,
    replacement_ref: InstitutionalReference | None = None,
    suspension_reason: str | None = None,
    conflict_refs: Sequence[str] | None = None,
) -> MandateDefinition:
    """Create an immutable, OCC-guarded Mandate lifecycle revision."""

    if current.temporal.revision != expected_revision:
        raise InstitutionalContextError(
            "Mandate revision conflict: the expected revision is stale."
        )
    if temporal.revision == current.temporal.revision:
        raise InstitutionalContextError(
            "A Mandate revision requires a new revision identifier."
        )
    if temporal.recorded_at is None or not str(temporal.change_reason or "").strip():
        raise InstitutionalContextError(
            "A Mandate revision requires recorded_at and change_reason."
        )
    if status not in _MANDATE_TRANSITIONS[current.status]:
        raise InstitutionalContextError(
            f"Mandate transition {current.status!r} to {status!r} is not allowed."
        )
    if status == "replaced" and replacement_ref is None:
        raise InstitutionalContextError(
            "Replacing a Mandate requires the replacement Mandate reference."
        )

    return replace(
        current,
        reference=replace(
            current.reference,
            version=temporal.revision,
            valid_at=temporal.valid_from or current.reference.valid_at,
        ),
        temporal=temporal,
        status=status,
        replacement_ref=replacement_ref if status == "replaced" else None,
        suspension_reason=(suspension_reason if status == "suspended" else None),
        conflict_refs=(
            tuple(conflict_refs) if conflict_refs is not None else current.conflict_refs
        ),
    )


@dataclass(frozen=True, slots=True)
class MandateResolutionRequest:
    tenant_id: str
    effective_at: datetime
    task_type: str
    authority_type: str
    organization_unit_ref: InstitutionalReference | None = None
    function_ref: InstitutionalReference | None = None
    jurisdiction_refs: tuple[InstitutionalReference, ...] = ()
    subject_type: str | None = None
    geo_ref: GeoReference | None = None

    def __post_init__(self) -> None:
        _require_identifier(self.tenant_id, "Mandate request tenant id")
        _require_aware_datetime(self.effective_at, "mandate request effective_at")
        _require_text(self.task_type, "Mandate request task type")
        _require_text(self.authority_type, "Mandate request authority type")
        _validate_reference_kind(
            self.organization_unit_ref,
            "organization_unit",
            "mandate request organization unit",
        )
        _validate_reference_kind(
            self.function_ref,
            "function",
            "mandate request function",
        )
        for item in self.jurisdiction_refs:
            _validate_reference_kind(
                item,
                "jurisdiction",
                "mandate request jurisdiction",
            )
        _validate_reference_tenants(
            self.tenant_id,
            (
                self.organization_unit_ref,
                self.function_ref,
                *self.jurisdiction_refs,
            ),
        )

    def to_dict(self) -> dict[str, object]:
        return {
            "tenant_id": self.tenant_id,
            "effective_at": self.effective_at.isoformat(),
            "task_type": self.task_type,
            "authority_type": self.authority_type,
            "organization_unit_ref": _reference_value(self.organization_unit_ref),
            "function_ref": _reference_value(self.function_ref),
            "jurisdiction_refs": [item.to_dict() for item in self.jurisdiction_refs],
            "subject_type": self.subject_type,
            "geo_ref": self.geo_ref.to_dict() if self.geo_ref else None,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "MandateResolutionRequest":
        geo = value.get("geo_ref")
        return cls(
            tenant_id=_required_text(value, "tenant_id"),
            effective_at=_required_datetime(value.get("effective_at")),
            task_type=_required_text(value, "task_type"),
            authority_type=_required_text(value, "authority_type"),
            organization_unit_ref=_optional_institutional_reference(
                value.get("organization_unit_ref")
            ),
            function_ref=_optional_institutional_reference(value.get("function_ref")),
            jurisdiction_refs=_institutional_references(value.get("jurisdiction_refs")),
            subject_type=_optional_text(value.get("subject_type")),
            geo_ref=GeoReference.from_mapping(geo)
            if isinstance(geo, Mapping)
            else None,
        )


@dataclass(frozen=True, slots=True)
class MandateResolution:
    competent: bool
    mandates: tuple[MandateDefinition, ...] = ()
    explanation: str | None = None
    conflict_refs: tuple[str, ...] = ()
    evidence: tuple[EvidenceReference, ...] = ()

    def __post_init__(self) -> None:
        _validate_text_tuple(
            self.conflict_refs,
            "Mandate resolution conflict references",
        )
        if self.competent and not self.mandates:
            raise InstitutionalContextError(
                "A competent mandate resolution requires at least one mandate."
            )

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "competent": self.competent,
            "mandates": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.mandates
            ],
            "explanation": self.explanation,
            "conflict_refs": list(self.conflict_refs),
            "evidence": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.evidence
            ],
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "MandateResolution":
        return cls(
            competent=_boolean_value(value, "competent", default=False),
            mandates=tuple(
                MandateDefinition.from_mapping(item)
                for item in _mapping_sequence(value.get("mandates"))
            ),
            explanation=_optional_text(value.get("explanation")),
            conflict_refs=_text_tuple(value.get("conflict_refs")),
            evidence=tuple(
                EvidenceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("evidence"))
            ),
        )


@runtime_checkable
class MandateResolver(Protocol):
    def resolve_mandate(
        self,
        session: object,
        principal: object,
        *,
        request: MandateResolutionRequest,
    ) -> MandateResolution: ...


def resolve_mandate_candidates(
    request: MandateResolutionRequest,
    candidates: Sequence[MandateDefinition],
) -> MandateResolution:
    """Resolve effective competence deterministically from governed candidates."""

    ordered = tuple(
        sorted(
            candidates,
            key=lambda item: (
                item.reference.object_id,
                item.temporal.revision,
            ),
        )
    )
    for mandate in ordered:
        if mandate.reference.tenant_id != request.tenant_id:
            raise InstitutionalContextError(
                "Mandate resolution candidates cannot cross tenants."
            )
    effective = tuple(
        mandate for mandate in ordered if _mandate_matches_request(mandate, request)
    )
    candidate_conflicts = tuple(
        dict.fromkeys(
            conflict for mandate in effective for conflict in mandate.conflict_refs
        )
    )
    if candidate_conflicts:
        return MandateResolution(
            competent=False,
            mandates=effective,
            explanation="Matching mandates have unresolved conflicts.",
            conflict_refs=candidate_conflicts,
            evidence=_mandate_evidence(effective),
        )
    if len(effective) != 1:
        conflicts = (
            tuple(
                dict.fromkeys(
                    f"mandate:{item.reference.object_id}@{item.temporal.revision}"
                    for item in effective
                )
            )
            if len(effective) > 1
            else ()
        )
        return MandateResolution(
            competent=False,
            mandates=effective,
            explanation=(
                "Mandate resolution requires exactly one effective active mandate."
            ),
            conflict_refs=conflicts,
            evidence=_mandate_evidence(effective),
        )
    return MandateResolution(
        competent=True,
        mandates=effective,
        explanation=(
            "Exactly one active mandate covers the effective time, task, "
            "authority, organization, function, jurisdiction, and subject."
        ),
        evidence=_mandate_evidence(effective),
    )


def _mandate_matches_request(
    mandate: MandateDefinition,
    request: MandateResolutionRequest,
) -> bool:
    if mandate.status != "active" or not mandate.temporal.effective_at(
        request.effective_at
    ):
        return False
    if (
        request.task_type not in mandate.task_types
        or request.authority_type not in mandate.authority_types
    ):
        return False
    if mandate.organization_unit_refs and not _reference_is_allowed(
        request.organization_unit_ref,
        mandate.organization_unit_refs,
    ):
        return False
    if mandate.function_refs and not _reference_is_allowed(
        request.function_ref,
        mandate.function_refs,
    ):
        return False
    requested_jurisdictions = {
        _stable_reference_key(item) for item in request.jurisdiction_refs
    }
    if mandate.jurisdiction_refs and not {
        _stable_reference_key(item) for item in mandate.jurisdiction_refs
    }.issubset(requested_jurisdictions):
        return False
    return not (
        mandate.subject_types and request.subject_type not in mandate.subject_types
    )


def _mandate_evidence(
    mandates: Sequence[MandateDefinition],
) -> tuple[EvidenceReference, ...]:
    evidence_by_key: dict[tuple[str, str, str, str, str | None], EvidenceReference] = {}
    for mandate in mandates:
        for item in mandate.evidence:
            key = (
                item.kind,
                item.owner_module,
                item.evidence_id,
                item.tenant_id,
                item.version,
            )
            evidence_by_key.setdefault(key, item)
    return tuple(evidence_by_key.values())


@dataclass(frozen=True, slots=True)
class ServiceBinding:
    kind: str
    reference: str
    required: bool = True

    def __post_init__(self) -> None:
        _require_text(self.kind, "Service binding kind")
        _require_identifier(self.reference, "Service binding reference")

    def to_dict(self) -> dict[str, object]:
        return {
            "kind": self.kind,
            "reference": self.reference,
            "required": self.required,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "ServiceBinding":
        return cls(
            kind=_required_text(value, "kind"),
            reference=_required_text(value, "reference"),
            required=_boolean_value(value, "required", default=True),
        )


@dataclass(frozen=True, slots=True)
class ServiceAvailabilityRequirement:
    kind: ServiceAvailabilityRequirementKind
    reference: str
    failure_state: ServiceAvailabilityFailureState = "unavailable"
    explanation_ref: str | None = None

    def __post_init__(self) -> None:
        if self.kind not in _SERVICE_AVAILABILITY_REQUIREMENT_KINDS:
            raise InstitutionalContextError(
                f"Unsupported Service availability requirement: {self.kind!r}."
            )
        _require_identifier(self.reference, "Service availability reference")
        if self.explanation_ref is not None:
            _require_identifier(
                self.explanation_ref,
                "Service availability explanation reference",
            )
        if self.failure_state not in {"unavailable", "hidden"}:
            raise InstitutionalContextError(
                f"Unsupported Service availability failure state: {self.failure_state!r}."
            )

    @property
    def key(self) -> str:
        return f"{self.kind}:{self.reference}"

    def to_dict(self) -> dict[str, object]:
        return {
            "kind": self.kind,
            "reference": self.reference,
            "failure_state": self.failure_state,
            "explanation_ref": self.explanation_ref,
        }

    @classmethod
    def from_mapping(
        cls,
        value: Mapping[str, object],
    ) -> "ServiceAvailabilityRequirement":
        return cls(
            kind=cast(
                ServiceAvailabilityRequirementKind,
                _required_text(value, "kind"),
            ),
            reference=_required_text(value, "reference"),
            failure_state=cast(
                ServiceAvailabilityFailureState,
                str(value.get("failure_state") or "unavailable"),
            ),
            explanation_ref=_optional_text(value.get("explanation_ref")),
        )


@dataclass(frozen=True, slots=True)
class ServiceAvailabilityAssessment:
    requirement_states: Mapping[str, bool]
    reason_codes: tuple[str, ...] = ()
    evidence: tuple[EvidenceReference, ...] = ()

    def __post_init__(self) -> None:
        for key, value in self.requirement_states.items():
            _require_text(key, "Service availability assessment key")
            if not isinstance(value, bool):
                raise InstitutionalContextError(
                    "Service availability assessment states must be booleans."
                )
        for code in self.reason_codes:
            _require_identifier(code, "Service availability reason code")


@dataclass(frozen=True, slots=True)
class ServiceDefinition:
    reference: InstitutionalReference
    key: str
    temporal: TemporalRevision
    title: str
    audience: tuple[str, ...]
    prerequisites: tuple[str, ...] = ()
    legal_bases: tuple[LegalBasisReference, ...] = ()
    required_evidence_types: tuple[str, ...] = ()
    fee_refs: tuple[str, ...] = ()
    deadline_refs: tuple[str, ...] = ()
    channels: tuple[str, ...] = ()
    responsible_organization_ref: InstitutionalReference | None = None
    responsible_function_ref: InstitutionalReference | None = None
    mandate_ref: InstitutionalReference | None = None
    jurisdiction_refs: tuple[InstitutionalReference, ...] = ()
    bindings: tuple[ServiceBinding, ...] = ()
    availability_requirements: tuple[ServiceAvailabilityRequirement, ...] = ()
    remedy_refs: tuple[str, ...] = ()
    service_level_refs: tuple[str, ...] = ()
    publication_state: ServicePublicationState = "draft"
    availability_explanation_ref: str | None = None
    derived_from_ref: InstitutionalReference | None = None

    def __post_init__(self) -> None:
        _validate_reference_kind(self.reference, "service", "service definition")
        _require_identifier(self.key, "Service key")
        _require_text(self.title, "Service title")
        if self.publication_state not in _SERVICE_PUBLICATION_STATES:
            raise InstitutionalContextError(
                f"Unsupported service publication state: {self.publication_state!r}."
            )
        _validate_text_tuple(self.audience, "Service audience", require=True)
        for label, values in (
            ("Service prerequisites", self.prerequisites),
            ("Service evidence types", self.required_evidence_types),
            ("Service fee references", self.fee_refs),
            ("Service deadline references", self.deadline_refs),
            ("Service channels", self.channels),
            ("Service remedy references", self.remedy_refs),
            ("Service level references", self.service_level_refs),
        ):
            _validate_text_tuple(values, label)
        _validate_reference_kind(
            self.responsible_organization_ref,
            "organization_unit",
            "service responsible organization",
        )
        _validate_reference_kind(
            self.responsible_function_ref,
            "function",
            "service responsible function",
        )
        _validate_reference_kind(self.mandate_ref, "mandate", "service mandate")
        _validate_reference_kind(
            self.derived_from_ref,
            "service",
            "parent service definition",
        )
        for item in self.jurisdiction_refs:
            _validate_reference_kind(item, "jurisdiction", "service jurisdiction")
        requirement_keys = tuple(item.key for item in self.availability_requirements)
        if len(requirement_keys) != len(set(requirement_keys)):
            raise InstitutionalContextError(
                "Service availability requirements cannot contain duplicates."
            )
        _validate_reference_tenants(
            self.reference.tenant_id,
            (
                self.responsible_organization_ref,
                self.responsible_function_ref,
                self.mandate_ref,
                self.derived_from_ref,
                *self.jurisdiction_refs,
            ),
        )

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "reference": self.reference.to_dict(),
            "key": self.key,
            "temporal": self.temporal.to_dict(),
            "title": self.title,
            "audience": list(self.audience),
            "prerequisites": list(self.prerequisites),
            "legal_bases": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.legal_bases
            ],
            "required_evidence_types": list(self.required_evidence_types),
            "fee_refs": list(self.fee_refs),
            "deadline_refs": list(self.deadline_refs),
            "channels": list(self.channels),
            "responsible_organization_ref": _reference_value(
                self.responsible_organization_ref
            ),
            "responsible_function_ref": _reference_value(self.responsible_function_ref),
            "mandate_ref": _reference_value(self.mandate_ref),
            "jurisdiction_refs": [item.to_dict() for item in self.jurisdiction_refs],
            "bindings": [item.to_dict() for item in self.bindings],
            "availability_requirements": [
                item.to_dict() for item in self.availability_requirements
            ],
            "remedy_refs": list(self.remedy_refs),
            "service_level_refs": list(self.service_level_refs),
            "publication_state": self.publication_state,
            "availability_explanation_ref": self.availability_explanation_ref,
            "derived_from_ref": _reference_value(self.derived_from_ref),
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "ServiceDefinition":
        return cls(
            reference=InstitutionalReference.from_mapping(
                _required_mapping(value, "reference")
            ),
            key=_required_text(value, "key"),
            temporal=TemporalRevision.from_mapping(
                _required_mapping(value, "temporal")
            ),
            title=_required_text(value, "title"),
            audience=_text_tuple(value.get("audience")),
            prerequisites=_text_tuple(value.get("prerequisites")),
            legal_bases=tuple(
                LegalBasisReference.from_mapping(item)
                for item in _mapping_sequence(value.get("legal_bases"))
            ),
            required_evidence_types=_text_tuple(value.get("required_evidence_types")),
            fee_refs=_text_tuple(value.get("fee_refs")),
            deadline_refs=_text_tuple(value.get("deadline_refs")),
            channels=_text_tuple(value.get("channels")),
            responsible_organization_ref=_optional_institutional_reference(
                value.get("responsible_organization_ref")
            ),
            responsible_function_ref=_optional_institutional_reference(
                value.get("responsible_function_ref")
            ),
            mandate_ref=_optional_institutional_reference(value.get("mandate_ref")),
            jurisdiction_refs=_institutional_references(value.get("jurisdiction_refs")),
            bindings=tuple(
                ServiceBinding.from_mapping(item)
                for item in _mapping_sequence(value.get("bindings"))
            ),
            availability_requirements=tuple(
                ServiceAvailabilityRequirement.from_mapping(item)
                for item in _mapping_sequence(value.get("availability_requirements"))
            ),
            remedy_refs=_text_tuple(value.get("remedy_refs")),
            service_level_refs=_text_tuple(value.get("service_level_refs")),
            publication_state=cast(
                ServicePublicationState,
                str(value.get("publication_state") or "draft"),
            ),
            availability_explanation_ref=_optional_text(
                value.get("availability_explanation_ref")
            ),
            derived_from_ref=_optional_institutional_reference(
                value.get("derived_from_ref")
            ),
        )


def derive_service_restriction(
    parent: ServiceDefinition,
    *,
    reference: InstitutionalReference,
    temporal: TemporalRevision,
    title: str | None = None,
    audience: Sequence[str] | None = None,
    add_prerequisites: Sequence[str] = (),
    add_required_evidence_types: Sequence[str] = (),
    channels: Sequence[str] | None = None,
    add_legal_bases: Sequence[LegalBasisReference] = (),
    add_bindings: Sequence[ServiceBinding] = (),
    publication_state: ServicePublicationState | None = None,
    availability_explanation_ref: str | None = None,
) -> ServiceDefinition:
    """Derive a Service specialization that cannot widen parent constraints."""

    _validate_reference_kind(reference, "service", "derived service definition")
    if reference.tenant_id != parent.reference.tenant_id:
        raise InstitutionalContextError("A Service restriction cannot cross tenants.")
    if reference.version != temporal.revision:
        raise InstitutionalContextError(
            "Derived Service reference version must match its temporal revision."
        )
    if temporal.recorded_at is None or not str(temporal.change_reason or "").strip():
        raise InstitutionalContextError(
            "A derived Service requires recorded_at and change_reason."
        )
    if parent.temporal.valid_from is not None and (
        temporal.valid_from is None or temporal.valid_from < parent.temporal.valid_from
    ):
        raise InstitutionalContextError(
            "A derived Service cannot start before its parent."
        )
    if parent.temporal.valid_to is not None and (
        temporal.valid_to is None or temporal.valid_to > parent.temporal.valid_to
    ):
        raise InstitutionalContextError(
            "A derived Service cannot remain valid beyond its parent."
        )

    narrowed_audience = tuple(audience) if audience is not None else parent.audience
    if not set(narrowed_audience).issubset(parent.audience):
        raise InstitutionalContextError(
            "A derived Service cannot widen its parent audience."
        )
    narrowed_channels = tuple(channels) if channels is not None else parent.channels
    if not set(narrowed_channels).issubset(parent.channels):
        raise InstitutionalContextError(
            "A derived Service cannot widen its parent channels."
        )
    next_publication_state = publication_state or parent.publication_state
    allowed_publication_states: Mapping[
        ServicePublicationState,
        frozenset[ServicePublicationState],
    ] = {
        "draft": frozenset({"draft"}),
        "published": frozenset({"draft", "published", "suspended", "retired"}),
        "suspended": frozenset({"suspended", "retired"}),
        "retired": frozenset({"retired"}),
    }
    if (
        next_publication_state
        not in allowed_publication_states[parent.publication_state]
    ):
        raise InstitutionalContextError(
            "A derived Service cannot widen its parent publication state."
        )

    return replace(
        parent,
        reference=reference,
        temporal=temporal,
        title=title if title is not None else parent.title,
        audience=narrowed_audience,
        prerequisites=_ordered_text_union(
            parent.prerequisites,
            add_prerequisites,
        ),
        required_evidence_types=_ordered_text_union(
            parent.required_evidence_types,
            add_required_evidence_types,
        ),
        channels=narrowed_channels,
        legal_bases=tuple(dict.fromkeys((*parent.legal_bases, *add_legal_bases))),
        bindings=tuple(dict.fromkeys((*parent.bindings, *add_bindings))),
        publication_state=next_publication_state,
        availability_explanation_ref=(
            availability_explanation_ref
            if availability_explanation_ref is not None
            else parent.availability_explanation_ref
        ),
        derived_from_ref=parent.reference,
    )


@runtime_checkable
class ServiceDefinitionProvider(Protocol):
    def get_service_definition(
        self,
        session: object,
        principal: object,
        *,
        reference: InstitutionalReference,
        effective_at: datetime | None = None,
    ) -> ServiceDefinition | None: ...

    def list_service_definitions(
        self,
        session: object,
        principal: object,
        *,
        tenant_id: str,
        query: str = "",
        limit: int = 100,
    ) -> Sequence[ServiceDefinition]: ...


@dataclass(frozen=True, slots=True)
class FormConditionExpression:
    kind: FormConditionKind
    field_key: str | None = None
    operator: FormConditionOperator | None = None
    value: object | None = None
    conditions: tuple["FormConditionExpression", ...] = ()

    def __post_init__(self) -> None:
        if self.kind not in _FORM_CONDITION_KINDS:
            raise InstitutionalContextError(
                f"Unsupported Form condition kind: {self.kind!r}."
            )
        if self.kind == "predicate":
            if self.field_key is None or self.operator is None:
                raise InstitutionalContextError(
                    "A Form predicate requires a field key and operator."
                )
            _require_identifier(self.field_key, "Form condition field key")
            if self.operator not in _FORM_CONDITION_OPERATORS:
                raise InstitutionalContextError(
                    f"Unsupported Form condition operator: {self.operator!r}."
                )
            if self.conditions:
                raise InstitutionalContextError(
                    "A Form predicate cannot contain nested conditions."
                )
            if self.operator in {"is_empty", "is_not_empty"} and self.value is not None:
                raise InstitutionalContextError(
                    f"Form condition operator {self.operator!r} does not take a value."
                )
            return
        if (
            self.field_key is not None
            or self.operator is not None
            or self.value is not None
        ):
            raise InstitutionalContextError(
                "A composite Form condition cannot declare predicate properties."
            )
        expected = 1 if self.kind == "not" else 2
        if len(self.conditions) < expected or (
            self.kind == "not" and len(self.conditions) != 1
        ):
            raise InstitutionalContextError(
                f"Form condition {self.kind!r} requires "
                f"{'exactly one child' if self.kind == 'not' else 'at least two children'}."
            )

    def to_dict(self) -> dict[str, object]:
        if self.kind == "predicate":
            payload: dict[str, object] = {
                "kind": self.kind,
                "field_key": self.field_key,
                "operator": self.operator,
            }
            if self.operator not in {"is_empty", "is_not_empty"}:
                payload["value"] = self.value
            return payload
        return {
            "kind": self.kind,
            "conditions": [item.to_dict() for item in self.conditions],
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormConditionExpression":
        return cls(
            kind=cast(FormConditionKind, _required_text(value, "kind")),
            field_key=_optional_text(value.get("field_key")),
            operator=cast(
                FormConditionOperator | None,
                _optional_text(value.get("operator")),
            ),
            value=value.get("value"),
            conditions=tuple(
                cls.from_mapping(item)
                for item in _mapping_sequence(value.get("conditions"))
            ),
        )

    @property
    def referenced_fields(self) -> tuple[str, ...]:
        if self.kind == "predicate":
            return (str(self.field_key),)
        return tuple(
            field_key
            for condition in self.conditions
            for field_key in condition.referenced_fields
        )


@dataclass(frozen=True, slots=True)
class FormSectionDefinition:
    key: str
    title: str
    field_keys: tuple[str, ...]
    description: str | None = None
    visibility_condition: FormConditionExpression | None = None

    def __post_init__(self) -> None:
        _require_identifier(self.key, "Form section key")
        _require_text(self.title, "Form section title")
        _validate_text_tuple(self.field_keys, "Form section field keys")
        if not self.field_keys:
            raise InstitutionalContextError(
                "A Form section requires at least one field key."
            )
        if len(self.field_keys) != len(set(self.field_keys)):
            raise InstitutionalContextError("Form section field keys must be unique.")

    def to_dict(self) -> dict[str, object]:
        payload: dict[str, object] = {
            "key": self.key,
            "title": self.title,
            "description": self.description,
            "field_keys": list(self.field_keys),
        }
        if self.visibility_condition is not None:
            payload["visibility_condition"] = self.visibility_condition.to_dict()
        return payload

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormSectionDefinition":
        condition = value.get("visibility_condition")
        if condition is not None and not isinstance(condition, Mapping):
            raise InstitutionalContextError(
                "Form section visibility_condition must be an object."
            )
        return cls(
            key=_required_text(value, "key"),
            title=_required_text(value, "title"),
            description=_optional_text(value.get("description")),
            field_keys=_text_tuple(value.get("field_keys")),
            visibility_condition=(
                FormConditionExpression.from_mapping(condition)
                if isinstance(condition, Mapping)
                else None
            ),
        )


@dataclass(frozen=True, slots=True)
class FormPageDefinition:
    key: str
    title: str
    sections: tuple[FormSectionDefinition, ...]
    description: str | None = None
    visibility_condition: FormConditionExpression | None = None

    def __post_init__(self) -> None:
        _require_identifier(self.key, "Form page key")
        _require_text(self.title, "Form page title")
        if not self.sections:
            raise InstitutionalContextError(
                "A Form page requires at least one section."
            )
        keys = tuple(item.key for item in self.sections)
        if len(keys) != len(set(keys)):
            raise InstitutionalContextError(
                "Form section keys must be unique within a page."
            )

    def to_dict(self) -> dict[str, object]:
        payload: dict[str, object] = {
            "key": self.key,
            "title": self.title,
            "description": self.description,
            "sections": [item.to_dict() for item in self.sections],
        }
        if self.visibility_condition is not None:
            payload["visibility_condition"] = self.visibility_condition.to_dict()
        return payload

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormPageDefinition":
        condition = value.get("visibility_condition")
        if condition is not None and not isinstance(condition, Mapping):
            raise InstitutionalContextError(
                "Form page visibility_condition must be an object."
            )
        return cls(
            key=_required_text(value, "key"),
            title=_required_text(value, "title"),
            description=_optional_text(value.get("description")),
            sections=tuple(
                FormSectionDefinition.from_mapping(item)
                for item in _mapping_sequence(value.get("sections"))
            ),
            visibility_condition=(
                FormConditionExpression.from_mapping(condition)
                if isinstance(condition, Mapping)
                else None
            ),
        )


@dataclass(frozen=True, slots=True)
class FormLocalization:
    locale: str
    title: str | None = None
    description: str | None = None
    field_labels: Mapping[str, str] = field(default_factory=dict)
    field_help_texts: Mapping[str, str] = field(default_factory=dict)
    option_labels: Mapping[str, Mapping[str, str]] = field(default_factory=dict)
    page_titles: Mapping[str, str] = field(default_factory=dict)
    section_titles: Mapping[str, str] = field(default_factory=dict)

    def __post_init__(self) -> None:
        clean_locale = self.locale.strip()
        if (
            not clean_locale
            or len(clean_locale) > 35
            or not re.fullmatch(r"[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*", clean_locale)
        ):
            raise InstitutionalContextError("Form localization locale is invalid.")
        for label, values in (
            ("field labels", self.field_labels),
            ("field help texts", self.field_help_texts),
            ("page titles", self.page_titles),
            ("section titles", self.section_titles),
        ):
            if not isinstance(values, Mapping):
                raise InstitutionalContextError(
                    f"Form localization {label} must be an object."
                )
            for key, text in values.items():
                _require_identifier(str(key), f"Form localization {label} key")
                _require_text(str(text), f"Form localization {label} value")
        if not isinstance(self.option_labels, Mapping):
            raise InstitutionalContextError(
                "Form localization option labels must be an object."
            )
        for field_key, labels in self.option_labels.items():
            _require_identifier(str(field_key), "Form option label field key")
            if not isinstance(labels, Mapping):
                raise InstitutionalContextError(
                    "Form option labels must map option keys to text."
                )
            for option_key, text in labels.items():
                _require_text(str(option_key), "Form option label key")
                _require_text(str(text), "Form option label value")

    def to_dict(self) -> dict[str, object]:
        return {
            "locale": self.locale,
            "title": self.title,
            "description": self.description,
            "field_labels": dict(self.field_labels),
            "field_help_texts": dict(self.field_help_texts),
            "option_labels": {
                key: dict(value) for key, value in self.option_labels.items()
            },
            "page_titles": dict(self.page_titles),
            "section_titles": dict(self.section_titles),
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormLocalization":
        def text_mapping(key: str) -> dict[str, str]:
            raw = value.get(key)
            if raw is None:
                return {}
            if not isinstance(raw, Mapping):
                raise InstitutionalContextError(
                    f"Form localization {key} must be an object."
                )
            return {str(item_key): str(item) for item_key, item in raw.items()}

        raw_option_labels = value.get("option_labels")
        if raw_option_labels is not None and not isinstance(raw_option_labels, Mapping):
            raise InstitutionalContextError(
                "Form localization option_labels must be an object."
            )
        return cls(
            locale=_required_text(value, "locale"),
            title=_optional_text(value.get("title")),
            description=_optional_text(value.get("description")),
            field_labels=text_mapping("field_labels"),
            field_help_texts=text_mapping("field_help_texts"),
            option_labels={
                str(field_key): {
                    str(option_key): str(label) for option_key, label in labels.items()
                }
                for field_key, labels in (raw_option_labels or {}).items()
                if isinstance(labels, Mapping)
            },
            page_titles=text_mapping("page_titles"),
            section_titles=text_mapping("section_titles"),
        )


@dataclass(frozen=True, slots=True)
class FormFieldDefinition:
    key: str
    label: str
    value_type: FormValueType = "text"
    required: bool = False
    help_text: str | None = None
    options: tuple[str, ...] = ()
    constraints: Mapping[str, object] = field(default_factory=dict)
    default_value: object | None = None
    visibility_condition: FormConditionExpression | None = None
    accessibility: Mapping[str, object] = field(default_factory=dict)

    def __post_init__(self) -> None:
        _require_identifier(self.key, "Form field key")
        _require_text(self.label, "Form field label")
        if self.value_type not in _FORM_VALUE_TYPES:
            raise InstitutionalContextError(
                f"Unsupported form field value type: {self.value_type!r}."
            )
        if not isinstance(self.required, bool):
            raise InstitutionalContextError("Form field required must be a boolean.")
        _validate_text_tuple(self.options, "Form field options")
        if self.value_type in {"choice", "multi_choice"} and not self.options:
            raise InstitutionalContextError(
                "Choice form fields require at least one option."
            )
        if self.value_type not in {"choice", "multi_choice"} and self.options:
            raise InstitutionalContextError(
                "Only choice form fields may declare options."
            )
        if not isinstance(self.constraints, Mapping):
            raise InstitutionalContextError("Form field constraints must be an object.")
        if not isinstance(self.accessibility, Mapping):
            raise InstitutionalContextError(
                "Form field accessibility metadata must be an object."
            )

    def to_dict(self) -> dict[str, object]:
        payload: dict[str, object] = {
            "key": self.key,
            "label": self.label,
            "value_type": self.value_type,
            "required": self.required,
            "help_text": self.help_text,
            "options": list(self.options),
            "constraints": dict(self.constraints),
            "default_value": self.default_value,
        }
        if self.visibility_condition is not None:
            payload["visibility_condition"] = self.visibility_condition.to_dict()
        if self.accessibility:
            payload["accessibility"] = dict(self.accessibility)
        return payload

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormFieldDefinition":
        constraints = value.get("constraints")
        if constraints is not None and not isinstance(constraints, Mapping):
            raise InstitutionalContextError("Form field constraints must be an object.")
        condition = value.get("visibility_condition")
        if condition is not None and not isinstance(condition, Mapping):
            raise InstitutionalContextError(
                "Form field visibility_condition must be an object."
            )
        accessibility = value.get("accessibility")
        if accessibility is not None and not isinstance(accessibility, Mapping):
            raise InstitutionalContextError(
                "Form field accessibility metadata must be an object."
            )
        return cls(
            key=_required_text(value, "key"),
            label=_required_text(value, "label"),
            value_type=cast(FormValueType, str(value.get("value_type") or "text")),
            required=_boolean_value(value, "required", default=False),
            help_text=_optional_text(value.get("help_text")),
            options=_text_tuple(value.get("options")),
            constraints=dict(constraints or {}),
            default_value=value.get("default_value"),
            visibility_condition=(
                FormConditionExpression.from_mapping(condition)
                if isinstance(condition, Mapping)
                else None
            ),
            accessibility=dict(accessibility or {}),
        )


@dataclass(frozen=True, slots=True)
class FormDefinition:
    reference: InstitutionalReference
    key: str
    temporal: TemporalRevision
    title: str
    fields: tuple[FormFieldDefinition, ...]
    description: str | None = None
    publication_state: FormPublicationState = "draft"
    allow_drafts: bool = True
    max_attachments: int = 0
    signature_requirement: FormSignatureRequirement = "none"
    policy_refs: tuple[str, ...] = ()
    handoff_kinds: tuple[str, ...] = ()
    pages: tuple[FormPageDefinition, ...] = ()
    fallback_locale: str | None = None
    localizations: tuple[FormLocalization, ...] = ()
    accessibility: Mapping[str, object] = field(default_factory=dict)
    metadata: Mapping[str, object] = field(default_factory=dict)

    def __post_init__(self) -> None:
        _validate_reference_kind(self.reference, "form", "form definition")
        _require_identifier(self.key, "Form key")
        _require_text(self.title, "Form title")
        if not self.reference.version:
            raise InstitutionalContextError(
                "A Form definition requires an exact reference version."
            )
        if self.reference.version != self.temporal.revision:
            raise InstitutionalContextError(
                "Form reference version must match its temporal revision."
            )
        if self.publication_state not in _FORM_PUBLICATION_STATES:
            raise InstitutionalContextError(
                f"Unsupported form publication state: {self.publication_state!r}."
            )
        if not self.fields:
            raise InstitutionalContextError(
                "A Form definition requires at least one field."
            )
        field_keys = tuple(item.key for item in self.fields)
        if len(field_keys) != len(set(field_keys)):
            raise InstitutionalContextError(
                "Form definition field keys must be unique."
            )
        if not isinstance(self.allow_drafts, bool):
            raise InstitutionalContextError("Form allow_drafts must be a boolean.")
        if (
            not isinstance(self.max_attachments, int)
            or isinstance(self.max_attachments, bool)
            or not 0 <= self.max_attachments <= 1000
        ):
            raise InstitutionalContextError(
                "Form max_attachments must be between 0 and 1000."
            )
        if self.signature_requirement not in _FORM_SIGNATURE_REQUIREMENTS:
            raise InstitutionalContextError("Unsupported form signature requirement.")
        _validate_text_tuple(self.policy_refs, "Form policy references")
        _validate_text_tuple(self.handoff_kinds, "Form handoff kinds")
        page_keys = tuple(item.key for item in self.pages)
        if len(page_keys) != len(set(page_keys)):
            raise InstitutionalContextError("Form page keys must be unique.")
        locales = tuple(item.locale.casefold() for item in self.localizations)
        if len(locales) != len(set(locales)):
            raise InstitutionalContextError("Form localization locales must be unique.")
        if self.fallback_locale is not None:
            if not self.localizations:
                raise InstitutionalContextError(
                    "Form fallback_locale requires at least one localization."
                )
            if self.fallback_locale.casefold() not in set(locales):
                raise InstitutionalContextError(
                    "Form fallback_locale must identify a declared localization."
                )
        if not isinstance(self.accessibility, Mapping):
            raise InstitutionalContextError(
                "Form accessibility metadata must be an object."
            )
        if not isinstance(self.metadata, Mapping):
            raise InstitutionalContextError("Form metadata must be an object.")

    def to_dict(self) -> dict[str, object]:
        payload: dict[str, object] = {
            "reference": self.reference.to_dict(disclose_label=True),
            "key": self.key,
            "temporal": self.temporal.to_dict(),
            "title": self.title,
            "description": self.description,
            "fields": [item.to_dict() for item in self.fields],
            "publication_state": self.publication_state,
            "allow_drafts": self.allow_drafts,
            "max_attachments": self.max_attachments,
            "signature_requirement": self.signature_requirement,
            "policy_refs": list(self.policy_refs),
            "handoff_kinds": list(self.handoff_kinds),
            "metadata": dict(self.metadata),
        }
        if self.pages:
            payload["pages"] = [item.to_dict() for item in self.pages]
        if self.localizations:
            payload["localizations"] = [item.to_dict() for item in self.localizations]
            payload["fallback_locale"] = self.fallback_locale
        if self.accessibility:
            payload["accessibility"] = dict(self.accessibility)
        return payload

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormDefinition":
        metadata = value.get("metadata")
        if metadata is not None and not isinstance(metadata, Mapping):
            raise InstitutionalContextError("Form metadata must be an object.")
        accessibility = value.get("accessibility")
        if accessibility is not None and not isinstance(accessibility, Mapping):
            raise InstitutionalContextError(
                "Form accessibility metadata must be an object."
            )
        raw_max_attachments = value.get("max_attachments", 0)
        if not isinstance(raw_max_attachments, int) or isinstance(
            raw_max_attachments, bool
        ):
            raise InstitutionalContextError("Form max_attachments must be an integer.")
        return cls(
            reference=InstitutionalReference.from_mapping(
                _required_mapping(value, "reference")
            ),
            key=_required_text(value, "key"),
            temporal=TemporalRevision.from_mapping(
                _required_mapping(value, "temporal")
            ),
            title=_required_text(value, "title"),
            description=_optional_text(value.get("description")),
            fields=tuple(
                FormFieldDefinition.from_mapping(item)
                for item in _mapping_sequence(value.get("fields"))
            ),
            publication_state=cast(
                FormPublicationState,
                str(value.get("publication_state") or "draft"),
            ),
            allow_drafts=_boolean_value(value, "allow_drafts", default=True),
            max_attachments=raw_max_attachments,
            signature_requirement=cast(
                FormSignatureRequirement,
                str(value.get("signature_requirement") or "none"),
            ),
            policy_refs=_text_tuple(value.get("policy_refs")),
            handoff_kinds=_text_tuple(value.get("handoff_kinds")),
            pages=tuple(
                FormPageDefinition.from_mapping(item)
                for item in _mapping_sequence(value.get("pages"))
            ),
            fallback_locale=_optional_text(value.get("fallback_locale")),
            localizations=tuple(
                FormLocalization.from_mapping(item)
                for item in _mapping_sequence(value.get("localizations"))
            ),
            accessibility=dict(accessibility or {}),
            metadata=dict(metadata or {}),
        )


@runtime_checkable
class FormDefinitionProvider(Protocol):
    def get_form_definition(
        self,
        session: object,
        principal: object,
        *,
        reference: InstitutionalReference,
        effective_at: datetime | None = None,
    ) -> FormDefinition | None: ...

    def list_form_definitions(
        self,
        session: object,
        principal: object,
        *,
        tenant_id: str,
        query: str = "",
        limit: int = 100,
    ) -> Sequence[FormDefinition]: ...


@dataclass(frozen=True, slots=True)
class ServiceLaunchRequest:
    service_ref: InstitutionalReference
    binding: ServiceBinding
    idempotency_key: str
    requested_at: datetime
    parameters: Mapping[str, object]

    def __post_init__(self) -> None:
        _validate_reference_kind(self.service_ref, "service", "service launch")
        if not self.service_ref.version:
            raise InstitutionalContextError(
                "Service launch requires an exact Service revision."
            )
        _require_text(self.idempotency_key, "Service launch idempotency key")
        _require_aware_datetime(self.requested_at, "Service launch requested_at")
        if len(self.parameters) > 100:
            raise InstitutionalContextError(
                "Service launch parameters are limited to 100 entries."
            )
        for key in self.parameters:
            _require_text(str(key), "Service launch parameter key")


@dataclass(frozen=True, slots=True)
class ServiceLaunchResult:
    service_ref: InstitutionalReference
    binding: ServiceBinding
    state: ServiceLaunchState
    metadata: Mapping[str, object]
    target_ref: InstitutionalReference | None = None
    href: str | None = None
    replayed: bool = False
    evidence: tuple[EvidenceReference, ...] = ()

    def __post_init__(self) -> None:
        _validate_reference_kind(self.service_ref, "service", "service launch result")
        if not self.service_ref.version:
            raise InstitutionalContextError(
                "Service launch result requires an exact Service revision."
            )
        if self.state not in {"started", "redirect"}:
            raise InstitutionalContextError("Unsupported Service launch state.")
        if self.target_ref is not None and (
            self.target_ref.tenant_id != self.service_ref.tenant_id
        ):
            raise InstitutionalContextError(
                "Service launch result cannot target another tenant."
            )
        if any(item.tenant_id != self.service_ref.tenant_id for item in self.evidence):
            raise InstitutionalContextError(
                "Service launch evidence cannot cross tenants."
            )
        _validate_service_launch_href(self.href)
        if self.state == "redirect" and self.href is None:
            raise InstitutionalContextError(
                "Redirect Service launches require a target URL."
            )
        if self.state == "started" and self.target_ref is None and self.href is None:
            raise InstitutionalContextError(
                "Started Service launches require a target reference or URL."
            )

    def to_dict(self) -> dict[str, object]:
        return {
            "service_ref": self.service_ref.to_dict(),
            "binding": self.binding.to_dict(),
            "state": self.state,
            "target_ref": _reference_value(self.target_ref),
            "href": self.href,
            "replayed": self.replayed,
            "evidence": [
                item.to_dict(include_inspection=False) for item in self.evidence
            ],
            "metadata": dict(self.metadata),
        }


def service_launch_capability(binding_kind: str) -> str:
    capabilities = {
        "case": "cases.service_launcher",
        "form": "forms_runtime.service_launcher",
        "workflow": "workflow_engine.service_launcher",
    }
    try:
        return capabilities[binding_kind]
    except KeyError as exc:
        raise InstitutionalContextError(
            f"Service binding kind {binding_kind!r} has no launch capability."
        ) from exc


@runtime_checkable
class ServiceLauncher(Protocol):
    def launch_service(
        self,
        session: object,
        principal: object,
        *,
        definition: ServiceDefinition,
        request: ServiceLaunchRequest,
    ) -> ServiceLaunchResult: ...


@runtime_checkable
class ServiceAvailabilityEvaluator(Protocol):
    def evaluate_service_availability(
        self,
        session: object,
        principal: object,
        *,
        definition: ServiceDefinition,
        effective_at: datetime,
    ) -> ServiceAvailabilityAssessment: ...


@dataclass(frozen=True, slots=True)
class PartySubjectReference:
    kind: PartySubjectKind
    provider: str
    subject_id: str
    tenant_id: str
    version: str | None = None

    def __post_init__(self) -> None:
        if self.kind not in _PARTY_SUBJECT_KINDS:
            raise InstitutionalContextError(
                f"Unsupported party subject kind: {self.kind!r}."
            )
        _require_text(self.provider, "Party subject provider")
        _require_identifier(self.subject_id, "Party subject id")
        _require_identifier(self.tenant_id, "Party subject tenant id")

    def to_dict(self) -> dict[str, object]:
        return {
            "kind": self.kind,
            "provider": self.provider,
            "subject_id": self.subject_id,
            "tenant_id": self.tenant_id,
            "version": self.version,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "PartySubjectReference":
        return cls(
            kind=cast(PartySubjectKind, _required_text(value, "kind")),
            provider=_required_text(value, "provider"),
            subject_id=_required_text(value, "subject_id"),
            tenant_id=_required_text(value, "tenant_id"),
            version=_optional_text(value.get("version")),
        )


@dataclass(frozen=True, slots=True)
class PartyRepresentation:
    representative_party_ref: InstitutionalReference
    represented_party_ref: InstitutionalReference
    power_ref: str
    permitted_actions: tuple[str, ...]
    temporal: TemporalRevision
    evidence: tuple[EvidenceReference, ...] = ()
    revoked_at: datetime | None = None

    def __post_init__(self) -> None:
        _validate_reference_kind(
            self.representative_party_ref, "party", "representative party"
        )
        _validate_reference_kind(
            self.represented_party_ref, "party", "represented party"
        )
        if (
            self.representative_party_ref.tenant_id
            != self.represented_party_ref.tenant_id
        ):
            raise InstitutionalContextError(
                "Party representation cannot cross tenants."
            )
        _require_identifier(self.power_ref, "Party representation power ref")
        _validate_text_tuple(
            self.permitted_actions,
            "Party representation permitted actions",
            require=True,
        )
        _require_aware_datetime(self.revoked_at, "party representation revoked_at")
        for item in self.evidence:
            if item.tenant_id != self.representative_party_ref.tenant_id:
                raise InstitutionalContextError(
                    "Party representation evidence belongs to a different tenant."
                )

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "representative_party_ref": self.representative_party_ref.to_dict(),
            "represented_party_ref": self.represented_party_ref.to_dict(),
            "power_ref": self.power_ref,
            "permitted_actions": list(self.permitted_actions),
            "temporal": self.temporal.to_dict(),
            "evidence": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.evidence
            ],
            "revoked_at": _datetime_value(self.revoked_at),
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "PartyRepresentation":
        return cls(
            representative_party_ref=InstitutionalReference.from_mapping(
                _required_mapping(value, "representative_party_ref")
            ),
            represented_party_ref=InstitutionalReference.from_mapping(
                _required_mapping(value, "represented_party_ref")
            ),
            power_ref=_required_text(value, "power_ref"),
            permitted_actions=_text_tuple(value.get("permitted_actions")),
            temporal=TemporalRevision.from_mapping(
                _required_mapping(value, "temporal")
            ),
            evidence=tuple(
                EvidenceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("evidence"))
            ),
            revoked_at=_optional_datetime(value.get("revoked_at")),
        )


@dataclass(frozen=True, slots=True)
class ProcedureParty:
    reference: InstitutionalReference
    procedure_ref: InstitutionalReference
    role: str
    subject: PartySubjectReference
    temporal: TemporalRevision
    preferred_channels: tuple[str, ...] = ()
    permitted_channels: tuple[str, ...] = ()
    delivery_recipient: bool = False
    representations: tuple[PartyRepresentation, ...] = ()
    contact_snapshot_refs: tuple[str, ...] = ()
    evidence: tuple[EvidenceReference, ...] = ()
    status: ProcedurePartyStatus = "active"

    def __post_init__(self) -> None:
        _validate_reference_kind(self.reference, "party", "procedure party")
        if self.procedure_ref.kind not in {"case", "workflow", "decision"}:
            raise InstitutionalContextError(
                "Procedure party must belong to a case, workflow, or decision."
            )
        if self.subject.tenant_id != self.reference.tenant_id:
            raise InstitutionalContextError(
                "Party subject belongs to a different tenant."
            )
        _validate_reference_tenants(self.reference.tenant_id, (self.procedure_ref,))
        _require_text(self.role, "Procedure party role")
        if self.status not in _PROCEDURE_PARTY_STATUSES:
            raise InstitutionalContextError(
                f"Unsupported procedure party status: {self.status!r}."
            )
        _validate_text_tuple(
            self.preferred_channels,
            "Procedure party preferred channels",
        )
        _validate_text_tuple(
            self.permitted_channels,
            "Procedure party permitted channels",
        )
        _validate_text_tuple(
            self.contact_snapshot_refs,
            "Procedure party contact snapshots",
        )
        if set(self.preferred_channels) - set(self.permitted_channels):
            raise InstitutionalContextError(
                "Preferred party channels must also be permitted."
            )
        for representation in self.representations:
            if (
                representation.representative_party_ref.tenant_id
                != self.reference.tenant_id
            ):
                raise InstitutionalContextError(
                    "Party representation belongs to a different tenant."
                )
        for item in self.evidence:
            if item.tenant_id != self.reference.tenant_id:
                raise InstitutionalContextError(
                    "Procedure party evidence belongs to a different tenant."
                )

    def to_dict(self, *, include_inspection: bool = False) -> dict[str, object]:
        return {
            "reference": self.reference.to_dict(),
            "procedure_ref": self.procedure_ref.to_dict(),
            "role": self.role,
            "subject": self.subject.to_dict(),
            "temporal": self.temporal.to_dict(),
            "preferred_channels": list(self.preferred_channels),
            "permitted_channels": list(self.permitted_channels),
            "delivery_recipient": self.delivery_recipient,
            "representations": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.representations
            ],
            "contact_snapshot_refs": list(self.contact_snapshot_refs),
            "evidence": [
                item.to_dict(include_inspection=include_inspection)
                for item in self.evidence
            ],
            "status": self.status,
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "ProcedureParty":
        return cls(
            reference=InstitutionalReference.from_mapping(
                _required_mapping(value, "reference")
            ),
            procedure_ref=InstitutionalReference.from_mapping(
                _required_mapping(value, "procedure_ref")
            ),
            role=_required_text(value, "role"),
            subject=PartySubjectReference.from_mapping(
                _required_mapping(value, "subject")
            ),
            temporal=TemporalRevision.from_mapping(
                _required_mapping(value, "temporal")
            ),
            preferred_channels=_text_tuple(value.get("preferred_channels")),
            permitted_channels=_text_tuple(value.get("permitted_channels")),
            delivery_recipient=_boolean_value(
                value,
                "delivery_recipient",
                default=False,
            ),
            representations=tuple(
                PartyRepresentation.from_mapping(item)
                for item in _mapping_sequence(value.get("representations"))
            ),
            contact_snapshot_refs=_text_tuple(value.get("contact_snapshot_refs")),
            evidence=tuple(
                EvidenceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("evidence"))
            ),
            status=cast(
                ProcedurePartyStatus,
                str(value.get("status") or "active"),
            ),
        )


def revise_procedure_party(
    current: ProcedureParty,
    *,
    expected_revision: str,
    temporal: TemporalRevision,
    status: ProcedurePartyStatus = "active",
    role: str | None = None,
    subject: PartySubjectReference | None = None,
    preferred_channels: Sequence[str] | None = None,
    permitted_channels: Sequence[str] | None = None,
    delivery_recipient: bool | None = None,
    representations: Sequence[PartyRepresentation] | None = None,
    contact_snapshot_refs: Sequence[str] | None = None,
    evidence: Sequence[EvidenceReference] | None = None,
) -> ProcedureParty:
    """Correct or close a procedure-party assignment as a new revision."""

    if current.temporal.revision != expected_revision:
        raise InstitutionalContextError(
            "Procedure party revision conflict: the expected revision is stale."
        )
    if temporal.revision == current.temporal.revision:
        raise InstitutionalContextError(
            "A procedure party revision requires a new revision identifier."
        )
    if temporal.recorded_at is None or not str(temporal.change_reason or "").strip():
        raise InstitutionalContextError(
            "A procedure party revision requires recorded_at and change_reason."
        )
    if status not in _PROCEDURE_PARTY_TRANSITIONS[current.status]:
        raise InstitutionalContextError(
            f"Procedure party transition {current.status!r} to {status!r} is not allowed."
        )
    return replace(
        current,
        reference=replace(
            current.reference,
            version=temporal.revision,
            valid_at=temporal.valid_from or current.reference.valid_at,
        ),
        temporal=temporal,
        status=status,
        role=role if role is not None else current.role,
        subject=subject if subject is not None else current.subject,
        preferred_channels=(
            tuple(preferred_channels)
            if preferred_channels is not None
            else current.preferred_channels
        ),
        permitted_channels=(
            tuple(permitted_channels)
            if permitted_channels is not None
            else current.permitted_channels
        ),
        delivery_recipient=(
            delivery_recipient
            if delivery_recipient is not None
            else current.delivery_recipient
        ),
        representations=(
            tuple(representations)
            if representations is not None
            else current.representations
        ),
        contact_snapshot_refs=(
            tuple(contact_snapshot_refs)
            if contact_snapshot_refs is not None
            else current.contact_snapshot_refs
        ),
        evidence=tuple(evidence) if evidence is not None else current.evidence,
    )


def revoke_party_representation(
    current: PartyRepresentation,
    *,
    expected_revision: str,
    temporal: TemporalRevision,
    revoked_at: datetime,
    evidence: Sequence[EvidenceReference] | None = None,
) -> PartyRepresentation:
    """Record effective revocation of representation authority with OCC."""

    if current.temporal.revision != expected_revision:
        raise InstitutionalContextError(
            "Party representation revision conflict: the expected revision is stale."
        )
    if current.revoked_at is not None:
        raise InstitutionalContextError("Party representation is already revoked.")
    if temporal.revision == current.temporal.revision:
        raise InstitutionalContextError(
            "A party representation revision requires a new revision identifier."
        )
    if temporal.recorded_at is None or not str(temporal.change_reason or "").strip():
        raise InstitutionalContextError(
            "A party representation revision requires recorded_at and change_reason."
        )
    _require_aware_datetime(revoked_at, "party representation revoked_at")
    if temporal.valid_from is not None and revoked_at < temporal.valid_from:
        raise InstitutionalContextError(
            "Party representation revocation cannot precede its valid interval."
        )
    return replace(
        current,
        temporal=temporal,
        revoked_at=revoked_at,
        evidence=tuple(evidence) if evidence is not None else current.evidence,
    )


@runtime_checkable
class PartyResolver(Protocol):
    def list_procedure_parties(
        self,
        session: object,
        principal: object,
        *,
        procedure_ref: InstitutionalReference,
        effective_at: datetime | None = None,
    ) -> Sequence[ProcedureParty]: ...


@dataclass(frozen=True, slots=True)
class DecisionEffectReference:
    effect_key: str
    state: str
    resource_refs: tuple[str, ...] = ()
    audit_event_refs: tuple[str, ...] = ()
    evidence_refs: tuple[str, ...] = ()

    def __post_init__(self) -> None:
        _require_text(self.effect_key, "Decision effect key")
        _require_text(self.state, "Decision effect state")
        for label, values in (
            ("Decision effect resource references", self.resource_refs),
            ("Decision effect audit references", self.audit_event_refs),
            ("Decision effect evidence references", self.evidence_refs),
        ):
            _validate_text_tuple(values, label)

    def to_dict(self) -> dict[str, object]:
        return _decision_effect_value(self)

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "DecisionEffectReference":
        return cls(
            effect_key=_required_text(value, "effect_key"),
            state=_required_text(value, "state"),
            resource_refs=_text_tuple(value.get("resource_refs")),
            audit_event_refs=_text_tuple(value.get("audit_event_refs")),
            evidence_refs=_text_tuple(value.get("evidence_refs")),
        )


@dataclass(frozen=True, slots=True)
class FormalDecision:
    reference: InstitutionalReference
    temporal: TemporalRevision
    decision_type: str
    subject_refs: tuple[InstitutionalReference, ...]
    state: DecisionState
    authority_context: GovernedContextEnvelope
    fact_evidence: tuple[EvidenceReference, ...]
    legal_bases: tuple[LegalBasisReference, ...]
    assurance_level: DecisionAssuranceLevel = "human"
    automation_preparation_refs: tuple[str, ...] = ()
    operative_result: str | None = None
    reasoning: str | None = None
    conditions: tuple[str, ...] = ()
    requested_effects: tuple[DecisionEffectReference, ...] = ()
    observed_effects: tuple[DecisionEffectReference, ...] = ()
    delivery_refs: tuple[str, ...] = ()
    publication_refs: tuple[str, ...] = ()
    remedy_refs: tuple[str, ...] = ()
    review_refs: tuple[str, ...] = ()
    correction_of_ref: InstitutionalReference | None = None
    revocation_of_ref: InstitutionalReference | None = None
    supersedes_ref: InstitutionalReference | None = None

    def __post_init__(self) -> None:
        _validate_reference_kind(self.reference, "decision", "formal decision")
        _require_text(self.decision_type, "Decision type")
        if self.state not in _DECISION_STATES:
            raise InstitutionalContextError(
                f"Unsupported decision state: {self.state!r}."
            )
        if self.assurance_level not in _DECISION_ASSURANCE_LEVELS:
            raise InstitutionalContextError(
                f"Unsupported decision assurance level: {self.assurance_level!r}."
            )
        actor = self.authority_context.actor
        if actor is None:
            raise InstitutionalContextError(
                "Formal decisions require a responsible actor."
            )
        if (
            self.assurance_level == "automated_under_mandate"
            and actor.service_account_id is None
        ):
            raise InstitutionalContextError(
                "Automated formal decisions require a responsible service account."
            )
        if (
            self.assurance_level != "automated_under_mandate"
            and actor.account_id is None
        ):
            raise InstitutionalContextError(
                "Human-assured formal decisions require a responsible account."
            )
        if not self.subject_refs:
            raise InstitutionalContextError(
                "Formal decisions require at least one subject reference."
            )
        if self.authority_context.tenant_id != self.reference.tenant_id:
            raise InstitutionalContextError(
                "Decision authority context belongs to a different tenant."
            )
        if self.authority_context.mandate_ref is None:
            raise InstitutionalContextError(
                "Formal decisions require a mandate in their authority context."
            )
        if not self.fact_evidence or not self.legal_bases:
            raise InstitutionalContextError(
                "Formal decisions require fact evidence and legal bases."
            )
        if (
            self.state in {"decided", "effective", "corrected"}
            and not str(self.operative_result or "").strip()
        ):
            raise InstitutionalContextError(
                "A decided formal outcome requires an operative result."
            )
        if (
            self.authority_context.decision_ref is not None
            and not _same_reference_identity(
                self.authority_context.decision_ref,
                self.reference,
            )
        ):
            raise InstitutionalContextError(
                "Decision authority context references a different decision."
            )
        _validate_reference_tenants(
            self.reference.tenant_id,
            (
                *self.subject_refs,
                self.correction_of_ref,
                self.revocation_of_ref,
                self.supersedes_ref,
            ),
        )
        for item in (
            self.correction_of_ref,
            self.revocation_of_ref,
            self.supersedes_ref,
        ):
            _validate_reference_kind(item, "decision", "decision history reference")
        for item in self.fact_evidence:
            if item.tenant_id != self.reference.tenant_id:
                raise InstitutionalContextError(
                    "Decision evidence belongs to a different tenant."
                )
        for label, values in (
            (
                "Decision automation preparation references",
                self.automation_preparation_refs,
            ),
            ("Decision conditions", self.conditions),
            ("Decision delivery references", self.delivery_refs),
            ("Decision publication references", self.publication_refs),
            ("Decision remedy references", self.remedy_refs),
            ("Decision review references", self.review_refs),
        ):
            _validate_text_tuple(values, label)

    def to_dict(self, *, include_protected: bool = False) -> dict[str, object]:
        return {
            "reference": self.reference.to_dict(disclose_label=include_protected),
            "temporal": self.temporal.to_dict(),
            "decision_type": self.decision_type,
            "subject_refs": [item.to_dict() for item in self.subject_refs],
            "state": self.state,
            "authority_context": self.authority_context.to_dict(
                include_inspection=include_protected
            ),
            "fact_evidence": [
                item.to_dict(include_inspection=include_protected)
                for item in self.fact_evidence
            ],
            "legal_bases": [
                item.to_dict(include_inspection=include_protected)
                for item in self.legal_bases
            ],
            "assurance_level": self.assurance_level,
            "automation_preparation_refs": list(self.automation_preparation_refs),
            "operative_result": self.operative_result if include_protected else None,
            "reasoning": self.reasoning if include_protected else None,
            "conditions": list(self.conditions) if include_protected else [],
            "requested_effects": [
                _decision_effect_value(item) for item in self.requested_effects
            ],
            "observed_effects": [
                _decision_effect_value(item) for item in self.observed_effects
            ],
            "delivery_refs": list(self.delivery_refs),
            "publication_refs": list(self.publication_refs),
            "remedy_refs": list(self.remedy_refs),
            "review_refs": list(self.review_refs),
            "correction_of_ref": _reference_value(self.correction_of_ref),
            "revocation_of_ref": _reference_value(self.revocation_of_ref),
            "supersedes_ref": _reference_value(self.supersedes_ref),
        }

    @classmethod
    def from_mapping(cls, value: Mapping[str, object]) -> "FormalDecision":
        return cls(
            reference=InstitutionalReference.from_mapping(
                _required_mapping(value, "reference")
            ),
            temporal=TemporalRevision.from_mapping(
                _required_mapping(value, "temporal")
            ),
            decision_type=_required_text(value, "decision_type"),
            subject_refs=_institutional_references(value.get("subject_refs")),
            state=cast(DecisionState, _required_text(value, "state")),
            authority_context=GovernedContextEnvelope.from_mapping(
                _required_mapping(value, "authority_context")
            ),
            fact_evidence=tuple(
                EvidenceReference.from_mapping(item)
                for item in _mapping_sequence(value.get("fact_evidence"))
            ),
            legal_bases=tuple(
                LegalBasisReference.from_mapping(item)
                for item in _mapping_sequence(value.get("legal_bases"))
            ),
            assurance_level=cast(
                DecisionAssuranceLevel,
                str(value.get("assurance_level") or "human"),
            ),
            automation_preparation_refs=_text_tuple(
                value.get("automation_preparation_refs")
            ),
            operative_result=_optional_text(value.get("operative_result")),
            reasoning=_optional_text(value.get("reasoning")),
            conditions=_text_tuple(value.get("conditions")),
            requested_effects=tuple(
                DecisionEffectReference.from_mapping(item)
                for item in _mapping_sequence(value.get("requested_effects"))
            ),
            observed_effects=tuple(
                DecisionEffectReference.from_mapping(item)
                for item in _mapping_sequence(value.get("observed_effects"))
            ),
            delivery_refs=_text_tuple(value.get("delivery_refs")),
            publication_refs=_text_tuple(value.get("publication_refs")),
            remedy_refs=_text_tuple(value.get("remedy_refs")),
            review_refs=_text_tuple(value.get("review_refs")),
            correction_of_ref=_optional_institutional_reference(
                value.get("correction_of_ref")
            ),
            revocation_of_ref=_optional_institutional_reference(
                value.get("revocation_of_ref")
            ),
            supersedes_ref=_optional_institutional_reference(
                value.get("supersedes_ref")
            ),
        )


def revise_formal_decision(
    current: FormalDecision,
    *,
    expected_revision: str,
    temporal: TemporalRevision,
    state: DecisionState,
    operative_result: str | None = None,
    reasoning: str | None = None,
    conditions: Sequence[str] | None = None,
    requested_effects: Sequence[DecisionEffectReference] | None = None,
    observed_effects: Sequence[DecisionEffectReference] | None = None,
    delivery_refs: Sequence[str] | None = None,
    publication_refs: Sequence[str] | None = None,
    remedy_refs: Sequence[str] | None = None,
    review_refs: Sequence[str] | None = None,
    assurance_level: DecisionAssuranceLevel | None = None,
    automation_preparation_refs: Sequence[str] | None = None,
) -> FormalDecision:
    """Create an immutable, OCC-guarded revision of a formal decision."""

    if current.temporal.revision != expected_revision:
        raise InstitutionalContextError(
            "Formal decision revision conflict: the expected revision is stale."
        )
    if temporal.revision == current.temporal.revision:
        raise InstitutionalContextError(
            "A formal decision revision requires a new revision identifier."
        )
    if temporal.recorded_at is None or not str(temporal.change_reason or "").strip():
        raise InstitutionalContextError(
            "A formal decision revision requires recorded_at and change_reason."
        )
    if state not in _DECISION_TRANSITIONS[current.state]:
        raise InstitutionalContextError(
            f"Formal decision transition {current.state!r} to {state!r} is not allowed."
        )

    previous_reference = current.reference
    revised_reference = replace(
        current.reference,
        version=temporal.revision,
        valid_at=temporal.valid_from or current.reference.valid_at,
    )
    authority_context = replace(
        current.authority_context,
        temporal=temporal,
        decision_ref=revised_reference,
    )
    return FormalDecision(
        reference=revised_reference,
        temporal=temporal,
        decision_type=current.decision_type,
        subject_refs=current.subject_refs,
        state=state,
        authority_context=authority_context,
        fact_evidence=current.fact_evidence,
        legal_bases=current.legal_bases,
        assurance_level=(
            assurance_level if assurance_level is not None else current.assurance_level
        ),
        automation_preparation_refs=(
            tuple(automation_preparation_refs)
            if automation_preparation_refs is not None
            else current.automation_preparation_refs
        ),
        operative_result=(
            operative_result
            if operative_result is not None
            else current.operative_result
        ),
        reasoning=reasoning if reasoning is not None else current.reasoning,
        conditions=(
            tuple(conditions) if conditions is not None else current.conditions
        ),
        requested_effects=(
            tuple(requested_effects)
            if requested_effects is not None
            else current.requested_effects
        ),
        observed_effects=(
            tuple(observed_effects)
            if observed_effects is not None
            else current.observed_effects
        ),
        delivery_refs=(
            tuple(delivery_refs) if delivery_refs is not None else current.delivery_refs
        ),
        publication_refs=(
            tuple(publication_refs)
            if publication_refs is not None
            else current.publication_refs
        ),
        remedy_refs=(
            tuple(remedy_refs) if remedy_refs is not None else current.remedy_refs
        ),
        review_refs=(
            tuple(review_refs) if review_refs is not None else current.review_refs
        ),
        correction_of_ref=(
            previous_reference if state == "corrected" else current.correction_of_ref
        ),
        revocation_of_ref=(
            previous_reference if state == "revoked" else current.revocation_of_ref
        ),
        supersedes_ref=previous_reference,
    )


@runtime_checkable
class DecisionRegistry(Protocol):
    def get_decision(
        self,
        session: object,
        principal: object,
        *,
        reference: InstitutionalReference,
    ) -> FormalDecision | None: ...

    def record_decision(
        self,
        session: object,
        principal: object,
        *,
        decision: FormalDecision,
        expected_revision: str | None = None,
    ) -> FormalDecision: ...


def _decision_effect_value(item: DecisionEffectReference) -> dict[str, object]:
    return {
        "effect_key": item.effect_key,
        "state": item.state,
        "resource_refs": list(item.resource_refs),
        "audit_event_refs": list(item.audit_event_refs),
        "evidence_refs": list(item.evidence_refs),
    }


def _validate_reference_kind(
    reference: InstitutionalReference | None,
    expected: InstitutionalReferenceKind,
    label: str,
) -> None:
    if reference is not None and reference.kind != expected:
        raise InstitutionalContextError(
            f"{label.capitalize()} must have kind {expected!r}, not {reference.kind!r}."
        )


def _validate_reference_tenants(
    tenant_id: str,
    references: Sequence[InstitutionalReference | None],
) -> None:
    for reference in references:
        if reference is not None and reference.tenant_id != tenant_id:
            raise InstitutionalContextError(
                f"Institutional reference {reference.kind}:{reference.object_id} "
                "belongs to a different tenant."
            )


def _reference_value(
    reference: InstitutionalReference | None,
) -> dict[str, object] | None:
    return reference.to_dict() if reference is not None else None


def _same_reference_identity(
    left: InstitutionalReference,
    right: InstitutionalReference,
) -> bool:
    return (
        left.kind,
        left.owner_module,
        left.object_id,
        left.tenant_id,
        left.version,
        left.valid_at,
    ) == (
        right.kind,
        right.owner_module,
        right.object_id,
        right.tenant_id,
        right.version,
        right.valid_at,
    )


def _stable_reference_key(
    reference: InstitutionalReference,
) -> tuple[str, str, str, str]:
    return (
        reference.kind,
        reference.owner_module,
        reference.object_id,
        reference.tenant_id,
    )


def _reference_is_allowed(
    reference: InstitutionalReference | None,
    allowed: Sequence[InstitutionalReference],
) -> bool:
    if reference is None:
        return False
    key = _stable_reference_key(reference)
    return any(_stable_reference_key(item) == key for item in allowed)


def _ordered_text_union(
    current: Sequence[str],
    additions: Sequence[str],
) -> tuple[str, ...]:
    return tuple(dict.fromkeys((*current, *additions)))


def _require_identifier(value: str, label: str) -> None:
    candidate = str(value or "").strip()
    if not _REFERENCE_ID_RE.fullmatch(candidate):
        raise InstitutionalContextError(f"{label} is invalid.")


def _require_text(value: str, label: str) -> None:
    if not str(value or "").strip():
        raise InstitutionalContextError(f"{label} is required.")


def _require_aware_datetime(value: datetime | None, label: str) -> None:
    if value is not None and (value.tzinfo is None or value.utcoffset() is None):
        raise InstitutionalContextError(f"{label} must include a timezone.")


def _datetime_value(value: datetime | None) -> str | None:
    return value.isoformat() if value is not None else None


def _optional_datetime(value: object | None) -> datetime | None:
    if value is None or value == "":
        return None
    if isinstance(value, datetime):
        return value
    try:
        return datetime.fromisoformat(str(value))
    except ValueError as exc:
        raise InstitutionalContextError(
            f"Invalid ISO datetime value: {value!r}."
        ) from exc


def _required_text(value: Mapping[str, object], key: str) -> str:
    result = _optional_text(value.get(key))
    if result is None:
        raise InstitutionalContextError(f"Institutional payload {key} is required.")
    return result


def _required_mapping(
    value: Mapping[str, object],
    key: str,
) -> Mapping[str, object]:
    result = value.get(key)
    if not isinstance(result, Mapping):
        raise InstitutionalContextError(
            f"Institutional payload {key} must be an object."
        )
    return result


def _required_datetime(value: object | None) -> datetime:
    result = _optional_datetime(value)
    if result is None:
        raise InstitutionalContextError("Institutional payload datetime is required.")
    return result


def _boolean_value(
    value: Mapping[str, object],
    key: str,
    *,
    default: bool,
) -> bool:
    result = value.get(key, default)
    if not isinstance(result, bool):
        raise InstitutionalContextError(
            f"Institutional payload {key} must be a boolean."
        )
    return result


def _optional_text(value: object | None) -> str | None:
    if value is None:
        return None
    result = str(value).strip()
    return result or None


def _text_tuple(value: object | None) -> tuple[str, ...]:
    if value is None:
        return ()
    if isinstance(value, str):
        return (value,)
    if not isinstance(value, Sequence):
        raise InstitutionalContextError("Expected a list of text values.")
    return tuple(str(item) for item in value)


def _validate_text_tuple(
    value: tuple[str, ...],
    label: str,
    *,
    require: bool = False,
) -> None:
    if require and not value:
        raise InstitutionalContextError(f"{label} are required.")
    if any(not item.strip() for item in value):
        raise InstitutionalContextError(f"{label} cannot contain empty values.")
    if len(value) != len(set(value)):
        raise InstitutionalContextError(f"{label} cannot contain duplicates.")


def _optional_float(value: object | None) -> float | None:
    return None if value is None else float(value)


def _validate_inspection_url(value: str | None) -> None:
    if value is None:
        return
    parsed = urlsplit(value)
    if parsed.scheme not in {"http", "https"} or not parsed.hostname:
        raise InstitutionalContextError("Inspection URLs must use HTTP or HTTPS.")
    if parsed.username is not None or parsed.password is not None:
        raise InstitutionalContextError("Inspection URLs must not contain credentials.")


def _validate_service_launch_href(value: str | None) -> None:
    if value is None:
        return
    if value.startswith("/") and not value.startswith("//"):
        return
    parsed = urlsplit(value)
    if (
        parsed.scheme not in {"http", "https"}
        or not parsed.hostname
        or parsed.username is not None
        or parsed.password is not None
    ):
        raise InstitutionalContextError(
            "Service launch URLs must be relative application paths or credential-free HTTP(S) URLs."
        )


def _mapping_sequence(value: object | None) -> tuple[Mapping[str, object], ...]:
    if value is None:
        return ()
    if not isinstance(value, Sequence) or isinstance(value, (str, bytes)):
        raise InstitutionalContextError("Expected a list of object payloads.")
    if any(not isinstance(item, Mapping) for item in value):
        raise InstitutionalContextError("Expected object payloads in list.")
    return cast(tuple[Mapping[str, object], ...], tuple(value))


def _optional_institutional_reference(
    value: object | None,
) -> InstitutionalReference | None:
    if value is None:
        return None
    if not isinstance(value, Mapping):
        raise InstitutionalContextError(
            "Institutional references must be object payloads."
        )
    return InstitutionalReference.from_mapping(value)


def _institutional_references(
    value: object | None,
) -> tuple[InstitutionalReference, ...]:
    return tuple(
        InstitutionalReference.from_mapping(item) for item in _mapping_sequence(value)
    )


def _optional_actor(value: object | None) -> ActorRepresentationReference | None:
    if value is None:
        return None
    if not isinstance(value, Mapping):
        raise InstitutionalContextError("Actor context must be an object payload.")
    return ActorRepresentationReference.from_mapping(value)


def _optional_governance(
    value: object | None,
) -> InformationGovernanceReference | None:
    if value is None:
        return None
    if not isinstance(value, Mapping):
        raise InstitutionalContextError(
            "Information governance must be an object payload."
        )
    return InformationGovernanceReference.from_mapping(value)


def _optional_presentation(value: object | None) -> PresentationReference | None:
    if value is None:
        return None
    if not isinstance(value, Mapping):
        raise InstitutionalContextError(
            "Presentation context must be an object payload."
        )
    return PresentationReference.from_mapping(value)


def _external_reference_from_mapping(
    value: Mapping[str, object],
) -> ExternalObjectReference:
    return ExternalObjectReference(
        system=_required_text(value, "system"),
        object_type=_required_text(value, "object_type"),
        object_id=_required_text(value, "object_id"),
        maturity=cast(IntegrationMaturity, str(value.get("maturity") or "link")),
        authority_mode=cast(
            SourceAuthorityMode,
            str(value.get("authority_mode") or "linked_reference"),
        ),
        connector_id=_optional_text(value.get("connector_id")),
        canonical_url=_optional_text(value.get("canonical_url")),
        version=_optional_text(value.get("version")),
        etag=_optional_text(value.get("etag")),
        observed_at=_optional_datetime(value.get("observed_at")),
        metadata=(
            dict(value.get("metadata"))
            if isinstance(value.get("metadata"), Mapping)
            else {}
        ),
    )


__all__ = [
    "CAPABILITY_DECISION_REGISTRY",
    "CAPABILITY_FORM_DEFINITIONS",
    "CAPABILITY_MANDATE_RESOLVER",
    "CAPABILITY_PARTY_RESOLVER",
    "CAPABILITY_SERVICE_DEFINITIONS",
    "CAPABILITY_SERVICE_AVAILABILITY",
    "INSTITUTIONAL_CONTEXT_CONTRACT_VERSION",
    "ActorRepresentationReference",
    "DecisionEffectReference",
    "DecisionAssuranceLevel",
    "DecisionRegistry",
    "EvidenceReference",
    "ExternalSourceReference",
    "FormConditionExpression",
    "FormConditionKind",
    "FormConditionOperator",
    "FormDefinition",
    "FormDefinitionProvider",
    "FormFieldDefinition",
    "FormLocalization",
    "FormPageDefinition",
    "FormPublicationState",
    "FormSectionDefinition",
    "FormSignatureRequirement",
    "FormValueType",
    "FormalDecision",
    "GeoReference",
    "GovernedContextEnvelope",
    "InformationGovernanceReference",
    "InstitutionalContextError",
    "InstitutionalReference",
    "LegalBasisReference",
    "MandateDefinition",
    "MandateResolution",
    "MandateResolutionRequest",
    "MandateResolver",
    "MandateStatus",
    "PartyRepresentation",
    "PartyResolver",
    "PartySubjectReference",
    "PresentationReference",
    "ProcedureParty",
    "ProcedurePartyStatus",
    "ServiceBinding",
    "ServiceAvailabilityAssessment",
    "ServiceAvailabilityEvaluator",
    "ServiceAvailabilityRequirement",
    "ServiceDefinition",
    "ServiceDefinitionProvider",
    "ServiceLaunchRequest",
    "ServiceLaunchResult",
    "ServiceLauncher",
    "ServiceLaunchState",
    "ServicePublicationState",
    "TemporalRevision",
    "derive_service_restriction",
    "service_launch_capability",
    "resolve_mandate_candidates",
    "revise_procedure_party",
    "revise_mandate_definition",
    "revise_formal_decision",
    "revoke_party_representation",
]
