"""Capability-Probe (PLAN.md §5, §5.2). Phase 0: plattformneutrale Basis-Erkennung (CPU/RAM/OS) und Tier-Vergabe nach gemessenen Fakten. GPU-/Decoder-/Display-Erkennung läuft auf dem Zielsystem (D3D11/GL/GLES); hier kein Fake-Ergebnis (§33: keine nicht getestete Dekodierung als Hardwarebeschleunigung ausgeben). """ from __future__ import annotations import enum class CapabilityTier(enum.StrEnum): DESKTOP_FULL = "DESKTOP_FULL" DESKTOP_LITE = "DESKTOP_LITE" PI_LITE = "PI_LITE" HEADLESS_CONTROL = "HEADLESS_CONTROL" # Mindest-VRAM für DESKTOP_FULL (§5) _DESKTOP_FULL_MIN_VRAM_GB = 8.0 def detect_cpu_ram() -> dict[str, object]: """Basis-Hardwareinformationen (plattformneutral, ohne Fake).""" import os import platform info: dict[str, object] = { "os": platform.system(), "os_release": platform.release(), "machine": platform.machine(), "cpu_count": os.cpu_count() or 1, "ram_total_gb": _ram_gb(), } return info def _ram_gb() -> float: """RAM in GB; Linux via /proc/meminfo, sonst -1 (unbekannt, nicht geraten).""" try: with open("/proc/meminfo", encoding="ascii") as fh: for line in fh: if line.startswith("MemTotal:"): kib = int(line.split()[1]) return round(kib / (1024 * 1024), 2) except (OSError, ValueError): pass return -1.0 class CapabilityReport: """Ergebnis des Capability-Selbsttests (Phase 0: Skelett). GPU/Decoder/Displays werden auf dem Zielsystem gemessen und hier ergänzt; ein Report ohne GPU-Messung kann kein DESKTOP-Tier vergeben. """ def __init__(self) -> None: self.cpu_ram = detect_cpu_ram() self.gpu: dict[str, object] | None = None self.decoders: dict[str, object] | None = None self.displays: dict[str, object] | None = None self.tier: CapabilityTier | None = None self.fingerprint: str = "" # an Messwerte gebunden (§5.2) def conclude_tier( self, has_gpu: bool, vram_gb: float | None, decode_ok: bool, has_display: bool, ) -> CapabilityTier | None: """Vergibt das Tier nach gemessenen Fakten; None wenn unklar. Unklar bedeutet: Gate 0 darf nicht grün melden, solange keine Messwerte vorliegen (§33). """ if not has_display: self.tier = CapabilityTier.HEADLESS_CONTROL return self.tier if not has_gpu or not decode_ok: return None if vram_gb is not None and vram_gb >= _DESKTOP_FULL_MIN_VRAM_GB: self.tier = CapabilityTier.DESKTOP_FULL else: self.tier = CapabilityTier.DESKTOP_LITE return self.tier def as_dict(self) -> dict[str, object]: return { "cpu_ram": self.cpu_ram, "gpu": self.gpu, "decoders": self.decoders, "displays": self.displays, "tier": self.tier.value if self.tier else None, "fingerprint": self.fingerprint, }