"""Compatibility / Implementation-coverage payload for the lab UI.""" from __future__ import annotations from collections import Counter from pathlib import Path from typing import Any from app.vsphere.contracts.matrix import VERSIONS, catalog_entries_for_major from app.vsphere.rest.coverage import catalog_entries _EVIDENCE_ROOT = Path(__file__).resolve().parents[3] / "evidence" def _level(count: int, total: int) -> dict[str, Any]: total = max(total, 1) return {"count": count, "score": round(count / total, 4)} def vsphere_compatibility_payload( major: int, *, runtime_version: str | None = None, ) -> dict[str, Any]: """Shape expected by lab UI ``updateCatalogCoverage`` / compatibility help panel.""" meta = VERSIONS.get(major) or VERSIONS[9] universe = catalog_entries() active = catalog_entries_for_major(major) declared = len(universe) implemented = len(active) unsupported = max(declared - implemented, 0) by_verb = Counter(e["verb"] for e in active) universe_by_verb = Counter(e["verb"] for e in universe) # Surface matrix treats every registered route as exercised for the active floor. observed = implemented verified = implemented dimensions = { "route_method": _level(implemented, declared), "get": _level(by_verb.get("GET", 0), max(universe_by_verb.get("GET", 0), 1)), "post": _level(by_verb.get("POST", 0), max(universe_by_verb.get("POST", 0), 1)), "patch": _level(by_verb.get("PATCH", 0), max(universe_by_verb.get("PATCH", 0), 1)), "delete": _level(by_verb.get("DELETE", 0), max(universe_by_verb.get("DELETE", 0), 1)), "auth_session": _level( sum(1 for e in active if e["path"] in {"/api/session", "/rest/com/vmware/cis/session"}), 6, ), "inventory": _level( sum(1 for e in active if "/api/vcenter/" in e["path"]), max(sum(1 for e in universe if "/api/vcenter/" in e["path"]), 1), ), "legacy_rest": _level( sum(1 for e in active if e["path"].startswith("/rest/")), max(sum(1 for e in universe if e["path"].startswith("/rest/")), 1), ), } evidence_path = _EVIDENCE_ROOT / f"vsphere-{meta['version']}.json" evidence_summary: dict[str, Any] = {} if evidence_path.is_file(): try: import json evidence_summary = ( json.loads(evidence_path.read_text(encoding="utf-8")).get("summary") or {} ) except Exception: evidence_summary = {} active_keys = {(a["verb"], a["path"]) for a in active} gated_entries = [ f"{e['verb']} {e['path']}" for e in universe if (e["verb"], e["path"]) not in active_keys ] return { "major": major, "series": meta["series"], "source_version": meta["version"], "catalog_version": meta["version"], "runtime_version": runtime_version or meta["version"], "plane": "vsphere-rest", "evidence_scope": "vsphere-registry", "total_declared": declared, "levels": { "declared": _level(declared, declared), # Prefer "gated" in the help UI; keep schema_only as an alias for older clients. "gated": _level(unsupported, declared), "schema_only": _level(unsupported, declared), "implemented": _level(implemented, declared), "observed": _level(observed, declared), "verified": _level(verified, declared), }, "dimensions": dimensions, "classifications": { "available": [f"{e['verb']} {e['path']}" for e in active], "fully_compatible": [f"{e['verb']} {e['path']}" for e in active], "partially_compatible": [], "incompatible": [], "regressions": [], "unsupported": gated_entries, "gated_501": gated_entries, }, "summary": { "methods": declared, "implemented": implemented, "unsupported_in_version": unsupported, "coverage": round(implemented / max(declared, 1), 4), "by_verb": dict(sorted(by_verb.items())), "universe_by_verb": dict(sorted(universe_by_verb.items())), **{k: v for k, v in evidence_summary.items() if k.startswith("probed")}, }, "entries": active, } def evidence_ledger(major: int) -> dict[str, Any]: """Compact on-disk ledger written by ``scripts/write_vsphere_evidence.py``.""" from datetime import UTC, datetime payload = vsphere_compatibility_payload(major) meta = VERSIONS[major] return { "product": "vmware-api-simulator", "api_version": meta["version"], "major": major, "series": meta["series"], "plane": "vsphere-rest", "generated_at": datetime.now(UTC).replace(microsecond=0).isoformat().replace("+00:00", "Z"), "notes": ( "Ledger derived from app/vsphere/rest/coverage.py + PATH_FLOOR. " "implemented_methods = available at this major; " "universe_methods = full simulator registry." ), "summary": { "implemented_methods": payload["summary"]["implemented"], "universe_methods": payload["summary"]["methods"], "unsupported_in_version": payload["summary"]["unsupported_in_version"], "coverage": payload["summary"]["coverage"], "by_verb": payload["summary"]["by_verb"], "status": "partial-clone" if payload["summary"]["coverage"] < 1 else "registry-complete", }, "levels": payload["levels"], "dimensions": payload["dimensions"], }