Communitygithub.com

genekogan/proof

Nimm einen ungeschnittenen, in Echtzeit ablaufenden Playwright-Beweisclip einer geänderten Benutzerreise auf einer lokalen Fake-Mind-Welt auf – mit Fortschrittsbalken und eingebranntem Zeitstempel – und hänge ihn an den Pull-Request an, ohne das Video ins Repository zu committen.

Was ist proof?

Dieses Skill erstellt einen ungeschnittenen, in Echtzeit ablaufenden Videobeweis einer Benutzerreise, die durch eine Codeänderung (T2 oder höher) beeinflusst wurde. Es verwendet Playwright, um die Aktionen auf einer lokalen, isolierten Welt mit einer Fake-Mind-Umgebung aufzuzeichnen. Der Clip enthält einen Fortschrittsbalken und einen eingebrannten Zeitstempel, damit ein Prüfer den Ablauf genau so sehen kann, wie ein Benutzer ihn sehen würde. Das Skill unterstützt die Aufzeichnung auf Desktop- und, bei Layoutänderungen, auf Smartphone-Viewports. Es automatisiert das Booten einer Fake-Mind-Welt, das Schreiben der Testschritte in einer JavaScript-Datei, die Aufnahme des Videos und das Hochladen des Clips als GitHub-Release-Anhang, ohne dass das Video ins Repository gelangt. Es ist besonders nützlich für Entwickler, die Pull-Requests mit visuellen Nachweisen versehen müssen, und funktioniert mit Claude Code, Cursor und anderen KI-Agenten, die Playwright- und ffmpeg-Workflows ausführen können. Das Skill enthält auch einen lokalen Smoke-Test, um die grundlegende Funktionalität der App zu überprüfen, bevor der eigentliche Clip aufgenommen wird.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/genekogan/souls/tree/HEAD/.claude/skills/proof

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Vorschau

Aus dem Skill-README

desktop.mp4

Dokumentation

proof – ein ungeschnittener Clip der geänderten Reise

Ein Prüfer sollte sehen können, was ein Benutzer sehen würde, in normaler Geschwindigkeit, von Anfang bis Ende. Der Clip ist der Beweis; ein Screenshot, eine Kontaktseite oder eine beschleunigte Aufnahme ist das nicht.

Quelle der Wahrheit dafür, was eine Stufe benötigt: docs/process/PROOF-POLICY.yml (T0 nichts; T1 fokussierte Tests + Typprüfung; T2 fügt einen Clip der geänderten Reise hinzu, Desktop, plus Telefon, wenn sich das Layout geändert hat, auf einer Fake-Mind-Welt; T3/T4 fügen mehr hinzu). Ermittle die Stufe des aktuellen Diffs mit node tools/proof/tier.mjs --base origin/main.

Regeln

  • Ungeschnitten und in Echtzeit. Ein Browserkontext, eine Aufnahme. Niemals trimmen, schneiden, beschleunigen oder verlangsamen. Wenn die Reise länger als die max_seconds der Richtlinie ist, nimm eine kürzere Reise auf, die die Änderung dennoch zeigt, nicht eine schnellere.
  • Die Aufnahme beginnt bei der Ankunft (Standard): Die Aufzeichnung beginnt, sobald die Welt auf dem Bildschirm ist und die Ankunftskarte verschwunden ist. Der Clip beginnt also mit der Welt, nicht mit dem Laden. Von dort ist es eine ungeschnittene, in Echtzeit ablaufende Aufnahme der Reise, wie es die Richtlinie verlangt. Wenn das Laden oder die Ankunft selbst Gegenstand der Änderung ist (die Ankunftskarte, ein Ladebildschirm, die erste Darstellung), oder die Reise nicht auf einer Weltseite stattfindet (die Weltliste, Anmeldung), übergib --from-load: Die Aufnahme beginnt dann bei der Seitenerstellung. Der Sidecar start (arrival oder load) gibt an, welcher verwendet wurde, und upload.mjs --proof kopiert ihn in die media[] von proof.json.
  • Bei Tag. Bei einer lokalen Welt-URL setzt der Rekorder die Welt auf Mittag, wobei die Uhr vor dem Öffnen der Seite angehalten wird (--time-of-day 12, Standard; die God-Env-Route als Dev-Besitzer). Dev-Welten starten um 06:00 Uhr und laufen einen Welt-Tag pro Echtzeitstunde, sodass eine Welt, die 40 Minuten läuft, ohne dies nachts ist. Das Setzen ist ein world-Eintrag in der God-Historie der Welt, und die Uhr bleibt danach angehalten. Übergib eine andere Stunde oder --time-of-day keep, wenn die Uhr, das Licht oder die God-Historie Gegenstand der Änderung ist. Der Sidecar worldTime gibt an, was gesetzt wurde.
  • Echte Eingabe. Steuere mit page.mouse, page.keyboard, page.touchscreen oder Locator-Klicks, wie ein Benutzer es tun würde. Rufe keine App-Interna von page.evaluate auf, um Dinge vor der Kamera passieren zu lassen.
  • Fake Minds, isolierte Daten. Nur lokale Welten, BRAIN_MODE=fake, ein frisches Datenverzeichnis. Niemals gegen eine Produktionswelt aufnehmen, es sei denn, der Betreuer bittet darum, und niemals mit einem angemeldeten persönlichen Browserprofil.
  • Video (oder Frames) niemals ins Repository committen. Arbeite unter .e2e/ (gitignoriert).
  • Der Clip muss die Änderung zeigen. Sieh ihn dir an (oder extrahiere zumindest Frames, siehe unten), bevor du ihn anhängst.

