"""
invarlock verify command
====================

Validates generated evaluation reports for internal consistency. The command
ensures schema compliance, checks that the primary metric ratio agrees with the
baseline reference, and enforces paired-window guarantees (match=1.0,
overlap=0.0).
"""

from __future__ import annotations

import hashlib
import json
import math
from pathlib import Path
from typing import Any

import typer
from rich.console import Console

from invarlock.cli.errors import InvarlockError
from invarlock.core.exceptions import (
    MetricsError as _MetricsError,
)
from invarlock.core.exceptions import (
    ValidationError as _ValidationError,
)
from invarlock.reporting import report_builder as _report_builder
from invarlock.reporting.report_builder import validate_report
from invarlock.reporting.report_schema import REPORT_JSON_SCHEMA, REPORT_SCHEMA_VERSION

from .._json import emit as _emit_json
from .._json import encode_error as _encode_error
from ..constants import VERIFY_FORMAT_VERSION as FORMAT_VERIFY
from .run import _enforce_provider_parity, _resolve_exit_code

console = Console()


def _coerce_float(value: Any) -> float | None:
    try:
        out = float(value)
    except (TypeError, ValueError):
        return None
    return out if math.isfinite(out) else None


def _coerce_int(value: Any) -> int | None:
    try:
        out = int(value)
    except (TypeError, ValueError):
        return None
    return out if out >= 0 else None


def _load_evaluation_report(path: Path) -> dict[str, Any]:
    """Load an evaluation report JSON from disk."""
    with path.open("r", encoding="utf-8") as handle:
        return json.load(handle)


def _validate_report_schema_strict(report: dict[str, Any]) -> bool:
    """Fail-closed schema validation for verify-time checks."""
    if not isinstance(report, dict):
        return False
    if report.get("schema_version") != REPORT_SCHEMA_VERSION:
        return False

    schema_lib = getattr(_report_builder, "jsonschema", None)
    if schema_lib is None:
        return False

    try:
        schema_lib.validate(instance=report, schema=REPORT_JSON_SCHEMA)
    except Exception:
        return False
    return True


def _validate_logspace_ci_identity(
    report: dict[str, Any], *, profile: str | None
) -> list[str]:
    """Validate paired ppl CI identity: display_ci ~= exp(ci)."""
    errors: list[str] = []
    pm = report.get("primary_metric", {}) or {}
    if not isinstance(pm, dict):
        return errors

    kind = str(pm.get("kind", "")).lower()
    if not kind.startswith("ppl"):
        return errors

    stats = report.get("dataset", {}).get("windows", {}).get("stats", {}) or {}
    if not isinstance(stats, dict):
        return errors

    pairing_reason = stats.get("window_pairing_reason")
    paired_windows = _coerce_int(stats.get("paired_windows"))
    match_fraction = _coerce_float(stats.get("window_match_fraction"))
    overlap_fraction = _coerce_float(stats.get("window_overlap_fraction"))
    paired = bool(
        pairing_reason is None
        and paired_windows is not None
        and paired_windows > 0
        and isinstance(match_fraction, float)
        and match_fraction >= 0.999999
        and isinstance(overlap_fraction, float)
        and overlap_fraction <= 1e-9
    )
    if not paired:
        return errors

    baseline_ref = report.get("baseline_ref", {}) or {}
    baseline_pm = (
        baseline_ref.get("primary_metric") if isinstance(baseline_ref, dict) else None
    )
    baseline_final = baseline_pm.get("final") if isinstance(baseline_pm, dict) else None
    if not (
        isinstance(baseline_final, int | float) and math.isfinite(float(baseline_final))
    ):
        return errors

    def _finite_bounds(bounds: Any) -> bool:
        return (
            isinstance(bounds, tuple | list)
            and len(bounds) == 2
            and all(
                isinstance(v, int | float) and math.isfinite(float(v)) for v in bounds
            )
        )

    prof = (profile or "").strip().lower() if isinstance(profile, str | None) else "dev"
    ci = pm.get("ci")
    display_ci = pm.get("display_ci")

    if prof in {"ci", "release"}:
        if not _finite_bounds(ci):
            errors.append(
                "primary_metric.ci missing for ppl-like metric under paired baseline in CI/Release."
            )
        if not _finite_bounds(display_ci):
            errors.append(
                "primary_metric.display_ci missing for ppl-like metric under paired baseline in CI/Release."
            )

    if not (_finite_bounds(ci) and _finite_bounds(display_ci)):
        return errors

    expected = (math.exp(float(ci[0])), math.exp(float(ci[1])))
    observed = (float(display_ci[0]), float(display_ci[1]))
    for obs, exp_val in zip(observed, expected, strict=False):
        tolerance = 5e-4 * max(1.0, abs(exp_val))
        if abs(obs - exp_val) > tolerance:
            errors.append(
                "primary_metric.display_ci mismatch: bounds do not match exp(ci)."
            )
            break
    return errors


