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_secondsder 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 Sidecarstart(arrivaloderload) gibt an, welcher verwendet wurde, undupload.mjs --proofkopiert ihn in diemedia[]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 einworld-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 SidecarworldTimegibt an, was gesetzt wurde. - Echte Eingabe. Steuere mit
page.mouse,page.keyboard,page.touchscreenoder Locator-Klicks, wie ein Benutzer es tun würde. Rufe keine App-Interna vonpage.evaluateauf, 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 globalesplaywright, sonst@playwright/testausmars/viewer). Kein GPU erforderlich; WebGL läuft auf SwiftShader. --max-secondsstandardmäßig aufmax_secondsder 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 Sidecartimecodegibt 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>.jsonSidecar: url, viewport, dauer,start,startedAt, markierungen (arriveddarunter),worldTime, konsolenfehler, commit und dirty-flag. Ein Playwright ohnepage.screencastzeichnet ab Seitenerstellung auf, selbst ohne--from-load; der Sidecar gibt das instartFallbackan. - 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-loadzu 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 gemeinsameproofs-Release erreicht hat.--release <tag>(oderSIM_PROOF_RELEASE) benennt eine andere Release. Assets werdenpr-<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
--proofwerden Clip- und Bildlinks in diemedia[]von proof.json geschrieben, andere Dateien (Logs, JSON) infiles[], 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.mjsein kleines animiertes GIF mit ffmpeg (<clip>.preview.gif: 6 s in Echtzeit ab derarrived-Markierung des Clips oder von 0 bei einem--from-load-Take; maximal 5 MB), lädt es neben dem Clip hoch, zeichnet es alsmedia[].previewauf und gibt eine Zeile wie[](…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-relativenrecord.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.
