Source code for aeat.domain.calculations.registry._validate_revision_sections

"""Per-revision registry section validation dispatch.

Orchestrates all per-section validators for a single
:class:`~aeat.domain.calculations.registry.ModeloRevision` within its
:class:`~aeat.domain.calculations.registry.ModeloDefinition`, collecting every
failure into a flat list returned to the registry-level validator.

The dispatcher builds a
:class:`~aeat.domain.calculations.registry._validate_revision_context.RevisionValidationContext`
once and reuses it across record, surface, dependency, algorithm, completeness,
and closure validators. Legal/source refs are checked through the shared
:class:`~aeat.domain.calculations.registry._validate_evidence.EvidenceValidator`.

See Also:
    :class:`aeat.domain.calculations.registry.RegistryValidator`
        Registry-level validator that calls :func:`validate_revision_definition`.
    :mod:`aeat.domain.calculations.registry._validate_record_sections`
        Record-section validators dispatched from this module.
    :mod:`aeat.domain.calculations.registry._validate_revision_closure`
        Closure validators dispatched after section-level checks.
"""

from __future__ import annotations

from collections.abc import Mapping
from pathlib import Path

from ._schema import LegalReference, ModeloDefinition, ModeloRevision, SourceReference
from ._validate_algorithms import validate_algorithm_binding_section, validate_algorithm_provider_section
from ._validate_completeness import _emit_completeness_gate_failures
from ._validate_dependency_sections import (
    validate_dependency_classification_section,
    validate_filing_schedule_section,
    validate_relation_section,
)
from ._validate_evidence import EvidenceValidator
from ._validate_exports import validate_export_layout_section
from ._validate_helpers import _missing_refs
from ._validate_record_sections import (
    validate_binding_section,
    validate_casilla_section,
    validate_extraction_profile_section,
    validate_formula_section,
    validate_parameter_section,
)
from ._validate_revision_closure import (
    _validate_revision_closure_sections,
    _validate_revision_reference_surfaces,
)
from ._validate_revision_context import RevisionValidationContext, build_revision_validation_context
from ._validate_revision_identity import (
    _emit_revision_payload_failures,
    revision_reference_identity_failures,
)
from ._validate_surfaces import (
    validate_application_link_section,
    validate_cross_reference_section,
    validate_deadline_window_section,
    validate_verification_expectation_section,
    validate_workbook_parity_section,
)

_REVISION_SOURCE_TIERS = ("official_source_guidance", "layout_authority")


def _validate_revision_surface_sections(
    failures: list[str],
    *,
    prefix: str,
    modelo_id: str,
    revision: ModeloRevision,
    context: RevisionValidationContext,
    legal_refs: Mapping[str, LegalReference],
    source_refs: Mapping[str, SourceReference],
    evidence: EvidenceValidator,
    justificante_corpus_root: Path | None,
) -> None:
    """Append section-surface failures for one revision.

    The :class:`~aeat.domain.calculations.registry.ModeloRevision` is validated
    with a shared
    :class:`~aeat.domain.calculations.registry._validate_revision_context.RevisionValidationContext`
    so record, surface, dependency, algorithm, export, and extraction-profile
    checks consume the same declared-id indexes.
    """
    validate_casilla_section(
        failures,
        prefix=prefix,
        revision=revision,
        formulas=context.formulas,
        bindings=context.bindings,
        export_field_ids=context.export_field_ids,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_formula_section(
        failures,
        prefix=prefix,
        revision=revision,
        casillas=context.casillas,
        bindings=context.bindings,
        parameters=context.parameters,
        relations=context.relations,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_parameter_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_binding_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_relation_section(
        failures,
        prefix=prefix,
        revision=revision,
        bindings=context.bindings,
        binding_by_id=context.binding_by_id,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_dependency_classification_section(
        failures,
        prefix=prefix,
        revision=revision,
        construct_by_id=context.construct_by_id,
        relation_by_id=context.relation_by_id,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_filing_schedule_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_algorithm_provider_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_algorithm_binding_section(
        failures,
        prefix=prefix,
        revision=revision,
        provider_by_id=context.provider_by_id,
        casillas=context.casillas,
        resolvable_values=context.resolvable_values,
        parameters=context.parameters,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_export_layout_section(
        failures,
        prefix=prefix,
        revision=revision,
        casillas=context.casillas,
        bindings=context.bindings,
        casilla_by_id=context.casilla_by_id,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_extraction_profile_section(
        failures,
        prefix=prefix,
        modelo_id=modelo_id,
        revision=revision,
        casillas=context.casillas,
        exported_casillas=context.exported_casillas,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
        corpus_root=justificante_corpus_root,
    )
    validate_cross_reference_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_workbook_parity_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
    )
    validate_verification_expectation_section(
        failures,
        prefix=prefix,
        revision=revision,
        casillas=context.casillas,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_application_link_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )
    validate_deadline_window_section(
        failures,
        prefix=prefix,
        revision=revision,
        legal_refs=legal_refs,
        source_refs=source_refs,
        evidence=evidence,
    )


[docs] def validate_revision_definition( modelo: ModeloDefinition, revision: ModeloRevision, *, legal_refs: Mapping[str, LegalReference], source_refs: Mapping[str, SourceReference], evidence: EvidenceValidator, justificante_corpus_root: Path | None, ) -> list[str]: """Return all registry validation failures for one modelo revision. The :class:`~aeat.domain.calculations.registry.ModeloDefinition` supplies the modelo scope and the :class:`~aeat.domain.calculations.registry.ModeloRevision` supplies the revision payload. The function applies revision-level reference/evidence gates, builds the validation context, dispatches all section validators, then runs closure validators before returning the accumulated failures. """ failures: list[str] = [] prefix = f"modelo {modelo.id} revision {revision.id}" failures.extend(_missing_refs(prefix, "revision", revision.legal_refs, legal_refs, "legal")) failures.extend(_missing_refs(prefix, "revision", revision.source_refs, source_refs, "source")) failures.extend(evidence.require_any_source_tier(prefix, "revision", revision.source_refs, _REVISION_SOURCE_TIERS)) _validate_revision_reference_surfaces( failures, prefix=prefix, revision=revision, legal_refs=legal_refs, source_refs=source_refs, evidence=evidence, ) context = build_revision_validation_context(revision) if not context.ids_by_kind["workbook parity reference"]: failures.append(f"{prefix}: revision must declare official workbook parity coverage") failures.extend(revision_reference_identity_failures(prefix, revision)) _emit_revision_payload_failures(failures, prefix, revision) _emit_completeness_gate_failures(failures, prefix, revision, modelo_id=modelo.id) _validate_revision_surface_sections( failures, prefix=prefix, modelo_id=modelo.id, revision=revision, context=context, legal_refs=legal_refs, source_refs=source_refs, evidence=evidence, justificante_corpus_root=justificante_corpus_root, ) _validate_revision_closure_sections( failures, prefix=prefix, modelo_id=modelo.id, revision=revision, context=context, legal_refs=legal_refs, source_refs=source_refs, evidence=evidence, ) return failures