proof — 변경된 여정의 편집되지 않은 클립
검토자는 사용자가 보는 것을 정상 속도로 처음부터 끝까지 볼 수 있어야 합니다. 클립이 증거이며, 스크린샷, 연락처 시트 또는 빨리 감기 녹화는 증거가 아닙니다.
티어에 필요한 사항의 출처: docs/process/PROOF-POLICY.yml (T0 없음; T1 집중 테스트 + 타입체크; T2는 변경된 여정의 클립 하나 추가, 데스크톱 및 레이아웃이 변경된 경우 모바일, 페이크-마인드 세계에서; T3/T4는 더 추가). 현재 diff의 티어는 node tools/proof/tier.mjs --base origin/main으로 확인합니다.
규칙
- 편집되지 않음 및 실제 속도. 하나의 브라우저 컨텍스트, 한 번의 테이크. 절대 트리밍, 접합, 속도 증가 또는 감소하지 마십시오. 여정이 정책의
max_seconds보다 길면 변경 사항을 여전히 보여주는 더 짧은 여정을 녹화하되, 더 빠른 여정은 안 됩니다. - 테이크는 도착 시점에 시작 (기본값): 세계가 화면에 나타나고 도착 카드가 사라진 후에 녹화가 시작되므로, 클립은 로딩이 아닌 세계에서 시작됩니다. 그 이후로 정책이 요구하는 대로 하나의 편집되지 않은 실제 속도 테이크입니다. 로딩 또는 도착 자체가 변경 사항인 경우(도착 카드, 로딩 화면, 첫 페인트), 또는 여정이 세계 페이지가 아닌 경우(세계 목록, 로그인)
--from-load를 전달합니다. 그러면 테이크가 페이지 생성 시점에 시작됩니다. 사이드카의start(arrival또는load)는 어떤 것이 사용되었는지 나타내며,upload.mjs --proof는 이를 proof.jsonmedia[]에 복사합니다. - 낮 시간에. 로컬 세계 URL에서 레코더는 페이지가 열리기 전에 세계를 정오로 설정하고 시계를 일시 중지합니다 (
--time-of-day 12, 기본값; 신 모드 라우트는 dev 소유자로). 개발 세계는 06:00에 부팅되며 실제 시간당 하루를 실행하므로, 40분 동안 켜져 있는 세계는 밤입니다. 설정하는 것은 세계의 신 기록에 하나의world항목이며, 이후 시계는 일시 중지된 상태로 유지됩니다. 다른 시간을 전달하거나, 시계, 조명 또는 신 기록 자체가 변경 사항인 경우--time-of-day keep을 전달합니다. 사이드카의worldTime은 설정된 값을 나타냅니다. - 실제 입력. 사용자가 하는 방식대로
page.mouse,page.keyboard,page.touchscreen또는 로케이터 클릭으로 구동합니다. 카메라에서 이벤트를 발생시키기 위해page.evaluate로 앱 내부를 호출하지 마십시오. - 페이크 마인드, 격리된 데이터. 로컬 세계만,
BRAIN_MODE=fake, 새로운 데이터 디렉토리. 유지관리자가 요청하지 않는 한 프로덕션 세계에 대해 녹화하지 말고, 개인 브라우저 프로필에 로그인하여 녹화하지 마십시오. - 비디오(또는 프레임)를 저장소에 커밋하지 마십시오.
.e2e/(gitignored)에서 작업합니다. - 클립은 변경 사항을 보여주어야 합니다. 첨부하기 전에 시청하십시오(또는 최소한 프레임 추출, 아래 참조).
1. 페이크-마인드 세계 부팅
빌드된 웹 클라이언트 필요 (pnpm install --frozen-lockfile && pnpm build; 변경 사항에 대해 apps/web/dist/index.html이 존재하고 최신이면 건너뜁니다). 새 클론에서 빌드의 사전 빌드 검사는 웹 미디어가 준비될 때까지 실패합니다: node tools/assets/pull.mjs --only 'apps/web/**' (몇 개의 파일)로 충분합니다.
node tools/god-skill/dev-world.mjs proof 4710 --genesis worlds/templates/hello-hamlet.json --fresh --data .local/proof
# http://127.0.0.1:4710/w/proof?dev=1 출력 (pid N, 로그 .lane/proof.log); 서버는 분리된 상태로 계속 실행됩니다
홈페이지(세계 목록, 새 세계)는 단일 세계가 아닌 세계 런처가 제공합니다. 거기서 시작하는 여정의 경우, 런처(항상 페이크 마인드를 얻는 세계)를 실행하고 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
# http://127.0.0.1:4720/ 에 대해 녹화; pid로 런처 중지 (런처는 세계를 중지합니다)
변경된 표면을 포함하는 템플릿 선택 (worlds/templates/: hello-hamlet은 작고 빠름; eden-2026, mars-two 등은 더 큼). 사용 가능한 포트 사용; e2e/config.mjs는 다른 하네스를 위해 예약된 포트를 나열합니다. 완료되면 kill <pid>로 서버를 중지합니다.
앱 작동 확인: 로컬 스모크
녹화 전에, 또는 서버나 웹 앱을 변경하는 T1 변경의 전체 증명으로, 로컬 스모크를 실행합니다. 자체 격리된 런처(페이크 마인드, 개발 로그인, 실행 디렉토리 아래 데이터)를 사용 가능한 포트에서 부팅하고, 세계 목록과 하나의 세계를 열고, 사람이 그려지고 콘솔 오류 및 실패한 요청이 없는지 확인한 다음 시작한 것을 중지합니다:
node e2e/local-smoke.mjs --port 9950 --clip # 새 클론에서는 --build 먼저; 사용 가능한 포트는 --port 생략
# → .local/e2e/<타임스탬프>/summary.json, shots/1-world-list.png 2-world.png 3-person.png, clip.mp4
node tools/proof/upload.mjs --pr $N .local/e2e/<타임스탬프>/summary.json .local/e2e/<타임스탬프>/shots/*.png
summary.json의 status: "pass"가 증거입니다. 해당 클립은 스모크 여정의 하나의 편집되지 않은 실제 속도 테이크입니다. 변경 사항의 클립이 아닙니다: T2 변경은 여전히 아래 자체 여정을 녹화합니다. 세부 사항: docs/testing/e2e.md#local-smoke.
2. 단계 작성
.claude/skills/proof/steps.example.mjs를 .e2e/proof/<slug>/steps.mjs에 복사하고 변경된 여정을 스크립팅합니다: 작업을 수행하고 결과를 보여줍니다. 기본 도착 시작으로 단계는 도착한 세계에서 시작합니다(arrived 마크는 0:00); --from-load를 사용하면 탐색 직후에 시작합니다. mark('label')은 사이드카에 챕터 시간을 스탬프하여 PR에서 "패널이 0:07에 열립니다"라고 말할 수 있도록 합니다. 변경 사항이 영향을 미치는 여정으로 유지하십시오.
3. 녹화
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
# 레이아웃 또는 터치가 변경되었습니까? 또한:
node .claude/skills/proof/record.mjs --url '...' --steps .e2e/proof/<slug>/steps.mjs \
--out .e2e/proof/<slug>/phone.mp4 --viewport phone
- 브라우저:
PLAYWRIGHT_BROWSERS_PATH사용, 그렇지 않으면/opt/pw-browsers(존재하는 경우). Chromium이 없는 경우:PLAYWRIGHT_BROWSERS_PATH="$PWD/.e2e/browsers" pnpm --filter mars-campus-viewer exec playwright install chromium. - Playwright는 플레이테스트 하네스와 동일한 방식으로 확인됩니다 (
tools/playtest/lib/platform.mjs: 전역playwright, 그렇지 않으면mars/viewer의@playwright/test). GPU 필요 없음; WebGL은 SwiftShader에서 실행됩니다. --max-seconds는 정책의max_seconds를 기본값으로 합니다. 종료 코드 3은 여정이 이를 초과했음을 의미합니다: 단축하십시오.- ffmpeg 사용: 하단에 진행 막대가 있고
hh:mm:ss / total타임코드가 있는 mp4 (타임코드는 drawtext로 빌드된 ffmpeg 필요; 사이드카의timecode는 존재 여부를 나타냄). ffmpeg 없음: 원시.webm; PR에 그렇게 명시하십시오 (플레이어는 여전히 자체 스크러브 바를 표시). - 각 클립에는
<클립>.json사이드카가 있습니다: url, viewport, duration,start,startedAt, 마크 (arrived포함),worldTime, 콘솔 오류, 커밋 및 더티 플래그.page.screencast가 없는 Playwright는--from-load없이도 페이지 생성 시점부터 녹화합니다. 사이드카는startFallback에서 이를 명시합니다. - 페이지는 테이크가 시작되기 전에 도착할 시간
--arrival-seconds(기본값 120)를 가집니다; 세계를 표시하지 않는 페이지는--from-load사용 힌트, 중단된 위치의 스틸 이미지 (<clip>.open-failed.png) 및 사이드카와 함께 실패합니다 (종료 코드 1). 사이드카의 콘솔 오류는 발견 사항입니다: 설명하거나 수정하십시오.
실행은 10분 포그라운드 제한보다 훨씬 짧습니다. 여러 클립을 한 번에 실행하려면 백그라운드에서 실행하십시오 (nohup setsid node ... > .e2e/proof/<slug>/rec.log 2>&1 &) 그리고 로그를 폴링하십시오.
4. 직접 확인
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
프레임을 확인하십시오 (PNG 읽기). 변경된 상태가 보여야 하고, 세계가 로드되어야 하며 (빈 캔버스나 로딩 캔버스가 아님), 프레임에 비공개 내용이 없어야 합니다. 변경 사항을 표시하지 않으면 단계를 수정하고 새 테이크를 녹화하십시오; 주장을 증명하지 않는 클립을 첨부하지 마십시오.
5. PR에 첨부 (커밋하지 않음)
게시 전에 모든 나가는 텍스트/JSON 페이로드를 node tools/proof/publication.mjs <페이로드 파일>로 확인하십시오. 미디어 픽셀, 오디오, 파일 이름 및 바이너리 메타데이터를 별도로 검사하십시오. 장치 경로, 호스트 이름, 장치/개인 IP, 로컬 URL 및 운영 식별자는 비공개 레코드에만 속합니다. 상대 경로와 중립 캡처 레이블을 사용하십시오. 업로더는 배치를 업로드하기 전에 감지된 텍스트 누출을 차단합니다. 이는 미디어 개인 정보를 인증할 수 없습니다.
node tools/proof/upload.mjs --pr $N --proof .e2e/journal/$ISSUE/proof.json .e2e/proof/$SLUG/desktop.mp4 .e2e/proof/$SLUG/phone.mp4
- 기본 대상은 PR 자체의 프리릴리스
proofs-<n>입니다 (기본 브랜치의 태그, 첫 사용 시 생성됨); PR당 하나의 릴리스는 각각을 GitHub의 1000-에셋 제한 아래에 유지하며, 이전 공유proofs릴리스가 도달했습니다.--release <tag>(또는SIM_PROOF_RELEASE)는 다른 릴리스를 지정합니다. 에셋 이름은pr-<n>.<file>이며, 재테이크는-2,-3을 얻으므로 실패한 것을 포함한 이전 테이크도 링크 가능합니다.SIM_PROOF_UPLOAD_URL(+SIM_PROOF_UPLOAD_TOKEN)은 CDN과 같은 다른 엔드포인트로 전환합니다. --proof를 사용하면 클립 및 이미지 링크가 proof.jsonmedia[]에 기록되고, 다른 파일(로그, JSON)은files[]에 기록되며, proof.json이 마지막으로 업로드됩니다. 링크와 클립 링크를 PR의 Proof 섹션에 붙여넣으십시오.journal스킬은 proof.json을 다룹니다.- 인라인 미리보기. GitHub는 릴리스 에셋을 다운로드로 제공하므로 mp4 링크는 PR에서 재생되지 않습니다. 각 비디오에 대해
upload.mjs는 ffmpeg로 작은 애니메이션 GIF를 만듭니다 (<clip>.preview.gif: 클립의arrived마크에서 6초 실제 속도, 또는--from-load테이크의 경우 0초; 최대 5 MB), 클립 옆에 업로드하고media[].preview로 기록하며[](...pr-412.desktop.mp4)와 같은 줄을 출력합니다. 해당 줄을 붙여넣으십시오: 미리보기가 PR에서 재생되고 클릭하면 전체 클립이 열립니다. 변경 사항이 클립의 나중에 표시되는 경우--preview-start <s>(및--preview-seconds <s>)로 창을 선택하십시오. 미리보기는 포인터일 뿐, 증거가 아닙니다: 편집되지 않은 mp4가 증거입니다. 각 미리보기 전에 항상 명시적인 전체 해상도 편집되지 않은 비디오 링크를 넣고 실제 인코딩된 해상도와 지속 시간을 명시하십시오. 캡처 해상도를 유지하고, 접촉을 검토할 수 있도록 액션을 프레임화하십시오. 캡처를 업스케일하거나 축소된 GIF를 사용하여 동작 증명을 주장하지 마십시오. - 종료 코드 3: 업로드가 차단됨 (
gh없음, 로그인되지 않음, 권한 없음, 또는 네트워크 없음, 많은 클라우드 세션에서처럼). 사용자에게 어떤 클립이 대기 중이고 어디에 있는지 알리십시오. 각 클립의 지속 시간, 뷰포트, 정리된 사이드카 요약(마크, 콘솔 오류, 커밋) 및 저장소-상대적인record.mjs명령과 단계 파일이 포함된 PR 댓글을 게시하여 누구든 다시 녹화할 수 있도록 하십시오. PR 본문에서 증명을 "업로드 보류 중"으로 표시하십시오. 비디오를 base64로 붙여넣거나, 커밋하거나, 다른 브랜치로 푸시하지 마십시오.
gh pr는 클라우드 세션에서 작동하지 않을 수 있습니다. 다음으로 댓글을 달으십시오:
gh api repos/$REPO/issues/$N/comments -F [email protected]/proof/$SLUG/comment.md.
클립 옆에 작성할 내용
클립당 한 줄: 어떤 여정, 어떤 세계 템플릿, 뷰포트, 지속 시간, 커밋, 변경 사항이 표시되는 순간 ("0:07 좌석이 강조 표시되고 영혼이 앉습니다"). 또한 콘솔 오류와 허용 가능한 이유를 포함하십시오.