1. Eine Fake-Mind-Welt starten

Erfordert einen gebauten Web-Client (pnpm install --frozen-lockfile && pnpm build; überspringe, wenn apps/web/dist/index.html existiert und für deine Änderung aktuell ist). In einem frischen Clone schlägt die Prebuild-Prüfung des Builds fehl, bis die Web-Medien vorhanden sind: node tools/assets/pull.mjs --only 'apps/web/**' (ein paar Dateien) reicht dafür.

node tools/god-skill/dev-world.mjs proof 4710 --genesis worlds/templates/hello-hamlet.json --fresh --data .local/proof
# gibt aus: http://127.0.0.1:4710/w/proof?dev=1 (PID N, Log .lane/proof.log); der Server läuft weiterhin im Hintergrund

Die Startseite (Weltliste, Neue Welt) wird vom Welt-Launcher bereitgestellt, nicht von einer einzelnen Welt. Für eine Reise, die dort beginnt, starte einen Launcher (seine Welten bekommen immer Fake Minds) und erstelle eine Welt für die Liste über seine API:

node tools/world-launcher/launcher.mjs --port 4720 --range 4721-4723 --data "$PWD/.local/proof-launcher" --eager 0 &
curl -s -X POST -H 'content-type: application/json' -H 'authorization: Bearer dev:proof' \
  -d '{"name":"Proof Garden","template":"hello-hamlet"}' http://127.0.0.1:4720/__sim/worlds
# nimm gegen http://127.0.0.1:4720/ auf; stoppe den Launcher mit seiner PID (er stoppt seine Welten)

Wähle die Vorlage, die die geänderte Oberfläche enthält (worlds/templates/: hello-hamlet ist klein und schnell; eden-2026, mars-two und andere sind größer). Verwende einen freien Port; e2e/config.mjs listet für andere Harness reservierte Ports auf. Stoppe den Server mit kill <pid>, wenn du fertig bist.

Kurzer Nachweis, dass die App funktioniert: der lokale Smoke-Test

Führe vor der Aufnahme oder als gesamten Beweis einer T1-Änderung, die den Server oder die Web-App betrifft, den lokalen Smoke-Test aus. Er startet seinen eigenen isolierten Launcher (Fake Minds, Dev-Anmeldung, Daten unter dem Laufverzeichnis) auf einem freien Port, öffnet die Weltliste und eine Welt, prüft, ob eine Person ohne Konsolenfehler und ohne fehlgeschlagene Anfragen gezeichnet wird, und stoppt, was er gestartet hat:

