# Intent: Visuelle Browser-Verifikation für den Board-Reviewer ## Ziel Der Reviewer-Bericht für `web-ui-system-darkmode` (Commit `4b2047e`) listete zwei "Unsicherheiten", die ein reines Text-Diff-Review nicht schließen kann: kein tatsächliches Rendering geprüft (nur die CSS-Variablenstruktur), keine berechnete WCAG-Kontrastprüfung, nur "visuell plausibilisiert anhand der gewählten Hex-Werte". Live-Diskussion auf dem Board selbst (10.09.2026): dem Reviewer eine echte visuelle Prüfmethode für HTML/CSS-Änderungen geben, statt nur aus dem Quelltext auf das Rendering zu schließen. ## Umfang - Neues, fixes Skript `board-agent/screenshot.py`: nimmt ausschließlich einen Commit-Hash und einen Repo-relativen `.html`-Pfad entgegen, extrahiert den exakten Dateiinhalt zum genannten Commit über `git show :` (nie den möglicherweise inzwischen weitergelaufenen Arbeitsbaum), rendert ihn headless per Chromium je einmal mit `prefers-color-scheme: light` und `: dark` und gibt beide PNG-Pfade auf stdout aus. - **Empirisch verifiziert (10.09.2026), nicht angenommen:** `--force-prefers-color-scheme` hat in der eingesetzten Chromium-Version headless keinerlei Effekt (identischer Output für beide Werte); erst `--blink-settings=preferredColorScheme=<0|1>` schaltet tatsächlich um (0 = dark, 1 = light, per gemessenem Pixelwert bestätigt, nicht aus der Enum-Reihenfolge angenommen). - `run_review()`s Claude-Zweig bekommt einen neuen, dynamisch aus `BOARD_SCREENSHOT_SCRIPT`/`sys.executable` zusammengesetzten `--allowedTools`-Eintrag, der ausschließlich genau diesen einen Skriptaufruf erlaubt (gleiches "Wrapper erzwingt, Modell schlägt vor"- Muster wie der bestehende `Bash(git *)`-Eintrag) — das Skript validiert seine beiden Argumente zusätzlich selbst (Commit-Hash-Form, `.html`-Endung, kein absoluter Pfad, kein `..`), unabhängig vom Allowlist-Muster. - `REVIEW_PROMPT_TEMPLATE` bekommt einen neuen, laufzeitabhängigen `{visual_verification}`-Abschnitt: für Claude die vollständige Gebrauchsanweisung inklusive des vorausgefüllten Befehls (Commit-Hash bereits eingesetzt, der Reviewer ergänzt nur noch den Dateipfad); für Codex/OpenRouter bleibt er leer. - Nur für die Claude-Runtime verdrahtet: Codex' `run_review()`-Zweig läuft mit `--sandbox read-only`, das jeden Schreibzugriff verweigert (verifiziert, siehe `board-agent/README.md`, "Why read-only, not a scoped writable dir") — Chromium hätte dort keinen Ort, um einen Screenshot abzulegen, also wird das Werkzeug dort erst gar nicht angeboten. - Neue Nix-Abhängigkeit `pkgs.chromium` (`BOARD_CHROMIUM_BIN`). Läuft mit `--no-sandbox`, da Chromiums eigener Setuid-Sandbox die Rechteausweitung braucht, die `NoNewPrivileges = true` auf `board-agent-worker.service` bereits verbietet — Eindämmung kommt in diesem Modus vollständig vom äußeren systemd-Sandbox (`ProtectSystem=strict`, `PrivateTmp`), nicht von Chromiums eigener Prozessisolation. Bewusster Kompromiss, kein Versehen: der gerenderte Inhalt ist in der Praxis ausschließlich dieses Repos eigene, bereits geprüfte Commits, nie Drittinhalte. - Ein fehlgeschlagener Screenshot-Aufruf (z. B. weil die Sandbox Chromium doch nicht starten lässt) ist laut Prompt kein Fehler des Reviews selbst — der Reviewer vermerkt das knapp unter "Unsicherheiten" und bewertet den Rest des Diffs normal weiter. ## Explizit ausgeschlossen - Keine automatische, berechnete WCAG-Kontrastprüfung (Diskussion ausdrücklich zugunsten des Browser-Screenshots vertagt) — der Reviewer beurteilt Kontrast weiterhin visuell aus dem Screenshot, nicht rechnerisch exakt. Eigener, separater Folgeintent, falls gewünscht. - Kein Einsatz für Codex/OpenRouter-Reviews (siehe oben, Sandbox-Grund). - Keine Ausweitung auf beliebige URLs oder externe Seiten — das Skript akzeptiert ausschließlich einen Repo-relativen `.html`-Pfad und lehnt jeden anderen selbst ab. - Keine Chromium-eigene Sandbox (`--no-sandbox` ist zwingend unter den bestehenden systemd-Härtungsoptionen) — kein Versuch, das zu umgehen, da es dafür eine echte Kompromittierung der bestehenden `NoNewPrivileges`-Einstellung bräuchte. ## Annahmen - Board-getriggerte Reviews betreffen aktuell ausschließlich `board.html` als einzige eigenständige HTML/CSS-Oberfläche dieses Repos (per Operator-Analyse zum Darkmode-Auftrag bereits bestätigt) — das Skript ist aber nicht auf diesen einen Dateinamen fest verdrahtet, falls eine zweite Oberfläche dazukommt. - Ein einzelnes, aus dem Commit extrahiertes HTML-Dokument ist selbstständig renderbar (kein externer Asset-Import über relative Pfade) — trifft auf `board.html` zu (vollständig inline CSS/JS), ist aber keine allgemeingültige Eigenschaft jeder künftigen HTML-Datei in diesem Repo. ## Offene Risiken - Noch nicht gegen den echten `board-agent-worker.service`-Sandbox live verifiziert (nur isoliert außerhalb des systemd-Sandbox getestet, 10.09.2026) — falls eine dort zusätzlich aktive Härtungsoption (`SystemCallFilter` o. Ä.) Chromium doch blockiert, greift der im Prompt vorgesehene "kein Fehler, nur Unsicherheiten-Vermerk"-Fallback, aber das ist noch nicht am echten Dienst beobachtet worden. - `pkgs.chromium` ist eine vergleichsweise schwere neue Abhängigkeit für ein sonst bewusst kleines, forkbares Grundsystem (siehe `docs/operator-prompt.md` §0) — explizit in Kauf genommen für diesen konkreten Anwendungsfall, kein Freibrief für weitere Browser-Automatisierung ohne erneute Abwägung.