This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/intent/board-reviewer-visual-verification.md
pijukka 9cb6111fed board: give the Claude Reviewer real visual verification for HTML/CSS diffs
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
2026-09-10 19:01:05 +02:00

102 lines
5.5 KiB
Markdown

# 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
<hash>:<pfad>` (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.