Verify Finite
Finite hat zwei Oberflächen, und die meisten Funktionen benötigen beide. Agenten bearbeiten Designs über MCP-Tools unter /mcp (die sechs doc6-Tools; call steuert die klassischen Tools unter /mcp/classic). Menschen schauen im Browser zu: die Designliste unter / und die Leinwand unter /design/?id=<designId>. Ein Beweis steuert die Agentenseite mit call und überprüft die menschliche Seite in der Seite, oder umgekehrt für Kommentare.
Die Testumgebung ist e2e/headless.mjs. .agents/skills/finite-headless/SKILL.md ist die dazugehörige Befehlsreferenz (Selektoren, die in Shadow Roots, sandboxed Iframes, --agent, Python hineinreichen). Lese sie einmal durch, bevor du deine erste Fahrt startest. Dieses Skill fügt Isolation, einen Doktor, einen Beweisordner, Vorher-/Nachher-Läufe und die Feature-Map hinzu.
Jeder folgende Befehl wird vom Checkout-Root aus ausgeführt:
V=.agents/skills/verify-finite/scripts/verify.sh
Shell-Variablen überleben nicht zwischen Tool-Aufrufen. Wiederhole V=... und RUN=... zu Beginn jedes Aufrufs.
Schritte
- Wähle Features aus. Finde die Features, die deine Änderung berührt, in der Tabelle unter „Which features a change touches“ in
features/README.md. - Starte einen Lauf mit deinem Code. Starte für einen Bugfix auch einen zweiten Lauf mit dem Code vor dem Fix (siehe „Vorher und nachher“).
- Untersuche jeden Lauf, bis er nur noch
ok-Zeilen ausgibt. - Steuere jeden Einstiegspunkt in jeder ausgewählten Feature-Datei an und sichere dabei Beweise.
- Räume jeden gestarteten Lauf auf, einschließlich fehlgeschlagener Läufe.
- Berichte im Format unter „Bericht“.
Du bist fertig, wenn jeder Einstiegspunkt jedes ausgewählten Features bewiesen, mit einem Grund übersprungen oder mit Beweisen fehlgeschlagen ist und $V list nichts Laufendes anzeigt.
Starten
$V launch # baut den Server, finite.wasm und die Web-App und startet sie dann
$V launch --no-build # verwendet die letzten Builds; wird verweigert, wenn sich der Code seit deren Erstellung geändert hat
$V launch --width 390 --height 844 # eine seite in Telefongröße (Standard ist 1440 × 900)
$V launch --at main # ein Lauf eines anderen Commits, in einem temporären Checkout (siehe „Vorher und nachher“)
Es gibt RUN=<run> aus. Merke dir diese ID: Jeder andere Befehl verwendet sie. Ein Kaltstart dauert etwa 2 Minuten, ein Build ohne Änderungen nur wenige Sekunden. Setze das Bash-Timeout auf 600000. --no-build spart nur die wenigen Sekunden eines Builds ohne Arbeit, also lass es bei Zweifeln weg.
Der Start ist abgeschlossen, wenn Finite at http://127.0.0.1:<port> ausgegeben wird. Die Testumgebung wartet auf /api/health und lädt die Designliste, bevor sie diese Zeile ausgibt. Der Datenordner ist anfangs leer, es gibt keine Seed-Daten, Migrationen oder Login. Eine Person postet Kommentare als „Guest“ und Agenten als „Agent“, es sei denn, du übergibst --agent <name>.
Jeder Lauf ist eine separate Sitzung (verify-<run>) mit eigenem freiem Port, temporärem Datenordner und Chrome-Profil, sodass Läufe nebeneinander laufen können. Steuere niemals ein Finite, das du nicht selbst gestartet hast. vp run dev bedient die echten Designs des Benutzers aus crates/server/data, und die Desktop-App bedient ebenfalls die eigenen Daten des Benutzers. Der Doktor schlägt bei einer Sitzung fehl, die sich mit einem fremden Server verbunden hat.
Ein Lauf stoppt sich selbst nach 30 Minuten Inaktivität. Danach schlägt doctor fehl: Räume auf und starte erneut.
Untersuchen (Doctor)
$V doctor $RUN
Es liest nur den Zustand aus, und jede Zeile sagt ok oder FAIL. Es prüft fünf Dinge:
- Die Sitzung lebt und besitzt einen privaten Ordner
finite-headless-data-*. /api/healthantwortet mitokund der Version auspackage.json.- Der laufende Build stimmt mit dem Code überein. Es vergleicht einen Hash der Build-Eingaben (
crates/,apps/web/, die Testumgebung, die Lockfiles, einschließlich unversionierter Dateien) mit dem Hash des Codes, aus dem der Lauf erstellt wurde. Bearbeitungen von Docs, Skills oder Tests zählen nicht. - Ein Chrome, Chromium oder Edge ist für
get_screenshotverfügbar. - Die Seite antwortet.
Dann gibt es die Konsolenausgabe der Seite seit dem letzten Aufruf aus. Führe es zuerst aus, nach jeder Überraschung und bevor du den endgültigen Beweis sicherst. Bei einem FAIL räume auf und starte neu, anstatt weiterzufahren. Wenn du Code änderst, schlägt die Build-Prüfung absichtlich fehl: Räume auf und starte neu.
Steuern (Drive)
$V h $RUN <command> ... führt jeden e2e/headless.mjs-Befehl für diesen Lauf aus. Die Befehle, die du am häufigsten verwenden wirst:
$V h $RUN call create_design '{"name":"Verify"}' # Agentenseite: gibt designId "<id>" aus
$V h $RUN call create_artboard @input.json # JSON inline, @file oder - für stdin
$V h $RUN design <designId> # Menschliche Seite: Leinwand öffnen, auf Artboards warten
$V h $RUN snapshot --selector main # Accessibility-Tree, was ein Mensch sieht
$V h $RUN click 'button[title="Kommentar (C)"]'
$V h $RUN click '[data-artboard] >>> h1' --shift # Umschalt+Klick
$V h $RUN upload 'input[type=file]' card.html # Datei auswählen, wie der OS-Dialog
$V h $RUN api GET /api/designs/<designId> # Das gespeicherte Design, inklusive Kommentare
Verwende diese stabilen Bezeichner. Sie sind die zugänglichen Namen und Titel der App:
| Wo | Bezeichner |
|---|---|
| Designliste | Überschrift Designs, Schaltfläche Neues Design, Suchfeld Designs nach Namen durchsuchen, ein link pro Designkarte |
| Leinwand oben | Link ← Designs, button[title="CSS-Variablen, die jedes Artboard verwendet, in jedem Modus"] (Tokens), button[title="Jeder Kommentar, offen und gelöst"] (Kommentare, mit der Anzahl der offenen im Namen), Import, Export, ein Chip pro anwesendem Agenten |
| Leinwand-Werkzeuge | Werkzeugleiste Werkzeuge: button[title="Zeiger (V)"], button[title="Kommentar (C)"]; Tasten v, c, Umschalt+1 (anpassen), =/- (Zoom) |
| Kommentarfeld | Textfeld Einen Kommentar hinzufügen, button[title="Namen ändern"], [data-selection-count], Schaltfläche Senden, Pins mit Namen Kommentar: <first message> |
| Kommentarthread | [role=dialog] mit Namen Kommentarthread: Schaltflächen Löschen, Lösen/Wieder öffnen, Schließen, Bearbeiten bei deiner neuesten Nachricht, Textfeld Antworten |
| Bereiche | aside[aria-label=Kommentare] mit Reitern Offen N / Gelöst N; section[aria-label=Tokens] mit form[aria-label="Einen Token hinzufügen"]; nav[aria-label=Seiten]; [role=menu][aria-label=Export]; aside[aria-label=Import] mit einem status |
| Artboard-Inhalt | [data-artboard="<artboardId>"] >>> <css>; die data-name-Attribute der Agenten bleiben im DOM erhalten |
Bevorzuge diese gegenüber Koordinaten. Koordinaten sind nur für sandboxed (Script-)Artboards, die Selektoren nicht erreichen können. click akzeptiert CSS, keinen Text, daher werden Schaltflächen ohne Titel nach Position ausgewählt: [role=dialog] button --nth 1, wobei query die Reihenfolge auflistet.
Die Texteingabe hat zwei Fallstricke. type hängt an das an, was ein Feld bereits enthält, und key Meta+a wählt über CDP keinen Text aus. Um den Text eines Feldes zu ersetzen, führe $V h $RUN eval "document.execCommand('selectAll')" bei fokussiertem Feld und dann type aus.
Hintergrundaufrufe
wait_for_comments blockiert, bis eine Person einen Kommentar postet, muss also ausgeführt werden, während du die Seite steuerst:
$V bg $RUN 02-wait call wait_for_comments '{"designId":"<D>","timeoutSeconds":30}'
# ...Seite steuern...
$V await $RUN 02-wait 30 # blockiert, bis der Aufruf zurückkehrt, gibt dann .verify/<run>/02-wait.txt aus
Lese das Ergebnis mit await, niemals durch direktes Lesen der Datei: Die Datei erscheint erst, wenn der Aufruf zurückgekehrt ist. Der Hintergrundaufruf überlebt zwischen Tool-Aufrufen.
Beweise
Alles wird im Checkout unter .verify/<run>/ gespeichert. .gitignore deckt es ab, und die Bereinigung behält es.
$V save $RUN 01-comment-posted snapshot --selector main # der Befehl, seine Ausgabe und der Exit-Code
$V shot $RUN 02-canvas # .verify/<run>/02-canvas.png
$V shot $RUN 03-panel --selector 'aside[aria-label=Kommentare]'
save akzeptiert jeden Headless-Befehl, einschließlich call, und schreibt <name>.txt mit dem Befehl, seiner Ausgabe und [exit N]. Nummeriere die Namen, damit der Lauf in der richtigen Reihenfolge gelesen wird. Lese jedes PNG mit dem Lese-Tool, bevor du dich darauf verlässt. get_screenshot-Bilder und alle Seiten-Screenshots, die ohne Pfad aufgenommen wurden, landen im temporären Ordner der Sitzung. Die Bereinigung kopiert sie nach .verify/<run>/tool-images/ und das Server-Log nach .verify/<run>/server.log. Dateien, die du als Testeingabe erstellst, z. B. eine zu importierende Datei, kommen ebenfalls nach .verify/<run>/.
Ein Beweis erfüllt diese Standards:
- Der echte Pfad. Eine Aktion einer Person erfolgt über die Seite (Klick, Taste, Eingabe, Upload) und eine Aktion eines Agenten über einen MCP-
call. Verwende die REST-API nur zum Lesen des gespeicherten Zustands. Ein Schreiben darüber überspringt die UI, die du beweist. - Aktion und Ergebnis. Speichere den Schritt, der die Sache tut, und den Zustand danach, nicht nur einen endgültigen Screenshot.
- Seiteneffekte. Zeige die Änderung sowohl gespeichert als auch angezeigt.
api GET /api/designs/<id>gibtmeta,nodesundcommentsso zurück, wie der Server sie gespeichert hat, und ein Lese-Tool eines Agenten (get_comments,get_tokens,get_tree_summary) zeigt, was der nächste Agent sehen wird. - Beide Richtungen für Live-Funktionen. Eine Bearbeitung eines Agenten muss ohne Neuladen in der Seite erscheinen. Ein Kommentar einer Person muss einen wartenden Agenten erreichen.
- Keine Mocks. Der Lauf verwendet den echten Server, den echten Browser und echte MCP-Sitzungen.
- Eine saubere Konsole. Beende mit
$V save $RUN <n>-console console. Eine Ausnahme oder eine fehlgeschlagene Anfrage dort verdirbt den Beweis.
Vorher und nachher
Ein Bugfix ist bewiesen, wenn dieselbe Reise mit dem alten Code fehlschlägt und mit dem neuen Code besteht. Führe beide nebeneinander aus:
$V launch --at main # RUN=<before>: ein temporäres Checkout von main, installiert und gebaut (ca. eine Minute)
$V launch # RUN=<after>: dieses Checkout
Steuere die gleichen Schritte in beiden, mit denselben Beweisnamen. Der vorherige Lauf muss den Bug zeigen. Tut er das nicht, erreicht deine Reise den Bug nicht, und der nachherige Lauf beweist nichts über den Fix. --at akzeptiert jeden Git-Ref: einen Branch, einen Tag, einen Commit oder HEAD, wenn dein Fix noch nicht committet ist. Der Doktor gibt den Ref und den Commit an, aus dem ein Lauf erstellt wurde. Die Bereinigung entfernt das temporäre Checkout und behält seine Beweise.
Bereinigen (Cleanup)
$V cleanup $RUN
Es stoppt den Daemon dieses Laufs. Der Daemon stoppt den von ihm gestarteten Server (SIGTERM, damit Designs zuerst gespeichert werden) und das von ihm gestartete Chrome, löscht dann deren temporäre Daten und Profile. Anschließend kopiert die Bereinigung das Server-Log und die Tool-Bilder in den Beweisordner, entfernt das temporäre Checkout eines --at-Laufs und listet auf, was behalten wurde. Es berührt nichts anderes, sodass andere Sitzungen, vp run dev und die Desktop-App weiterlaufen.
$V list gibt die Läufe dieses Checkouts aus, die noch laufen oder ein Checkout hinterlassen haben. Räume jeden mit $V cleanup <run> auf, niemals mit pkill. $V prune [days] löscht die Beweise von bereinigten Läufen, die älter als die angegebene Anzahl Tage sind (Standard 7). Bereinige niemals einen Lauf, dessen Beweise du noch melden möchtest.
Bericht (Report)
Beende mit einem Block pro gesteuertem Feature:
<Feature-ID> via <Einstiegspunkt>: proven | skipped | failed
Beweise: .verify/<run>/<dateien>
Grund (übersprungen oder fehlgeschlagen): <der ausgeführte Befehl und was gefehlt hat oder falsch war>
Gib dann die Lauf-IDs, die Ausgabe des Doktors für jeden Lauf und, bei einem Fix, die Beweise des vorherigen Laufs an, die den Bug zeigen. Melde einen übersprungenen Einstiegspunkt als übersprungen, selbst wenn ein anderer Einstiegspunkt das gleiche Verhalten bewiesen hat.
Helfer
scripts/verify.sh akzeptiert diese Befehle: launch, doctor, h, save, shot, bg, await, cleanup, list und prune. Führe es ohne Argumente aus, um deren Argumente zu sehen. Es ist eine dünne Schicht über e2e/headless.mjs: die Sitzung ist verify-<run> und die Beweise gehen nach .verify/<run>/.