#!/usr/bin/env python3 """Evaluate technical conformance separately from one named target consumer.""" from __future__ import annotations import argparse import json import subprocess import sys import tempfile from pathlib import Path from typing import Any VERDICTS = {"PASS", "FAIL", "BLOCKED", "UNVERIFIED"} class ContractError(Exception): pass def load(path: str, label: str) -> dict[str, Any]: try: value = json.loads(Path(path).read_text()) except (OSError, json.JSONDecodeError) as exc: raise ContractError(f"could not load {label}: {exc}") from exc if not isinstance(value, dict): raise ContractError(f"{label} root must be an object") return value def target_sources(target: dict[str, Any]) -> None: basis = target.get("requirement_basis") if basis not in {"official_documentation", "observed_behavior", "mixed"}: raise ContractError( "target requirement_basis must be official_documentation, observed_behavior, or mixed" ) sources = target.get("sources") if not isinstance(sources, list) or not sources: raise ContractError("target requirements need at least one source record") for source in sources: if ( not isinstance(source, dict) or not source.get("locator") or not source.get("accessed_at") or not source.get("claim") ): raise ContractError("each target source needs locator, accessed_at, and claim") if source.get("basis") not in {"official_documentation", "observed_behavior"}: raise ContractError("each target source needs an explicit evidence basis") def overall(*verdicts: str) -> str: for verdict in ("FAIL", "BLOCKED", "UNVERIFIED"): if verdict in verdicts: return verdict return "PASS" def run_technical(contract: dict[str, Any], probe_path: str) -> dict[str, Any]: isolated = dict(contract) isolated["downstream"] = {} with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temporary: json.dump(isolated, temporary) temporary.flush() command = [ sys.executable, str(Path(__file__).with_name("media-verify")), temporary.name, probe_path, "--json", ] result = subprocess.run(command, capture_output=True, text=True, check=False) try: report = json.loads(result.stdout) except json.JSONDecodeError as exc: raise ContractError("technical verifier did not return JSON") from exc if result.returncode == 2: raise ContractError(str(report.get("error", "invalid technical contract"))) report["boundary"] = "local_ffprobe_and_declared_technical_requirements" return report def add_maximum(criteria: list[dict[str, Any]], name: str, observed: Any, maximum: Any) -> str: try: actual = float(observed) limit = float(maximum) except (TypeError, ValueError): verdict = "UNVERIFIED" reason = "probe value or maximum is absent or nonnumeric" else: verdict = "PASS" if actual <= limit else "FAIL" reason = None if verdict == "PASS" else "observed value exceeds target maximum" criteria.append( { "criterion": name, "boundary": "target_technical_policy", "verdict": verdict, "expected": {"maximum": maximum}, "observed": observed, "evidence": "output probe", "reason": reason, } ) return verdict def downstream_result( target: dict[str, Any], lane: dict[str, Any], evidence: dict[str, Any] ) -> dict[str, Any]: target_id = target["id"] result = evidence.get("target_consumer") if isinstance(result, dict): verdict = result.get("status") if verdict not in VERDICTS: verdict = "UNVERIFIED" reason = "target-consumer status is missing or invalid" elif result.get("target_id") != target_id: verdict = "FAIL" reason = "target-consumer evidence names a different target" elif not result.get("artifact") or not result.get("method"): verdict = "UNVERIFIED" reason = "target-consumer evidence needs artifact identity and method" else: reason = result.get("reason") return { "target_id": target_id, "target_version": result.get("target_version"), "verdict": verdict, "method": result.get("method"), "artifact": result.get("artifact"), "warnings": result.get("warnings", []), "reason": reason, "boundary": "named_target_consumer", } unavailable = lane.get("unavailable_reason") return { "target_id": target_id, "target_version": None, "verdict": "BLOCKED" if unavailable else "UNVERIFIED", "method": lane.get("method"), "artifact": None, "warnings": [], "reason": unavailable or "no evidence from the named target consumer was supplied", "boundary": "named_target_consumer", } def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("manifest") parser.add_argument("output_probe") parser.add_argument("--target-evidence") parser.add_argument("--json", action="store_true") args = parser.parse_args() try: manifest = load(args.manifest, "compatibility manifest") probe = load(args.output_probe, "output probe") evidence = load(args.target_evidence, "target evidence") if args.target_evidence else {} if manifest.get("schema_version") != 1: raise ContractError("compatibility manifest schema_version must be 1") target = manifest.get("target") contract = manifest.get("technical_requirements") lane = manifest.get("target_lane") if not isinstance(target, dict) or not target.get("id") or not target.get("name"): raise ContractError("target needs id and name") if not isinstance(contract, dict) or not isinstance(lane, dict): raise ContractError("technical_requirements and target_lane must be objects") target_sources(target) technical = run_technical(contract, args.output_probe) limits = manifest.get("target_limits", {}) if not isinstance(limits, dict): raise ContractError("target_limits must be an object") limit_verdicts: list[str] = [] if "maximum_duration_seconds" in limits: limit_verdicts.append( add_maximum( technical["criteria"], "target_maximum_duration", probe.get("format", {}).get("duration"), limits["maximum_duration_seconds"], ) ) if "maximum_file_size_bytes" in limits: limit_verdicts.append( add_maximum( technical["criteria"], "target_maximum_file_size", probe.get("format", {}).get("size"), limits["maximum_file_size_bytes"], ) ) technical["overall_verdict"] = overall(technical["overall_verdict"], *limit_verdicts) target_result = downstream_result(target, lane, evidence) verdict = overall(technical["overall_verdict"], target_result["verdict"]) payload = { "ok": verdict == "PASS", "schema_version": 1, "target": target, "requirements_provenance": target["sources"], "technical_probe_result": technical, "target_consumer_result": target_result, "overall_verdict": verdict, "boundary_statement": f"This result applies only to target {target['id']}; local FFprobe/FFmpeg success and this target result do not establish compatibility with any other player, editor, host, archive, or service.", "platform_operation": "not_performed", } print( json.dumps(payload, sort_keys=True, separators=(",", ":")) if args.json else json.dumps(payload, indent=2, sort_keys=True) ) return 0 if verdict == "PASS" else 1 except ContractError as exc: print( json.dumps({"ok": False, "status": "INVALID_INPUT", "error": str(exc)}, sort_keys=True) ) return 2 if __name__ == "__main__": raise SystemExit(main())