---
title: "Read a trailer's beats, their calls and every take."
method: GET
path: "/trailers/{jobId}/beats"
tags: ["Trailer"]
---

# Read a trailer's beats, their calls and every take.

`GET /trailers/{jobId}/beats`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/trailers/{jobId}/beats`
- Auth: HTTP bearer

Returns the trailer's beats as they render: each beat's plan fields and its render calls (at most 10s each) — duration, audio mode, the plate rung the render opens on, the cast on camera, the shots and the lines spoken in them, the cast's speech track — and every take with its checks: whether each line was heard in a voice of its own (`voiceMissLineRefs`: a line not heard, or said in a voice too like another character's — a flag; `ownReadingLineRefs`: a line said in the take's own voice, heard and distinct, kept and never a flag), whether it opened on its planned framing (`openingMiss`), whether a mouth did not do what its line asks — the speaker's not following an on-camera line, or lips moving under someone else's voice (`mouthMiss`, with the `mouths` check) — whether it was the call's one automatic retake at our cost (`atOurCost`), whether it was not checked for a person shown twice (`duplicateNotChecked`: the check could not judge it even on its retry — never a pass, and it ranks below checked takes), whether its lip sync was not checked (`mouthNotChecked`: no on-camera speaker's mouth could be read, even after the face locator's denser retry — never a pass and never a retake, and it ranks below a take whose mouths were measured passing), whether its lip sync is uncertain (`mouthUncertain`: measured, but a reading sat inside the band around its limit, so the same file could read either side of it — never a pass and never a retake, ranked below a measured pass and above a measured miss), each criterion the mouth check missed or was uncertain on, with its line, face, number and limit (`mouthFindings`), a content refusal (released, never retried; `reference_render_provider_ip_refused` is a shot refused as possibly someone else's intellectual property, whose notice names what to edit before it renders again), the selection, what a priced retake would cost, and the repair engine's state: what the take watcher saw (`watch`), the remedy decided and the rule that fired (`repair`), where a take came from (`lineage`: repaired from, trimmed from, or a new take after, an earlier take), what a repair cost (`repairCost`), what repairing it in place would cost now (`repairQuote`), what a free trim of it may keep (`trimBounds`: never into a spoken line) and, on a trimmed take, the span it kept (`trim`: its cut plays that length). Also the beat's cut and poster, `stale` when the plan changed since it rendered, the master (a 480p preview in review, finished once the finish completes), the delivery class, the warnings the finish and export carry, and `reviewUrl`. A read: it never compiles, renders or makes a plate. Scope: `story:read`.

## Response `200`

The trailer's beats, calls and takes + a browser review link.

- TrailerBeats: A trailer's beats as they render (reads only: it never compiles, renders or makes a plate). Statuses: draft → rendering → review → finishing → complete | failed.
  - `jobId` string, required
  - `title` string, required: The trailer's one name: the writer's own (rename_trailer), else its theme. Never a length (`master.durationSeconds` is the length).
  - `status` 'pending' | 'draft' | 'rendering' | 'review' | 'finishing' | 'complete' | 'failed', required: Where the trailer is. A retired storyboard-era status is terminal and read-only.
  - `shotDensity` 'held' | 'standard' | 'dense', required: How many shots each render of a beat carries (`held`, `standard` or `dense`), set when the trailer was planned. Cuts inside a render are free: it never changes the price.
  - `intent` VideoStoryIntent: What a deck or trailer is FOR. Every deck and trailer is planned from an explicit intent — what the video is for, its logline, theme, central question, stakes, what a first-time viewer is promised, a four-stage arc (setup, escalation, turn, closing question) and how the ending lands the question. Every chapter or beat names the arc stage it serves (`arcStage`), how it advances the central question (`advancesQuestion`) and, after the first, why it follows the one before it (`whyItFollows`: the visible link — a cause, an answer, a contrast, a match cut, a look, an object, a sound — and what it moves forward; one line, never shown on screen). Plan coverage first writes what a first-time viewer would take away from the plan without seeing the intent (`viewerTakeaway`, with how much of the story the words recited rather than let them work out: `toldVersusShown`, and where they lost the thread: `lostTheThread`), then compares it with the intent: intent clarity, the central question, the buildup and whether the theme is carried each fail the plan on their own, and so do subtext — a plan that recites its plot instead of posing its question — and transitions — a part that follows the one before it for no reason a first-time viewer can feel (`weakTransitions` names the weakest, each with its fix); voices (do the characters speak, rather than the narrator carrying everything) is scored beside them.
    - `purpose` string, required: What this video is for: a pitch sells the series, a showcase shows the world AS the story, a trailer hooks the episode.
    - `audience` string: Who it is for (a pitch's buyer, a trailer's audience). Optional.
    - `logline` string, required: What this show is about, in one sentence.
    - `theme` string, required: What it is really about underneath.
    - `centralQuestion` string, required: The dramatic question the video poses and leaves open.
    - `stakes` string, required: What is at risk, and for whom.
    - `viewerPromise` string, required: What a first-time viewer should feel and want by the end.
    - `arc` VideoIntentArcEntry[], required: The four stages, in order: setup, escalation, turn, closing_question.
      - `stage` 'setup' | 'escalation' | 'turn' | 'closing_question', required: Which stage: the arc is exactly setup, escalation, turn, closing_question, in that order.
      - `purpose` string, required: What this stage does for a first-time viewer.
      - `temperature` string, required: The emotional temperature, in words.
      - `intensity` integer, required: The same temperature on a 1–10 scale. It rises to the turn: the escalation runs hotter than the setup, and the turn is the peak of the first three (the closing question may fall quiet).
    - `ending` string, required: How the final moment lands the central question — posed, sharpened, and left open.
  - `reviewUrl` string, nullable, required: Logged-in browser link to the trailer in the Videos tab, where the cut plays — motion cannot play in a terminal.
  - `deliveryResolution` '720p' | '1080p', required: What the finish delivers: the writer's choice, else 720p.
  - `master` object, required: The stitched master: a 480p `preview` in review, `finished` once the finish completes. Only a finished master exports.
    - `url` string, nullable, required
    - `stage` 'preview' | 'finished' | 'null', nullable, required
    - `resolution` string, nullable, required
    - `interim` boolean, required: True while the master is an EARLY LOOK: a take landed while it was stitched, so the cut with every new take is put together after it and replaces it by itself. Nothing reviews an early look; only the latest master is watched.
    - `durationSeconds` number, nullable, required: `master.durationSeconds` is how long the cut runs as it was stitched — every chapter or beat at the length its take plays, the black between them and the closing — the one length to say (never the length the plan asked for). `master.posterUrl` is the still to show before it plays (null when no chapter or beat has one). Null before there is a master.
    - `posterUrl` string, nullable, required: The still to show before the master plays; null when no part of it has one.
  - `platformExports` VideoPlatformExport[], required: The master's copies levelled for another platform (POST `video-export` with a `target`): one per target asked for, in target order, with its link once ready. Empty when none was asked for.
    - `target` 'youtube' | 'x', required
    - `status` 'waiting' | 'queued' | 'rendering' | 'complete' | 'failed', required: `waiting` while the master it is made from is rebuilt; `queued`, `rendering`; `complete` with its link; `failed` with `error` (ask again).
    - `url` string, nullable, required: The levelled copy, once `complete`.
    - `current` boolean, required: False once a newer master replaced the one the copy was made from: export again for a copy of the new one.
    - `loudness` object, nullable, required: What the delivered copy measured on the EBU R128 meter: within 0.5 LU of `targetLufs`, its true peak at or under `truePeakCeilingDbtp`. Null until complete, and for a master with no sound.
      - `integratedLufs` number, required
      - `truePeakDbtp` number, required
      - `loudnessRangeLu` number, nullable, required
      - `levelling` 'linear' | 'dynamic', required: `linear`: one gain, the master's dynamics kept. `dynamic`: the peaks left no room for one gain, so the loudness pass limited them.
    - `targetLufs` number, required: The integrated loudness the copy is levelled to.
    - `truePeakCeilingDbtp` number, required: The true peak the copy never goes over.
    - `error` string, nullable, required
    - `updatedAt` string, date-time, nullable, required
  - `beats` TrailerBeat[], required
    - `beatIndex` integer, required: Zero-based position used by beat tool inputs and stored keys.
    - `beatNumber` integer, required: One-based number shown to the writer: beatIndex 2 is beatNumber 3.
    - `label` string, nullable
    - `name` string, required: What the beat is called on every surface: its label, else what it says or shows (its narration, its words, the app capture it plays), else "Beat N".
    - `storyBeat` string, required: What the beat delivers dramatically: the source its shots are compiled from.
    - `captionText` string
    - `compositionKind` 'image' | 'text' | 'both' | 'capture', required: image = footage only, text = on-screen text only, both = text over footage, capture = one of the project's app captures played as recorded.
    - `capture` object, nullable: A capture beat's capture, as it stands now; null on every other beat. A capture beat plays one of the project's app captures (a real screen recording, `ready`) as it was recorded: set it with the beat refine (`compositionKind: 'capture'` and the capture's `captureId`). It plays the whole capture, or only the stretch of it you keep (`captureKeep`: a start and an end, in seconds of the capture); what it plays runs 4 to 30 seconds, so a longer capture plays a kept stretch of it. The capture must be in the trailer's shape. The beat carries no on-screen text (its caption is cleared and none can be set), and is never rendered or retaken, so it costs nothing. A beat that already has rendered shots cannot become one: add a beat for the capture instead.
      - `captureId` string, required
      - `status` 'uploading' | 'ready' | 'rejected' | 'missing', required: `missing`: deleted, or not one of this trailer's project's captures.
      - `label` string, nullable, required
      - `durationMs` integer, nullable, required
      - `width` integer, nullable, required
      - `height` integer, nullable, required
      - `hasAudio` boolean, nullable, required
      - `soundLufs` number, nullable, required: The take's own sound as its capture finalize measured it, LUFS — its loudest 400 ms, the one number persisted beside `soundSpans` (BL-607), which the mix matches the kept stretch toward -18 LUFS at and this read names. Null when nothing was measured (silence, or a capture predating the field): the take plays as recorded.
      - `ownSoundLufs` number, nullable, required: How loud the take's own sound plays, LUFS, measured once when it was recorded and stored on the take beside its smoothness; null when nobody measured it (a hand upload, or a take recorded before the measurement), never the same as silence.
      - `keepStartMs` integer, nullable, required: Where the stretch of the capture the beat keeps starts, in ms of the capture; null when it plays the whole capture. The stretch of its capture a capture beat plays: `captureKeep` with `startSeconds` and `endSeconds` (seconds of the capture, decimals allowed). The kept stretch must start before it ends, end inside the capture, and run 4 to 30 seconds; the beat then runs that long, and its sound, cursor and camera follow the stretch. Null plays the whole capture again. Changing the beat's capture drops the kept stretch unless you send one with it. Free.
      - `keepEndMs` integer, nullable, required: Where the kept stretch ends, in ms of the capture; null when it plays the whole capture.
      - `problem` string, nullable, required: Why the beat cannot play it now (the sentence the plan approval refuses with); null when it can.
      - `stutter` object, nullable, required: The stretches of what the beat plays whose picture steps instead of moving (in ms of the capture), with the sentence to show; null when it is smooth or was never measured. A flag, never a refusal: the beat still plays. Re-take it on a GPU runner: record the same tour on a machine with a graphics card (a Linux box with an NVIDIA GPU: `sleeperhit capture record <tour.json> --gpu nvidia`, or a Mac), import the new take, and play it instead.
        - `spans` object[], required
          - `startMs` number, required
          - `endMs` number, required
          - `drawFps` number, required: How fast the recording machine drew the page there.
        - `message` string, required
      - `stutterSpansAll` object[], nullable, required: Every stretch of the take's picture that steps, measured over the whole take with no keep window applied, in ms of the capture; the suggestion reads it so it can clear a stutter the current keep hides. `stutter.spans` stays the display-scoped list. Null when the take was never measured for smoothness.
        - `startMs` number, required
        - `endMs` number, required
    - `keepsSound` boolean: True when a beat plays its takes' own sound in the master. A beat that keeps its sound (`keepsSound: true`) plays what its own footage carries in the master: a capture's own recorded track (a table read's voices, the app's own sounds), or a rendered beat's own take sound (a crowd, singers, a room's own sound) instead of the cut's planned silence, room tone and laid lines. It plays over the score: the music dips about 12 dB under it, wherever it sounds. The narration dips it only while a line is spoken, and it comes straight back after; a beat that does not plays the cut's planned sound. A capture only keeps its sound when it has one. Free: in review the master is rebuilt from what it has, and a finished trailer's master is stitched again.
    - `scoreUnderOwnSound` 'duck' | 'out' | 'hold': What the music does under its own sound: `duck` (Lower, the default), `out` (Stop) or `hold` (Keep). Where a beat plays its own sound (a capture's recorded track, a cut that kept its takes' sound, a chapter's kept scene sound), `scoreUnderOwnSound` says what the music does under it: `duck` (Lower, the default) dips it about 12 dB; `out` (Stop) fades it to silence over a quarter second and back after, for a captured video that carries its own score; `hold` (Keep) leaves it at its level (a spoken line still dips it). `ownSoundGainDb` (−12 to +18, null clears) raises or lowers the beat's own sound itself. The score to picture is composed around it, thinning or stopping there, so a score composed before the change is out of date: score to picture again. Free: in review the master is rebuilt from what it has, and a finished video's master is stitched again.
    - `ownSoundGainDb` number, nullable: Its own sound raised or lowered in the master, in dB; null when it plays as recorded.
    - `narrationOverOwnSound` object, nullable: Its narration speaks over its own sound, which dips under the line (the read's `warnings` say so too): `overlapMs` how long, `narration` the line's window and `ownSound` the spans it covers, in ms from its start. Null when they do not overlap.
      - `overlapMs` integer, required
      - `narration` object, required
        - `startMs` integer, required
        - `endMs` integer, required
      - `ownSound` object[], required
        - `startMs` integer, required
        - `endMs` integer, required
    - `writtenSound` string, nullable: What the beat's story beat wrote about its sound, in one line: its held dead air, where the score enters, the sound it carries past its cut into the next beat, and every written sound fact the film could not keep, with why. Null when its story beat wrote none.
    - `screenTrack` object, nullable: A story film's over-the-shoulder plate: whether the laptop's screen was found and followed through the plate's chosen take, so the real recording rides it and then pushes into full screen. When `found` is false the recording played full frame in the plate's place, and `reason` says why. Null on every other beat, and on a plate not rendered yet.
      - `found` boolean, required: The screen was followed through the take: the recording rides it, then pushes into full screen.
      - `trackedSeconds` number, nullable, required: How many seconds into the plate the screen was followed (the push into full screen lands by then); null when it was not.
      - `reason` string, nullable, required: Why the recording played full frame instead, in plain words; null when the screen was followed.
    - `depthPreset` 'flat' | 'subtle' | 'cinematic' | 'showcase' | 'hero' | 'none', nullable: A capture beat's own depth preset: a preset, `none` (full frame whatever the trailer's), or null when it follows the trailer's (GET /trailers/{jobId}/capture-depth). A capture beat's depth plays its recording as a floating window on a branded stage instead of full frame: flat, subtle, cinematic, showcase, hero, shallowest first. Above flat the camera finds the result — it punches in (at most 2× the recording's own pixels) on what each click changed, arriving as it changes, pushes in slowly while the viewer reads, never moves during a scroll and never crops the cursor — and cinematic, showcase and hero add a frame and a 3D turn (cinematic on the opening; showcase and hero hold it through the wide shots, square again before every punch-in), its move varied beat to beat — the left or right side turned away, the top or bottom edge tipped away, a slow push, or held square for about a quarter to a third of the beats. Where the words are read, a held turn is kept strong and made readable: it holds at most of its angle, keeps the words read in focus while the far side falls softly out of focus, and eases only as far as their measured size needs. Showcase sets the recording close up in a laptop or phone on a drifting brand background, and a punch-in never crops the device out of the picture. Each depth beat is rendered beside a flat version and checked: one that got harder to read (smaller text, a softer text crop, words out of focus, or a camera that moves too fast) is first framed closer on its words, keeping its preset and its turn — closer up, the camera pushed in on them, and never a word cut at the frame's edge — and only steps down one preset when that still reads worse, each time rendered again at no charge and keeping the look it asked for (its frame, background and cursor). When the full version cannot be rendered, a quicker version plays instead: subtle, at 720p. Set it for the whole trailer, or per beat; a beat's own preset wins, and `none` plays the recording full frame as recorded. Free.
    - `depthOverrides` CaptureDepthOverrides: Depth tuning deltas over a preset (M-003): cursor/camera/tilt numbers, each clamped to the preset bounds when read, the stage's look (S3b: a device frame, the background's colours and motion — a project's brand, and how much room is around the app, how round its window's corners are and how deep its shadow falls) and the cursor's look (S3c: arrow, hand or auto, its size, colour, shadow, click bounce and sparks, motion blur) and the tap mark's timing on a phone (BL-1223: how early it appears before a press, how long it holds and fades, and how far its lift's ring grows); stored as deltas only. A preset's look (its device frame, its background and its cursor) stays when a beat plays calmer: a beat moved to a gentler preset so its words stay readable, the still version it is checked against, and the quicker version made when the full one cannot be rendered all keep the look that was asked for and lose only motion (the camera and the tilt). Only reading outranks the look: when the app's words would render smaller than the preset's smallest readable size, the margins shrink first, then the device frame is left off.
      - `stage` object: The stage's look: the device the recording sits in, the background behind it, and how much room is around the app, how round its corners are and how deep its shadow falls.
        - `frame` object
          - `bezelPx` number: On a drawn laptop or phone (BL-1225): how thick its black screen edge is, px at 1080p.
          - `radiusPx` number: On a drawn laptop or phone (BL-1225): how round its screen corners are, px at 1080p (a phone follows its own size).
          - `barShare` number: On a window or browser frame (BL-2537): how tall its title bar or tab strip is, a share of the recording's height (0.05 on a window and 0.075 on a browser today). A laptop, a phone or no frame ignores it.
          - `kind` 'none' | 'auto' | 'window' | 'browser' | 'laptop' | 'phone': The device frame: none, auto (the device that fits the recording: a laptop around a landscape one, a phone around a portrait one), a window bar, a browser bar, a laptop or a phone. A laptop or phone always follows the recording's shape.
          - `tone` 'dark' | 'light'
        - `shadow` object: The window's shadow: which way it falls (BL-464) and how deep it falls (BL-394).
          - `from` 'light' | 'down': Which way the window's shade falls: `down` — today's picture, what an absent key reads as; `light` — away from the stage's lit middle. Omit to leave it as it is.
          - `opacity` number: How deep the window's shadow falls: 0 is none.
          - `blurPx` number: How soft the window's shadow is, px at 1080p (BL-2416).
          - `offsetYPx` number: How far the window's shadow drops below it, px at 1080p (BL-2416).
          - `spreadPx` number: How far the shadow is pulled in under the window, px at 1080p (BL-2416); lower tucks it in.
        - `framing` object: How big the app sits in the frame and where (BL-2416): `whole` inside the stage's room (sized by `padding`), or `close`, a product shot filling `fill` of the frame and moved off centre by `offsetX`/`offsetY`. Setting `fill` or an offset without `kind` frames the app close. A close framing that would cut off the words a beat is about plays whole for that beat.
          - `kind` 'whole' | 'close'
          - `fill` number: The share of the frame the recording fills; past 1 the device bleeds off the frame.
          - `offsetX` number: Left (negative) or right (positive) of centre, a share of the frame.
          - `offsetY` number: Up (negative) or down (positive) of centre, a share of the frame.
        - `background` object
          - `stops` string[]: The background's colours, darkest first.
          - `motion` 'still' | 'drift' | 'waves': Whether the background holds still, drifts slowly, or rolls in slow waves.
          - `driftSeconds` number: On a drifting stage: how long the drift takes to travel its lap, seconds (4–60; 24 today). Lower is faster.
          - `driftReach` number: On a drifting stage: how far it drifts, as a share of the frame (0–0.1; 0.04 today). Higher travels further.
          - `auroraWash` number: On an aurora stage (BL-2539): how far the base colour washes toward the second colour (0–0.6; 0.2 today). A gradient or solid stage ignores it.
          - `auroraGlow` number: On an aurora stage: how strong its glows are, a multiplier on each (0–2; 1 today, 0 none).
          - `auroraEdgeFalloff` number: On an aurora stage: how much of the centre's light the frame's edges keep (0.3–1; 0.62 today, 1 no falloff).
          - `source` 'brand' | 'scene': Where the stage stands: `brand` — the project's brand gradient (as every stage stood until now); `scene` — the beat's own room, its location's accepted plate blurred and darkened behind the window. Omit to leave it as it is.
        - `reflection` boolean: True draws a faint mirror of the window's own bottom edge on the stage underneath it; false draws none. Omit to leave it as it is.
        - `padding` number: How much room is around the app: 0 fills the frame with the window, 0.6 leaves the widest margin.
        - `radiusPx` number: How round the window's corners are, px at 1080p: 0 is square.
        - `pageLoadDim` number: How far a dark app's white page load is dimmed (BL-1168): 0 leaves it exactly as recorded, 0.85 (today) the deepest.
        - `address` object: The browser frame's address pill (BL-2536). Omit either to keep today's.
          - `labelMax` integer: How many characters of a long address the pill keeps, the last one an ellipsis (64 today).
          - `loadFadeMs` number: How long the page-load fill under the address takes to leave once the page has loaded, ms (200 today; 0 cuts it at once).
          - `markTone` string: The little site letter's tile colour on any barred frame (BL-2534), #rrggbb: held to the nearest of the 32 site-letter tones (same lightness, every hue). Omit it and each site's name picks its own tone.
        - `windowRim` object: The hairline edge around a window on the stage (BL-2535); a laptop or a phone draws its own body edge and takes none. Omit for the automatic hairline.
          - `widthPx` number: How thick the edge is, px at 1080p (absent: about 1 px, one per 600 px of the window's short side).
          - `tone` 'auto' | 'light' | 'dark': `auto` — the stage decides (white on a dark stage, near-black on a light one); `light` — a white edge; `dark` — a near-black edge.
        - `mirror` object: The mirror under the window (BL-1325): how far it reaches, how soft its far edge goes and how strong it starts. Each omitted is today's mirror; `reflection: false` still turns it off.
          - `reach` number: How far the mirror hangs, as a share of the window's height (a third today).
          - `blurPx` number: How soft its far edge goes, px at 1080p (6 today).
          - `opacity` number: How strong it starts at the window's edge (absent: the frame's tone decides — 0.3 on a dark frame, 0.22 on a light one).
      - `cursor` object: The cursor: its look (S3c: never stepped down) and its feel. Sizes and shadow offsets are px at 1080p.
        - `skin` 'arrow' | 'hand' | 'auto': arrow, hand, or auto (the hand over anything clickable, the arrow elsewhere).
        - `sizePx` number: The cursor's height in px at 1080p.
        - `fill` string: The cursor's fill colour.
        - `shadow` object: Its drop shadow: where it sits under the pointer, how soft it is, and how deep (opacity 0 is none).
          - `offsetX` number: Across, px at 1080p.
          - `offsetY` number: Down, px at 1080p.
          - `blurPx` number: How soft, px at 1080p.
          - `opacity` number
        - `click` object: A click: bounce 0–2 (a squash, an overshoot and a spring back; 0 is the press alone) sparks (the click's flourish: short strokes off the hand's fingertip, a soft ring under the arrow; false draws neither) ripple 0–1 (how strongly the arrow's ring shows; 0 is none, 1 the default) and sparkSize 0.5–2 (how big the hand's spark burst is, scaled as one; 1 the default).
          - `bounce` number
          - `sparks` boolean
          - `ripple` number
          - `sparkSize` number
        - `motionBlur` number: How much it smears along its path while it moves fast: higher is a longer, softer smear, 0 is none (0–1).
        - `smoothing` number: How softly it eases into and out of each move: higher is a smoother, rounder path, lower a crisper one (0–1).
        - `pressScale` number: How far it dips on every click, as a share of its own size: lower is a deeper press, 1 is no dip (0.8–1).
        - `pressMs` number: How long it stays pressed on every click, ms: shorter is a snappier press (40–250).
        - `glideMinMs` number: The least time it takes for any move, even a short hop, ms: higher keeps it from jumping onto a button (150–600).
        - `glideMaxMs` number: The most time it takes for any move, even across the whole screen, ms: higher is slower travel, lower if it drags; never under the least time for a move (300–1000).
        - `preClickPauseMs` number: How long it rests on its target before it clicks, ms: 0 clicks the moment it arrives (0–400).
        - `leanDeg` number: How far the pointer itself leans into its sideways travel, degrees (0 stands it upright). The screen's own lean into the move is tilt.lean.
        - `lift` number: How far the pointer lifts off the page while it travels (its shadow spreads, softens and fades in flight): 0 keeps the shadow glued to the page, 1 is the full lift and the default (0–1).
      - `touch` object: The tap mark a phone frame draws instead of the cursor (BL-1223): how early it appears before the press, how long it holds, how long it fades and how far the lift's ring grows past the disc. The three times are milliseconds; ringGrowth is a share of the disc's radius.
        - `leadMs` number
        - `holdMs` number
        - `fadeMs` number
        - `ringGrowth` number
      - `typing` object: The glow over the field being typed into (BL-2497): how early it arrives before the first keystroke and how long it lingers after the last. A secret field's veil eases in over the same lead.
        - `glow` object
          - `leadMs` number: How early the glow arrives before the typing, ms (150 today).
          - `tailMs` number: How long the glow lingers after the typing, ms (400 today).
          - `strength` number: How big and bright the glow is, as a share of today's halo (1 today; 0 draws none; BL-2481).
      - `follow` object: How closely the camera follows the pointer between shots (BL-2496): how far off-centre the pointer may sit before the camera drifts, how far past that the drift firms up, and how firmly it corrects.
        - `deadZone` number: How far off-centre the pointer may sit before the camera drifts after it, a share of the half-frame (0.5 today).
        - `ramp` number: How far past that the drift eases from its gentlest to its firmest, a share of the half-frame (0.15 today; 0 firm at once).
        - `strength` number: How firmly the drift corrects toward the pointer, × today's (1 today; 0 never follows).
      - `clickImpact` object: How a click presses and rocks the picture (BL-1286).
        - `ms` number: How long the press plays, ms (260 today).
        - `dip` number: How deep the picture dips (0.24 today).
        - `rise` number: How far it rebounds past the press (0.16 today).
        - `rockDeg` number: How far the picture rocks at a tap near its edge, degrees (1.9 today).
        - `sparkMs` number: How long a click's flourish (the hand's sparks, the arrow's ring) flies and fades, ms (420 today; 0 draws none; BL-1322).
      - `clickSound` object: How the clicks sound (BL-1246).
        - `levelDb` number: How loud a click sounds, dBFS (−12 today).
        - `underVoiceDb` number: How loud under a spoken line, dBFS — never louder than levelDb (−30 today).
        - `minGapMs` number: The least time between two clicks heard, ms (120 today).
      - `resultTrace` object: The ring around what a click opened (BL-1285): its clock after the result appears, held drawMs ≤ holdMs ≤ endMs, and its stroke.
        - `drawMs` number: Drawn in by, ms (350 today).
        - `holdMs` number: Held at full until, ms (900 today).
        - `endMs` number: Gone by, ms (1300 today).
        - `ringPx` number: Its stroke, px at 1080p (2 today; 0 draws none).
      - `caption` object: How the stage caption (and the callout pointing from it) arrives and leaves (BL-1287).
        - `enterDelayMs` number: The wait after the picture lands, ms (250 today).
        - `enterMs` number: How long it takes to arrive, ms (450 today).
        - `rise` number: How far it rises into place, a share of its size (0.35 today).
        - `exitMs` number: How long it takes to leave, ms (300 today).
        - `shortBeatMs` number: A beat shorter than this captions at once, ms (1600 today).
        - `shortEnterMs` number: A short beat's caption arrives over this, ms (300 today).
      - `closer` object: The close-up (BL-2417): how a beat framed closer for reading (the video review found its words hard to read) shows the app. Changes nothing on a beat that is not framed closer.
        - `fill` number: The recording's share of the stage (past 1 it crops into the app's own margins, only with no device frame, never past a word).
        - `pushScale` number: The slow push toward the words while they are read; 1 is no push (the off value).
        - `fitMargin` number: The air left around the words, a share of the frame.
      - `camera` object
        - `move` 'auto' | 'yawLeft' | 'yawRight' | 'pitchUp' | 'pitchDown' | 'dolly' | 'hold': The camera move (S3d) through the wide shots between the punch-ins: yawLeft or yawRight (the left or right side turned away), pitchUp or pitchDown (the top or bottom edge tipped away), dolly (square, a slow push in), hold (square and still), or auto (the trailer varies it: never the same move twice in a row, about a quarter to a third held square). The click punch-ins play on every move.
        - `maxScale` number
        - `readHold` object
          - `scale` number
          - `ms` number
          - `minGapMs` number
        - `orbit` number
        - `driftPerSecond` number
        - `dollyScale` number
        - `openWideMs` number: How long the recording holds the whole screen wide at the start, ms (0: it starts already punched in).
        - `closeWideMs` number: How long the recording holds the whole screen wide at the end, ms (0: it ends without coming back out).
        - `leastBetweenWidesMs` number: How close two wide moments may sit, ms: under this the two shots merge into one or one is dropped.
        - `rampBaseMs` number
        - `rampPerLnMs` number
        - `tailMs` number: How long the camera rests wide after a read, ms (BL-1266).
        - `mergeGapMs` number: How close two click punch-ins may sit before they plan as one move, ms.
        - `chainGapMs` number: The gap under which two moves chain into a pan instead of cutting, ms.
        - `minHoldMs` number: The least the camera holds a punch-in on what it shows before it may leave, ms (1800 today); a punch-in with no room for it is skipped (BL-2494).
        - `chainPanMs` number: How long a chained pan travels from one move to the next, ms (1000 today; BL-2494).
        - `fitMargin` number: How much air a punch-in leaves around what it holds, a share of the frame on each side (BL-2470): 0 frames it tight to the edge, 0.25 leaves a quarter of the frame as air; 0.12 by default.
        - `followCaret` boolean: Whether a typing punch-in follows the caret (BL-2538): true (the default) slides the framing along the line as the text fills; false holds it on the field's centre for the whole beat.
        - `holdOnResult` boolean: Whether the picture holds a moment on what the beat's last click changed (BL-463): true (the default) stops the recording briefly on the result while the cursor, caption and click sound keep going; false lets it run straight through. The beat's length never changes.
      - `tilt` object
        - `angleScale` number: The 3D turn's strength against the preset's (0 is no turn: no 3D depth at all).
        - `lean` number
        - `hold` 'opening' | 'wide': Where the turn is held (S3d): on the opening only, or through every wide stretch (square again before each punch-in and read).
        - `startDeg` number: The turn's angle in degrees on its move's main axis at the beat's first frame (with `endDeg`, both or neither; a yaw turns at most 25.2°). Replaces the preset's strength × the beat's varied angle.
        - `endDeg` number: The turn's angle in degrees at the beat's last frame, eased from `startDeg` (the same number holds one angle).
        - `rampMs` number: How long the 3D turn takes to ease in and out, ms (700–800 today; BL-2418).
        - `minHoldMs` number: With `hold: wide`, the shortest wide stretch the turn is held through, ms (1600–1800 today); a shorter one stays square (BL-2418).
        - `minEstablishMs` number: The shortest quiet opening (or establish-mark stretch) a turn is laid on, ms (1000–1200 today; BL-2418). It never delays a turn: a turning beat opens already turned (easing in from square after a cut); longer drops the turn from beats whose quiet opening is shorter.
      - `dof` object: The depth of field on a turned screen (S3d): its far side softly out of focus, sharp toward its near edge.
        - `maxBlurPx` number: The far side's blur at full turn, px at 1080p; 0 is none.
        - `focus` number: How much of the turned screen stays sharp, from its near edge inward; 0.8 keeps the most.
      - `spotlight` object: The spotlight while a shot holds on one control (BL-1163): how far the rest of the app dims, how long it takes to dim, and the shortest hold that dims at all.
        - `dim` number: How dark the rest of the screen goes while a shot holds on one control, 0–0.85; 0 is no dim.
        - `rampMs` number: How long the dim takes to come in, ms, 0–600.
        - `minHoldMs` number: The shortest hold that dims at all, ms, 0–2000.
    - `stageCaption` string, nullable: A capture beat's stage caption, or null. A capture beat's stage caption is a few words (at most 60 characters) shown in the stage's margin below the floating window, never over the captured screen. It needs a depth preset: a beat played full frame has no margin.
    - `captureSpeedUp` 'off' | 'gentle' | 'standard' | 'brisk', nullable: A capture beat's own speed-up, or null when it plays the default (`standard`). A capture beat plays the stretches where the viewer would only wait (the page loading or an answer streaming in, a long run of typing, a long scroll, an idle pause) sped up and eased in and out, while every click, its result and the moments to read play at real speed; the narrator's line still lands on its click, and the beat is never cut shorter than its line. On by default. `captureSpeedUp` sets it for one capture beat: `off` (real time), `gentle` (about 2× through waits), `standard` (the default, about 4×) or `brisk` (about 8×); null puts the beat back on the default. A beat that keeps its recording's own sound plays in real time unless it is set.
    - `depth` string, nullable: A capture beat's depth in one sentence: what it asks for, and what the last master played (stepped down, or rendered as the quicker version, and why). Null on every other beat.
    - `shotType` string, nullable: The beat's framing as the plan wrote it.
    - `characterAction` string, required: What the people in this beat physically do, in order. A beat held as one shot is filmed from it; a beat with a cut list is filmed from its shots' own characterAction instead. When it changes what the beat films, its takes go out of date. Never on-screen text — words on the screen belong in captionText. An empty string clears it. Empty when the plan states none.
    - `stagingNotes` string, required: Where the people and things in this beat are and how the picture is arranged. A beat held as one shot is filmed from it; a beat with a cut list is filmed from its shots instead. When it changes what the beat films, its takes go out of date. Never on-screen text. An empty string clears it. Empty when the plan states none.
    - `motionPrompt` string: The beat's camera-motion prompt (`trailer refine --motion-prompt`), which the render reads; '' when unset.
    - `transitionPrompt` string: The handoff out of this beat into the next (`trailer refine --transition-prompt`); '' when unset.
    - `transitionIn` string: The incoming side of the seam into this beat (`trailer refine --transition-in`); '' when unset.
    - `shots` TrailerShot[], nullable: The beat's cut list, or null when the beat is one held shot.
      - `shotType` string, required: THIS shot's framing — the point of a cut list is that the framing changes between entries. Shot 1's framing picks the plate rung the render opens on.
      - `storyBeat` string, required: What this shot delivers dramatically: the fragment of the build that happens here, not the beat's whole arc.
      - `cameraMove` string: What the camera does in THIS shot: holds, pushes in, travels, cranes, follows. Keep the move inside this shot: the next one starts on a hard cut.
      - `characterAction` string: What the figure physically does during this shot.
      - `visibleCharacters` string[]: Exact project-canon cast names visible in THIS shot (max 3).
      - `spokenLine` string: Exact words a VISIBLE character speaks during this shot.
      - `spokenLineCharacter` string: Who says `spokenLine` in this shot.
      - `location` string: Where THIS shot is, when it is not the beat's own place. A beat names where it is set in its `location`: a canonical location key, the place its location image is made of. A beat may travel: a shot set somewhere else names that place in its own `location` (a key, or a place in plain words), and the render follows it there.
      - `durationSeconds` number: How long this shot holds, in seconds (at least 2; as short as 1 in a montage beat). Optional: the fitter rescales written rhythms to the beat, and an all-unwritten list is split evenly.
    - `visibleCharacters` string[]: The named characters in the picture (an identity reference each). Unnamed people are not listed.
    - `location` string, nullable: Where the beat is set: a canonical location key (the room's key in the location plates read, e.g. INT_TAVERN), never a scene heading. A beat names where it is set in its `location`: a canonical location key, the place its location image is made of. A beat may travel: a shot set somewhere else names that place in its own `location` (a key, or a place in plain words), and the render follows it there.
    - `arcStage` 'setup' | 'escalation' | 'turn' | 'closing_question' | 'null', nullable: The stage of the intent's arc this unit serves (setup, escalation, turn, closing_question), or null when the plan names none — a blocking plan defect on a plan with an intent.
    - `advancesQuestion` string, nullable: How this unit advances the intent's central question, or null when the plan says nothing — a blocking plan defect on a plan with an intent.
    - `whyItFollows` string, nullable: Why this unit follows the one before it — the link a viewer sees or hears (a cause, an answer, a contrast, a match cut, a look, an object, a sound) and what it moves forward; never on screen. Null when the plan says nothing: after the first unit, the blocking plan defect `transition_unexplained`.
    - `narrationText` string, required: What the narrator says over this beat: one line in the cut's narrator voice, laid over the finished picture (never part of the footage). Heard only when the cut narrates (`audioPolicy: narrate`). Write what the cut means, never what is on screen, and leave it empty on a beat whose character speaks. It never makes a take stale; on a rendered trailer that narrates, the new line is voiced and the master stitched again, free. An empty string clears it. Empty when the plan states none.
    - `montage` boolean: True when the beat is a rapid intercut run: brief shots cut tight across the people and places it names (its shots may run as short as 1 s).
    - `clipUrl` string, nullable: The beat's cut, assembled from its calls' selected takes.
    - `clipResolution` string, nullable
    - `posterUrl` string, nullable
    - `textClipUrl` string, nullable
    - `audioUrl` string, nullable: The narrator's line over this beat, voiced; null before it is voiced, after its words change (the next master voices them again), or when the beat has none.
    - `stale` boolean, required: The plan changed since this beat rendered: render it again to bring it in line. Its takes stay playable.
    - `motionError` string, nullable
    - `calls` TrailerCall[], required
      - `callId` string, required
      - `durationSeconds` number, required
      - `audioMode` 'dialogue' | 'ambient' | 'silent', required
      - `plateKey` string, nullable, required: The location plate the render opens on (the rung matched to shot 1's framing), or null for a text-only render: no named character on camera and no speech track, so no reference image is sent.
      - `cast` string[], required: Who is on camera (a body figure each).
      - `blocking` string
      - `shots` object[]
        - `framing` string
        - `onCamera` string[]
        - `setup` string
        - `action` string
        - `startSeconds` number
        - `endSeconds` number
        - `lines` object[]
          - `lineRef` integer
          - `speaker` string
          - `text` string
          - `voice` string
      - `speechTrack` object, nullable: The cast's recorded lines the selected take was sent with (dialogue calls).
        - `url` string
        - `seconds` number
      - `takes` TrailerTake[], required
        - `take` integer, required
        - `status` 'accepted' | 'rejected' | 'failed' | 'pending', required
        - `videoUrl` string, nullable
        - `atOurCost` boolean, required: True for the call's ONE automatic retake (a line not heard or said in another character's voice, a mouth that did not do what its line asks, or an opening off its framing): we paid for it, never the writer.
        - `selected` boolean, required
        - `selectedBy` 'default' | 'writer' | 'null', nullable
        - `voiceMissLineRefs` integer[], required: Lines this take failed by voice: not heard where they belong, or said in a voice too like another speaking character's. A flag: the take is retaken once automatically, ranks below a take without one, and may still be selected by the writer.
        - `ownReadingLineRefs` integer[], required: Lines this take said in its own reading, heard and distinct from the other voices, and kept: never a flag. Every take plays its own sound under its own picture, so the lips follow what is heard; such a line does not sound like the cast card's voice.
        - `openingMiss` boolean, required: True when shot 1 opened off its planned framing.
        - `mouthMiss` boolean, required: True when the mouth check measured a mouth that did not do what its line asks, past the band around the limit, or the quiet-mouth check measured a face moving its lips as if speaking where no line is heard (`quiet_mouth_motion`): the speaker's mouth not following an on-camera line (or following it too late or early, or still moving after it), or lips moving under someone else's voice or a voice-over. `mouthFindings` names each criterion and its number. Where the speaker's mouth could not be measured (a face too small, not found or hidden — or a miss read on a face too small to trust), the take watcher's own look at the lips decides the line (unmeasurable → decided by the watcher, finding `watcher_lip_sync`): a mouth it saw not speak the line is a miss. A reading inside the band, or an unread speaker the watcher saw speak, is `mouthUncertain`, never a miss.
        - `mouthUncertain` boolean, required: True when the take's lip sync is UNCERTAIN: measured, but a criterion sat inside the band around its limit — r within 0.10 of 0.35, one frame too many open after the line, a listener's openings just past the limit — so the same file could read either side of it; or unmeasurable → decided by the watcher, which saw the speaker's mouth speak the line (`watcher_lip_sync`, uncertain). Never a pass and never a retake (automatic or priced): the take ranks below a measured pass and above a measured miss, and its `warning` names the criterion and its number. Also true when a face where no line is heard is TOO CLOSE TO CALL (`quietMouths`: read near its bar, or a pod reading of lips moving that the take watcher did not see too): its words are in `mouthFindings` (outcome `uncertain`), it is the writer's to retake (the call's `retake`), and it is never retaken automatically nor ranks the take down.
        - `mouthFindings` object[], required: Every criterion the mouth check missed (`outcome: fail`) or was uncertain on (`outcome: uncertain`), misses first. Speaker: `correlation` (r, the least that passes), `lag` (ms the mouth trails the voice, negative when it leads; the most that passes), `trailing_motion` (the share of the frames after the line with the mouth open), `articulation` (the lips barely part under the voice: the mean openness of the voiced frames, 0 closed to 3 wide; the least that passes), `articulation_stretch` (voiced frames running on lips that never open; the most that passes). Still face: `still_open_run` (frames), `still_open_share`, `still_openings`. `watcher_lip_sync`: unmeasurable → decided by the watcher — a speaker whose mouth could not be measured (or whose miss was read on a face too small to trust) is decided by the take watcher's own look at the lips: `fail` when it saw the mouth not speak the line (a miss, retaken like any), `uncertain` when it saw it speak; `value` is the watcher's severity on the speaker (0 none, 1 minor, 2 major, 3 critical), `limit` 1. Empty on a pass and when the lips were not checked.
          - `lineRef` integer, required
          - `name` string, required
          - `role` 'speaker' | 'still', required
          - `criterion` 'correlation' | 'lag' | 'trailing_motion' | 'articulation' | 'articulation_stretch' | 'still_open_run' | 'still_open_share' | 'still_openings' | 'watcher_lip_sync' | 'quiet_mouth_motion', required: `quiet_mouth_motion`: a face whose lips were MEASURED moving as if speaking where NO line is heard (the quiet-mouth check; `lineRef` 0, `startSeconds`–`endSeconds` say where in the take; `value` its lip movement or mouth motion, `limit` the bar it crossed).
          - `outcome` 'fail' | 'uncertain', required
          - `value` number, required
          - `limit` number, required
          - `words` string, required: The sentence every surface shows, with the numbers.
          - `startSeconds` number: Where in the take it was seen, when narrower than its line (`articulation_stretch`, `quiet_mouth_motion`).
          - `endSeconds` number
        - `playthrough` object, nullable: The per-line check that the take played the cast's recorded lines: `{ status: checked | unavailable | not_applicable, pass, lines[], reason }`.
        - `opening` object, nullable: The opening-framing check: `{ status: judged | unavailable, pass, plannedFraming, observedFraming, detail, reason }`.
        - `quietMouths` object, nullable: The QUIET-MOUTH check — every named face on camera where NO line is heard (a silent or ambient take throughout, a dialogue take between and around its lines), MEASURED, two ways (`measure`): `lips` — the render box found the face and outlined its lips (Apple Vision), and `energy` is how far the lips' openness swung across the stretch once its slow drift is out — a smile, a head turn, a push-in or the light read still (still under 0.06, speaking at 0.08 or more; `box` is where the face was); `motion` — no box answered, so the face was located and its lower face's motion that no head or camera move explains was measured against its upper face's (still under 0.13, speaking at 0.18 or more), and a `motion` reading of `speaking` counts only where the take watcher saw lips moving too (else `uncertain`, with why: a push-in, a flare or a smile reads the same). `{ status: checked | unmeasurable | unavailable | not_applicable, pass, uncertain, spans[{ shot, startSeconds, endSeconds, onCamera, faces[{ name, status: measured | unmeasurable, verdict: still | uncertain | speaking | null, energy, measure: lips | motion, box, exempt, faceHeightPx, startSeconds, endSeconds, pairs, pairsSetAside, words }], keepsSceneSound }], reason, version, clipSha256, cached }`. A face the box read in a shot with more than one person is named by where it sits ("the face on the left") unless it moved, when the face locator names it. Where the chapter keeps its own sound (`keepsSceneSound`: a crowd, singers), only the cast's named faces are held: a moving face none of the cast is recorded with `exempt: kept_scene_sound`, never a miss. A face `speaking` is a mouth miss (`mouthMiss`, a `quiet_mouth_motion` finding), but never retaken on its own: the same staging brings it back, so the take's decision offers a new take held `restage_needed` (restage the shot: one face, framed closer), unless the lips run on past the take's last line, which is trimmed free (`trim_overrun`). `uncertain` is shown (`mouthUncertain`, and a minor review finding marked `uncertain`) and is the writer's to retake, never retaken automatically and never a veto. Null when it never ran on this take.
        - `quietTrack` 'silence' | 'room_tone', nullable: The trailer's quiet track this take was sent as its voice track (a render with no spoken line, while the trailer sends one: get_trailer_quiet_track); null: none. Compare the quiet-mouth checks of takes with and without it.
        - `mouths` object, nullable: The mouth check: `{ status: checked | unmeasurable | unavailable | not_applicable, pass, uncertain, lines[{ lineRef, speaker, voice, shot, status: measured | unmeasurable, pass, uncertain, reason, faces[{ name, role: speaker | still, status, pass, uncertain, findings[{ criterion, outcome, value, limit, words }], correlation, lagMs, openShareAfter, speechOnCameraSeconds, box, states }], locatorFrames, locatorRetried, decidedBy: mouth_reader | watcher | null, watcher: { basis: unread | small_face, verdict: rigid | speaking, finding, words } | null }], reason, version, clipSha256, cached }`. A line with `decidedBy: watcher` is unmeasurable → decided by the watcher: its speaker's mouth could not be measured (or its miss was read on a face shorter than the reader is trusted on alone), so the take watcher's judgment decided it — `rigid` is a miss, `speaking` is uncertain. The verdict is stored by the take file's content hash (`clipSha256`) and the check `version` (the code, its numbers, both judging rows and their models): the same file always returns the same verdict (`cached: true` on a re-check). The face locator reads frames across each line's speech (`locatorFrames`, in seconds) with each person's identity image, and once more, denser, when it finds the speaker in none (`locatorRetried`); in `states`, one character per tenth of a second, `.` is off camera. Each line's `measure` says how its mouths were read: `lips` (the render box's lip outlines, measured; no `locatorFrames`) or `reader` (the face locator and the mouth reader). Null when it never ran on this take.
        - `abandoned` boolean, required: True for A TAKE THAT NEVER FINISHED (RELEASED): the job holding its claim died (a restart, a redeploy) before anything was sent, so the claim was released, any credits reserved for it were released once, and the shot's next take was decided again. It is recorded `failed` (`failure.code` `take_never_finished`, `failure.message` says why), never selected, and never counts against the shot's automatic retake. Say "a take that never finished (released)".
        - `checksPending` boolean, required: True while the take's CHECKS HAVE NOT COMPLETED — its QA, its mouth or duplicate-person check, or its watch (a redeploy can interrupt them; the worker runs them again): nothing proves the take is clean yet. It ranks below every take whose checks completed, so it is never selected by default over one, and its `warning` says so. Say "checks pending", never "clean".
        - `identitySwaps` object[], required: Every line the WRONG PERSON speaks: the mouth check found the line's `speaker` nowhere on camera across it, and `face` — another member of the call's cast, matched by their identity image — following it. A measured miss of its own kind (`mouthMiss` is true too): it earns the call's automatic retake, told whose face must say the line, and the take never plays over one the right person speaks. Empty when none.
          - `lineRef` integer, required
          - `speaker` string, required
          - `face` string, required
        - `mouthNotChecked` boolean, required: True when the take's lip sync was NOT CHECKED: the mouth check could not read an on-camera speaker's mouth (the face not found even after the locator's denser retry, too small or hidden) and no watch of the take could decide it instead, read no line, or could not run. A speaker the take watcher decided is a `mouthMiss` or `mouthUncertain`, not this. Never a pass: the take ranks below every take whose mouths were measured passing, and its `warning` says why. It earns no retake, automatic or priced: only a measured `mouthMiss` does.
        - `duplicatePerson` boolean, required: True when the duplicate-person check saw one person in the picture twice at once. It earns the call's one automatic retake, and the take ranks below every other take for the default selection.
        - `duplicateNotChecked` boolean, required: True when the take was NOT CHECKED for a person shown twice: the duplicate-person check could not judge it, even on its one retry (or never ran on it). Never a pass: the take ranks below every take whose check passed, and its `warning` says so. It earns no automatic retake.
        - `duplicates` object, nullable: The duplicate-person check: `{ status: judged | unavailable, pass, duplicates[{ name, shot, seconds, detail }], reason }`. `unavailable` (after one retry) proves nothing and is never a pass: see `duplicateNotChecked`. Null when it never ran on this take.
        - `warning` string, nullable: The sentence the finish quote and the export carry if this take is kept.
        - `failure` object, nullable: Why the take produced nothing. `moderation: true` is a content refusal: released (nothing charged) and never retried. `code: reference_render_provider_ip_refused` is the provider refusing the shot as possibly someone else's intellectual property: the same shot is refused again, so the call's notice says what to edit (and the likely trigger: currency, a logo or brand, a named work) before it is rendered again.
          - `code` string
          - `message` string
          - `moderation` boolean
        - `billedSeconds` number, nullable
        - `recordedAt` string, date-time
        - `watch` TakeWatch: The take watcher's pass over one take. `unavailable`: the watch could not finish (after one retry with more room), so it proves nothing either way and the take is UNWATCHED — its decision reads `unwatched`, never clean, and `decision: rewatch` watches it again, free; `skipped` was not watched on purpose (the checks alone then decide).
          - `status` 'watched' | 'unavailable' | 'skipped', required
          - `defects` TakeDefect[], required
            - `kind` 'anachronism' | 'signage' | 'stray_person' | 'duplicate_person' | 'crowd_unison' | 'lighting' | 'camera_path' | 'speed_ramp' | 'timing' | 'invented_cut' | 'drawn_screen' | 'identity' | 'identity_swap' | 'lip_sync' | 'line_voice' | 'other', required
            - `source` 'watcher' | 'playthrough' | 'mouths' | 'duplicates' | 'opening' | 'dissolves', required: `watcher`: the take watcher saw it; the others are the checks that measured it.
            - `severity` 'minor' | 'major' | 'critical', required: `minor` is shown and never acted on; `major` and `critical` earn a remedy.
            - `startSeconds` number, required: Seconds from the start of the take.
            - `endSeconds` number, required
            - `description` string, required
            - `removableInPlace` boolean, required: True when it can be removed or replaced in place without a new take.
            - `replaceWith` string, nullable: For a removable defect: what should be there instead, in plain words (never a word to write).
          - `reason` string, nullable, required
          - `watchedAt` string, date-time, required
        - `repair` TakeRepairDecision: What the repair engine decided for one take, and why. Every rendered take is watched with its sound after its checks. A cut nobody asked for at the start or end of an otherwise good take is trimmed off first, before any new take: free, frame for frame, only where the cut is measured in the file, outside every spoken line (each kept whole with a breath after it), and only when what is left keeps its chapter or beat within a quarter of its planned length. When the shot's automatic new take is spent and the take it plays still has such a cut outside its line, that end is trimmed as a last resort: past the quarter, as long as the line stays whole, at least 2 seconds are left and the chapter or beat keeps half its planned length. A cut inside a spoken line is never trimmed. A speaker whose lips keep moving past the take's last line, where nothing is heard, is trimmed half a second after the line, free and frame for frame. Lips moving where no line is heard are never retaken on their own: the same staging brings them back, so the shot is offered for restaging (one face, framed closer), a trim, or your call. Any other defect is remedied by rule during processing, at our cost: first a new take told what to avoid; a repair in place when the same problem comes back after a new take, or when the take passed every other check and only something removable (a period anachronism, garbled lettering, a stray or doubled person) or the light is wrong. Camera movement and its speed (a move that rushes, or dies into a hold at the end), timing, cuts and a crowd moving as one (extras in step, everyone turning or looking down at once, repeated faces) are only ever fixed by a new take, or by the free trim when they sit only at an end of the take. A made-up screen or app the shot never had (a display or app window painted into the picture where none was filmed) is only ever fixed by a new take, or by the free trim when it sits only at an end of the take; spoken shots are not repaired in place. A line the speaker's mouth did not speak on two takes is no longer retaken on camera: the next take stages it as a voice-over, the speaker seen from behind, the line heard over the picture. Every take plays its own sound under its own picture, so the lips follow what is heard: a line said in the take's own reading is kept, and only a line not heard, or said in a voice too like another character's, is a defect (a new take). Where a speaker's mouth cannot be measured (or the face is too small to trust a miss), the watcher's own judgment of the lips decides the line: a mouth it saw not speak is a miss, one it saw speak is uncertain. Each shot gets at most one automatic new take, one automatic repair in place and one automatic voice-over re-stage, so a new take whose removable defect came back is repaired in the same pass; a repaired or trimmed take is never remedied again on its own. A repair that fails on the repair service's own side (never one declined at its content check) and cost nothing is sent again once; if that fails too, a new take instead. A repaired take keeps the take's own sound, is judged again, and is kept as a new take linked to the one it repairs; it plays only when it passes. A trimmed take plays over the take it came from when it passes, or when it shows only part of what that take showed, with the same speech and faces: it is judged by time window, so anything seen inside the span it keeps counts as that take's own footage too, and it wins when the trim cut something off.
          - `remedy` 'none' | 'wan_retake' | 'aleph_repair' | 'trim' | 'stage_as_voice_over', required: `none`; `trim`: a cut nobody asked for at the start or end of the take is cut off (free, frame for frame, never into a spoken line; see `trim`); `wan_retake`: a new take, told what to avoid; `stage_as_voice_over`: a new take that plays a line whose speaker's lips failed it on two takes as a voice-over (see `voiceOver`); `aleph_repair`: a repair in place.
          - `rule` 'not_judged' | 'clean' | 'writer_kept' | 'first_remedy_is_a_new_take' | 'recurred_after_new_take' | 'clean_but_removable' | 'needs_a_new_render' | 'spoken_shot_held_from_repair' | 'repair_refused_before' | 'repair_unavailable' | 'writer_requested' | 'trim_edge' | 'writer_trimmed' | 'repair_failed_at_host' | 'line_revoiced_twice' | 'mouth_failed_twice' | 'writer_staged_voice_over' | 'trim_last_resort' | 'trim_overrun' | 'unwatched', required: The rule that fired. `unwatched`: the take's watch could not finish, so nothing is decided for it (never `clean`, never a remedy on its own); `defects` lists what its other checks measured, and `take-repair-override` with `decision: rewatch` watches it again, free.
          - `reason` string, required: The rule in plain words, with what was found.
          - `defects` TakeDefect[], required
            - `kind` 'anachronism' | 'signage' | 'stray_person' | 'duplicate_person' | 'crowd_unison' | 'lighting' | 'camera_path' | 'speed_ramp' | 'timing' | 'invented_cut' | 'drawn_screen' | 'identity' | 'identity_swap' | 'lip_sync' | 'line_voice' | 'other', required
            - `source` 'watcher' | 'playthrough' | 'mouths' | 'duplicates' | 'opening' | 'dissolves', required: `watcher`: the take watcher saw it; the others are the checks that measured it.
            - `severity` 'minor' | 'major' | 'critical', required: `minor` is shown and never acted on; `major` and `critical` earn a remedy.
            - `startSeconds` number, required: Seconds from the start of the take.
            - `endSeconds` number, required
            - `description` string, required
            - `removableInPlace` boolean, required: True when it can be removed or replaced in place without a new take.
            - `replaceWith` string, nullable: For a removable defect: what should be there instead, in plain words (never a word to write).
          - `automatic` boolean, required: True when the engine applied (or applies) it on its own, at our cost.
          - `heldBy` 'one_remedy_per_pass' | 'new_take_budget_spent' | 'repair_budget_spent' | 'spend_gate' | 'next_take_is_the_writers' | 'writer_overrode' | 'failed_repair_billed' | 'voice_over_budget_spent' | 'restage_needed' | 'null', nullable, required: Why it was not applied automatically: it is offered to the writer instead.
          - `outcome` 'applied' | 'offered' | 'failed' | 'refused' | 'pending' | 'none', required: `refused` only when the repair was declined at the content check (never sent again unchanged).
          - `resultTake` integer, nullable, required: The take the remedy made, once it exists.
          - `outcomeMessage` string, nullable, required
          - `decidedAt` string, date-time, required
          - `trim` TakeTrimPlan: A trim: the span of the take that is kept (frame-exact) and what was cut off at each end.
            - `keepStartSeconds` number, required
            - `keepEndSeconds` number, required
            - `keptSeconds` number, required: The kept span's length: what the trimmed take plays in its cut.
            - `takeSeconds` number, required: The take's length before the trim.
            - `edges` TakeTrimEdge[], required
              - …
            - `basis` 'outside_the_line' | 'dying_move' | 'last_resort_after_retakes' | 'speaker_overrun', nullable: Why the engine trimmed it, recorded with the take's checks: `outside_the_line` ("invented edge cut trimmed: outside the line": the free trim before any new take, the invented edge cut lying outside every spoken line and the chapter or beat kept within a quarter of its plan), `dying_move` ("camera move dying into a hold trimmed: outside the line": the same free trim of a camera move that dies into a hold at the end, cut at the hold's first frame, never slowed or padded) or `last_resort_after_retakes` ("invented edge cut trimmed: last resort after retakes": the shot's automatic new take was spent, so the take it plays was trimmed past the quarter, the line kept whole, at least 2 s left, the chapter or beat at least half its plan). Null for the writer's own trim.
            - `droppedLineRefs` integer[], nullable: The lines this trim cut OUT of the take (the writer cut the chapter's line out and kept the rest of its footage): the span kept is one side of them. Null for every other trim, which keeps every line whole.
          - `voiceOver` TakeVoiceOver: Lines a take plays as a VOICE-OVER that its call says on camera: the speaker seen from behind, the line heard over the picture.
            - `lineRefs` integer[], required
            - `speakers` string[], required
        - `lineage` TakeLineage: Where a take came from: the take it remedies, and how.
          - `repairedFrom` integer, required
          - `remedy` 'wan_retake' | 'aleph_repair' | 'trim' | 'stage_as_voice_over', required: `trim`: a trim of the take (free); `wan_retake`: a new take after it; `stage_as_voice_over`: a new take after it that plays its line as a voice-over; `aleph_repair`: a repair of it in place.
          - `rule` 'not_judged' | 'clean' | 'writer_kept' | 'first_remedy_is_a_new_take' | 'recurred_after_new_take' | 'clean_but_removable' | 'needs_a_new_render' | 'spoken_shot_held_from_repair' | 'repair_refused_before' | 'repair_unavailable' | 'writer_requested' | 'trim_edge' | 'writer_trimmed' | 'repair_failed_at_host' | 'line_revoiced_twice' | 'mouth_failed_twice' | 'writer_staged_voice_over' | 'trim_last_resort' | 'trim_overrun' | 'unwatched', required
          - `automatic` boolean, required: True for the engine's automatic remedy (at our cost).
        - `repairCost` TakeRepairCost: What a repair cost on our ledger: the repair host's own billed units and their dollars.
          - `hostCredits` number, nullable, required
          - `estimatedHostCredits` number, nullable, required
          - `usd` number, nullable, required
          - `billedSeconds` number, required
        - `repairQuote` TakeRepairQuoteLine: What a writer-requested repair of this take would cost now: the price table's TAKE_REPAIR line (4 credits a second, a two-second minimum). `credits` is null when the take cannot be repaired in place (`reason` says why).
          - `credits` integer, nullable, required
          - `seconds` number, required: The seconds a repair sends: the whole take, or only the shots its defect sits in.
          - `available` boolean, required
          - `reason` string, nullable, required: Why it cannot be asked for right now.
        - `trimBounds` TakeTrimBounds: What a free trim of this take may keep. A trim never cuts into a spoken line.
          - `takeSeconds` number, required
          - `speech` object, nullable, required: Where the take's spoken lines sit (the first line's start, the last one's end); a trim must keep all of it. Null for a take that speaks nothing.
            - `startSeconds` number, required
            - `endSeconds` number, required
          - `minimumSeconds` number, required: The shortest a trimmed take may be.
          - `suggested` object, nullable, required: The engine's own trim of this take (a cut it measured at an end), or null.
            - `keepStartSeconds` number, required
            - `keepEndSeconds` number, required
          - `available` boolean, required
          - `reason` string, nullable, required: Why it cannot be trimmed right now.
        - `trim` TakeTrimPlan: A trim: the span of the take that is kept (frame-exact) and what was cut off at each end.
          - `keepStartSeconds` number, required
          - `keepEndSeconds` number, required
          - `keptSeconds` number, required: The kept span's length: what the trimmed take plays in its cut.
          - `takeSeconds` number, required: The take's length before the trim.
          - `edges` TakeTrimEdge[], required
            - `edge` 'head' | 'tail', required
            - `transition` 'cut' | 'dissolve' | 'settle' | 'writer', required: `cut`: a hard cut (one frame, or a few the render smeared it over); `dissolve`: a blend over several frames, cut at its first blended frame; `settle`: the camera's move dying into a hold at the end, cut at the hold's first frame (nothing is slowed or padded); `writer`: the writer's own span (nothing measured).
            - `transitionStartSeconds` number, required
            - `transitionEndSeconds` number, required
          - `basis` 'outside_the_line' | 'dying_move' | 'last_resort_after_retakes' | 'speaker_overrun', nullable: Why the engine trimmed it, recorded with the take's checks: `outside_the_line` ("invented edge cut trimmed: outside the line": the free trim before any new take, the invented edge cut lying outside every spoken line and the chapter or beat kept within a quarter of its plan), `dying_move` ("camera move dying into a hold trimmed: outside the line": the same free trim of a camera move that dies into a hold at the end, cut at the hold's first frame, never slowed or padded) or `last_resort_after_retakes` ("invented edge cut trimmed: last resort after retakes": the shot's automatic new take was spent, so the take it plays was trimmed past the quarter, the line kept whole, at least 2 s left, the chapter or beat at least half its plan). Null for the writer's own trim.
          - `droppedLineRefs` integer[], nullable: The lines this trim cut OUT of the take (the writer cut the chapter's line out and kept the rest of its footage): the span kept is one side of them. Null for every other trim, which keeps every line whole.
        - `voiceOver` TakeVoiceOver: Lines a take plays as a VOICE-OVER that its call says on camera: the speaker seen from behind, the line heard over the picture.
          - `lineRefs` integer[], required
          - `speakers` string[], required
        - `voiceOverRestage` TakeVoiceOverRestage: What a writer's voice-over re-stage of this take would stage — the call's on-camera lines whose speaker's lips failed them on a take of it, else every line it says on camera — and its price (a new take of the call).
          - `available` boolean, required
          - `reason` string, nullable, required: Why it cannot be asked for right now.
          - `lineRefs` integer[], required
          - `credits` integer, nullable, required
      - `selectedTake` integer, nullable, required: The take the cut plays and the finish delivers. Null when the call has no accepted take yet: render it again.
      - `notices` object[]
        - `take` integer
        - `code` string
        - `message` string: Plain words for the writer. For a content refusal it is the action that can work: an IP refusal (`code: reference_render_provider_ip_refused`) names what to edit and the likely trigger.
        - `moderation` boolean: True for a content refusal: released, never retried.
      - `rendering` boolean, required: A take of this call is in flight now.
      - `retake` object, required: A priced new take of this call (the render-clip op): its take number and credits.
        - `take` integer
        - `credits` number
    - `lineDrops` TrailerLineDrop[]: Each of the beat's spoken lines, in order (its shots' lines, then its own), and what cutting it out of the footage would do now (POST …/beats/{beatIndex}/drop-line with its `line`). Empty outside review and complete.
      - `available` boolean, required
      - `reason` string, nullable, required: Why not, in one plain sentence.
      - `code` string, nullable, required: `drop_line_in_middle`, `drop_line_too_short`, `drop_line_empties_chapter`, `drop_line_cuts_other_line`, `drop_line_narrated`, `drop_line_not_rendered`, `drop_line_no_take`, `drop_line_unplaced`, `drop_line_no_file` or `drop_line_no_line`.
      - `trims` PitchDeckLineDropTrim[], required
        - `callId` string, required
        - `take` integer, required
        - `keep` 'before' | 'after', required
        - `keepStartSeconds` number, required
        - `keepEndSeconds` number, required
        - `lineStartSeconds` number, required: Where the take says the line, padded: cut out with it.
        - `lineEndSeconds` number, required
        - `takeSeconds` number, required
      - `sides` object[], required: A line in the middle: the sides that could be kept instead (`keep`), per take.
        - `callId` string
        - `take` integer
        - `keep` 'before' | 'after'
        - `keepStartSeconds` number
        - `keepEndSeconds` number
        - `seconds` number
      - `line` integer, required: The line's number in the beat: what `line` names.
      - `speaker` string, required
      - `text` string, required
      - `shotNumber` integer, nullable, required: The shot of the beat's cut list that carries it (from 1), or null: the beat's own line.
    - `droppedLines` TrailerDroppedLine[]: The lines already cut out of this beat's footage, oldest first, with each trim's state.
      - `speaker` string, nullable, required
      - `text` string, required
      - `movedTo` object, nullable, required
        - `beatIndex` integer
        - `beatNumber` integer
      - `at` string, date-time, required
      - `trims` object[], required
        - `callId` string
        - `take` integer: The take the line was cut out of.
        - `trimTake` integer: The trimmed take that keeps the rest.
        - `keep` 'before' | 'after'
        - `keepStartSeconds` number
        - `keepEndSeconds` number
        - `state` 'pending' | 'playing' | 'landed' | 'failed'
  - `finish` Finish, required: The finish is a film look laid on the picture when the master is assembled: a look (camera, period-35mm, night-interior, none), an intensity (light, standard, strong; standard by default) and, optionally, single effects set to a level (adjust: { effect: off | subtle | medium | strong }; effects: steady-light, match-shots, halation, mist, shoulder, colour, vignette, weave, grain, soften). New decks and trailers start on camera. Titles and captions are laid after it, so type stays crisp, and the sound and timing are never touched. Setting it is free; on a rendered deck or trailer the master is assembled again with it (free), and setting the same finish again changes nothing.
    - `look` 'camera' | 'period-35mm' | 'night-interior' | 'none', required: The look: `camera` (Shot on a camera: fine moving grain, dense blacks under gently rolled-off highlights, a touch of mist on the lights, softer digital edges, steadied exposure and matched shots. No colour shift.); `period-35mm` (Period film: a muted 19th-century palette (warm candle and amber interiors, cold blue-grey exteriors, quieter greens and blues), a warm glow around flames, fine 35mm grain, a soft vignette and a very slight gate weave, with steadied exposure and matched shots.); `night-interior` (Candle and lamplight: cool shadows under warm highlights, a glow and a little mist around every flame, a deeper vignette and fine grain. The flame's own flicker is kept.); `none` (As rendered: no finish, the picture plays as it was rendered.).
    - `intensity` 'light' | 'standard' | 'strong', required: How strong: `light` (Barely there: every effect one step down (the grain and the invisible corrections stay on).); `standard` (Noticeable: the look as designed.); `strong` (Strong: every effect one step up.).
    - `adjust` object: Single effects set to an explicit level, over what the look and intensity give them.
      - `steady-light` 'off' | 'subtle' | 'medium' | 'strong': Steadies the exposure pumping from frame to frame, within each cut.
      - `match-shots` 'off' | 'subtle' | 'medium' | 'strong': Matches the colour and exposure of the shots inside a cut that share a room and its light, so they play as one camera; a shot set somewhere else is left alone.
      - `halation` 'off' | 'subtle' | 'medium' | 'strong': A warm red-amber glow bleeding from the brightest highlights, as on film.
      - `mist` 'off' | 'subtle' | 'medium' | 'strong': A faint mist around the lights, like a diffusion filter.
      - `shoulder` 'off' | 'subtle' | 'medium' | 'strong': A gentle highlight shoulder over dense blacks.
      - `colour` 'off' | 'subtle' | 'medium' | 'strong': Mutes over-saturated colour a little.
      - `vignette` 'off' | 'subtle' | 'medium' | 'strong': Darkens the corners a little.
      - `weave` 'off' | 'subtle' | 'medium' | 'strong': A very slight gate weave: the frame wanders a pixel or two.
      - `grain` 'off' | 'subtle' | 'medium' | 'strong': Fine moving film grain, strongest in the mid-tones and none in pure black or white.
      - `soften` 'off' | 'subtle' | 'medium' | 'strong': Takes the digital edge off, scaled to the resolution.
  - `camera` CameraReadSummary, required: The camera motion in a deck's or trailer's read: the handheld strength, and each unit the camera touches with its move and state (the full read is `/camera`).
    - `handheld` 'off' | 'subtle' | 'medium', required
    - `on` boolean, required
    - `units` object[], required
      - `unit` integer, required
      - `unitNumber` integer, required
      - `state` 'on' | 'waiting' | 'partly' | 'off', required
      - `move` CameraMove, nullable, required: A chapter's or beat's move, as chosen.
        - `move` 'snap' | 'reframe', required: `snap`: a snap zoom onto a reaction; `reframe`: a slow reframe from one face to another.
        - `shot` integer, required: The shot's number in the cut, 1-based.
        - `target` string, required: The face the move lands on.
        - `from` string, nullable, required: A reframe's first face.
        - `zoom` number, nullable, required: A snap zoom's zoom.
      - `moveState` 'applied' | 'dropped', nullable, required
      - `moveReason` 'moving' | 'speaks' | 'too_short' | 'not_found' | 'no_clean_framing' | 'letterboxed', nullable, required
      - `sentence` string, nullable, required
  - `warnings` string[], required: Warnings the finish quote and the export carry: one per flagged take the writer kept (a line not heard or in another character's voice, an opening off its plan).
  - `assembly` MasterAssembly, required: `assembly` is the master being put together right now, null when nothing is being assembled: `stage` (the 480p `preview` or the `finished` cut), the `step` it is on (`cutting`: joining each chapter's or beat's chosen takes, with `unit` the one being joined and `done` of `total` joined so far; `text`: laying the on-screen text (the finished cut only); `sound`: laying the voices, music and sound under the cut; `finish_look`: laying the finish look on the picture (only when one is set); `stitching`: stitching everything into one video, with `percent` from the renderer's own frame count; `delivering`: levelling the sound and saving the file), `steps` in order, `startedAt`, and `sentence`, which says it in words. Nothing renders and nothing is charged while a cut is assembled, and it cannot be stopped: it is free and ends on its own.
    - `stage` 'preview' | 'finished', required: Which master: the 480p preview the writer reviews, or the finished cut.
    - `step` 'cutting' | 'text' | 'sound' | 'finish_look' | 'stitching' | 'delivering', required: The step the assembly is on, in the order it runs them.
    - `unit` integer, nullable, required: `cutting`: the chapter or beat whose takes are being joined, by its number in the cut (from 1).
    - `done` integer, nullable, required: `cutting`: how many of this assembly's chapters or beats are joined so far.
    - `total` integer, nullable, required: `cutting`: how many chapters or beats this assembly joins (only the ones whose chosen takes changed).
    - `percent` integer, nullable, required: `stitching`: how far the stitch is, 0 to 100, from the renderer's own frame count.
    - `finishLook` boolean, required: Whether a finish look is laid on the picture (its step runs only then).
    - `title` string, nullable, required: What is being stitched, as the writer knows it.
    - `runtimeMs` integer, nullable, required: How long the cut being stitched runs, as planned.
    - `startedAt` string, date-time, required: When the assembly began.
    - `stepStartedAt` string, date-time, required: When the current step began.
    - `updatedAt` string, date-time, required: When the worker last reported. A record no worker has touched for twenty minutes is not returned.
    - `steps` object[], required: The steps this assembly runs, in order, each done, current or upcoming.
      - `step` 'cutting' | 'text' | 'sound' | 'finish_look' | 'stitching' | 'delivering', required
      - `label` string, required
      - `state` 'done' | 'current' | 'upcoming', required
    - `sentence` string, required: The assembly in one sentence, as every surface says it to the writer.
  - `reassembly` RenderReassembly, required: A deck's or trailer's free re-assembly. A cut whose `assemble` (the 480p preview) or `finish_assemble` (the finished master) failed for good lost nothing it paid for, and is put back together free from the takes it already has. A cut in `review` or `complete` has its master REBUILT, free and fresh, with the current sound rules: the preview assembly in review (`assemble`), the finished master stitched again at its class when complete (`restitch`, the cut stays complete).
    - `failedStage` string, nullable, required: The stage a FAILED cut failed in: rendering, assemble, finishing or finish_assemble. Null when it failed before the stage was recorded, and for a cut in review or complete.
    - `available` boolean, required: True when a re-assembly (or a rebuild) would run now (free: nothing rendered, upscaled or reserved).
    - `stage` 'assemble' | 'finish_assemble' | 'restitch' | 'null', nullable, required: The stage it runs: `assemble` / `finish_assemble` for a failed cut, `assemble` (review) or `restitch` (complete) for a rebuild; null when it is not available.
    - `refusal` string, nullable, required: Why it would be refused, in plain words (a rebuild: a master already being assembled, a take in flight, a finished take missing); null when it is available.
    - `leftOut` RenderReassemblyLeftOut[]: What a re-assembly that runs LEAVES OUT of the master. A deck's preview follows the master's rule: a chapter with no accepted take has no footage, so it is left out (the master plays the chapters around it) and named here — tell the writer which chapter is missing. Empty when nothing is, when it would not run, and always for a trailer and for the finished master (those refuse instead).
      - `name` string, required: How a person names it: "chapter 4".
      - `number` integer, nullable, required: Its place in the deck from 1 (the chapterNumber a person says).
      - `reason` string, required: Why it has no footage: the shot with no accepted take.
      - `message` string, required: The sentence to show: "Chapter 4 is left out of the master: … Render it again to put it back."
  - `verdict` VideoVerdict, required: `verdict` is the review in the writer's words — lead with it: `progress` (one line: rendering, fixing N shots the review flagged, ready to watch), `verdict` (one paragraph naming the problems that are left, by chapter or beat), `working` (true while the engine works: nothing to do but wait), and `choices` (at most two, only once it has stopped: `finish`, `finish_anyway` — the finish with `acknowledgeVideoCoverage` — or `more_fixes` with its `credits`), and `fixes` — ONE FIX FOR EACH PROBLEM `verdict` NAMES, in its order: `retake` (a new take of `callId`, or of the whole chapter or beat when it is null: the unit's render op, quoted first without `confirmed`) or `ask_slug` (nothing one action fixes from here: ask Slug with `problem` and `suggestion`). Offer each with its quoted price; never state a problem without its fix. The scores, findings, takes and checks stay in `videoCoverage`, the chapters' calls and `autoFix` for anyone who wants to step in.
    - `state` 'rendering' | 'assembling' | 'reviewing' | 'fixing' | 'ready' | 'your_call' | 'finishing' | 'finished' | 'failed', required
    - `working` boolean, required: True while the engine works and nothing needs the writer.
    - `progress` string, required: One plain progress line.
    - `verdict` string, nullable, required: One paragraph in the writer's words, naming the problems that are left.
    - `choices` object[], required: Empty while the engine works.
      - `action` 'finish' | 'finish_anyway' | 'more_fixes', required: `finish` and `finish_anyway` are the finish op (`finish_anyway` with `acknowledgeVideoCoverage: true`); `more_fixes` is the more-fixes op.
      - `label` string, required
      - `credits` integer, nullable, required: Known up front only for `more_fixes`; a finish is priced when chosen.
    - `fixes` object[], required: One fix for each problem `verdict` names, in its order. Empty when it names none, or while `more_fixes` is offered (that is the fix). Offer each with its quoted price.
      - `action` 'retake' | 'ask_slug', required: `retake`: the unit's priced render op for `callId` (null: every shot of the unit) — call it without `confirmed` for the price, then with `confirmed: true`. `ask_slug`: nothing one action fixes from here (a capture beat or title card has nothing to take again; the music; the plan): ask Slug with `problem` and `suggestion`.
      - `unitIndex` integer, nullable, required: The chapter's or beat's key; null for a problem outside one.
      - `unitNumber` integer, nullable, required
      - `callId` string, nullable, required
      - `label` string, required: The button: "Retake beat 4", "Fix beat 4 with Slug".
      - `problem` string, required: The problem it fixes, in the verdict's words.
      - `suggestion` string, required: What the review suggested; empty when it said nothing.
      - `startSeconds` number, required: Where the problem starts on the master.
  - `autoFix` AutoFix, required: `autoFix` is the AUTOMATIC FIXES: the approval quote carries an automatic-fix allowance for paid fixes beside the 480p render (`autoFixAllowance`), reserved with it — none for a cut with nothing a new take could redo (app captures, title cards) or a balance that holds only the render. FREE FIXES RUN WHATEVER THE ALLOWANCE: an app capture's narration the review hears off its picture is laid again on it (`kind: retime`, 0 credits), and a capture beat whose line is cut at the cut (or has no room to land on its press) keeps more of its recording (`kind: stretch`, 0 credits), and one whose picture goes blank for a frame at its start or end keeps a stretch that does not show it (`kind: trim`, 0 credits), and a unit whose narration is measured under the music has the music under it lowered (`kind: duck`, `duckDb`, 0 credits); free fixes run on a review that cleared the bar and after the rounds are run too. After the preview is stitched the engine watches it (video coverage) and retakes the shots the review flags — each new take told what the review saw, a shot at most twice, re-staged as a voice-over where the take rules allow — and renders flagged on-screen text again, inside the allowance; then it stitches and watches the preview again. It stops at a clean 480p preview (`state: clean`), when the allowance is spent (`no_allowance` when none was held), when the review flags nothing a fix can clear, or after `maxRounds` rounds (`state: stopped`, `stopReason`, `stoppedBecause`). `state` is `waiting` (first pass rendering), `reviewing` or `fixing` while it works — do not retake or finish then, just poll. `allowanceCredits` is the ceiling, `drawnCredits` what fixes took from it (each charged only when its take lands), `heldCredits` what is still reserved (released when it stops); `rounds[]` lists each round's fixes with `why`. When it stopped short, `moreFixes` (if not null) offers one more grant of `credits` (the more-fixes op, priced first); otherwise the writer finishes anyway. The 720p finish is always the writer's own approval.
    - `state` 'waiting' | 'reviewing' | 'fixing' | 'clean' | 'stopped', required: `waiting` (the first pass renders), `reviewing` (the preview is being watched), `fixing` (fixes are rendering), `clean`, or `stopped`.
    - `stopReason` 'clean' | 'allowance_spent' | 'cannot_clear' | 'rounds_spent' | 'review_unavailable' | 'writer_stopped' | 'finished' | 'no_allowance' | 'deleted' | 'null', nullable, required: Why it stopped (null while it works).
    - `allowanceCredits` integer, required: The ceiling approved for fixes: every grant together.
    - `drawnCredits` integer, required: What fixes drew from it (each charged only when its take lands; back to the writer when it fails).
    - `heldCredits` integer, required: What the allowance still holds for fixes; 0 once it stops (released).
    - `round` integer, required: Rounds of fixes run, never more than `maxRounds` (free fixes after the rounds are listed in `rounds` without counting as one).
    - `maxRounds` integer, required: The most rounds it runs.
    - `fixesInFlight` integer, required: Fixes still rendering.
    - `rounds` object[], required: Each round: the review it answered and the fixes it applied.
      - `round` integer, required
      - `reportId` string, nullable, required: The video coverage report it answered.
      - `overallScore` number, nullable, required
      - `startedAt` string, date-time, required
      - `fixes` object[], required
        - `kind` 'retake' | 'text' | 'retime' | 'stretch' | 'trim' | 'duck', required: `retake`: a new take of a shot; `text`: the unit's on-screen text rendered again; `retime`: an app capture's narration laid again on its picture; `stretch`: more of an app capture's recording kept so its narration fits (cut at the cut, or no room to land on its press); `trim`: an app capture's kept stretch moved off a blank frame measured at its start or end (`trim`); `duck`: the music under a unit whose narration was measured under it lowered by `duckDb`. `retime`, `stretch`, `trim` and `duck` are free, whatever the allowance.
        - `unitIndex` integer, required: The chapter's or beat's key.
        - `unitNumber` integer, required: Its place in the cut.
        - `callId` string, nullable, required
        - `take` integer, nullable, required
        - `credits` integer, required: What it drew from the allowance (0 when it could not start).
        - `ended` boolean, required: Its job has ended (landed, failed or refused).
        - `why` string[], required: What the review saw that it answers; a retake is told to avoid it.
        - `trim` object, nullable, required: `trim` only: the end of the beat the blank frames sat at and how many; null for every other kind.
          - `edge` 'head' | 'tail', required
          - `frames` integer, required
        - `duckDb` number, nullable, required: `duck` only: how many dB the music under the unit was lowered; null for every other kind.
    - `moreFixes` object, nullable, required: When it stopped short and one more grant could help: what that grant would hold (POST …/more-fixes). Null otherwise.
      - `credits` integer, required
    - `stoppedBecause` string, nullable, required: Why it stopped short of clean, in plain words.
    - `sentence` string, required: Where it stands, in one sentence.
  - `earlyLook` VideoEarlyLook, required: `earlyLook` (while the first pass renders; null once the preview exists) lists every chapter or beat whose shots all have a take, with each take's clip in shot order (`units[].clips[].url`), and `roughCut` once two have landed: they can be watched as they land, nothing to do. `musicPlan` is the music the cut will carry, known before the stitch: the beds on its timeline (`source: timeline`), or for a deck with none the table read's score as the assembly will lay it (`table_read_score`), each bed with the chapters or beats it plays under and a `url` to listen to — say it early, so a music change is made before the finish. A score to picture asked for (`score`, from a draft on) leads with its direction and, once its sketch to the planned cut is composed, `score.sketchUrl` to listen to; while one is asked for, the table read's beds are not laid or projected. When a score asked for with a direction could not be composed (`score.status: failed`), the beds are not laid in its place either: the sentence says so plainly ("The score couldn't be composed (reason in Details). The bell plays alone. Score to picture to try again.") — say it to the writer.
    - `units` object[], required
      - `unitIndex` integer, required
      - `unitNumber` integer, required
      - `title` string, required
      - `clips` object[], required
        - `callId` string, required
        - `url` string, required
        - `seconds` number, required
    - `of` integer, required: How many units have footage to render.
    - `roughCut` boolean, required: Two or more units have landed: a rough cut can play.
    - `sentence` string, required
  - `musicPlan` VideoMusicPlan, required: `earlyLook` (while the first pass renders; null once the preview exists) lists every chapter or beat whose shots all have a take, with each take's clip in shot order (`units[].clips[].url`), and `roughCut` once two have landed: they can be watched as they land, nothing to do. `musicPlan` is the music the cut will carry, known before the stitch: the beds on its timeline (`source: timeline`), or for a deck with none the table read's score as the assembly will lay it (`table_read_score`), each bed with the chapters or beats it plays under and a `url` to listen to — say it early, so a music change is made before the finish. A score to picture asked for (`score`, from a draft on) leads with its direction and, once its sketch to the planned cut is composed, `score.sketchUrl` to listen to; while one is asked for, the table read's beds are not laid or projected. When a score asked for with a direction could not be composed (`score.status: failed`), the beds are not laid in its place either: the sentence says so plainly ("The score couldn't be composed (reason in Details). The bell plays alone. Score to picture to try again.") — say it to the writer.
    - `source` 'timeline' | 'table_read_score' | 'none', required
    - `beds` object[], required
      - `label` string, required
      - `url` string, nullable, required: The bed to listen to (null while it is still being made).
      - `units` integer[], required: The chapters or beats it plays under, by their number in the cut.
    - `score` object, nullable, required: A score to picture asked for (from a draft on): its music direction, shown before anything renders, where it stands, and its sketch to the planned cut. While one is asked for, a deck projects none of the table read's beds: they are not laid under it.
      - `status` string, required: `waiting_for_master`, `queued`, `composing`, `laid` or `failed`.
      - `direction` string, nullable, required
      - `url` string, nullable, required: The laid score, once laid.
      - `sketchUrl` string, nullable, required: The sketch composed to the planned cut while the score waits for its master: listen before anything renders. Never laid; null until composed and once the score is on its way to the real cut.
    - `sentence` string, required
  - `interludes` TrailerInterlude[], required: The trailer's black interludes, in cut order, with what the master made of each. Replace them with POST /trailers/{jobId}/interludes.
    - `afterBeatIndex` integer, required: The `beatIndex` of the beat the black follows (its place in the trailer, from 0).
    - `afterBeatNumber` integer, required: The place of that beat in the trailer, from 1: "after beat 3".
    - `seconds` number, required: How long the black holds, as planned.
    - `line` string: The words heard over the black, when it carries a line.
    - `speaker` string: Who says `line`: a canon cast name, or NARRATOR (the trailer's narrator). Always heard as a voice-over.
    - `sound` string: The one sound heard in the dark, when it carries one.
    - `durationMs` integer, required: How long it holds black in the master: its seconds, or as long as its voiced line needs (at most 5 s).
    - `audioUrl` string, nullable, required: The voiced line, once an assembly has made it for the line as it stands.
    - `soundUrl` string, nullable, required: The sound, once an assembly has made it for the sound as it stands.
    - `error` string, nullable, required: Why its line or its sound could not be made, when one could not (a narrator line on a trailer with no narrator, a cast member with no voice, a sound with a voice in it).
  - `closingSequence` ClosingSequenceView, required: A deck's closing sequence ends its master, after the last chapter, and mirrors its title sequence: optionally a closing quote (`quote`: its words, quoted exactly, and where they are from, cited exactly — one that answers the opening's epigraph, often from the same source), then "Coming Soon" (`comingSoon`, up to 40 characters; "Coming Soon" when left out), then the production credit (`productionCredit`; "Sleeper Hit Studio" when left out), each quiet on black, faded in and out and held long enough to read. It ADDS to the deck's length: no chapter is shortened for it. When the title sequence cuts on its bell beat grid, each card starts on a beat of that same grid and the bell lane accents it. Across it the music (the score or the beds) and the bell lane fade out smoothly to silence on the master's last frame: what still sounds at the last chapter's cut plays on under the cards. A card with no direction of its own wears the opening's look (the quote the epigraph's, the credit the source credit's, "Coming Soon" the title's or the epigraph's background), so the deck is sandwiched by one style. It is free: nothing is rendered for it, and a rendered deck's master is stitched again with it. `enabled: false` keeps it without playing it. How its words look and move is directed separately (`closingElement` on the direct-text-motion call; read back as `textMotion`), and a save keeps those directions. THE LOGO CARD (`logoCard: true`, off when left out) ends the sequence on the project's brand logo, alone on black after the production credit, faded in and out and held 3 seconds. The logo is the project's (`brandLogoUrl` on the project, set on the site's Closing card, with the Story API project update's `brandLogo`, or on the CLI with `projects update --brand-logo-file`); a save that turns the card on while the project has no logo is refused, and the save copies the logo the project has at that moment (read back as `logoUrl`), so save the closing again after replacing the logo. Free like the rest of the sequence.
    - `enabled` boolean, required: Whether the deck or trailer ends on it. False keeps it without playing it.
    - `quote` object: A closing quote shown first, alone on black, held long enough to read (about 3 words a second, at least 4 s).
      - `text` string, required: Its words, exactly as the source gives them.
      - `attribution` string: Where the words are from, cited exactly.
    - `comingSoon` string, required: "Coming Soon" as the master sets it (the default when left out).
    - `productionCredit` string, required: The production credit as the master sets it (the studio's name when left out).
    - `logoCard` boolean, required: Whether it ends on the project's brand logo.
    - `logoUrl` string, nullable, required: The logo the logo card shows: the project's brand logo as it was when the closing was saved with the card on (null while the card is off).
    - `logo` object: The logo as stored on the closing (READ ONLY: copied from the project by the save that turns the logo card on).
      - `url` string, required
    - `playing` boolean, required: True when it plays in the master (enabled, and a chapter or beat before it).
    - `durationMs` integer, required: How long it runs in the master: what it adds to the deck's or trailer's length.
    - `startSeconds` number, nullable, required: Where it starts in the master (null while it does not play).
    - `onBeatGrid` boolean, required: Whether its cards keep the title sequence's bell beat grid (each starting on a beat).
    - `textMotion` object: How its cards look and move, as directed (absent for a card that wears the opening's look or its own type). Set by POST /pitch-decks/{jobId}/storyboard/direct-text-motion with a `closingElement`, never by a save (which keeps them). The closing sequence's words are directed like the title sequence's, in the writer's own words, through the same direct-text-motion call with a `closingElement` instead of a `chapterIndex`: `quote`, `comingSoon` or `productionCredit` ("the same candlelight and grain as the epigraph", "Coming Soon wide and slow, a faint vignette breathing behind it"). The same director compiles the sentence into a motion-text spec (face, colour, size, motion and a quiet background) and saves it with the sentence on the closing sequence (`textMotion`). The words stay the closing's: a direction says how they look, never what they say. `clear: true` puts a card back in the opening's look (or its own type). Free: an LLM call, no credits; a rendered deck's master is stitched again with it, and nothing else renders.
      - `quote` PitchDeckTitleTextMotion: One of the title sequence's words, directed: the writer's sentence and the motion-text spec compiled from it, which the master executes.
        - `direction` string, required: The writer's own words for how it looks and moves.
        - `spec` object, required: The motion-text spec: version, layers (each a text, atmosphere, particle… layer with its face, fit, colours and keyframed steps).
      - `comingSoon` PitchDeckTitleTextMotion: One of the title sequence's words, directed: the writer's sentence and the motion-text spec compiled from it, which the master executes.
        - `direction` string, required: The writer's own words for how it looks and moves.
        - `spec` object, required: The motion-text spec: version, layers (each a text, atmosphere, particle… layer with its face, fit, colours and keyframed steps).
      - `productionCredit` PitchDeckTitleTextMotion: One of the title sequence's words, directed: the writer's sentence and the motion-text spec compiled from it, which the master executes.
        - `direction` string, required: The writer's own words for how it looks and moves.
        - `spec` object, required: The motion-text spec: version, layers (each a text, atmosphere, particle… layer with its face, fit, colours and keyframed steps).
    - `cards` object[], required: Its cards in order: the quote (when it has one), "Coming Soon", the production credit, and the project's logo (when the logo card is on).
      - `card` 'quote' | 'comingSoon' | 'productionCredit' | 'logo', required
      - `text` string, required: Its words (empty on the logo card).
      - `attribution` string, nullable, required
      - `imageUrl` string, nullable, required: The image it shows: the project's logo on the logo card, else null.
      - `seconds` number, required: How long it is on screen, its fades included.
      - `startSeconds` number, nullable, required: Where it starts in the master (null while the closing does not play).
      - `beat` integer, nullable, required: The bell beat it starts on, on the grid (null off the grid).
      - `look` 'own' | 'opening' | 'null', nullable, required: `own`: its own direction; `opening`: the opening's look, borrowed; null: its own type on black.
      - `lookFrom` 'title' | 'epigraph' | 'sourceCredit' | 'nameSupers' | 'null', nullable, required: The opening element its look is borrowed from.
      - `backgroundOnly` boolean, required: True when only a background is borrowed: the card keeps its own type over it.
    - `fadeOut` object, nullable, required: Where the master fades the music (the score or the beds) and the bell lane out: from the closing's first frame to silence on the master's last (null while it does not play).
      - `fromSeconds` number, required
      - `toSeconds` number, required
  - `masterHold` TrailerMasterHold: On a rendered trailer with no screenplay, a blank beat holds its video: nothing rebuilds it until each blank beat is a capture beat or a title card, or removed (then it is rebuilt, free); the answer's `masterHold` names the beats and the fix, and the export is refused with it (`trailer_capture_only`).
    - `blankBeats` integer[], required: The blank beats, numbered from 1.
    - `message` string, required: The sentence to show: the beats, that the video keeps playing, and the fix.
  - `videoCoverage` VideoCoverage, required: VIDEO COVERAGE of a deck's or trailer's stitched master: a model watched the video with its sound and scored its quality and its adherence to the shot list against a bar (`gateThreshold`, with `vetoDimensions` that fail it on their own). It runs by itself, free to the writer, when the 480p preview is stitched and again when the finished master is. While `blocksFinish` is true the finish is refused unless the writer finishes anyway; a report still running, one that could not run, an unavailable provider, or a report of an earlier master never holds the finish.
    - `status` 'missing' | 'generating' | 'complete' | 'failed', required
    - `planKind` 'pitch_deck' | 'trailer', required
    - `jobId` string, required
    - `stage` 'preview' | 'finished' | 'null', nullable, required: Which master the report watched.
    - `masterUrl` string, nullable, required: The master the report watched.
    - `currentMasterUrl` string, nullable, required: The master the cut has now.
    - `current` boolean, required: True when the report watched the master the cut has now.
    - `available` boolean, required: False when no provider can watch a video right now (that never holds the finish).
    - `gatePassed` boolean, required
    - `gateThreshold` number, required: The bar the composed overall and every veto dimension must reach.
    - `vetoDimensions` string[], required: Dimensions that fail the video on their own below the bar.
    - `gateReasons` string[], required: Every reason the bar was not cleared; empty on a pass.
    - `blocksFinish` boolean, required: True only when this report holds the paid finish: complete, of the current master, below the bar.
    - `summary` string, required: One sentence for the writer: where the coverage stands and what it means for the finish.
    - `trigger` 'auto' | 'manual' | 'null', nullable, required: `auto`: run after a stitch; `manual`: asked for.
    - `reportId` string, nullable, required
    - `reportVersion` integer, nullable, required
    - `rubricVersion` integer, nullable, required
    - `overallScore` number, nullable, required: The composed score the bar was decided on: the lower of the model's overall and the weighted dimensions — over the MEDIAN of each score when more than one watch judged it (`report.judging`).
    - `model` string, nullable, required
    - `progressDetail` string, nullable, required
    - `failureMessage` string, nullable, required: Why the run stopped, as one plain sentence for the writer — never a provider's or the database's raw wording. Populated when `status: failed`.
    - `report` VideoCoverageReport, required: What the model reported after watching the master with its sound: its quality and its adherence to the shot list, never its story.
      - `overallScore` number, required: The model's own holistic score. The bar is decided on the composed score (VideoCoverage.overallScore).
      - `verdict` 'pass' | 'needs_work' | 'fail', required
      - `oneLineDiagnosis` string, required
      - `dimensions` object, required: Each scored 0–10: lipSync (the right mouth moves to each line, in time; voice-overs over closed mouths), promptAdherence (each shot does what its call asked: framing, who is on screen, staging, room, camera), visualFidelity (artifacts, morphing, frozen or waxy faces, warped hands, burned-in text), motionNaturalness, identityContinuity (people, wardrobe, rooms), textPlacement (never over a face or other text, legible, a short dwell), audioSync, transitions (each cut follows the part before it by a link a viewer sees or hears).
        - `lipSync` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `promptAdherence` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `visualFidelity` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `motionNaturalness` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `identityContinuity` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `textPlacement` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `audioSync` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
        - `transitions` object, required
          - `score` number, required: The score the bar reads: the median across the watches that judged it, or the score carried from an earlier master with the same picture (`judging.dimensions`). A watch's dimension held down by its worst finding's severity (critical caps it at 4.0, major at 6.0) keeps the model's own number in `modelScore`.
          - `finding` string, required
          - `modelScore` number: Present only when the score was held down by a finding's severity: the model's own number.
      - `findings` VideoCoverageFinding[], required
        - `dimension` 'lipSync' | 'promptAdherence' | 'visualFidelity' | 'motionNaturalness' | 'identityContinuity' | 'textPlacement' | 'audioSync' | 'transitions', required
        - `severity` 'minor' | 'major' | 'critical', required: `critical`: a viewer cannot watch past it; `major`: clearly wrong; `minor`: noticed on a second look.
        - `startSeconds` number, required: Seconds from the start of the master (a player seeks here).
        - `endSeconds` number, required
        - `timecode` string, required: `m:ss–m:ss`, for a person.
        - `observation` string, required: Exactly what is on screen or heard that falls short.
        - `fix` string, required: The concrete production change that would fix it.
        - `shouldShow` string, required: What the picture should show there instead, in positive words that never name the problem; empty when no change to the picture fixes it. A new take of the shot (`retake_call`) is told this, never the observation.
        - `unit` object, nullable, required
          - `kind` 'chapter' | 'beat' | 'interlude' | 'title', required: `interlude` is a deck's black interlude between two chapters: `index` is the chapter it follows. `title` is a deck's title sequence.
          - `index` integer, required: The chapter's or beat's key (what every edit and render takes).
          - `number` integer, required: Its place in the cut, from 1: the number a person says.
          - `title` string, required
        - `callId` string, nullable, required: The render call playing at that moment (retake it with the render-clip op and this `callId`).
        - `shotIndex` integer, nullable, required: The shot inside that call, from 0.
        - `remedy` VideoCoverageRemedy, required: `retake_call`: render a new take of `callId` (priced); `rerender_text`: render the unit's on-screen text again (priced); `rescore`: the score laid under the master is measured silent there — score the cut to picture again (a retake never fixes dead air in the score); `revise_plan`: a cut that does not follow because the plan gives it no link (or one too weak to carry it) — give the unit its link in the plan (the chapter or beat refine: `whyItFollows`, and the look, object or sound staged in it); `trim_capture`: measured — the picture went blank for `frames` frames at the `head` or `tail` of an app-capture beat, and the beat keeps a stretch of its recording that does not show them (free, run by the automatic fixes); `lift_voice`: measured — the narration there sits only `gapLu` LU over the music between its lines, under the 6 LU it needs, and the automatic fixes lower the music under it (free; a mix, never a sync or a retake); `none`: nothing one action fixes.
          - `kind` 'retake_call' | 'rerender_text' | 'rescore' | 'revise_plan' | 'trim_capture' | 'lift_voice' | 'none', required
          - `gapLu` number: `lift_voice` only: how many LU the narration sits over the music between its lines, as measured on the master.
          - `callId` string
          - `edge` 'head' | 'tail': `trim_capture` only: the end of the beat the blank frames sit at.
          - `frames` integer: `trim_capture` only: how many blank frames were measured there.
        - `source` 'judge' | 'measured': Who saw it: `judge` (the model that watched the master) or `measured` (code measured it: a spoken line's mouth read against its voice on the take it plays from, or the score's dead air). A measured lip-sync miss holds the lip-sync score down (major 6.0, critical 4.0) whatever the judge scored: the judge cannot clear it. Absent on a finding stored before this was recorded (the judge's).
        - `uncertain` true: A measurement TOO CLOSE TO CALL: a quiet face read near its bar, or a pod reading of lips moving where no line is heard that the take watcher did not see too (a push-in, a flare or a smile reads the same). Severity minor: shown with its retake (`remedy`) for the writer to choose, never retaken by the automatic fixes and never holding a score down. Absent on every other finding.
      - `priorityFixes` string[], required: At most eight, most important first.
      - `judging` VideoCoverageJudging: HOW THE VERDICT WAS REACHED. One watch is too noisy to gate on near the bar (two watches of one frame-identical picture have scored prompt adherence 9.5 and 6.0), so a first watch within `nearGateMargin` of the bar is followed by a second, two watches on opposite sides of the bar by a third, and the bar reads the MEDIAN of each score. A master whose picture is frame-identical to an earlier judged master carries that report's picture scores (prompt adherence, visual fidelity, motion naturalness, identity continuity, text placement) and judges only lip sync, audio sync and transitions again — nothing at all when the sound is identical too. The rubric, the weights and the bar are unchanged.
        - `watches` VideoCoverageWatch[], required: This report's watches, in order (empty when every score was carried).
          - `watch` integer, required: 1, 2, 3 — in the order taken.
          - `reason` 'first' | 'near_gate' | 'disagreement', required: `first`; `near_gate`: the first watch sat within `nearGateMargin` of the bar (its composed overall or a veto dimension); `disagreement`: two watches sat on opposite sides of the bar on some gating score.
          - `model` string, required
          - `watchedAt` string, date-time, required
          - `overallScore` number, required: The model's own holistic number on this watch.
          - `composedScore` number, nullable, required: The bar's composed score for this watch alone, carried scores in place.
          - `gatePassed` boolean, required: Whether this watch alone cleared the bar.
          - `dimensions` object, required: Each dimension as this watch scored it, after its own findings' severity caps.
            - `lipSync` number, required
            - `promptAdherence` number, required
            - `visualFidelity` number, required
            - `motionNaturalness` number, required
            - `identityContinuity` number, required
            - `textPlacement` number, required
            - `audioSync` number, required
            - `transitions` number, required
          - `costUsd` number, required: What this watch counts against the extra-watch spend cap (USD).
          - `priced` boolean, required: False when the model has no price on file and `costUsd` is the flat per-watch estimate.
        - `dimensions` object, required
          - `lipSync` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `promptAdherence` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `visualFidelity` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `motionNaturalness` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `identityContinuity` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `textPlacement` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `audioSync` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
          - `transitions` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
            - `scores` number[], required: In watch order (carried: the carried report's own).
            - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
            - `watches` integer[], required: Which of this report's watches it used; empty when carried.
            - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
              - …
        - `overall` VideoCoverageScoreDistribution, required: How one score was decided: the scores of the watches it used and their median (the number the bar reads), or the report it was carried from.
          - `scores` number[], required: In watch order (carried: the carried report's own).
          - `median` number, required: The median of `scores` (an even count: the mean of the middle two) — equal to the report's score.
          - `watches` integer[], required: Which of this report's watches it used; empty when carried.
          - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
            - `reportId` string, required
            - `reportVersion` integer, nullable, required
            - `masterUrl` string, required: The master that report watched.
        - `carriedFrom` VideoCoverageCarriedFrom, required: The earlier report a score was carried from: a master of the same cut whose picture is frame-identical (its sampled decoded frames hash the same) and was asked the same things.
          - `reportId` string, required
          - `reportVersion` integer, nullable, required
          - `masterUrl` string, required: The master that report watched.
        - `stoppedBecause` 'decisive' | 'agreement' | 'max_watches' | 'spend_cap' | 'watch_failed' | 'carried', required: `decisive`: one watch, clear of the bar by the margin; `agreement`: two watches on the same side of the bar on every gating score; `max_watches`: three; `spend_cap`: another was wanted but this master's extra-watch spend cap was reached; `watch_failed`: another was wanted but could not run; `carried`: no watch, picture and sound identical to an earlier judged master.
        - `nearGateMargin` number, required: Within this many points of the bar a single watch is not trusted.
        - `maxWatches` integer, required
        - `extraSpendUsd` number, required: What this report spent on watches beyond its first (USD).
        - `extraSpendCapUsd` number, required: The most every report of one master may spend on watches beyond their first (USD).
        - `pictureFingerprint` string, nullable, required: Hash of the master's sampled decoded frames and what each part was asked to show (null: not measured).
        - `soundFingerprint` string, nullable, required: Hash of its decoded sound on that picture and what it was meant to sound like (null: not measured, or no sound).
      - `lipSync` VideoCoverageLipSync: MEASURED LIP SYNC: every spoken line of the master, measured on the take it plays from. The judge is shown these; each `miss` is also a `measured` lip-sync finding.
        - `metricVersion` string, required: The mouth check's code version the lines were judged under.
        - `lines` VideoCoverageLipSyncLine[], required
          - `unit` object, nullable, required
            - `kind` 'chapter' | 'beat', required
            - `index` integer, required
            - `number` integer, required
            - `title` string, required
          - `callId` string, required: The render call the line plays from (a miss is retaken with the render-clip op and this `callId`).
          - `take` integer, nullable, required: The selected take the master plays.
          - `lineRef` integer, required
          - `speaker` string, required
          - `text` string, required: The line's words.
          - `voice` string, required: `on_camera`, `voice_over` or `off_screen`.
          - `startSeconds` number, required: Where it is spoken, in seconds of the master.
          - `endSeconds` number, required
          - `timecode` string, required
          - `verdict` 'pass' | 'miss' | 'uncertain' | 'not_measured', required: `miss`: a measured miss — also a `measured` lip-sync finding the judge cannot clear; `uncertain`: a reading inside the band around its limit (neither); `pass`; `not_measured`: no face could be read or the check never ran (a take watcher's look is not a measurement) — the judge's own look decides it.
          - `severity` 'minor' | 'major' | 'critical', nullable, required: A miss's severity: `critical` when the mouth does not move at all or the wrong face speaks the line, else `major`. Null otherwise.
          - `criteria` object[], required: Each criterion missed or uncertain, misses first: the face, `criterion` (`correlation`, `lag`, `trailing_motion`, `articulation` — the lips barely part under the voice — `articulation_stretch`, `still_open_run`, `still_open_share`, `still_openings`, `watcher_lip_sync`), its `value`, its `limit` and its `words`.
            - `name` string, required
            - `role` 'speaker' | 'still', required
            - `criterion` string, required
            - `outcome` 'fail' | 'uncertain', required
            - `value` number, required
            - `limit` number, required
            - `words` string, required
          - `reason` string, nullable, required: Why it missed, is uncertain, or could not be measured, with the numbers. Null on a pass.
          - `faceHeightPx` number, nullable, required: The speaker's face height in the take's pixels.
          - `correlation` number, nullable, required: The speaker's mouth against the voice (r at the best lag).
          - `voicedOpenness` number, nullable, required: The speaker's mean openness under the voice, 0 closed to 3 wide (a speaking mouth averages at least 1.35).
          - `rejudged` boolean, required: True when the take's stored reading was judged again under the current numbers against the voice it was sent.
      - `transitions` VideoCoverageTransition[], nullable: EVERY CUT of the master, in order, and whether it follows the part before it. Each cut that is `weak` or `lost` is also a `transitions` finding with the same remedy. Absent on a report written before cuts were judged.
        - `from` object, nullable, required
          - `kind` 'chapter' | 'beat' | 'title', required
          - `index` integer, required
          - `number` integer, required
          - `title` string, required
        - `to` object, required
          - `kind` 'chapter' | 'beat' | 'title', required
          - `index` integer, required: The key every edit takes.
          - `number` integer, required
          - `title` string, required
        - `atSeconds` number, required: Where the cut falls, in seconds of the master.
        - `timecode` string, required: `m:ss`, for a person.
        - `verdict` 'follows' | 'weak' | 'lost', required: `follows`; `weak` (the link is faint, or half carries the viewer); `lost` (nothing connects the two: a non-sequitur).
        - `observation` string, required: What carries a viewer across the cut — the look, the object, the sound, the cause, the contrast — or what is missing.
        - `planned` string, nullable, required: The link the plan states for this cut (`whyItFollows` of `to`), or null when it states none.
        - `plannedLink` 'seen' | 'not_seen' | 'none_planned', required: Whether the watcher saw or heard the planned link: `seen`, `not_seen`, or `none_planned` (always, when the plan states none).
        - `fix` string, required: The concrete change that makes the cut follow; empty when it follows.
        - `remedy` VideoCoverageRemedy, required: `retake_call`: render a new take of `callId` (priced); `rerender_text`: render the unit's on-screen text again (priced); `rescore`: the score laid under the master is measured silent there — score the cut to picture again (a retake never fixes dead air in the score); `revise_plan`: a cut that does not follow because the plan gives it no link (or one too weak to carry it) — give the unit its link in the plan (the chapter or beat refine: `whyItFollows`, and the look, object or sound staged in it); `trim_capture`: measured — the picture went blank for `frames` frames at the `head` or `tail` of an app-capture beat, and the beat keeps a stretch of its recording that does not show them (free, run by the automatic fixes); `lift_voice`: measured — the narration there sits only `gapLu` LU over the music between its lines, under the 6 LU it needs, and the automatic fixes lower the music under it (free; a mix, never a sync or a retake); `none`: nothing one action fixes.
          - `kind` 'retake_call' | 'rerender_text' | 'rescore' | 'revise_plan' | 'trim_capture' | 'lift_voice' | 'none', required
          - `gapLu` number: `lift_voice` only: how many LU the narration sits over the music between its lines, as measured on the master.
          - `callId` string
          - `edge` 'head' | 'tail': `trim_capture` only: the end of the beat the blank frames sit at.
          - `frames` integer: `trim_capture` only: how many blank frames were measured there.
    - `createdAt` string, date-time, nullable, required
    - `updatedAt` string, date-time, nullable, required

## Other responses

- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The named project or source does not exist or is owned by another account.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/64c1102ccb2f?raw)
