"""Profile compatibility helpers for club-3090 v0.7.0.

Requires PyYAML. On Debian/Ubuntu this is usually available from
``python3-yaml``; otherwise install with ``pip install pyyaml``.
"""

from __future__ import annotations

import json
import logging
import os
import subprocess
import time
from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path
from typing import Any, Optional

try:
    import yaml
except ImportError as exc:  # pragma: no cover - exercised only on missing dep
    raise RuntimeError("scripts.lib.profiles.compat requires PyYAML; install python3-yaml or pip install pyyaml") from exc

from .compose_registry import COMPOSE_REGISTRY


SUPPORTED_SCHEMA_VERSIONS = {1}
PROFILE_ROOT = Path(__file__).resolve().parent
REPO_ROOT = Path(__file__).resolve().parents[3]
CONSTRAINT_IDS = [f"C{i}" for i in range(1, 17)]
ESTATE_CONSTRAINT_IDS = [f"E{i}" for i in range(1, 5)]


class ProfileError(Exception):
    """Base class for profile loading/validation errors."""


class UnsupportedSchemaVersionError(ProfileError):
    """Raised when a profile schema_version is not supported."""


class CrossReferenceError(ProfileError):
    """Raised when a profile references a missing profile id."""


class TopologyClass(str, Enum):
    SINGLE_CARD = "single_card"
    HOMOGENEOUS = "homogeneous"
    VRAM_MATCHED_COMPUTE_MISMATCHED = "vram_matched_compute_mismatched"
    VRAM_MISMATCHED = "vram_mismatched"
    HETEROGENEOUS_MIXED = "heterogeneous_mixed"


TOPOLOGY_ADVISORY = {
    TopologyClass.SINGLE_CARD: None,
    TopologyClass.HOMOGENEOUS: None,
    TopologyClass.VRAM_MATCHED_COMPUTE_MISMATCHED: (
        "Compute mismatch detected (VRAM matched). TP=N works fine but the faster card "
        "waits at every NCCL allreduce — effective throughput caps at slower card's speed "
        "(~30% of faster card idle at allreduce). Full per-card VRAM capacity preserved. "
        "Alternative: estate planner (--estate) to run different models per card at full speed."
    ),
    TopologyClass.VRAM_MISMATCHED: (
        "VRAM mismatch detected. TP=N would cap to smaller card's usable model size. "
        "Recommended paths: (a) llama.cpp `--tensor-split` for weighted layer split, "
        "(b) PP=N (manual flag flip — `--pipeline-parallel-size N` on a vllm/dual compose; "
        "no shipping PP compose), (c) estate planner (--estate) to run different models per card."
    ),
    TopologyClass.HETEROGENEOUS_MIXED: (
        "Heterogeneous hardware detected (multiple VRAM and compute tiers). Manual selection "
        "recommended. Consider the estate planner (--estate) to put different models on "
        "different card subsets, or run a single model on the largest matched subset."
    ),
}


def _logger() -> logging.Logger:
    logger = logging.getLogger("compat")
    if not logger.handlers:
        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter("[compat] %(message)s"))
        logger.addHandler(handler)
    level = os.environ.get("CLUB3090_LOG_LEVEL", "INFO").upper()
    logger.setLevel(getattr(logging, level, logging.INFO))
    logger.propagate = False
    return logger


def _tuple(value: Any) -> tuple:
    if value is None:
        return ()
    if isinstance(value, tuple):
        return value
    if isinstance(value, list):
        return tuple(value)
    return (value,)


def _dict(value: Any) -> dict:
    return dict(value or {})


def _number_or_none(value: Any) -> Optional[float]:
    return value if isinstance(value, (int, float)) else None


@dataclass(frozen=True)
class HardwareProfile:
    schema_version: int
    id: str
    display_name: str
    sm: float
    vram_gb: float
    arch: str
    mem_util_safe: float
    supported_kv_formats: tuple[str, ...]
    kv_format_default: dict[str, str]
    cudagraph: str
    driver_pin_recommended: dict[str, Any]
    nvlink_capable: bool
    power_cap_w_optimal: Optional[int] = None
    power_cap_w_prefill: Optional[int] = None
    power_cap_w_max: Optional[int] = None
    notes: Optional[str] = None


def classify_hardware_topology(hardware: list[HardwareProfile]) -> TopologyClass:
    """Classify selected GPUs for TP-vs-PP/estate advisory output."""
    if not hardware:
        raise ProfileError("classify_hardware_topology requires at least one HardwareProfile")
    if len(hardware) == 1:
        return TopologyClass.SINGLE_CARD

    vrams = sorted(hw.vram_gb for hw in hardware)
    sms = {hw.sm for hw in hardware}

    vram_clusters = 1
    for i in range(1, len(vrams)):
        if vrams[i] - vrams[i - 1] > 1.0:
            vram_clusters += 1

    if vram_clusters == 1 and len(sms) == 1:
        return TopologyClass.HOMOGENEOUS
    if vram_clusters == 1 and len(sms) > 1:
        return TopologyClass.VRAM_MATCHED_COMPUTE_MISMATCHED
    if vram_clusters > 1:
        return TopologyClass.VRAM_MISMATCHED
    return TopologyClass.HETEROGENEOUS_MIXED