def _validate_primary_metric(report: dict[str, Any]) -> list[str]:
    """Validate primary metric ratio consistency with baseline reference."""
    errors: list[str] = []
    pm = report.get("primary_metric", {}) or {}
    if not isinstance(pm, dict) or not pm:
        errors.append("report missing primary_metric block.")
        return errors

    def _is_finite_number(value: Any) -> bool:
        return isinstance(value, (int, float)) and math.isfinite(float(value))

    def _declares_invalid_primary_metric(metric: dict[str, Any]) -> bool:
        if bool(metric.get("invalid")):
            return True
        reason = metric.get("degraded_reason")
        if isinstance(reason, str):
            r = reason.strip().lower()
            return r.startswith("non_finite") or r in {
                "primary_metric_invalid",
                "evaluation_error",
            }
        return False

    kind = str(pm.get("kind", "")).lower()
    ratio_vs_baseline = pm.get("ratio_vs_baseline")
    final = pm.get("final")
    pm_invalid = _declares_invalid_primary_metric(pm)

    if kind.startswith("ppl"):
        baseline_ref = report.get("baseline_ref", {}) or {}
        baseline_pm = (
            baseline_ref.get("primary_metric")
            if isinstance(baseline_ref, dict)
            else None
        )
        baseline_final = None
        if isinstance(baseline_pm, dict):
            bv = baseline_pm.get("final")
            if isinstance(bv, (int | float)):
                baseline_final = float(bv)
        if _is_finite_number(final) and _is_finite_number(baseline_final):
            if float(baseline_final) <= 0.0:
                errors.append(
                    f"Baseline final must be > 0.0 to compute ratio (found {baseline_final})."
                )
            else:
                expected_ratio = float(final) / float(baseline_final)
                if not _is_finite_number(ratio_vs_baseline):
                    errors.append(
                        "report is missing a finite primary_metric.ratio_vs_baseline value."
                    )
                elif not math.isclose(
                    float(ratio_vs_baseline), expected_ratio, rel_tol=1e-6, abs_tol=1e-6
                ):
                    errors.append(
                        "Primary metric ratio mismatch: "
                        f"recorded={float(ratio_vs_baseline):.12f}, expected={expected_ratio:.12f}"
                    )
        else:
            # If the primary metric is non-finite, it must be explicitly marked invalid.
            # This is expected for structural error-injection runs (NaN/Inf weights).
            if (isinstance(final, (int | float)) and not _is_finite_number(final)) and (
                not pm_invalid
            ):
                errors.append(
                    "Primary metric final is non-finite but primary_metric.invalid is not set."
                )
    else:
        if pm_invalid:
            return errors
        if ratio_vs_baseline is None or not isinstance(ratio_vs_baseline, int | float):
            errors.append(
                "report missing primary_metric.ratio_vs_baseline for non-ppl metric."
            )
        elif not _is_finite_number(ratio_vs_baseline):
            errors.append(
                "report is missing a finite primary_metric.ratio_vs_baseline value."
            )

    return errors


def _validate_pairing(report: dict[str, Any]) -> list[str]:
    """Validate window pairing metrics (PM-only location)."""
    errors: list[str] = []
    stats = report.get("dataset", {}).get("windows", {}).get("stats", {})

    match_fraction = stats.get("window_match_fraction")
    overlap_fraction = stats.get("window_overlap_fraction")
    pairing_reason = stats.get("window_pairing_reason")
    paired_windows = _coerce_int(stats.get("paired_windows"))

    if pairing_reason is not None:
        errors.append(
            "window_pairing_reason must be null/None for paired reports "
            f"(found {pairing_reason!r})."
        )
    if paired_windows is None:
        errors.append("report missing paired_windows metric.")
    elif paired_windows == 0:
        errors.append("paired_windows must be > 0 for paired reports (found 0).")

    if match_fraction is None:
        errors.append("report missing window_match_fraction metric.")
    elif match_fraction < 0.999999:
        errors.append(
            f"window_match_fraction must be 1.0 for paired runs (found {match_fraction:.6f})."
        )

    if overlap_fraction is None:
        errors.append("report missing window_overlap_fraction metric.")
    elif overlap_fraction > 1e-9:
        errors.append(
            f"window_overlap_fraction must be 0.0 (found {overlap_fraction:.6f})."
        )

    return errors


def _validate_counts(report: dict[str, Any]) -> list[str]:
    """Validate preview/final window counts align with dataset configuration."""
    errors: list[str] = []
    dataset = report.get("dataset", {})
    dataset_windows = dataset.get("windows", {})
    expected_preview = dataset_windows.get("preview")
    expected_final = dataset_windows.get("final")

    stats = dataset_windows.get("stats", {})
    coverage = stats.get("coverage", {})

    preview_used = coverage.get("preview", {}).get("used") if coverage else None
    final_used = coverage.get("final", {}).get("used") if coverage else None
    paired_windows = stats.get("paired_windows")

    if expected_preview is not None:
        if preview_used is None:
            errors.append("report missing coverage.preview.used for preview windows.")
        elif int(preview_used) != int(expected_preview):
            errors.append(
                f"Preview window count mismatch: expected {expected_preview}, observed {preview_used}."
            )

    if expected_final is not None:
        if final_used is None:
            errors.append("report missing coverage.final.used for final windows.")
        elif int(final_used) != int(expected_final):
            errors.append(
                f"Final window count mismatch: expected {expected_final}, observed {final_used}."
            )

    if (
        paired_windows is not None
        and expected_preview is not None
        and int(paired_windows) != int(expected_preview)
    ):
        errors.append(
            f"Paired window count mismatch: expected {expected_preview}, observed {paired_windows}."
        )

    return errors