node e2e/local-smoke.mjs --port 9950 --clip      # --build zuerst auf einem frischen Clone; --port weglassen für einen beliebigen freien Port
# → .local/e2e/<timestamp>/summary.json, shots/1-world-list.png 2-world.png 3-person.png, clip.mp4
node tools/proof/upload.mjs --pr $N .local/e2e/<timestamp>/summary.json .local/e2e/<timestamp>/shots/*.png

status: "pass" in summary.json ist der Beweis; sein Clip ist eine ungeschnittene, in Echtzeit ablaufende Aufnahme der Smoke-Reise. Es ist kein Clip deiner Änderung: Eine T2-Änderung zeichnet trotzdem weiter unten ihre eigene Reise auf. Details: docs/testing/e2e.md#local-smoke.

2. Die Schritte schreiben

Kopiere .claude/skills/proof/steps.example.mjs nach .e2e/proof/<slug>/steps.mjs und schreibe die geänderte Reise: mache die Sache, zeige das Ergebnis. Mit dem Standard-Ankunftsstart beginnen die Schritte auf der angekommenen Welt (die arrived-Markierung ist 0:00); mit --from-load beginnen sie direkt nach der Navigation. mark('label') stampelt eine Kapitelzeit in den Sidecar, sodass der PR sagen kann "das Panel öffnet sich um 0:07". Halte es bei der Reise, die die Änderung betrifft.

3. Aufnehmen

node .claude/skills/proof/record.mjs --url 'http://127.0.0.1:4710/w/proof?dev=1' \
  --steps .e2e/proof/<slug>/steps.mjs --out .e2e/proof/<slug>/desktop.mp4 --viewport desktop
# Layout oder Touch geändert? auch:
node .claude/skills/proof/record.mjs --url '...' --steps .e2e/proof/<slug>/steps.mjs \
  --out .e2e/proof/<slug>/phone.mp4 --viewport phone
  • Browser: Verwendet PLAYWRIGHT_BROWSERS_PATH, sonst /opt/pw-browsers, falls vorhanden. Wenn Chromium fehlt: PLAYWRIGHT_BROWSERS_PATH="$PWD/.e2e/browsers" pnpm --filter mars-campus-viewer exec playwright install chromium.
  • Playwright wird auf die gleiche Weise aufgelöst wie der Playtest-Harness (tools/playtest/lib/platform.mjs: ein globales playwright, sonst @playwright/test aus mars/viewer). Kein GPU erforderlich; WebGL läuft auf SwiftShader.
  • --max-seconds standardmäßig auf max_seconds der Richtlinie. Exit 3 bedeutet, dass die Reise darüber hinausgelaufen ist: kürze sie.
  • Mit ffmpeg: ein mp4 mit einem Fortschrittsbalken am unteren Rand und einem hh:mm:ss / total-Zeitstempel (der Zeitstempel benötigt ein ffmpeg, das mit drawtext gebaut wurde; der Sidecar timecode gibt an, ob er vorhanden ist). Ohne ffmpeg: das rohe .webm; gib das im PR an (Player zeigen trotzdem ihren eigenen Scrub-Balken).
  • Jeder Clip bekommt einen <clip>.json Sidecar: url, viewport, dauer, start, startedAt, markierungen (arrived darunter), worldTime, konsolenfehler, commit und dirty-flag. Ein Playwright ohne page.screencast zeichnet ab Seitenerstellung auf, selbst ohne --from-load; der Sidecar gibt das in startFallback an.
  • Die Seite hat --arrival-seconds (Standard 120), um vor Beginn der Aufnahme anzukommen; eine Seite, die nie eine Welt zeigt, schlägt fehl (exit 1) mit einem Hinweis, --from-load zu verwenden, einem Standbild, wo sie hängt (<clip>.open-failed.png) und einem Sidecar. Konsolenfehler im Sidecar sind Erkenntnisse: erkläre oder behebe sie.

Der Lauf bleibt deutlich unter dem 10-Minuten-Vordergrundlimit. Für mehrere Clips in einem Durchgang führe sie im Hintergrund aus (nohup setsid node ... > .e2e/proof/<slug>/rec.log 2>&1 &) und überprüfe das Log.

4. Selbst prüfen

for t in 1 4 8; do ffmpeg -loglevel error -y -ss $t -i .e2e/proof/<slug>/desktop.mp4 -frames:v 1 .e2e/proof/<slug>/t$t.png; done

Schau dir die Frames an (lies die PNGs). Der geänderte Zustand muss sichtbar sein, die Welt muss geladen haben (keine leere oder ladende Leinwand), und nichts im Frame sollte privat sein. Wenn es die Änderung nicht zeigt, korrigiere die Schritte und nimm eine neue Aufnahme auf; hänge keinen Clip an, der die Behauptung nicht beweist.

5. An den PR anhängen (niemals committen)

Prüfe jedes ausgehende Text-/JSON-Payload mit node tools/proof/publication.mjs <payload files> vor der Veröffentlichung. Untersuche Medienpixel, Audio, Dateinamen und binäre Metadaten separat. Gerätepfade, Hostnamen, Geräte-/private IPs, lokale URLs und betriebliche Kennungen gehören nur in private Aufzeichnungen. Verwende relative Pfade und neutrale Aufnahme-Beschriftungen. Der Uploader blockiert erkannte Textlecks vor dem Hochladen des Batches; dies kann die Medienprivatsphäre nicht zertifizieren.

node tools/proof/upload.mjs --pr $N --proof .e2e/journal/$ISSUE/proof.json .e2e/proof/$SLUG/desktop.mp4 .e2e/proof/$SLUG/phone.mp4
  • Das Standardziel ist die eigene Prerelease proofs-<n> des PRs (Tag auf dem Standardbranch, beim ersten Gebrauch erstellt); eine Release pro PR hält jedes unter GitHub's 1000-Asset-Limit, das die alte gemeinsame proofs-Release erreicht hat. --release <tag> (oder SIM_PROOF_RELEASE) benennt eine andere Release. Assets werden pr-<n>.<file> genannt, und eine Wiederholung bekommt -2, -3, sodass frühere Aufnahmen, einschließlich fehlgeschlagener, verlinkbar bleiben. SIM_PROOF_UPLOAD_URL (+ SIM_PROOF_UPLOAD_TOKEN) wechselt zu einem anderen Endpunkt, z. B. einem CDN.
  • Mit --proof werden Clip- und Bildlinks in die media[] von proof.json geschrieben, andere Dateien (Logs, JSON) in files[], und proof.json wird zuletzt hochgeladen. Kopiere seinen Link und die Cliplinks in den Proof-Abschnitt des PRs. Das Journal-Skill deckt proof.json ab.
  • Inline-Vorschau. GitHub liefert Release-Assets als Downloads aus, sodass ein mp4-Link im PR nie abgespielt wird. Für jedes Video erstellt upload.mjs ein kleines animiertes GIF mit ffmpeg (<clip>.preview.gif: 6 s in Echtzeit ab der arrived-Markierung des Clips oder von 0 bei einem --from-load-Take; maximal 5 MB), lädt es neben dem Clip hoch, zeichnet es als media[].preview auf und gibt eine Zeile wie [![desktop.mp4](…pr-412.desktop.preview.gif)](…pr-412.desktop.mp4) aus. Kopiere diese Zeile: Die Vorschau wird im PR abgespielt, und beim Klicken wird der vollständige Clip geöffnet. Wenn die Änderung später im Clip erscheint, wähle das Fenster mit --preview-start <s> (und --preview-seconds <s>). Die Vorschau ist ein Hinweis, nicht der Beweis: Das ungeschnittene mp4 ist es. Setze immer einen expliziten Full-Resolution ungeschnittener Video-Link vor jede Vorschau, der die tatsächliche codierte Auflösung und Dauer angibt. Bewahre die Aufnahmeauflösung und rahme die Aktion so ein, dass der Kontakt überprüft werden kann. Skaliere eine Aufnahme nicht hoch oder verwende das verkleinerte GIF, um Bewegungsbeweise zu behaupten.
  • Exit 3: Der Upload ist blockiert (kein gh, nicht angemeldet, keine Berechtigung oder kein Netzwerk, wie in vielen Cloud-Sitzungen). Sage dem Benutzer, welche Clips warten und wo. Veröffentliche einen PR-Kommentar mit der Dauer jedes Clips, Viewport, bereinigter Sidecar-Zusammenfassung (Markierungen, Konsolenfehler, Commit) und einem repository-relativen record.mjs-Befehl und der Steps-Datei, damit jeder sie neu aufnehmen kann. Markiere den Proof als "Upload ausstehend" im PR-Text. Gib Video niemals als base64 aus, committe es niemals und pushe es niemals auf einen anderen Branch.

gh pr funktioniert möglicherweise nicht in Cloud-Sitzungen; kommentiere mit gh api repos/$REPO/issues/$N/comments -F [email protected]/proof/$SLUG/comment.md.

Was neben den Clip schreiben

Eine Zeile pro Clip: welche Reise, welche Weltenvorlage, Viewport, Dauer, Commit und der Moment, in dem die Änderung sichtbar ist ("0:07 die Sitz-Highlights und die Seele setzt sich"). Plus alle Konsolenfehler und warum sie akzeptabel sind.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Verwandte Skills