@dataclass(frozen=True)
class ModelProfile:
    schema_version: int
    id: str
    display_name: str
    family: str
    hidden_size: int
    num_hidden_layers: int
    num_attn_heads: int
    num_kv_heads: int
    max_ctx_supported: int
    attention_k_eq_v: bool
    weights: dict[str, dict[str, Any]]
    default_weight_variant: str
    compatible_drafters: tuple[str, ...]
    valid_tp: tuple[int, ...]
    requires_genesis: bool
    intermediate_size: Optional[int] = None
    num_gdn_layers: Optional[int] = None
    num_attn_layers: Optional[int] = None
    num_full_attn_layers: Optional[int] = None
    num_sliding_attn_layers: Optional[int] = None
    head_dim_attn: Optional[int] = None
    linear_num_v_heads: Optional[int] = None
    linear_num_k_heads: Optional[int] = None
    linear_v_head_dim: Optional[int] = None
    linear_k_head_dim: Optional[int] = None
    linear_conv_kernel_dim: Optional[int] = None
    head_dim_sliding: Optional[int] = None
    global_head_dim: Optional[int] = None
    sliding_window: Optional[int] = None
    # Asymmetric KV head counts for SWA-hybrid models where global layers
    # have a different KV head count than sliding layers (e.g. Gemma 4
    # 26B-A4B: 8 sliding, 2 global). Leave None for symmetric models.
    num_global_kv_heads: Optional[int] = None
    # MoE fields (None for dense models; set for MoE variants)
    num_experts: Optional[int] = None
    num_experts_per_tok: Optional[int] = None
    moe_intermediate_size: Optional[int] = None
    shared_expert_intermediate_size: Optional[int] = None
    active_params_b: Optional[float] = None
    # Optional architectural metadata
    mtp_num_hidden_layers: Optional[int] = None
    attn_output_gate: Optional[bool] = None
    vision_capable: Optional[bool] = None
    # C12 (KV projection via tools/kv-calc.py) only supports models whose
    # architecture has been added to MODEL_SPECS in kv-calc.py. New MoE /
    # hybrid models can set kv_calc_supported=false to skip C12 until
    # kv-calc gains MoE-aware activation/KV formulas.
    kv_calc_supported: bool = True

    def hf_repos_for(self, variant: str) -> tuple[str, ...]:
        """v0.8.0 Pull-Gate — full HF slugs that resolve to this model's
        ``weights.<variant>``. Empty tuple when the variant declares none.

        Surfaced from ``weights.<variant>.hf_repos`` (a variant-scoped, NOT
        model-level, schema field — Codex-r5 Med-3). ``_model()`` normalizes
        every variant to carry an ``hf_repos`` list so this never KeyErrors;
        consumers that predate v0.8.0 are unaffected (they never read it)."""
        meta = self.weights.get(variant) or {}
        return tuple(meta.get("hf_repos", ()) or ())

    def all_hf_repos(self) -> dict[str, tuple[str, ...]]:
        """Map of weights_variant -> tuple of HF slugs for this model."""
        return {
            variant: tuple(meta.get("hf_repos", ()) or ())
            for variant, meta in self.weights.items()
        }


@dataclass(frozen=True)
class WorkloadProfile:
    schema_version: int
    id: str
    display_name: str
    description: str
    priorities: dict[str, str]
    defaults: dict[str, Any]
    requires_features: tuple[str, ...]


@dataclass(frozen=True)
class EngineProfile:
    schema_version: int
    id: str
    display_name: str
    type: str
    stability: str
    install: dict[str, Any]
    min_sm: float
    supported_model_families: tuple[str, ...]
    features: dict[str, Any]
    supported_kv_formats: tuple[str, ...]
    supported_drafters: tuple[str, ...]
    supported_weight_formats: tuple[str, ...]
    required_overlays: tuple[Any, ...]
    vendored_overlays: tuple[Any, ...]
    required_genesis: bool
    feature_provenance: dict[str, Any] = field(default_factory=dict)
    genesis_pin: Optional[str] = None
    notes: Optional[str] = None


@dataclass(frozen=True)
class DrafterProfile:
    schema_version: int
    id: str
    display_name: str
    spec_method: str
    model_compat: tuple[str, ...]
    n_default: int
    n_max: int
    download: Any
    vram_footprint_gb: Any
    status: str
    engine_compat: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class CalibrationProfile:
    schema_version: int
    model: str
    rows: tuple[dict[str, Any], ...]


@dataclass(frozen=True)
class Profiles:
    hardware: dict[str, HardwareProfile]
    models: dict[str, ModelProfile]
    workloads: dict[str, WorkloadProfile]
    engines: dict[str, EngineProfile]
    drafters: dict[str, DrafterProfile]
    calibration: dict[str, CalibrationProfile] = field(default_factory=dict)


@dataclass
class FitsResult:
    valid: bool
    reasons: list[str] = field(default_factory=list)
    notes: list[str] = field(default_factory=list)
    recommended_kv_format: Optional[str] = None
    effective_mem_util: Optional[float] = None
    effective_max_ctx: Optional[int] = None
    effective_max_num_seqs: Optional[int] = None
    effective_cudagraph_mode: Optional[str] = None
    world_size: Optional[int] = None
    bottleneck_vram_gb: Optional[float] = None
    homogeneous: Optional[bool] = None
    topology_class: Optional[TopologyClass] = None
    kv_projection: Optional[dict[str, Any]] = None
    compose_name: Optional[str] = None
    weights_variant: Optional[str] = None
    diagnostics: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class InstanceSpec:
    """One endpoint in a multi-model estate."""

    name: str
    compose_name: str
    gpu_indices: tuple[int, ...]
    port: int


@dataclass
class EstateResult:
    valid: bool
    per_instance: dict[str, FitsResult]
    cross_instance_failures: list[str]
    notes: list[str]
    diagnostics: dict[str, Any]


def _check_schema(path: Path, data: dict[str, Any]) -> None:
    version = data.get("schema_version")
    if version not in SUPPORTED_SCHEMA_VERSIONS:
        msg = (
            f"{path.relative_to(PROFILE_ROOT)} has unsupported schema_version={version}. "
            "Upgrade club-3090 profile tooling or pin older profiles."
        )
        _logger().error(msg)
        raise UnsupportedSchemaVersionError(msg)


def _load_yaml(path: Path) -> dict[str, Any]:
    log = _logger()
    try:
        with path.open("r", encoding="utf-8") as fh:
            data = yaml.safe_load(fh) or {}
    except yaml.YAMLError as exc:
        log.error("failed to load %s: %s", path, exc)
        raise ProfileError(f"failed to load {path}: {exc}") from exc
    _check_schema(path, data)
    log.debug("loaded %s", path.relative_to(PROFILE_ROOT))
    return data


def _load_dir(root: Path, subdir: str, factory) -> dict[str, Any]:
    out = {}
    for path in sorted((root / subdir).glob("*.yml")):
        data = _load_yaml(path)
        profile = factory(data)
        out[profile.id if hasattr(profile, "id") else profile.model] = profile
    return out


