feat(detection-core): authenticate post-spend case release

This commit is contained in:
Marius Ciepluch
2026-11-01 10:18:02 +01:00
parent 007dd7aa77
commit 44516cf29f
5 changed files with 1129 additions and 1 deletions
@@ -0,0 +1,138 @@
"""Closed object-graph whitelist for immutable admission cases."""
from __future__ import annotations
from openultrasast.core._closed_graph import closed_graph_problem
from openultrasast.core._model_result import ModelResult, ModelStatus, PreservedModelResponse
from openultrasast.core.budget import BudgetDerivation, ChangeComplexity, ReferenceHardware, ReferenceWorkload
from openultrasast.core.canonical import ContentRef
from openultrasast.core.coverage import CoverageFunnel, InputManifest, InputReadReceipt, ReasonCount, RelationStatusCount
from openultrasast.core.custody import LineagePurpose
from openultrasast.core.evidence import (
AnalyzedScope,
Decision,
EvidenceBasis,
EvidencePacket,
EvidenceRecord,
NeutralOutcome,
SourceRegion,
)
from openultrasast.core.family import (
DecisionRule,
FamilyContract,
FieldSpec,
ObjectSpec,
RelationOriginPolicy,
ResidualQuestion,
RoleSpec,
)
from openultrasast.core.lineage import LineageManifest, LineageUse
from openultrasast.core.measurement import ScopeKey
from openultrasast.core.model import CompletenessItem, ModelProgramDeclaration, ModelRequest
from openultrasast.core.proof import (
ControlBinding,
DifferentialProofRecord,
ProofAttachment,
ProofOutcome,
ProofProducerIdentity,
ProofSideResult,
ProofVerificationReceipt,
)
from openultrasast.core.provenance import (
DecisionProvenance,
ModelCallIdentity,
NamedInput,
NamedInputs,
ProvenanceInputRole,
ProvenanceStamp,
)
from openultrasast.core.semantics import (
EvidenceProvenance,
FieldKind,
FieldValue,
Observation,
ProvenanceKind,
RelationKind,
RelationStatus,
SemanticNode,
SemanticRelation,
SourceLocation,
)
from openultrasast.core.validation import EvidenceValidationInput
from openultrasast.core.verdict_v2 import BoundedSatisfaction, BoundedSilence, DefectClaim
_DATACLASSES: tuple[type[object], ...] = (
ScopeKey,
EvidenceValidationInput,
EvidenceRecord,
EvidencePacket,
Decision,
AnalyzedScope,
SourceRegion,
SourceLocation,
SemanticNode,
EvidenceProvenance,
FieldValue,
SemanticRelation,
Observation,
ProvenanceStamp,
DecisionProvenance,
ModelCallIdentity,
NamedInput,
NamedInputs,
ContentRef,
ModelRequest,
ModelProgramDeclaration,
CompletenessItem,
ModelResult,
PreservedModelResponse,
FamilyContract,
FieldSpec,
ObjectSpec,
RoleSpec,
DecisionRule,
ResidualQuestion,
LineageManifest,
LineageUse,
DefectClaim,
BoundedSatisfaction,
BoundedSilence,
ProofAttachment,
DifferentialProofRecord,
ProofProducerIdentity,
ProofSideResult,
ControlBinding,
ProofVerificationReceipt,
CoverageFunnel,
RelationStatusCount,
ReasonCount,
InputManifest,
InputReadReceipt,
ChangeComplexity,
BudgetDerivation,
ReferenceWorkload,
ReferenceHardware,
)
_ENUMS: tuple[type[object], ...] = (
NeutralOutcome,
EvidenceBasis,
FieldKind,
RelationKind,
RelationStatus,
ProvenanceKind,
RelationOriginPolicy,
ProvenanceInputRole,
LineagePurpose,
ModelStatus,
ProofOutcome,
)
def admission_case_problem(value: object, case_type: type[object], role_type: type[object]) -> str | None:
return closed_graph_problem(
value,
dataclass_types=(case_type, *_DATACLASSES),
enum_types=(role_type, *_ENUMS),
path="admission case result",
)
@@ -0,0 +1,299 @@
"""Validation helpers for authenticated post-spend admission-case releases."""
from __future__ import annotations
import re
from collections import Counter
from collections.abc import Sequence
from openultrasast.core import canonical
from openultrasast.core.admission_case import (
ADMISSION_CASE_RELEASE_SCHEMA,
AdmissionCaseRelease,
AdmissionCaseReleaseError,
AdmissionCaseResult,
AdmissionCaseRole,
ReleasedCaseBinding,
derive_admission_case_release_digest,
derive_admission_case_release_payload_digest,
derive_admission_case_result_digest,
derive_released_case_binding_digest,
validate_admission_case_shape,
)
from openultrasast.core.admission_context import AdmissionValidationContext
from openultrasast.core.admission_review import AdmissionManifestV2
from openultrasast.core.admission_spend import AdmissionAuthorization, AdmissionPreparation
from openultrasast.core.coverage import derive_input_manifest_digest, validate_instrument
from openultrasast.core.custody import PopulationCustodyPort, PopulationUseReceipt
from openultrasast.core.factpack import (
FactPackValidationError,
IndependenceAttestation,
ReviewIndependencePolicy,
derive_independence_attestation_digest,
derive_review_independence_policy_digest,
)
from openultrasast.core.measurement import ScopeKey
from openultrasast.core.provenance import ProvenanceInputRole
from openultrasast.core.validation import derive_evidence_validation_input_digest, validate_evidence_input
_DIGEST = re.compile(r"[0-9a-f]{64}")
def _digest(value: object, field: str) -> None:
if not isinstance(value, str) or _DIGEST.fullmatch(value) is None:
raise AdmissionCaseReleaseError(f"{field} must be a full lowercase SHA-256 digest")
def _digest_tuple(value: object, field: str, *, nonempty: bool = True) -> None:
if type(value) is not tuple or (nonempty and not value):
raise AdmissionCaseReleaseError(f"{field} must be a{' nonempty' if nonempty else ''} exact tuple")
for item in value:
_digest(item, field)
if value != tuple(sorted(set(value))):
raise AdmissionCaseReleaseError(f"{field} must be unique and canonically ordered")
def _validate_policy(policy: ReviewIndependencePolicy) -> None:
try:
policy.__post_init__()
except FactPackValidationError as exc:
raise AdmissionCaseReleaseError(f"release review policy is invalid: {exc}") from exc
expected = derive_review_independence_policy_digest(
policy.reviewed_reviewer_digests,
policy.forbidden_identity_pairs,
policy.trusted_store_identities,
policy.maximum_evidence_bytes,
)
if policy.policy_digest != expected:
raise AdmissionCaseReleaseError("release review policy digest cannot be re-derived")
def _validate_review(
release: AdmissionCaseRelease,
receipt: PopulationUseReceipt,
policy: ReviewIndependencePolicy,
resolver: canonical.ContentResolver,
) -> None:
review = release.review
if type(review) is not IndependenceAttestation:
raise AdmissionCaseReleaseError("release review must be an exact independence attestation")
try:
review.__post_init__()
review.conflict_disclosure.__post_init__()
except (FactPackValidationError, ValueError) as exc:
raise AdmissionCaseReleaseError(f"release review is invalid: {exc}") from exc
if review.subject_digest != release.release_payload_digest:
raise AdmissionCaseReleaseError("release review subject does not match payload digest")
if review.producer_identity != release.custodian_identity or review.producer_identity != receipt.custodian_identity:
raise AdmissionCaseReleaseError("release review producer must be the exact spend custodian")
if review.producer_identity == review.reviewer_identity:
raise AdmissionCaseReleaseError("release review producer and reviewer must be independent")
if review.reviewer_identity not in policy.reviewed_reviewer_digests:
raise AdmissionCaseReleaseError("release reviewer is not admitted by policy")
if (review.producer_identity, review.reviewer_identity) in policy.forbidden_identity_pairs:
raise AdmissionCaseReleaseError("release producer/reviewer pair is forbidden")
if review.attestation_digest != derive_independence_attestation_digest(review):
raise AdmissionCaseReleaseError("release review attestation digest cannot be re-derived")
content = canonical.resolve_content(
review.conflict_disclosure,
resolver,
trusted_store_identities=policy.trusted_store_identities,
maximum_bytes=policy.maximum_evidence_bytes,
)
if not content:
raise AdmissionCaseReleaseError("release conflict disclosure must be nonempty")
def _validate_binding_shape(binding: ReleasedCaseBinding) -> None:
if type(binding) is not ReleasedCaseBinding:
raise AdmissionCaseReleaseError("release binding must use the exact contract type")
if type(binding.scope) is not ScopeKey or type(binding.role) is not AdmissionCaseRole:
raise AdmissionCaseReleaseError("release binding scope and role must use exact contract types")
binding.scope.__post_init__()
for value, field in (
(binding.case_id_digest, "case identity digest"),
(binding.case_result_digest, "case result digest"),
(binding.input_manifest_digest, "input manifest digest"),
(binding.binding_digest, "binding digest"),
):
_digest(value, field)
if binding.role is AdmissionCaseRole.ORDINARY:
if binding.pair_id_digest is not None:
raise AdmissionCaseReleaseError("ordinary release binding cannot carry a pair identity")
else:
_digest(binding.pair_id_digest, "pair identity digest")
_digest_tuple(binding.evidence_input_digests, "evidence input digests")
_digest_tuple(binding.change_input_digests, "change input digests")
if binding.binding_digest != derive_released_case_binding_digest(binding):
raise AdmissionCaseReleaseError("release binding digest cannot be re-derived")
def _validate_pair_integrity(bindings: tuple[ReleasedCaseBinding, ...]) -> None:
pairs: dict[tuple[str, str, str], Counter[AdmissionCaseRole]] = {}
for binding in bindings:
if binding.pair_id_digest is None:
continue
key = (binding.scope.family_id, binding.scope.ecosystem, binding.pair_id_digest)
pairs.setdefault(key, Counter())[binding.role] += 1
expected = Counter({AdmissionCaseRole.VULNERABLE: 1, AdmissionCaseRole.FIXED: 1})
if any(counts != expected for counts in pairs.values()):
raise AdmissionCaseReleaseError("every scoped release pair must contain one vulnerable and one fixed case")
def _validate_release_shape(release: AdmissionCaseRelease) -> None:
if type(release) is not AdmissionCaseRelease or release.schema_version != ADMISSION_CASE_RELEASE_SCHEMA:
raise AdmissionCaseReleaseError("unknown or substituted admission case-release schema")
for value, field in (
(release.population_digest, "population digest"),
(release.manifest_digest, "manifest digest"),
(release.authorization_digest, "authorization digest"),
(release.preparation_digest, "preparation digest"),
(release.label_release_receipt_digest, "label release receipt digest"),
(release.custodian_identity, "custodian identity"),
(release.release_payload_digest, "release payload digest"),
(release.release_digest, "release digest"),
):
_digest(value, field)
if type(release.bindings) is not tuple or not release.bindings:
raise AdmissionCaseReleaseError("release bindings must be a nonempty exact tuple")
for binding in release.bindings:
_validate_binding_shape(binding)
case_ids = tuple(item.case_id_digest for item in release.bindings)
if case_ids != tuple(sorted(case_ids)) or len(case_ids) != len(set(case_ids)):
raise AdmissionCaseReleaseError("release bindings must have unique canonical case identities")
_validate_pair_integrity(release.bindings)
if release.release_payload_digest != derive_admission_case_release_payload_digest(release):
raise AdmissionCaseReleaseError("release payload digest cannot be re-derived")
if release.release_digest != derive_admission_case_release_digest(release):
raise AdmissionCaseReleaseError("release digest cannot be re-derived")
def _validate_header(
manifest: AdmissionManifestV2,
preparation: AdmissionPreparation,
receipt: PopulationUseReceipt,
authorization: AdmissionAuthorization,
release: AdmissionCaseRelease,
) -> None:
expected = (
manifest.identity.population_digest,
manifest.manifest_digest,
authorization.authorization_digest,
preparation.preparation_digest,
receipt.receipt_digest,
receipt.custodian_identity,
)
actual = (
release.population_digest,
release.manifest_digest,
release.authorization_digest,
release.preparation_digest,
release.label_release_receipt_digest,
release.custodian_identity,
)
if actual != expected:
fields = (
"population digest",
"manifest digest",
"authorization digest",
"preparation digest",
"label release receipt digest",
"custodian",
)
changed = next(field for field, left, right in zip(fields, actual, expected, strict=True) if left != right)
raise AdmissionCaseReleaseError(f"release {changed} does not match the exact spent admission")
def _validated_case_inputs(
case: AdmissionCaseResult,
context: AdmissionValidationContext,
custody: PopulationCustodyPort,
resolver: canonical.ContentResolver,
) -> tuple[tuple[str, ...], tuple[str, ...]]:
evidence: list[str] = []
changes: set[str] = set()
for value in case.evidence_inputs:
if value.input_digest != derive_evidence_validation_input_digest(value):
raise AdmissionCaseReleaseError("case evidence input digest cannot be re-derived")
validate_evidence_input(value, context.evidence, custody, resolver)
evidence.append(value.input_digest)
matches = tuple(item.identity for item in value.named_inputs.inputs if item.role is ProvenanceInputRole.CHANGE_INPUT)
if len(matches) != 1 or matches[0] != value.record.packet.provenance.change_input_digest:
raise AdmissionCaseReleaseError("case change input cannot be re-derived from validated provenance")
changes.add(matches[0])
ordered_evidence = tuple(sorted(evidence))
ordered_changes = tuple(sorted(changes))
_digest_tuple(ordered_evidence, "case evidence input digests")
_digest_tuple(ordered_changes, "case change input digests")
return ordered_evidence, ordered_changes
def _binding_for_case(
case: AdmissionCaseResult,
context: AdmissionValidationContext,
custody: PopulationCustodyPort,
resolver: canonical.ContentResolver,
) -> ReleasedCaseBinding:
validate_admission_case_shape(case)
expected_manifest = derive_input_manifest_digest(case.input_manifest.tracked_input_ids)
if case.input_manifest.manifest_digest != expected_manifest:
raise AdmissionCaseReleaseError("case input manifest digest cannot be re-derived")
validate_instrument(case.input_manifest, case.input_receipts)
if case.result_digest != derive_admission_case_result_digest(case):
raise AdmissionCaseReleaseError("case result digest cannot be re-derived")
evidence, changes = _validated_case_inputs(case, context, custody, resolver)
draft = ReleasedCaseBinding(
case.case_id_digest,
case.scope,
case.role,
case.pair_id_digest,
case.result_digest,
evidence,
changes,
case.input_manifest.manifest_digest,
"0" * 64,
)
return draft
def _canonical_binding(
case: AdmissionCaseResult,
context: AdmissionValidationContext,
custody: PopulationCustodyPort,
resolver: canonical.ContentResolver,
) -> ReleasedCaseBinding:
draft = _binding_for_case(case, context, custody, resolver)
return ReleasedCaseBinding(
draft.case_id_digest,
draft.scope,
draft.role,
draft.pair_id_digest,
draft.case_result_digest,
draft.evidence_input_digests,
draft.change_input_digests,
draft.input_manifest_digest,
derive_released_case_binding_digest(draft),
)
def validate_case_bindings(
release: AdmissionCaseRelease,
cases: Sequence[AdmissionCaseResult],
context: AdmissionValidationContext,
custody: PopulationCustodyPort,
resolver: canonical.ContentResolver,
) -> None:
selected = tuple(cases)
if not selected:
raise AdmissionCaseReleaseError("case population must be nonempty")
case_ids = tuple(case.case_id_digest for case in selected)
if len(case_ids) != len(set(case_ids)):
raise AdmissionCaseReleaseError("case population contains duplicate identities")
expected = tuple(
sorted(
(_canonical_binding(case, context, custody, resolver) for case in selected),
key=lambda item: item.case_id_digest,
)
)
if release.bindings != expected:
raise AdmissionCaseReleaseError("authenticated release binding does not match the exact case population")
+280
View File
@@ -0,0 +1,280 @@
"""Immutable admission-case contracts and canonical commitments."""
from __future__ import annotations
from collections.abc import Sequence
from dataclasses import dataclass
from enum import Enum
from openultrasast.core import canonical
from openultrasast.core._admission_case_shape import admission_case_problem
from openultrasast.core.admission_context import AdmissionValidationContext
from openultrasast.core.admission_review import AdmissionManifestV2
from openultrasast.core.admission_spend import AdmissionPreparation, validate_pre_label_spend
from openultrasast.core.budget import BudgetDerivation, ChangeComplexity
from openultrasast.core.coverage import CoverageFunnel, InputManifest, InputReadReceipt
from openultrasast.core.custody import PopulationCustodyPort, PopulationUseReceipt
from openultrasast.core.factpack import IndependenceAttestation
from openultrasast.core.measurement import DenominatorPolicy, ScopeKey
from openultrasast.core.proof import ProofAttachment
from openultrasast.core.readiness import ReadinessResult
from openultrasast.core.validation import EvidenceValidationInput
from openultrasast.core.verdict_v2 import BoundedSatisfaction, BoundedSilence, DefectClaim
ADMISSION_CASE_RELEASE_SCHEMA = "openultrasast.detection-core.admission-case-release.v2"
ADMISSION_CASE_RELEASE_PAYLOAD_SCHEMA = "openultrasast.detection-core.admission-case-release-payload.v2"
RELEASED_CASE_BINDING_SCHEMA = "openultrasast.detection-core.released-case-binding.v2"
class AdmissionCaseReleaseError(ValueError):
"""The post-spend case release cannot authorize admission scoring."""
class AdmissionCaseRole(Enum):
VULNERABLE = "vulnerable"
FIXED = "fixed"
ORDINARY = "ordinary"
@dataclass(frozen=True)
class AdmissionCaseResult:
case_id_digest: str
scope: ScopeKey
role: AdmissionCaseRole
pair_id_digest: str | None
evidence_inputs: tuple[EvidenceValidationInput, ...]
defect_claims: tuple[DefectClaim, ...]
satisfactions: tuple[BoundedSatisfaction, ...]
silence: tuple[BoundedSilence, ...]
proof_attachments: tuple[ProofAttachment, ...]
coverage: CoverageFunnel
input_manifest: InputManifest
input_receipts: tuple[InputReadReceipt, ...]
complexity: ChangeComplexity
budget: BudgetDerivation
total_reply_ms: int
result_digest: str
@dataclass(frozen=True)
class ReleasedCaseBinding:
case_id_digest: str
scope: ScopeKey
role: AdmissionCaseRole
pair_id_digest: str | None
case_result_digest: str
evidence_input_digests: tuple[str, ...]
change_input_digests: tuple[str, ...]
input_manifest_digest: str
binding_digest: str
@dataclass(frozen=True)
class AdmissionCaseRelease:
schema_version: str
population_digest: str
manifest_digest: str
authorization_digest: str
preparation_digest: str
label_release_receipt_digest: str
custodian_identity: str
bindings: tuple[ReleasedCaseBinding, ...]
release_payload_digest: str
review: IndependenceAttestation
release_digest: str
def _coverage_value(value: CoverageFunnel) -> canonical.JsonValue:
return {
"inputs_read": value.inputs_read,
"questions_formed": value.questions_formed,
"sites_considered": value.sites_considered,
"sites_recognized": value.sites_recognized,
"transitions_materialized": value.transitions_materialized,
"security_objects_constructed": value.security_objects_constructed,
"constraints_evaluated": value.constraints_evaluated,
"determinate_outcomes": value.determinate_outcomes,
"findings_emitted": value.findings_emitted,
"relation_status_counts": tuple((item.status.value, item.count) for item in value.relation_status_counts),
"unresolved_by_reason": tuple((item.reason, item.count) for item in value.unresolved_by_reason),
}
def derive_case_coverage_digest(case_id_digest: str, scope: ScopeKey, coverage: CoverageFunnel) -> str:
return canonical.content_digest(
{
"case_id_digest": case_id_digest,
"scope": {"family_id": scope.family_id, "ecosystem": scope.ecosystem},
"coverage": _coverage_value(coverage),
}
)
def _claim_value(value: DefectClaim) -> canonical.JsonValue:
location = value.location
return {
"record_id": value.record.record_id,
"basis": value.basis.value,
"location": {"path": location.path, "line": location.line, "column": location.column, "symbol": location.symbol},
"anchor": (value.change_anchor.path, value.change_anchor.start_line, value.change_anchor.end_line),
}
def derive_admission_case_result_digest(value: AdmissionCaseResult) -> str:
return canonical.content_digest(
{
"case_id_digest": value.case_id_digest,
"scope": (value.scope.family_id, value.scope.ecosystem),
"role": value.role.value,
"pair_id_digest": value.pair_id_digest,
"evidence_input_digests": tuple(item.input_digest for item in value.evidence_inputs),
"defect_claims": tuple(_claim_value(item) for item in value.defect_claims),
"satisfactions": tuple((item.question_ids, tuple(record.record_id for record in item.records)) for item in value.satisfactions),
"silence": tuple(
(item.question_ids, item.reasons, item.evidence_record_digests, item.coverage_digest) for item in value.silence
),
"proof_attachment_ids": tuple(item.proof_id for item in value.proof_attachments),
"coverage": _coverage_value(value.coverage),
"input_manifest_digest": value.input_manifest.manifest_digest,
"input_receipts": tuple(
(item.input_id, item.path, item.opened, item.byte_count, item.content_digest) for item in value.input_receipts
),
"complexity": (
value.complexity.change_id,
value.complexity.workload_class,
value.complexity.changed_regions,
value.complexity.transition_count,
value.complexity.changed_bytes,
value.complexity.measurement.content_digest,
),
"budget_derivation_digest": value.budget.derivation_digest,
"total_reply_ms": value.total_reply_ms,
}
)
def validate_admission_case_shape(value: AdmissionCaseResult) -> None:
problem = admission_case_problem(value, AdmissionCaseResult, AdmissionCaseRole)
if problem is not None:
raise ValueError(f"closed admission case violation: {problem}")
def create_admission_case_result(**values: object) -> AdmissionCaseResult:
draft = AdmissionCaseResult(**values, result_digest="0" * 64) # type: ignore[arg-type]
validate_admission_case_shape(draft)
return AdmissionCaseResult(**values, result_digest=derive_admission_case_result_digest(draft)) # type: ignore[arg-type]
def _scope_value(scope: ScopeKey) -> dict[str, canonical.JsonValue]:
return {"family_id": scope.family_id, "ecosystem": scope.ecosystem}
def _binding_value(binding: ReleasedCaseBinding) -> dict[str, canonical.JsonValue]:
return {
"schema_version": RELEASED_CASE_BINDING_SCHEMA,
"case_id_digest": binding.case_id_digest,
"scope": _scope_value(binding.scope),
"role": binding.role.value,
"pair_id_digest": binding.pair_id_digest,
"case_result_digest": binding.case_result_digest,
"evidence_input_digests": binding.evidence_input_digests,
"change_input_digests": binding.change_input_digests,
"input_manifest_digest": binding.input_manifest_digest,
}
def derive_released_case_binding_digest(binding: ReleasedCaseBinding) -> str:
return canonical.content_digest(_binding_value(binding))
def _content_ref_value(reference: canonical.ContentRef) -> dict[str, canonical.JsonValue]:
return {
"artifact_id": reference.artifact_id,
"content_digest": reference.content_digest,
"media_type": reference.media_type,
"byte_length": reference.byte_length,
"retention_policy_digest": reference.retention_policy_digest,
"storage_receipt_digest": reference.storage_receipt_digest,
}
def _review_value(review: IndependenceAttestation) -> dict[str, canonical.JsonValue]:
return {
"subject_digest": review.subject_digest,
"producer_identity": review.producer_identity,
"reviewer_identity": review.reviewer_identity,
"conflict_disclosure": _content_ref_value(review.conflict_disclosure),
"attestation_digest": review.attestation_digest,
}
def _release_payload_value(release: AdmissionCaseRelease) -> dict[str, canonical.JsonValue]:
return {
"schema_version": ADMISSION_CASE_RELEASE_PAYLOAD_SCHEMA,
"release_schema_version": release.schema_version,
"population_digest": release.population_digest,
"manifest_digest": release.manifest_digest,
"authorization_digest": release.authorization_digest,
"preparation_digest": release.preparation_digest,
"label_release_receipt_digest": release.label_release_receipt_digest,
"custodian_identity": release.custodian_identity,
"bindings": tuple({**_binding_value(item), "binding_digest": item.binding_digest} for item in release.bindings),
}
def derive_admission_case_release_payload_digest(release: AdmissionCaseRelease) -> str:
return canonical.content_digest(_release_payload_value(release))
def derive_admission_case_release_digest(release: AdmissionCaseRelease) -> str:
return canonical.content_digest(
{
"schema_version": ADMISSION_CASE_RELEASE_SCHEMA,
"release_payload_digest": release.release_payload_digest,
"review": _review_value(release.review),
}
)
def validate_admission_case_release(
manifest: AdmissionManifestV2,
denominator: DenominatorPolicy,
readiness: Sequence[ReadinessResult],
context: AdmissionValidationContext,
preparation: AdmissionPreparation,
receipt: PopulationUseReceipt,
release: AdmissionCaseRelease,
cases: Sequence[AdmissionCaseResult],
custody: PopulationCustodyPort,
resolver: canonical.ContentResolver,
) -> AdmissionCaseRelease:
"""Validate the custodian's exact post-spend case-to-operational-input mapping."""
from openultrasast.core._admission_release import (
_validate_header,
_validate_policy,
_validate_release_shape,
_validate_review,
validate_case_bindings,
)
try:
authorization = validate_pre_label_spend(
manifest,
denominator,
readiness,
context,
preparation,
receipt,
custody,
resolver,
)
_validate_policy(context.admission_review_policy)
_validate_release_shape(release)
_validate_header(manifest, preparation, receipt, authorization, release)
_validate_review(release, receipt, context.admission_review_policy, resolver)
validate_case_bindings(release, cases, context, custody, resolver)
return release
except AdmissionCaseReleaseError:
raise
except (AttributeError, LookupError, TypeError, ValueError) as exc:
raise AdmissionCaseReleaseError(f"admission case release refused: {exc}") from exc