def _validate_drift_band(report: dict[str, Any]) -> list[str]:
    """Validate preview→final drift stays within the configured band.

    Defaults to 0.95–1.05 unless the report provides `primary_metric.drift_band`.
    """
    errors: list[str] = []
    pm = report.get("primary_metric", {}) or {}
    if not isinstance(pm, dict) or not pm:
        errors.append("report missing primary_metric block.")
        return errors
    if bool(pm.get("invalid")):
        # Drift is undefined when the primary metric is invalid (e.g., NaN/Inf weights).
        return errors
    drift_ratio = None
    try:
        prev = pm.get("preview")
        fin = pm.get("final")
        if (
            isinstance(prev, int | float)
            and isinstance(fin, int | float)
            and math.isfinite(float(prev))
            and math.isfinite(float(fin))
            and prev > 0
        ):
            drift_ratio = float(fin) / float(prev)
    except Exception:
        drift_ratio = None

    if not isinstance(drift_ratio, int | float):
        errors.append("report missing preview/final to compute drift ratio.")
        return errors

    drift_min = 0.95
    drift_max = 1.05
    band = pm.get("drift_band")
    try:
        if isinstance(band, dict):
            lo = band.get("min")
            hi = band.get("max")
            if isinstance(lo, int | float) and isinstance(hi, int | float):
                lo_f = float(lo)
                hi_f = float(hi)
                if math.isfinite(lo_f) and math.isfinite(hi_f) and 0 < lo_f < hi_f:
                    drift_min = lo_f
                    drift_max = hi_f
        elif isinstance(band, list | tuple) and len(band) == 2:
            lo_raw, hi_raw = band[0], band[1]
            if isinstance(lo_raw, int | float) and isinstance(hi_raw, int | float):
                lo_f = float(lo_raw)
                hi_f = float(hi_raw)
                if math.isfinite(lo_f) and math.isfinite(hi_f) and 0 < lo_f < hi_f:
                    drift_min = lo_f
                    drift_max = hi_f
    except Exception:
        pass

    if not drift_min <= float(drift_ratio) <= drift_max:
        errors.append(
            f"Preview→final drift ratio out of band ({drift_min:.2f}–{drift_max:.2f}): observed {drift_ratio:.6f}."
        )

    return errors


def _validate_tokenizer_hash(report: dict[str, Any]) -> list[str]:
    """Validate tokenizer hash consistency between baseline and edited runs.

    The check is enforced only when both hashes are present. When present and
    different, the verification fails.
    """
    errors: list[str] = []
    meta = report.get("meta", {}) or {}
    dataset = report.get("dataset", {}) or {}
    edited_hash = None
    try:
        # Prefer meta.tokenizer_hash; fall back to dataset.tokenizer.hash
        edited_hash = meta.get("tokenizer_hash") or (
            (dataset.get("tokenizer") or {}).get("hash")
            if isinstance(dataset.get("tokenizer"), dict)
            else None
        )
    except Exception:
        edited_hash = None

    baseline_ref = report.get("baseline_ref", {}) or {}
    baseline_hash = baseline_ref.get("tokenizer_hash")

    if isinstance(edited_hash, str) and isinstance(baseline_hash, str):
        if edited_hash and baseline_hash and edited_hash != baseline_hash:
            errors.append("Tokenizer hash mismatch between baseline and edited runs.")
    # If either hash is missing, skip the check
    return errors


def _resolve_path(payload: Any, path: str) -> Any:
    """Resolve dotted paths within nested dictionaries."""
    current = payload
    for segment in path.split("."):
        if isinstance(current, dict):
            current = current.get(segment)
        else:
            return None
    return current


def _measurement_contract_digest(contract: Any) -> str | None:
    if not isinstance(contract, dict) or not contract:
        return None
    try:
        canonical = json.dumps(contract, sort_keys=True, default=str)
    except Exception:
        return None
    return hashlib.sha256(canonical.encode()).hexdigest()[:16]


def _validate_measurement_contracts(
    report: dict[str, Any], *, profile: str
) -> list[str]:
    """Enforce measurement-contract presence and baseline pairing for guards."""
    errors: list[str] = []
    prof = (profile or "").strip().lower()
    resolved_policy = report.get("resolved_policy") or {}

    for guard_key in ("spectral", "rmt"):
        block = report.get(guard_key) or {}
        if not isinstance(block, dict):
            continue
        evaluated = bool(block.get("evaluated", True))
        if not evaluated:
            continue

        mc = block.get("measurement_contract")
        mc_hash = _measurement_contract_digest(mc)
        expected_hash = block.get("measurement_contract_hash")
        if not isinstance(mc, dict) or not mc:
            errors.append(f"report missing {guard_key}.measurement_contract.")
        elif isinstance(expected_hash, str) and expected_hash:
            if mc_hash and mc_hash != expected_hash:
                errors.append(
                    f"{guard_key}.measurement_contract_hash mismatch: expected={expected_hash}, computed={mc_hash}."
                )
        else:
            errors.append(f"report missing {guard_key}.measurement_contract_hash.")

        rp_guard = (
            resolved_policy.get(guard_key)
            if isinstance(resolved_policy, dict)
            else None
        )
        rp_mc = (
            rp_guard.get("measurement_contract") if isinstance(rp_guard, dict) else None
        )
        rp_hash = _measurement_contract_digest(rp_mc)
        if not isinstance(rp_mc, dict) or not rp_mc:
            errors.append(
                f"report missing resolved_policy.{guard_key}.measurement_contract."
            )
        elif mc_hash and rp_hash and mc_hash != rp_hash:
            errors.append(
                f"{guard_key} measurement_contract differs between analysis and resolved_policy "
                f"(analysis={mc_hash}, resolved_policy={rp_hash})."
            )

        if prof in {"ci", "release"}:
            match = block.get("measurement_contract_match")
            if match is not True:
                errors.append(
                    f"{guard_key} measurement contract must match baseline for {prof} profile."
                )

    return errors