def _hardware(data: dict[str, Any]) -> HardwareProfile:
    return HardwareProfile(
        schema_version=data["schema_version"],
        id=data["id"],
        display_name=data["display_name"],
        sm=float(data["sm"]),
        vram_gb=float(data["vram_gb"]),
        arch=data["arch"],
        mem_util_safe=float(data["mem_util_safe"]),
        supported_kv_formats=_tuple(data.get("supported_kv_formats")),
        kv_format_default=_dict(data.get("kv_format_default")),
        cudagraph=data.get("cudagraph", "full"),
        driver_pin_recommended=_dict(data.get("driver_pin_recommended")),
        nvlink_capable=bool(data.get("nvlink_capable", False)),
        power_cap_w_optimal=data.get("power_cap_w_optimal"),
        power_cap_w_prefill=data.get("power_cap_w_prefill"),
        power_cap_w_max=data.get("power_cap_w_max"),
        notes=data.get("notes"),
    )


def _normalize_weights(raw: Any) -> dict[str, dict[str, Any]]:
    """v0.8.0 Pull-Gate — preserve ``weights.<variant>.hf_repos`` (P2 owns
    this schema edit). ``_dict()`` already kept nested variant keys by
    reference; here we additionally guarantee every variant carries an
    ``hf_repos`` list (default ``[]``) so ``ModelProfile.hf_repos_for`` and
    the cross-ref invariants never have to special-case absence. Variant
    sub-dicts are shallow-copied so the normalized default does not leak back
    into the YAML-loaded cache. Additive: no existing key is altered."""
    out: dict[str, dict[str, Any]] = {}
    for variant, meta in dict(raw or {}).items():
        meta = dict(meta or {})
        repos = meta.get("hf_repos")
        if repos is None:
            meta["hf_repos"] = []
        else:
            meta["hf_repos"] = [str(r) for r in repos]
        out[variant] = meta
    return out


def _model(data: dict[str, Any]) -> ModelProfile:
    return ModelProfile(
        schema_version=data["schema_version"],
        id=data["id"],
        display_name=data["display_name"],
        family=data["family"],
        hidden_size=int(data["hidden_size"]),
        intermediate_size=data.get("intermediate_size"),
        num_hidden_layers=int(data["num_hidden_layers"]),
        num_gdn_layers=data.get("num_gdn_layers"),
        num_attn_layers=data.get("num_attn_layers"),
        num_full_attn_layers=data.get("num_full_attn_layers"),
        num_sliding_attn_layers=data.get("num_sliding_attn_layers"),
        num_attn_heads=int(data["num_attn_heads"]),
        num_kv_heads=int(data["num_kv_heads"]),
        head_dim_attn=data.get("head_dim_attn"),
        linear_num_v_heads=data.get("linear_num_v_heads"),
        linear_num_k_heads=data.get("linear_num_k_heads"),
        linear_v_head_dim=data.get("linear_v_head_dim"),
        linear_k_head_dim=data.get("linear_k_head_dim"),
        linear_conv_kernel_dim=data.get("linear_conv_kernel_dim"),
        head_dim_sliding=data.get("head_dim_sliding"),
        global_head_dim=data.get("global_head_dim"),
        sliding_window=data.get("sliding_window"),
        num_global_kv_heads=data.get("num_global_kv_heads"),
        num_experts=data.get("num_experts"),
        num_experts_per_tok=data.get("num_experts_per_tok"),
        moe_intermediate_size=data.get("moe_intermediate_size"),
        shared_expert_intermediate_size=data.get("shared_expert_intermediate_size"),
        active_params_b=data.get("active_params_b"),
        mtp_num_hidden_layers=data.get("mtp_num_hidden_layers"),
        attn_output_gate=data.get("attn_output_gate"),
        vision_capable=data.get("vision_capable"),
        max_ctx_supported=int(data["max_ctx_supported"]),
        attention_k_eq_v=bool(data["attention_k_eq_v"]),
        weights=_normalize_weights(data.get("weights")),
        default_weight_variant=data["default_weight_variant"],
        compatible_drafters=_tuple(data.get("compatible_drafters")),
        valid_tp=tuple(int(x) for x in _tuple(data.get("valid_tp"))),
        requires_genesis=bool(data.get("requires_genesis", False)),
        kv_calc_supported=bool(data.get("kv_calc_supported", True)),
    )


def _workload(data: dict[str, Any]) -> WorkloadProfile:
    return WorkloadProfile(
        schema_version=data["schema_version"],
        id=data["id"],
        display_name=data["display_name"],
        description=data.get("description", ""),
        priorities=_dict(data.get("priorities")),
        defaults=_dict(data.get("defaults")),
        requires_features=_tuple(data.get("requires_features")),
    )


def _engine(data: dict[str, Any]) -> EngineProfile:
    return EngineProfile(
        schema_version=data["schema_version"],
        id=data["id"],
        display_name=data["display_name"],
        type=data["type"],
        stability=data["stability"],
        install=_dict(data.get("install")),
        min_sm=float(data["min_sm"]),
        supported_model_families=_tuple(data.get("supported_model_families")),
        features=_dict(data.get("features")),
        feature_provenance=_dict(data.get("feature_provenance")),
        supported_kv_formats=_tuple(data.get("supported_kv_formats")),
        supported_drafters=_tuple(data.get("supported_drafters")),
        supported_weight_formats=_tuple(data.get("supported_weight_formats")),
        required_overlays=_tuple(data.get("required_overlays")),
        vendored_overlays=_tuple(data.get("vendored_overlays")),
        required_genesis=bool(data.get("required_genesis", False)),
        genesis_pin=data.get("genesis_pin"),
        notes=data.get("notes"),
    )


def _drafter(data: dict[str, Any]) -> DrafterProfile:
    return DrafterProfile(
        schema_version=data["schema_version"],
        id=data["id"],
        display_name=data["display_name"],
        spec_method=data["spec_method"],
        model_compat=_tuple(data.get("model_compat")),
        engine_compat=_dict(data.get("engine_compat")),
        n_default=int(data["n_default"]),
        n_max=int(data["n_max"]),
        download=data.get("download"),
        vram_footprint_gb=data.get("vram_footprint_gb"),
        status=data["status"],
    )


