--- name: review-video-with-pingfusi description: Have any video reviewed by a real human, through iterative pingfusi review rounds. Use when asked to "review this video", "check the rendered video", "does this video match the prompt/brief", "what do people think of this ad/trailer/demo", or after rendering a Remotion composition or AI-generated clip that no test can judge. Works with or without a brief behind the video, and you author the questions and the verdict wording. Do not use for web pages (use fix-with-pingfusi or beautify-with-pingfusi) or for pixel-matching a site (use pixel-perfect-clone). --- # Review a video with pingfusi A machine can render a video; it cannot tell you whether the result lands. This skill puts the video in front of a real human reviewer who scrubs it, pins comments to exact timestamps, draws on frames, answers your questions, and returns a verdict — then you fix the source, re-render, and refile until it passes. Two shapes, one tool. Matching your own render against a brief you wrote is the iteration loop it was built for. But the brief is optional: point it at any video and ask your own questions when there is no prompt behind it to match. ## Non-negotiables - Publish before review. The reviewer is remote: `video_url` must be a public, long-lived MP4 whose host answers Range requests with `206` + `Content-Range` (the service probes it at file time and refuses the round otherwise). A new render is a new URL — never mutate the bytes behind a URL a round already cites. - The brief must be honest, when there is one. `current_brief` is what the video must match NOW. Superseded prompts go into `prompt_history` marked `replaced` — never silently dropped; the reviewer resolves conflicts by state, not guesswork. `requirements` are concrete, checkable claims, each naming the `prompt_ids` it came from. All three are OPTIONAL: a video you did not generate from prompts you control — a competitor's ad, a tutorial, a clip someone sent you — has no brief, and you say what to judge with `video_intro` and `steps` instead. - Everything except `title` is private until claim. `steps`, `verdict_options`, `video_headline`, `video_intro`, the brief, the history and the requirements all travel in a payload delivered to exactly one reviewer when they take the job, so a question may quote the brief it belongs to. `title` is the opposite: it is the PUBLIC headline on the row every reviewer sees while browsing, before anyone claims. Put nothing in it you would not publish. - Ask what you actually want to know. Omit `steps` and `verdict_options` and you get the generic prompt-match questionnaire with `Matches the prompt` / `Needs another pass`, which is right for a render-against-brief loop and wrong for almost everything else. A round asking "would you keep watching past five seconds?" tells you something the generic pair cannot. - Act on feedback in the SOURCE. A timestamped comment means a fix in the composition code, the prompt, or the asset that produced that moment — never a hand-patched frame or a trimmed clip to dodge the note. - Never approve your own render, and never infer approval from prose. Done is a fresh `core.review.verify(stateFile)` returning `ok === true` on the declared verdict. ## Workflow 1. Run `pingfusi doctor`. If the review login is missing, stop and have the user run `pingfusi setup`; there is no offline substitute for a human verdict. 2. Assemble the review context before rendering anything final: every prompt in authored order (`active` / `replaced` / `context`), the distilled `current_brief`, and `requirements` with prompt provenance. The complete context caps at 250 KB. 3. Render the MP4 and publish it through Pingfusi hosting by default: ```sh pingfusi publish --name -round-1 \ --record .pingfusi/video//round-1.json --json ``` The command creates the player wrapper, uploads immutable bytes, and returns a direct `asset_url`; use that value as `video_url`. Pingfusi serves it with `206` and `Content-Range`, so the native player can scrub. The current hosted-video cap is 25 MB per render. If a render cannot fit after reasonable encoding, use another long-lived public host that serves Range requests; do not introduce a live-site tunnel for a file. 4. File the round against a caller-owned state file: Matching a render against a brief you wrote — the iteration loop: ```js const core = require("pingfusi/packages/core"); const { ping_id } = await core.review.file(stateFile, { media_type: "video", video_url, current_brief, prompt_history, // [{ id, text, state: "active"|"replaced"|"context", replaced_by? }] requirements, // [{ id, text, prompt_ids }] n_target: 1, approve_verdicts: ["Matches the prompt"], // local bookkeeping, stripped before the wire }); ``` Judging any other video — no brief, your own questions: ```js const { ping_id } = await core.review.file(stateFile, { media_type: "video", video_url, title: "Launch video, third cut", // PUBLIC — on the browsing row video_headline: "Does this ad land?", // private, top of the reviewer's panel video_intro: "Watch it once at full speed, then scrub back to anything that made you hesitate.", steps: [ // private; your questions { text: "Would you keep watching past the first five seconds?", options: ["Yes", "No"] }, { text: "What is this selling, in your words?" }, ], verdict_options: ["Ready to run", "Needs another cut"], // private n_target: 3, approve_verdicts: ["Ready to run"], }); ``` Mix them freely: keep `requirements` without a `prompt_history` when you want timestamped notes linked to specific claims, or send a `current_brief` with your own `steps`. The one rule is that the reviewer must have something to answer — a brief, requirements, steps, or an intro. `url` and `draft_url` must be absent; video mode refuses them. 5. The filing command automatically chains client-safe wait legs until feedback. If a raw MCP leg returns pending, immediately call `pingfusi_wait` again; never return pending to the user or file a duplicate. Each leg renews the short idle lease; passive result/verify reads do not (a lapse only pulls the round from the feed for new claims; a reviewer mid-review can still finish). When results land, read the envelope: comments arrive sorted by `video_anchor.time_ms`, drawn annotations in normalized frame coordinates (0 = left/top, 1 = right/bottom), questionnaire answers attached to their questions. Fix every noted moment in the source, re-render, publish the NEW file under a new receipt/URL, and refile with the same context — update `current_brief`/`requirements` only if the user's ask actually changed. 6. Repeat until `core.review.verify(stateFile)` returns `ok === true` on your declared approving verdict — `Matches the prompt` by default, or whichever of your own `verdict_options` you named in `approve_verdicts`. Record the receipt; stop only on approval or when the user says stop.