def _apply_profile_lints(report: dict[str, Any]) -> list[str]:
    """Apply model-profile specific lint rules embedded in the report."""
    errors: list[str] = []
    meta = report.get("meta", {})
    profile = meta.get("model_profile") if isinstance(meta, dict) else None
    if not isinstance(profile, dict):
        return errors

    lints = profile.get("cert_lints", [])
    if not isinstance(lints, list):
        return errors

    for lint in lints:
        if not isinstance(lint, dict):
            continue
        lint_type = str(lint.get("type", "")).lower()
        path = lint.get("path")
        expected = lint.get("value")
        message = lint.get("message") or "Model profile lint failed."
        actual = _resolve_path(report, path) if isinstance(path, str) else None

        if lint_type == "equals":
            if actual != expected:
                errors.append(
                    f"{message} Expected {path} == {expected!r}, observed {actual!r}."
                )
        elif lint_type == "gte":
            try:
                actual_val = float(actual)
                expected_val = float(expected)
            except (TypeError, ValueError):
                errors.append(
                    f"{message} Expected numeric comparison for {path}, observed {actual!r}."
                )
            else:
                if actual_val < expected_val:
                    errors.append(
                        f"{message} Expected {path} ≥ {expected_val}, observed {actual_val}."
                    )
        elif lint_type == "lte":
            try:
                actual_val = float(actual)
                expected_val = float(expected)
            except (TypeError, ValueError):
                errors.append(
                    f"{message} Expected numeric comparison for {path}, observed {actual!r}."
                )
            else:
                if actual_val > expected_val:
                    errors.append(
                        f"{message} Expected {path} ≤ {expected_val}, observed {actual_val}."
                    )

    return errors


def _validate_evaluation_report_payload(
    path: Path, *, profile: str | None = None
) -> list[str]:
    """Run all verification checks for a single evaluation report."""
    errors: list[str] = []
    report = _load_evaluation_report(path)
    try:
        prof = (
            (profile or "").strip().lower()
            if isinstance(profile, str | None)
            else "dev"
        )
    except Exception:
        prof = "dev"

    # CI/Release fail closed on schema; dev keeps historical lenient behavior.
    if prof in {"ci", "release"} and not _validate_report_schema_strict(report):
        errors.append("report schema validation failed.")
        return errors

    # Structural checks and validation flag typing.
    if not validate_report(report):
        errors.append("report schema validation failed.")
        return errors

    errors.extend(_validate_primary_metric(report))
    errors.extend(_validate_pairing(report))
    errors.extend(_validate_counts(report))
    errors.extend(_validate_logspace_ci_identity(report, profile=profile))
    # Drift band is a CI/Release enforcement check; dev profile should not
    # fail verification due to preview→final drift.
    if prof in {"ci", "release"}:
        errors.extend(_validate_drift_band(report))
    errors.extend(_apply_profile_lints(report))
    errors.extend(_validate_tokenizer_hash(report))
    if prof in {"ci", "release"}:
        errors.extend(_validate_measurement_contracts(report, profile=prof))

    # strict/fast assurance mode checks were removed; verification gates rely on
    # structural schema + guard metric contracts instead.

    # Release-only enforcement: guard overhead must be measured or explicitly skipped.
    if prof == "release":
        go = report.get("guard_overhead")
        if not isinstance(go, dict) or not go:
            errors.append(
                "Release verification requires guard_overhead (missing). "
                "Set INVARLOCK_SKIP_OVERHEAD_CHECK=1 to explicitly skip during evaluation."
            )
        else:
            skipped = bool(go.get("skipped", False)) or (
                str(go.get("mode", "")).strip().lower() == "skipped"
            )
            if not skipped:
                evaluated = go.get("evaluated")
                if evaluated is not True:
                    errors.append(
                        "Release verification requires evaluated guard_overhead (not evaluated). "
                        "Set INVARLOCK_SKIP_OVERHEAD_CHECK=1 to explicitly skip during evaluation."
                    )
                ratio = go.get("overhead_ratio")
                if ratio is None:
                    errors.append(
                        "Release verification requires guard_overhead.overhead_ratio (missing)."
                    )
    # Legacy cross-checks removed; primary_metric is canonical

    return errors