def _calibration(data: dict[str, Any]) -> CalibrationProfile:
    return CalibrationProfile(
        schema_version=data["schema_version"],
        model=data["model"],
        rows=tuple(dict(row) for row in data.get("rows", [])),
    )


def _known(items: dict[str, Any]) -> str:
    return ", ".join(sorted(items))


def _validate_cross_refs(profiles: Profiles) -> None:
    failures: list[str] = []

    for model in profiles.models.values():
        if model.default_weight_variant not in model.weights:
            failures.append(
                f"models/{model.id}.yml default_weight_variant `{model.default_weight_variant}` "
                f"not in weights. Available variants: {', '.join(sorted(model.weights))}"
            )
        for drafter_id in model.compatible_drafters:
            if drafter_id not in profiles.drafters:
                failures.append(
                    f"models/{model.id}.yml references unknown drafter `{drafter_id}`. "
                    f"Available drafters: {_known(profiles.drafters)}"
                )

    # v0.8.0 Pull-Gate schema invariants (Codex-r5 Med-3):
    #   (1) every hf_repos slug is globally unique across all variants/models;
    #   (2) hf_repos only attaches to safetensors-compatible variants — a
    #       gguf / non-safetensors variant must carry none (the deriver
    #       surfaces a slug→gguf collision as honest stratum-1
    #       `unsupported-format`, never a silent mismatch).
    _NON_SAFETENSORS_FORMATS = {"gguf"}
    seen_slugs: dict[str, str] = {}
    for model in profiles.models.values():
        for variant, meta in model.weights.items():
            repos = meta.get("hf_repos", []) or []
            fmt = str(meta.get("format", "")).lower()
            if repos and fmt in _NON_SAFETENSORS_FORMATS:
                failures.append(
                    f"models/{model.id}.yml weights.{variant}.hf_repos is set "
                    f"but format={fmt!r} is not safetensors-compatible "
                    f"(hf_repos must only attach to safetensors variants)"
                )
            for slug in repos:
                key = str(slug).strip().lower()
                where = f"{model.id}.weights.{variant}"
                if key in seen_slugs:
                    failures.append(
                        f"hf_repos slug `{slug}` is not globally unique: "
                        f"declared on both {seen_slugs[key]} and {where}"
                    )
                else:
                    seen_slugs[key] = where

    for drafter in profiles.drafters.values():
        for model_id in drafter.model_compat:
            if model_id not in profiles.models:
                failures.append(
                    f"drafters/{drafter.id}.yml references unknown model `{model_id}`. "
                    f"Available models: {_known(profiles.models)}"
                )

    for cal in profiles.calibration.values():
        if cal.model not in profiles.models:
            failures.append(
                f"calibration/{cal.model}.yml references unknown model `{cal.model}`. "
                f"Available models: {_known(profiles.models)}"
            )
        for row in cal.rows:
            compose = row.get("compose")
            if compose not in COMPOSE_REGISTRY:
                failures.append(f"calibration/{cal.model}.yml references unknown compose `{compose}`")

    for name, entry in COMPOSE_REGISTRY.items():
        for field_name, table in (
            ("model", profiles.models),
            ("workload", profiles.workloads),
            ("engine", profiles.engines),
        ):
            ref = entry.get(field_name)
            if ref not in table:
                failures.append(f"COMPOSE_REGISTRY[{name!r}].{field_name} references unknown `{ref}`")
        drafter_id = entry.get("drafter")
        if drafter_id is not None and drafter_id not in profiles.drafters:
            failures.append(f"COMPOSE_REGISTRY[{name!r}].drafter references unknown `{drafter_id}`")
        model = profiles.models.get(entry.get("model"))
        if model and entry.get("weights_variant") not in model.weights:
            failures.append(
                f"COMPOSE_REGISTRY[{name!r}].weights_variant references unknown "
                f"`{entry.get('weights_variant')}` for {model.id}"
            )
        if "default_port" not in entry:
            failures.append(f"COMPOSE_REGISTRY[{name!r}] missing default_port")
        if "gpu_assignment_mode" not in entry:
            failures.append(f"COMPOSE_REGISTRY[{name!r}] missing gpu_assignment_mode")

    if failures:
        msg = "cross-reference validation failed:\n  " + "\n  ".join(failures)
        _logger().error(msg)
        raise CrossReferenceError(msg)


def load_profiles(root: Path = PROFILE_ROOT) -> Profiles:
    """Load profile YAML files and validate all cross-references."""

    log = _logger()
    root = Path(root)
    profiles = Profiles(
        hardware=_load_dir(root, "hardware", _hardware),
        models=_load_dir(root, "models", _model),
        workloads=_load_dir(root, "workloads", _workload),
        engines=_load_dir(root, "engines", _engine),
        drafters=_load_dir(root, "drafters", _drafter),
        calibration=_load_dir(root, "calibration", _calibration),
    )
    _validate_cross_refs(profiles)

    cal_counts = ", ".join(f"{model}={len(cal.rows)}" for model, cal in sorted(profiles.calibration.items()))
    log.info(
        "Loaded %d profiles from %s",
        len(profiles.hardware) + len(profiles.models) + len(profiles.workloads)
        + len(profiles.engines) + len(profiles.drafters) + len(profiles.calibration),
        root,
    )
    log.info(
        "  hardware: %d, models: %d, workloads: %d, engines: %d, drafters: %d",
        len(profiles.hardware),
        len(profiles.models),
        len(profiles.workloads),
        len(profiles.engines),
        len(profiles.drafters),
    )
    log.info("  calibration rows: %s", cal_counts)
    log.info("  compose_registry entries: %d", len(COMPOSE_REGISTRY))
    return profiles


def _cudagraph_mode(hardware: list[HardwareProfile]) -> Optional[str]:
    if not hardware:
        return None
    rank = {"full": 0, "partial": 1, "enforce-eager": 2, "enforce-eager-required": 2}
    return max((hw.cudagraph for hw in hardware), key=lambda mode: rank.get(mode, 0))


