A live review report (web-ui-system-darkmode, commit 4b2047e) flagged
two uncertainties a text-only diff review genuinely can't close: no
actual rendering checked, and contrast only "visually plausibilized"
from hex values. Adds a fixed, narrowly-scoped screenshot.py: given a
commit hash and a repo-relative .html path, it extracts that exact file
via `git show <hash>:<path>` (never the live working tree, which may
have moved on by review time) and renders it headless in both light and
dark prefers-color-scheme, for the Reviewer to inspect via its own Read
tool.
Wired only into run_review()'s Claude branch -- Codex's --sandbox
read-only blocks every write, so Chromium has nowhere to put a
screenshot there. --allowedTools gets a second, dynamically-built entry
pinning the exact resolved script invocation, same fixed-command
precedent as the existing Bash(git *) grant; the script re-validates
its own arguments regardless.
Two things verified live before wiring anything up, not assumed:
--force-prefers-color-scheme has no effect in this Chromium build
(--blink-settings=preferredColorScheme=<0|1> does, confirmed by actual
pixel color); and --allowedTools does honor a fixed-script pattern the
same way it honors Bash(git *). New pkgs.chromium dependency, run with
--no-sandbox since NoNewPrivileges=true already forbids the privilege
escalation Chromium's own setuid sandbox needs -- containment comes
from the outer systemd sandbox instead, a deliberate trade-off noted in
both the intent doc and README.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016w25covboHfcYuLXBAvX3g
5.5 KiB
5.5 KiB
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 übergit show <hash>:<pfad>(nie den möglicherweise inzwischen weitergelaufenen Arbeitsbaum), rendert ihn headless per Chromium je einmal mitprefers-color-scheme: lightund: darkund gibt beide PNG-Pfade auf stdout aus. - Empirisch verifiziert (10.09.2026), nicht angenommen:
--force-prefers-color-schemehat 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 ausBOARD_SCREENSHOT_SCRIPT/sys.executablezusammengesetzten--allowedTools-Eintrag, der ausschließlich genau diesen einen Skriptaufruf erlaubt (gleiches "Wrapper erzwingt, Modell schlägt vor"- Muster wie der bestehendeBash(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_TEMPLATEbekommt 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, sieheboard-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, dieNoNewPrivileges = trueaufboard-agent-worker.servicebereits 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-sandboxist zwingend unter den bestehenden systemd-Härtungsoptionen) — kein Versuch, das zu umgehen, da es dafür eine echte Kompromittierung der bestehendenNoNewPrivileges-Einstellung bräuchte.
Annahmen
- Board-getriggerte Reviews betreffen aktuell ausschließlich
board.htmlals 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.htmlzu (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 (SystemCallFiltero. Ä.) 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.chromiumist eine vergleichsweise schwere neue Abhängigkeit für ein sonst bewusst kleines, forkbares Grundsystem (siehedocs/operator-prompt.md§0) — explizit in Kauf genommen für diesen konkreten Anwendungsfall, kein Freibrief für weitere Browser-Automatisierung ohne erneute Abwägung.