def _warn_adapter_family_mismatch(cert_path: Path, report: dict[str, Any]) -> None:
    """Emit a soft warning if adapter families differ between baseline and edited.

    This is a non-fatal hint to catch inadvertent cross-family comparisons.
    Tries to load the baseline report referenced in the report provenance.
    """
    try:
        plugins = report.get("plugins") or {}
        adapter_meta = plugins.get("adapter") if isinstance(plugins, dict) else None
        edited_family = None
        edited_lib = None
        edited_ver = None
        if isinstance(adapter_meta, dict):
            prov = adapter_meta.get("provenance")
            if isinstance(prov, dict):
                edited_family = str(prov.get("family") or "").lower() or None
                edited_lib = prov.get("library") or None
                edited_ver = prov.get("version") or None

        baseline_prov = (
            report.get("provenance")
            if isinstance(report.get("provenance"), dict)
            else {}
        )
        baseline_report_path = None
        if isinstance(baseline_prov, dict):
            baseline_ref = baseline_prov.get("baseline")
            if isinstance(baseline_ref, dict):
                baseline_report_path = baseline_ref.get("report_path")

        baseline_family = None
        base_lib = None
        base_ver = None
        if isinstance(baseline_report_path, str) and baseline_report_path:
            p = Path(baseline_report_path)
            if p.exists():
                with p.open("r", encoding="utf-8") as fh:
                    baseline_report = json.load(fh)
                meta = (
                    baseline_report.get("meta", {})
                    if isinstance(baseline_report, dict)
                    else {}
                )
                base_plugins = meta.get("plugins") if isinstance(meta, dict) else None
                if isinstance(base_plugins, dict):
                    base_adapter = base_plugins.get("adapter")
                    if isinstance(base_adapter, dict):
                        base_prov = base_adapter.get("provenance")
                        if isinstance(base_prov, dict):
                            val = base_prov.get("family")
                            if isinstance(val, str) and val:
                                baseline_family = val.lower()
                            base_lib = base_prov.get("library") or None
                            base_ver = base_prov.get("version") or None

        if edited_family and baseline_family and edited_family != baseline_family:
            # Clarify with backend library versions where available
            base_backend = base_lib or "—"
            base_version = f"=={base_ver}" if base_lib and base_ver else "—"
            edited_backend = edited_lib or "—"
            edited_version = f"=={edited_ver}" if edited_lib and edited_ver else "—"
            console.print(
                "[yellow]⚠️  Adapter family differs between baseline and edited runs:[/yellow]"
            )
            console.print(
                f"[yellow]   • baseline: family={baseline_family}, backend={base_backend} {base_version}[/yellow]"
            )
            console.print(
                f"[yellow]   • edited  : family={edited_family}, backend={edited_backend} {edited_version}[/yellow]"
            )
            console.print(
                "[yellow]   Ensure this cross-family comparison is intentional (Compare & Evaluate flows should normally match families).[/yellow]"
            )
    except Exception:
        # Non-fatal and best-effort; suppress errors
        return