def resolve_kv_format(workload: WorkloadProfile, hardware: list[HardwareProfile]) -> str:
    if not hardware:
        return "bf16"
    if workload.priorities.get("max_ctx") == "high":
        context = "long_context"
    elif workload.priorities.get("concurrency") == "high":
        context = "multi_stream"
    else:
        context = "balanced"

    candidates = [hw.kv_format_default.get(context) for hw in hardware]
    if len(set(candidates)) == 1 and candidates[0]:
        return candidates[0]
    if all("fp8_e5m2" in hw.supported_kv_formats for hw in hardware):
        return "fp8_e5m2"
    return "bf16"


def resolve_weights_variant(model: ModelProfile, engine: EngineProfile, explicit: Optional[str] = None) -> str:
    if explicit is not None:
        return explicit
    default = model.default_weight_variant
    default_format = model.weights.get(default, {}).get("format")
    if default_format in engine.supported_weight_formats:
        return default

    status_rank = {"production": 0, "experimental": 1, "historical": 2}
    variants = sorted(
        model.weights.items(),
        key=lambda item: (status_rank.get(item[1].get("status"), 99), list(model.weights).index(item[0])),
    )
    for name, meta in variants:
        if meta.get("format") in engine.supported_weight_formats:
            return name
    return default


def compatible_kv_formats(hardware: list[HardwareProfile], engine: EngineProfile) -> list[str]:
    supported = set(engine.supported_kv_formats)
    for hw in hardware:
        supported &= set(hw.supported_kv_formats)
    return sorted(supported)


def valid_tp_values(model: ModelProfile, world_size: int) -> list[int]:
    return [tp for tp in model.valid_tp if tp > 0 and world_size % tp == 0]


def compatible_drafters(
    model: ModelProfile,
    engine: EngineProfile,
    profiles: Optional[Profiles] = None,
) -> list[DrafterProfile]:
    profiles = profiles or load_profiles()
    out = []
    for drafter_id in model.compatible_drafters:
        drafter = profiles.drafters[drafter_id]
        if drafter.spec_method not in engine.supported_drafters:
            continue
        engine_type = drafter.engine_compat.get("engine_type")
        if engine_type and engine_type != engine.type:
            continue
        out.append(drafter)
    return out


def compatible_engines(
    hardware: list[HardwareProfile],
    model: ModelProfile,
    profiles: Optional[Profiles] = None,
) -> list[EngineProfile]:
    profiles = profiles or load_profiles()
    out = []
    for engine in profiles.engines.values():
        if any(hw.sm < engine.min_sm for hw in hardware):
            continue
        if engine.type == "vllm" and model.requires_genesis and not engine.required_genesis:
            continue
        if model.family not in engine.supported_model_families:
            continue
        out.append(engine)
    return out


def _kv_calc_weights_variant(model: ModelProfile, variant: str) -> str:
    # Intel AutoRound INT8 (W8A16) — ~half the bf16 footprint. Keyed on the
    # variant (not family) so gemma4-unified's single-card int8 path resolves to
    # kv-calc's int8 weight size instead of the bf16 fallback (was a false FAIL).
    if variant == "autoround-int8":
        return "int8"
    if model.family == "gemma4-swa-dense":
        if variant == "awq":
            return "awq"
        if variant == "bf16":
            return "bf16"
        return "int4"
    if model.family == "gemma4-swa-moe":
        if variant == "awq":
            return "awq"
        return "int4"
    if model.family == "qwen3-next-moe":
        if variant == "gptq_int4":
            return "gptq"
        return "default"
    return "default"


def _drafter_gb(drafter: Optional[DrafterProfile]) -> float:
    if drafter is None:
        return 0.0
    return float(_number_or_none(drafter.vram_footprint_gb) or 0.0)


def _run_kv_calc(
    *,
    model: ModelProfile,
    drafter: Optional[DrafterProfile],
    kv_format: str,
    max_ctx: int,
    max_num_seqs: int,
    tp: int,
    mem_util: float,
    vram_gb: float,
    weights_variant: str,
) -> tuple[Optional[dict[str, Any]], Optional[str]]:
    args = [
        "bash",
        str(REPO_ROOT / "tools/kv-calc.py"),
        "--model",
        model.id,
        "--kv-format",
        kv_format,
        "--max-ctx",
        str(max_ctx),
        "--max-num-seqs",
        str(max_num_seqs),
        "--tp",
        str(tp),
        "--mem-util",
        str(mem_util),
        "--vram",
        str(vram_gb),
        "--weights-variant",
        _kv_calc_weights_variant(model, weights_variant),
        "--json",
    ]
    if drafter and drafter.spec_method in {"mtp", "mtp_assistant"}:
        args.append("--mtp")
    else:
        args.append("--no-mtp")
    drafter_gb = _drafter_gb(drafter)
    if drafter_gb:
        args.extend(["--drafter-gb", str(drafter_gb)])

    proc = subprocess.run(args, cwd=REPO_ROOT, text=True, capture_output=True, check=False)
    if not proc.stdout.strip():
        return None, f"kv-calc.py produced no JSON (exit {proc.returncode}): {proc.stderr.strip()}"
    try:
        data = json.loads(proc.stdout)
    except json.JSONDecodeError as exc:
        return None, f"kv-calc.py produced invalid JSON: {exc}: {proc.stdout[:200]}"
    if proc.returncode not in (0, 1):
        return data, f"kv-calc.py failed with exit {proc.returncode}: {proc.stderr.strip()}"
    return data, None


def fits(
    hardware: list[HardwareProfile],
    model: ModelProfile,
    workload: WorkloadProfile,
    engine: EngineProfile,
    drafter: Optional[DrafterProfile] = None,
    *,
    tp: int = 1,
    pp: int = 1,
    kv_format: Optional[str] = None,
    max_ctx: Optional[int] = None,
    max_num_seqs: Optional[int] = None,
    mem_util: Optional[float] = None,
    weights_variant: Optional[str] = None,
    nvlink_active: bool = False,
    requires_nvlink: bool = False,
    required_engine_features: Optional[list[str]] = None,
    required_sm: Optional[float] = None,
    project_vram: bool = True,
) -> FitsResult:
    start = time.monotonic()
    reasons: list[str] = []
    notes: list[str] = []
    passed: list[str] = []
    failed: list[str] = []
    skipped: list[str] = []
    kv_projection: Optional[dict[str, Any]] = None
    kv_calc_invoked = False

    def ok(cid: str) -> None:
        passed.append(cid)

    def fail(cid: str, reason: str) -> None:
        failed.append(cid)
        reasons.append(f"{cid}: {reason}")

    def skip(cid: str, note: str) -> None:
        skipped.append(cid)
        notes.append(note)

    required_engine_features = list(required_engine_features or [])
    world_size = tp * pp
    effective_kv = kv_format or resolve_kv_format(workload, hardware)
    effective_mem_util = mem_util if mem_util is not None else min((hw.mem_util_safe for hw in hardware), default=None)
    effective_max_ctx = max_ctx if max_ctx is not None else model.max_ctx_supported
    effective_max_num_seqs = max_num_seqs if max_num_seqs is not None else int(workload.defaults.get("max_num_seqs", 1))
    effective_weights = resolve_weights_variant(model, engine, weights_variant)
    homogeneous = len({hw.id for hw in hardware}) <= 1
    topology_class = classify_hardware_topology(hardware) if hardware else None
    bottleneck = min((hw.vram_gb for hw in hardware), default=None)
    effective_cudagraph = _cudagraph_mode(hardware)

    if not homogeneous and hardware:
        smallest = min(hardware, key=lambda hw: hw.vram_gb)
        notes.append(f"Heterogeneous GPU set; bottleneck is {smallest.id} ({smallest.vram_gb:g} GB)")
        notes.append("Power-cap settings are not unified; tune per card")
        if tp > 1:
            notes.append("Tensor parallel on heterogeneous cards wastes VRAM on larger cards")
    if pp > 1:
        notes.append("Pipeline parallel (PP>1) is allowed but layer split is not benchmarked on this stack")

    if len(hardware) != world_size:
        fail("C1", f"tp={tp} * pp={pp} = {world_size} != {len(hardware)} cards selected")
    else:
        ok("C1")

    if tp not in model.valid_tp:
        fail("C2", f"tp={tp} not in model.valid_tp {list(model.valid_tp)} for {model.id}")
    else:
        ok("C2")

    min_sm = max(float(engine.min_sm), float(required_sm or engine.min_sm))
    low_sm = [hw for hw in hardware if hw.sm < min_sm]
    if low_sm:
        fail("C3", f"engine/compose requires sm >= {min_sm:g}; below floor: " + ", ".join(f"{hw.id}=sm_{hw.sm:g}" for hw in low_sm))
    else:
        ok("C3")

    if effective_kv not in engine.supported_kv_formats:
        fail("C4", f"kv_format={effective_kv} not in {engine.id}.supported_kv_formats {list(engine.supported_kv_formats)}")
    else:
        ok("C4")

    # fp8_e4m3 KV runs on Ampere (sm_86) ONLY for fp8-weights checkpoints: those route
    # to FlashInfer (native fp8 storage on Ampere), whereas non-fp8 weights (e.g. Gemma
    # W4A16) route to Triton, whose fp8e4nv path needs SM89+. `weights_variant` is a
    # validated proxy for that backend split — Qwen fp8 dual/multi-max WORK on the 3090
    # (#594: boot/decode/NIAH/quality/soak all green), while gemma-4-31b + fp8_e4m3 FAILS
    # at KV-init on the same sm_86/v0.24.0 stack (learnings/gemma-4-31b.md 2026-07-01).
    # So bypass the hardware supported_kv_formats gate for fp8_e4m3 + fp8-weights on
    # sm>=8.6 without listing fp8_e4m3 in the Ampere profile (keeps Gemma correctly
    # rejected). See docs/DTYPE_MATRIX.md. Caveat: a future Gemma-*fp8-weights* checkpoint
    # would route to Triton and still fail — this proxy would wrongly allow it; revisit then.
    _fp8w_ampere_kv = effective_kv == "fp8_e4m3" and str(effective_weights or "").startswith("fp8")
    unsupported_hw = [
        hw.id for hw in hardware
        if effective_kv not in hw.supported_kv_formats
        and not (_fp8w_ampere_kv and hw.sm >= 8.6)
    ]
    if unsupported_hw:
        fail("C5", f"kv_format={effective_kv} not supported by hardware: {', '.join(unsupported_hw)}")
    else:
        ok("C5")

    if engine.type == "vllm" and model.requires_genesis and not engine.required_genesis:
        fail("C6", f"{model.id}.requires_genesis=true; engine {engine.id}.required_genesis=false")
    else:
        ok("C6")

    if drafter is None:
        ok("C7")
        ok("C8")
        ok("C9")
    else:
        if drafter.spec_method not in engine.supported_drafters:
            fail("C7", f"drafter {drafter.id} has spec_method={drafter.spec_method}; {engine.id}.supported_drafters={list(engine.supported_drafters)} excludes it")
        else:
            ok("C7")
        if model.id not in drafter.model_compat:
            fail("C8", f"drafter {drafter.id}.model_compat={list(drafter.model_compat)} excludes {model.id}")
        else:
            ok("C8")
        engine_type = drafter.engine_compat.get("engine_type")
        if engine_type and engine_type != engine.type:
            fail("C9", f"drafter {drafter.id}.engine_compat.engine_type={engine_type}; selected engine type is {engine.type}")
        else:
            ok("C9")

    if model.family not in engine.supported_model_families:
        fail("C10", f"engine {engine.id} supported_model_families={list(engine.supported_model_families)} excludes {model.family}")
    else:
        ok("C10")

    if effective_max_ctx > model.max_ctx_supported:
        fail("C11", f"max_ctx={effective_max_ctx} > model.max_ctx_supported={model.max_ctx_supported}")
    else:
        ok("C11")

    if requires_nvlink and not nvlink_active:
        fail("C13", "compose requires active NVLink, but nvlink_active=false")
    elif requires_nvlink and any(not hw.nvlink_capable for hw in hardware):
        fail("C13", "compose requires NVLink, but not all selected cards are NVLink-capable")
    else:
        ok("C13")

    weight_meta = model.weights.get(effective_weights)
    if weight_meta is None:
        fail("C14", f"weights_variant={effective_weights} not in model.weights {list(model.weights)}")
    elif weight_meta.get("format") not in engine.supported_weight_formats:
        fail(
            "C14",
            f"model.weights.{effective_weights}.format={weight_meta.get('format')} not in "
            f"{engine.id}.supported_weight_formats {list(engine.supported_weight_formats)}",
        )
    else:
        ok("C14")

    missing_features = [feature for feature in required_engine_features if not engine.features.get(feature)]
    if missing_features:
        fail("C15", f"engine {engine.id} does not satisfy required features {missing_features}")
    else:
        ok("C15")

    if failed:
        skip("C12", "KV projection not run; resolve fast-constraint failures first.")
    elif not project_vram:
        skipped.append("C12")
        notes.append("KV projection skipped because project_vram=false")
    elif engine.type != "vllm":
        skipped.append("C12")
        notes.append("KV projection not available for non-vLLM engines")
    elif not model.kv_calc_supported:
        skipped.append("C12")
        notes.append(f"KV projection skipped: {model.id} not yet wired into tools/kv-calc.py")
    else:
        kv_calc_invoked = True
        if effective_mem_util is None or bottleneck is None:
            fail("C12", "cannot run KV projection without mem_util and bottleneck VRAM")
        else:
            kv_projection, err = _run_kv_calc(
                model=model,
                drafter=drafter,
                kv_format=effective_kv,
                max_ctx=effective_max_ctx,
                max_num_seqs=effective_max_num_seqs,
                tp=tp,
                mem_util=effective_mem_util,
                vram_gb=bottleneck,
                weights_variant=effective_weights,
            )
            if err:
                fail("C12", err)
            else:
                kv_projection = dict(kv_projection or {})
                kv_projection.setdefault("confidence", "HIGH")
                for note in kv_projection.get("notes", []):
                    notes.append(f"kv-calc: {note}")
                verdict = kv_projection.get("verdict")
                if verdict == "FAIL" and pp > 1:
                    kv_projection["verdict"] = "TIGHT"
                    kv_projection["confidence"] = "PP_ESTIMATE"
                    notes.append(
                        "PP>1 is not modelled by kv-calc; demoted C12 FAIL to advisory TIGHT "
                        "because per-card weights are conservatively over-counted"
                    )
                    ok("C12")
                elif verdict == "FAIL":
                    fail("C12", f"KV projection verdict FAIL: predicted total {kv_projection.get('total_gb')} GB/card > budget {kv_projection.get('budget_gb')} GB")
                else:
                    ok("C12")

    if topology_class is None:
        skip("C16", "Topology advisory not run; no hardware profiles provided.")
    else:
        ok("C16")
        advisory = TOPOLOGY_ADVISORY.get(topology_class)
        if advisory:
            notes.append(f"C16 topology={topology_class.value}: {advisory}")

    diagnostics = {
        "constraints_evaluated": list(CONSTRAINT_IDS),
        "constraints_passed": passed,
        "constraints_failed": failed,
        "constraints_skipped": skipped,
        "kv_calc_invoked": kv_calc_invoked,
        "elapsed_ms": round((time.monotonic() - start) * 1000, 3),
    }
    return FitsResult(
        valid=not reasons,
        reasons=reasons,
        notes=notes,
        recommended_kv_format=effective_kv,
        effective_mem_util=effective_mem_util,
        effective_max_ctx=effective_max_ctx,
        effective_max_num_seqs=effective_max_num_seqs,
        effective_cudagraph_mode=effective_cudagraph,
        world_size=world_size,
        bottleneck_vram_gb=bottleneck,
        homogeneous=homogeneous,
        topology_class=topology_class,
        kv_projection=kv_projection,
        weights_variant=effective_weights,
        diagnostics=diagnostics,
    )