def verify_command(
    reports: list[Path] = typer.Argument(
        ...,
        exists=True,
        dir_okay=False,
        readable=True,
        resolve_path=True,
        help="One or more evaluation report JSON files to verify.",
    ),
    baseline: Path | None = typer.Option(
        None,
        "--baseline",
        help="Optional baseline evaluation report (or run report) JSON to enforce provider parity.",
    ),
    tolerance: float = typer.Option(
        1e-9,
        "--tolerance",
        help="Tolerance for analysis-basis comparisons (mean log-loss).",
    ),
    profile: str | None = typer.Option(
        "dev",
        "--profile",
        help="Execution profile affecting parity enforcement and exit codes (dev|ci|release).",
    ),
    json_out: bool = typer.Option(
        False,
        "--json",
        help="Emit machine-readable JSON (suppresses human-readable output)",
    ),
) -> None:
    """
    Verify evaluation report integrity.

    Ensures each evaluation report passes schema validation, ratio consistency checks,
    and strict pairing requirements (match=1.0, overlap=0.0).
    """

    overall_ok = True
    # Coerce tolerance for programmatic calls where typer.Option may be passed
    try:
        tol = float(tolerance)
    except Exception:
        tol = 1e-9

    # Optional: preload baseline provider digest for parity enforcement
    baseline_digest = None
    try:
        if baseline is not None:
            bdata = json.loads(baseline.read_text(encoding="utf-8"))
            # Accept either an evaluation report or a run report (report.json); look under provenance when present.
            prov = bdata.get("provenance") if isinstance(bdata, dict) else None
            if isinstance(prov, dict):
                pd = prov.get("provider_digest")
                if isinstance(pd, dict):
                    baseline_digest = pd
    except Exception:
        # Baseline is an optional hint only; ignore issues here and proceed
        baseline_digest = None

    malformed_any = False
    try:
        for cert_path in reports:
            cert_obj = _load_evaluation_report(cert_path)

            # Enforce provider digest presence in CI/Release profiles
            try:
                prof = (profile or "").strip().lower()
            except Exception:
                prof = "dev"
            prov = cert_obj.get("provenance") if isinstance(cert_obj, dict) else None
            subj_digest = None
            if isinstance(prov, dict):
                subj_digest = prov.get("provider_digest")
            if prof in {"ci", "release"}:
                if not (
                    isinstance(subj_digest, dict) and subj_digest.get("ids_sha256")
                ):
                    raise InvarlockError(
                        code="E004",
                        message=(
                            "PROVIDER-DIGEST-MISSING: subject missing provider_digest.ids_sha256"
                        ),
                    )
                # If baseline provided, enforce tokenizer/masking parity
                if baseline_digest is not None:
                    _enforce_provider_parity(
                        subj_digest, baseline_digest, profile=profile
                    )

            # Structural checks
            errors = _validate_evaluation_report_payload(cert_path, profile=profile)
            # JSON path: emit a typed ValidationError for schema failures to include error.code
            if json_out and any(
                "schema validation failed" in str(e).lower() for e in errors
            ):
                raise _ValidationError(
                    code="E601",
                    message="REPORT-SCHEMA-INVALID: schema validation failed",
                    details={"path": str(cert_path)},
                )
            # Determine malformed vs policy-fail for this cert
            is_malformed = any(
                ("schema validation failed" in e.lower())
                or ("missing primary_metric.ratio_vs_baseline" in e)
                or ("report is missing a finite primary_metric.ratio_vs_baseline" in e)
                for e in errors
            )
            malformed_any = malformed_any or is_malformed

            # Determinism: recompute analysis basis when possible
            pm = (
                cert_obj.get("primary_metric", {}) if isinstance(cert_obj, dict) else {}
            )
            kind = (
                str(pm.get("kind") or "").strip().lower()
                if isinstance(pm, dict)
                else ""
            )
            win = (
                cert_obj.get("evaluation_windows", {})
                if isinstance(cert_obj, dict)
                else {}
            )
            fin = win.get("final") if isinstance(win, dict) else None

            # Accuracy/VQA recompute — do not swallow exceptions in dev; must influence exit
            if kind in {"accuracy", "vqa_accuracy"}:
                cls = (
                    cert_obj.get("metrics", {}).get("classification", {})
                    if isinstance(cert_obj.get("metrics"), dict)
                    else {}
                )
                n_correct = cls.get("n_correct") if isinstance(cls, dict) else None
                n_total = cls.get("n_total") if isinstance(cls, dict) else None
                if (
                    isinstance(n_correct, int | float)
                    and isinstance(n_total, int | float)
                    and n_total > 0
                ):
                    acc = float(n_correct) / float(n_total)
                    disp_final = pm.get("final")
                    if isinstance(disp_final, int | float):
                        if abs(float(disp_final) - acc) > max(1e-12, tol):
                            errors.append(
                                f"Accuracy mismatch: final={float(disp_final):.12f} recomputed={acc:.12f}"
                            )
                else:
                    if prof in {"ci", "release"}:
                        raise InvarlockError(
                            code="E004",
                            message=(
                                "PROVIDER-DIGEST-MISSING: missing classification aggregates for recompute in CI/Release"
                            ),
                        )
                    elif not json_out:
                        console.print(
                            "[yellow]⚠️  Cannot recompute accuracy: missing aggregates (dev mode).[/yellow]"
                        )

            # ppl-like recompute guarded in try/except
            else:
                if isinstance(pm, dict) and isinstance(fin, dict):
                    ll = fin.get("logloss")
                    wc = fin.get("token_counts")
                    if (
                        isinstance(ll, list)
                        and isinstance(wc, list)
                        and ll
                        and wc
                        and len(ll) == len(wc)
                    ):
                        try:
                            num = sum(
                                float(a) * float(b)
                                for a, b in zip(ll, wc, strict=False)
                            )
                            den = sum(float(b) for b in wc)
                            if den > 0:
                                recomputed_mean = float(num / den)
                                ap_final = pm.get("analysis_point_final")
                                if isinstance(ap_final, int | float):
                                    if abs(float(ap_final) - recomputed_mean) > tol:
                                        errors.append(
                                            f"Basis mismatch: analysis_point_final={ap_final:.12f} recomputed={recomputed_mean:.12f}"
                                        )
                                else:
                                    disp_final = pm.get("final")
                                    if isinstance(disp_final, int | float):
                                        if abs(
                                            float(math.exp(recomputed_mean))
                                            - float(disp_final)
                                        ) > max(1e-12, tol):
                                            errors.append(
                                                f"Display mismatch: final={float(disp_final):.12f} exp(basis)={math.exp(recomputed_mean):.12f}"
                                            )
                        except Exception:
                            pass
                    else:
                        if prof in {"ci", "release"}:
                            raise InvarlockError(
                                code="E004",
                                message=(
                                    "PROVIDER-DIGEST-MISSING: evaluation_windows.final missing for recompute in CI/Release"
                                ),
                            )
                        elif not json_out:
                            console.print(
                                "[yellow]⚠️  Cannot recompute basis: evaluation_windows.final missing or incomplete (dev mode).[/yellow]"
                            )

            # Treat recompute mismatches as fatal in CI/Release
            if (
                errors
                and prof in {"ci", "release"}
                and any(("mismatch" in str(e).lower()) for e in errors)
            ):
                first = next(
                    (e for e in errors if "mismatch" in str(e).lower()), errors[0]
                )
                raise _MetricsError(
                    code="E602",
                    message="RECOMPUTE-MISMATCH: report values disagree with recomputation",
                    details={"example": str(first)},
                )

            if errors:
                overall_ok = False
                if not json_out:
                    console.print(f"[red]FAIL[/red] {cert_path}")
                    for err in errors:
                        console.print(f"  ↳ {err}")
            else:
                if not json_out:
                    console.print(f"[green]PASS[/green] {cert_path}")
                # Emit soft adapter-family warning after a successful structural check
                try:
                    _warn_adapter_family_mismatch(cert_path, cert_obj)
                except Exception:
                    pass

        if not overall_ok:
            code = 2 if malformed_any else 1
            if json_out:
                # Build per-report results payload
                results: list[dict[str, Any]] = []
                for cert_path in reports:
                    try:
                        cert_obj = _load_evaluation_report(cert_path)
                    except Exception:
                        cert_obj = {}
                    pm = (
                        cert_obj.get("primary_metric", {})
                        if isinstance(cert_obj, dict)
                        else {}
                    )
                    kind = str(
                        (pm.get("kind") if isinstance(pm, dict) else "") or ""
                    ).lower()
                    ratio = (
                        pm.get("ratio_vs_baseline") if isinstance(pm, dict) else None
                    )
                    ci = pm.get("display_ci") if isinstance(pm, dict) else None
                    if not (isinstance(ci, tuple | list) and len(ci) == 2):
                        ci_out = None
                    else:
                        try:
                            ci_out = [float(ci[0]), float(ci[1])]  # type: ignore[index]
                        except Exception:
                            ci_out = None
                    # Recompute summary for JSON (best-effort)
                    recompute: dict[str, Any] | None = None
                    try:
                        fam = (
                            "accuracy"
                            if kind in {"accuracy", "vqa_accuracy"}
                            else ("ppl" if kind.startswith("ppl") else "other")
                        )
                        if fam == "accuracy":
                            cls = (
                                cert_obj.get("metrics", {}).get("classification", {})
                                if isinstance(cert_obj.get("metrics"), dict)
                                else {}
                            )
                            n_correct = (
                                cls.get("n_correct") if isinstance(cls, dict) else None
                            )
                            n_total = (
                                cls.get("n_total") if isinstance(cls, dict) else None
                            )
                            if (
                                isinstance(n_correct, int | float)
                                and isinstance(n_total, int | float)
                                and n_total > 0
                            ):
                                acc = float(n_correct) / float(n_total)
                                df = pm.get("final") if isinstance(pm, dict) else None
                                ok = bool(
                                    isinstance(df, int | float)
                                    and abs(float(df) - acc) <= max(1e-12, tol)
                                )
                                recompute = {
                                    "family": fam,
                                    "ok": ok,
                                    "reason": None if ok else "mismatch",
                                }
                            else:
                                recompute = {
                                    "family": fam,
                                    "ok": True,
                                    "reason": "skipped",
                                }
                        elif fam == "ppl":
                            ev = (
                                cert_obj.get("evaluation_windows", {})
                                if isinstance(cert_obj, dict)
                                else {}
                            )
                            finw = ev.get("final") if isinstance(ev, dict) else None
                            if isinstance(finw, dict):
                                ll = finw.get("logloss")
                                wc = finw.get("token_counts")
                                if (
                                    isinstance(ll, list)
                                    and isinstance(wc, list)
                                    and ll
                                    and wc
                                    and len(ll) == len(wc)
                                ):
                                    try:
                                        num = sum(
                                            float(a) * float(b)
                                            for a, b in zip(ll, wc, strict=False)
                                        )
                                        den = sum(float(b) for b in wc)
                                        ok = True
                                        if den > 0:
                                            recomputed = float(math.exp(num / den))
                                            df = (
                                                pm.get("final")
                                                if isinstance(pm, dict)
                                                else None
                                            )
                                            ok = bool(
                                                isinstance(df, int | float)
                                                and abs(float(df) - recomputed)
                                                <= max(1e-12, tol)
                                            )
                                        recompute = {
                                            "family": fam,
                                            "ok": ok,
                                            "reason": None if ok else "mismatch",
                                        }
                                    except Exception:
                                        recompute = {
                                            "family": fam,
                                            "ok": True,
                                            "reason": "skipped",
                                        }
                                else:
                                    recompute = {
                                        "family": fam,
                                        "ok": True,
                                        "reason": "skipped",
                                    }
                        # else: leave None
                    except Exception:
                        recompute = None

                    item = {
                        "id": str(cert_path),
                        "schema_version": "v1",
                        "kind": kind,
                        "ok": False,
                        "reason": "malformed" if malformed_any else "policy_fail",
                        "ratio_vs_baseline": float(ratio)
                        if isinstance(ratio, int | float)
                        and math.isfinite(float(ratio))
                        else None,
                        "ci": ci_out,
                        "recompute": recompute,
                    }
                    results.append(item)
                payload = {
                    "format_version": FORMAT_VERIFY,
                    "summary": {
                        "ok": False,
                        "reason": "malformed" if malformed_any else "policy_fail",
                    },
                    "evaluation_report": {"count": len(reports)},
                    "results": results,
                    "resolution": {"exit_code": code},
                }
                _emit_json(payload, code)
            raise SystemExit(code)

        # Success emission
        if json_out:
            # Build per-report success results payload
            results: list[dict[str, Any]] = []
            for cert_path in reports:
                try:
                    cert_obj = _load_evaluation_report(cert_path)
                except Exception:
                    cert_obj = {}
                pm = (
                    cert_obj.get("primary_metric", {})
                    if isinstance(cert_obj, dict)
                    else {}
                )
                kind = str(
                    (pm.get("kind") if isinstance(pm, dict) else "") or ""
                ).lower()
                ratio = pm.get("ratio_vs_baseline") if isinstance(pm, dict) else None
                ci = pm.get("display_ci") if isinstance(pm, dict) else None
                if not (isinstance(ci, tuple | list) and len(ci) == 2):
                    ci_out = None
                else:
                    try:
                        ci_out = [float(ci[0]), float(ci[1])]  # type: ignore[index]
                    except Exception:
                        ci_out = None
                # Recompute summary for JSON (best-effort)
                recompute: dict[str, Any] | None = None
                try:
                    fam = (
                        "accuracy"
                        if kind in {"accuracy", "vqa_accuracy"}
                        else ("ppl" if kind.startswith("ppl") else "other")
                    )
                    if fam == "accuracy":
                        cls = (
                            cert_obj.get("metrics", {}).get("classification", {})
                            if isinstance(cert_obj.get("metrics"), dict)
                            else {}
                        )
                        n_correct = (
                            cls.get("n_correct") if isinstance(cls, dict) else None
                        )
                        n_total = cls.get("n_total") if isinstance(cls, dict) else None
                        if (
                            isinstance(n_correct, int | float)
                            and isinstance(n_total, int | float)
                            and n_total > 0
                        ):
                            acc = float(n_correct) / float(n_total)
                            df = pm.get("final") if isinstance(pm, dict) else None
                            ok = bool(
                                isinstance(df, int | float)
                                and abs(float(df) - acc) <= max(1e-12, tol)
                            )
                            recompute = {
                                "family": fam,
                                "ok": ok,
                                "reason": None if ok else "mismatch",
                            }
                        else:
                            recompute = {"family": fam, "ok": True, "reason": "skipped"}
                    elif fam == "ppl":
                        ev = (
                            cert_obj.get("evaluation_windows", {})
                            if isinstance(cert_obj, dict)
                            else {}
                        )
                        finw = ev.get("final") if isinstance(ev, dict) else None
                        if isinstance(finw, dict):
                            ll = finw.get("logloss")
                            wc = finw.get("token_counts")
                            if (
                                isinstance(ll, list)
                                and isinstance(wc, list)
                                and ll
                                and wc
                                and len(ll) == len(wc)
                            ):
                                try:
                                    num = sum(
                                        float(a) * float(b)
                                        for a, b in zip(ll, wc, strict=False)
                                    )
                                    den = sum(float(b) for b in wc)
                                    ok = True
                                    if den > 0:
                                        recomputed = float(math.exp(num / den))
                                        df = (
                                            pm.get("final")
                                            if isinstance(pm, dict)
                                            else None
                                        )
                                        ok = bool(
                                            isinstance(df, int | float)
                                            and abs(float(df) - recomputed)
                                            <= max(1e-12, tol)
                                        )
                                    recompute = {
                                        "family": fam,
                                        "ok": ok,
                                        "reason": None if ok else "mismatch",
                                    }
                                except Exception:
                                    recompute = {
                                        "family": fam,
                                        "ok": True,
                                        "reason": "skipped",
                                    }
                            else:
                                recompute = {
                                    "family": fam,
                                    "ok": True,
                                    "reason": "skipped",
                                }
                    # else: leave None
                except Exception:
                    recompute = None

                item = {
                    "id": str(cert_path),
                    "schema_version": "v1",
                    "kind": kind,
                    "ok": True,
                    "reason": "ok",
                    "ratio_vs_baseline": float(ratio)
                    if isinstance(ratio, int | float) and math.isfinite(float(ratio))
                    else None,
                    "ci": ci_out,
                    "recompute": recompute,
                }
                results.append(item)
            payload = {
                "format_version": FORMAT_VERIFY,
                "summary": {"ok": True, "reason": "ok"},
                "evaluation_report": {"count": len(reports)},
                "results": results,
                "resolution": {"exit_code": 0},
            }
            _emit_json(payload, 0)
        else:
            # Human-friendly success line
            try:
                last = _load_evaluation_report(reports[-1]) if reports else {}
                pm = last.get("primary_metric", {}) if isinstance(last, dict) else {}
                kind = str(pm.get("kind") or "").strip()
                ppl = last.get("ppl", {}) if isinstance(last, dict) else {}
                n_prev = (
                    ppl.get("stats", {})
                    .get("coverage", {})
                    .get("preview", {})
                    .get("used")
                    if isinstance(ppl, dict)
                    else None
                )
                n_fin = (
                    ppl.get("stats", {})
                    .get("coverage", {})
                    .get("final", {})
                    .get("used")
                    if isinstance(ppl, dict)
                    else None
                )
                ratio = pm.get("ratio_vs_baseline") if isinstance(pm, dict) else None
                ci = pm.get("display_ci") if isinstance(pm, dict) else None
                width = (
                    (float(ci[1]) - float(ci[0]))
                    if (isinstance(ci, tuple | list) and len(ci) == 2)
                    else None
                )
                parts = ["VERIFY OK"]
                if kind:
                    parts.append(f"metric={kind}")
                if n_prev is not None and n_fin is not None:
                    parts.append(f"n={n_prev}/{n_fin}")
                if isinstance(ratio, int | float):
                    parts.append(f"point={float(ratio):.6f}")
                if isinstance(ci, tuple | list) and len(ci) == 2:
                    parts.append(f"ci=[{float(ci[0]):.6f},{float(ci[1]):.6f}]")
                if isinstance(width, int | float):
                    parts.append(f"width={width:.6f}")
                console.print(" ".join(parts))
            except Exception:
                pass

    except InvarlockError as ce:
        code = _resolve_exit_code(ce, profile=profile)
        if json_out:
            reason = "malformed" if isinstance(ce, _ValidationError) else "policy_fail"
            payload = {
                "format_version": FORMAT_VERIFY,
                "summary": {"ok": False, "reason": reason},
                "results": [
                    {
                        "id": str(reports[0]) if reports else "",
                        "schema_version": "v1",
                        "kind": "",
                        "ok": False,
                        "reason": reason,
                        "ratio_vs_baseline": None,
                        "ci": None,
                    }
                ],
                "resolution": {"exit_code": code},
                "error": _encode_error(ce),
            }
            _emit_json(payload, code)
        else:
            console.print(str(ce))
        raise SystemExit(code) from ce
    except SystemExit:
        raise
    except typer.Exit:
        # Ensure single JSON emission path; let Typer/Click control exit
        raise
    except Exception as e:
        code = _resolve_exit_code(e, profile=profile)
        if json_out:
            reason = (
                "malformed" if isinstance(e, json.JSONDecodeError) else "policy_fail"
            )
            payload = {
                "format_version": FORMAT_VERIFY,
                "summary": {"ok": False, "reason": reason},
                "results": [
                    {
                        "id": str(reports[0]) if reports else "",
                        "schema_version": "v1",
                        "kind": "",
                        "ok": False,
                        "reason": reason,
                        "ratio_vs_baseline": None,
                        "ci": None,
                    }
                ],
                "resolution": {"exit_code": code},
                "error": _encode_error(e),
            }
            _emit_json(payload, code)
        else:
            console.print(f"[red]❌ Verification failed: {e}[/red]")
        raise SystemExit(code) from e