def from_compose_name(
    name: str,
    hardware: list[HardwareProfile],
    nvlink_active: bool,
    profiles: Optional[Profiles] = None,
    *,
    project_vram: bool = True,
) -> FitsResult:
    profiles = profiles or load_profiles()
    if name not in COMPOSE_REGISTRY:
        return FitsResult(
            valid=False,
            reasons=[f"unknown compose `{name}`. Available composes: {', '.join(COMPOSE_REGISTRY)}"],
            diagnostics={
                "constraints_evaluated": [],
                "constraints_passed": [],
                "constraints_failed": [],
                "constraints_skipped": list(CONSTRAINT_IDS),
                "kv_calc_invoked": False,
                "elapsed_ms": 0.0,
            },
        )
    entry = COMPOSE_REGISTRY[name]
    drafter = profiles.drafters[entry["drafter"]] if entry.get("drafter") else None
    result = fits(
        hardware=hardware,
        model=profiles.models[entry["model"]],
        workload=profiles.workloads[entry["workload"]],
        engine=profiles.engines[entry["engine"]],
        drafter=drafter,
        tp=entry["tp"],
        pp=entry.get("pp", 1),
        kv_format=entry["kv_format"],
        max_ctx=entry["max_ctx"],
        max_num_seqs=entry["max_num_seqs"],
        mem_util=entry.get("mem_util"),
        weights_variant=entry["weights_variant"],
        nvlink_active=nvlink_active,
        requires_nvlink=bool(entry.get("requires_nvlink", False)),
        required_engine_features=list(entry.get("required_engine_features", [])),
        # fallback_sm (weight-only fallback floor, e.g. NVFP4→Marlin W4A16 @7.5)
        # replaces required_sm as the HARD floor when present — the C3 gate then
        # admits fallback-band hardware (sm_86 live-confirmed 2026-07-11).
        required_sm=entry.get("fallback_sm") or entry.get("required_sm"),
        project_vram=project_vram,
    )
    result.compose_name = name
    return result


def to_compose_name(
    model: ModelProfile,
    engine: EngineProfile,
    drafter: Optional[DrafterProfile],
    kv_format: str,
    tp: int,
    pp: int,
    *,
    workload: WorkloadProfile,
    weights_variant: str,
    nvlink_active: bool = False,
    max_ctx: Optional[int] = None,
    max_num_seqs: Optional[int] = None,
) -> Optional[str]:
    drafter_id = drafter.id if drafter else None
    for name, entry in COMPOSE_REGISTRY.items():
        if entry["model"] != model.id:
            continue
        if entry["engine"] != engine.id:
            continue
        if entry.get("drafter") != drafter_id:
            continue
        if entry["kv_format"] != kv_format:
            continue
        if entry["tp"] != tp or entry.get("pp", 1) != pp:
            continue
        if entry["workload"] != workload.id:
            continue
        if entry["weights_variant"] != weights_variant:
            continue
        if max_ctx is not None and entry["max_ctx"] != max_ctx:
            continue
        if max_num_seqs is not None and entry["max_num_seqs"] != max_num_seqs:
            continue
        if entry.get("requires_nvlink", False) and not nvlink_active:
            continue
        return name
    return None


def calibration_status(profiles: Profiles, compose_name: str, hardware: list[HardwareProfile], max_ctx: Optional[int] = None) -> tuple[str, Optional[dict[str, Any]]]:
    entry = COMPOSE_REGISTRY.get(compose_name)
    if not entry:
        return "predicted", None
    cal = profiles.calibration.get(entry["model"])
    if not cal:
        return "predicted", None
    vram = min((hw.vram_gb for hw in hardware), default=None)
    for row in cal.rows:
        if row.get("status") != "active":
            continue
        if row.get("compose") != compose_name:
            continue
        if vram is not None and float(row.get("vram_gb", -1)) != float(vram):
            continue
        ctx_override = row.get("ctx_override")
        if ctx_override is not None and max_ctx is not None and int(ctx_override) != int(max_ctx):
            continue
        return "verified", row
    return "predicted", None


def _dummy_instance_result(reason: str) -> FitsResult:
    return FitsResult(
        valid=False,
        reasons=[reason],
        diagnostics={
            "constraints_evaluated": [],
            "constraints_passed": [],
            "constraints_failed": [],
            "constraints_skipped": list(CONSTRAINT_IDS),
            "kv_calc_invoked": False,
            "elapsed_ms": 0.0,
        },
    )


def validate_estate(
    instances: list[InstanceSpec],
    hardware: list[HardwareProfile],
    profiles: Profiles,
    nvlink_active: bool,
    nvlink_pairs: Optional[list[tuple[int, int]]] = None,
) -> EstateResult:
    start = time.monotonic()
    per_instance: dict[str, FitsResult] = {}
    failures: list[str] = []
    notes: list[str] = []
    passed: list[str] = []
    failed: list[str] = []

    claimed: dict[int, list[str]] = {}
    ports: dict[int, list[str]] = {}
    normalized_pairs = {tuple(sorted(pair)) for pair in (nvlink_pairs or [])}

    for inst in instances:
        for idx in inst.gpu_indices:
            claimed.setdefault(idx, []).append(inst.name)
        ports.setdefault(inst.port, []).append(inst.name)

        bad_indices = [idx for idx in inst.gpu_indices if idx < 0 or idx >= len(hardware)]
        if bad_indices:
            per_instance[inst.name] = _dummy_instance_result(
                f"instance {inst.name} references GPU indices outside rig: {bad_indices}"
            )
            continue
        selected = [hardware[idx] for idx in inst.gpu_indices]
        per_instance[inst.name] = from_compose_name(
            inst.compose_name,
            hardware=selected,
            nvlink_active=nvlink_active,
            profiles=profiles,
        )

    e1_failures = []
    for idx, names in sorted(claimed.items()):
        if idx < 0 or idx >= len(hardware):
            e1_failures.append(f"GPU index {idx} is outside rig size {len(hardware)}")
        if len(names) > 1:
            e1_failures.append(f"GPU {idx} claimed by {', '.join(names)}")
    if e1_failures:
        failures.extend(f"E1: {msg}" for msg in e1_failures)
        failed.append("E1")
    else:
        passed.append("E1")

    passed.append("E2")
    notes.append("E2 no-op: all v0.7.0 compose entries use contiguous exclusive GPU assignment")

    e3_failures = []
    for inst in instances:
        entry = COMPOSE_REGISTRY.get(inst.compose_name, {})
        if not entry.get("requires_nvlink"):
            continue
        pair = tuple(sorted(inst.gpu_indices))
        if nvlink_active and len(pair) == 2 and normalized_pairs and pair not in normalized_pairs:
            e3_failures.append(
                f"instance {inst.name} uses {inst.compose_name} on GPUs {pair}, not in nvlink_pairs={sorted(normalized_pairs)}"
            )
        if nvlink_active and len(pair) != 2:
            e3_failures.append(f"instance {inst.name} requires one NVLink pair but has GPUs {pair}")
        if nvlink_active and normalized_pairs:
            for nv_pair in normalized_pairs:
                if set(pair) & set(nv_pair) and not set(nv_pair).issubset(set(pair)):
                    e3_failures.append(f"instance {inst.name} splits NVLink pair {nv_pair}")
    if e3_failures:
        failures.extend(f"E3: {msg}" for msg in e3_failures)
        failed.append("E3")
    else:
        passed.append("E3")

    e4_failures = [f"port {port} claimed by {', '.join(names)}" for port, names in sorted(ports.items()) if len(names) > 1]
    if e4_failures:
        failures.extend(f"E4: {msg}" for msg in e4_failures)
        failed.append("E4")
    else:
        passed.append("E4")

    if any(not result.valid for result in per_instance.values()):
        notes.append("One or more estate instances failed per-instance fits() validation")

    diagnostics = {
        "constraints_evaluated": list(ESTATE_CONSTRAINT_IDS),
        "constraints_passed": passed,
        "constraints_failed": failed,
        "constraints_skipped": [],
        "elapsed_ms": round((time.monotonic() - start) * 1000, 3),
    }
    return EstateResult(
        valid=not failures and all(result.valid for result in per_instance.values()),
        per_instance=per_instance,
        cross_instance_failures=failures,
        notes=notes,
        diagnostics=diagnostics,
    )
