# Pilot Preview Render V2 — Controlled First Approval Video

Use this reference when the user explicitly approves a *preview/concept* render for a single TrueTraceShorts/AutoShortsBot candidate, but has **not** approved Wan/AI final rendering.

## Trigger phrase / approval state

Example approval command:

```text
APPROVED_FOR_PREVIEW_RENDER <candidate_id> <version> <script_hash>
```

This approval permits only Resource Tier 1 preview work:

- TTS generation for the approved script.
- Subtitle/caption cue generation.
- Deterministic local preview/animatic rendering.
- Local MP4 assembly via FFmpeg.
- Telegram delivery of the preview video, if the current chat supports media delivery.

It does **not** permit:

- Wan-2.2 final render.
- AI image/styleframe generation, unless separately approved with `APPROVE_STYLEFRAME`.
- Platform APIs, publishing, OAuth, scheduling, or auto-posting.
- Batch production beyond the approved single candidate.

## Resource gate addition

Extend the preview/resource-gating model with:

```python
RenderApprovalState.APPROVED_FOR_PREVIEW_RENDER = "approved_for_preview_render"
```

Rules:

- `TEXT_REASONING`: always allowed after identity/hash checks.
- `DETERMINISTIC_PREVIEW`: allowed at `READY_FOR_REVIEW` and `APPROVED_FOR_PREVIEW_RENDER`.
- `AI_STYLEFRAME`: still requires `APPROVED_FOR_STYLEFRAME`; preview approval is not enough.
- `WAN_FINAL_RENDER`: still requires `APPROVED_FOR_FINAL_RENDER`; preview approval is not enough.
- `PUBLISHING`: always blocked.
- Candidate ID, version, and script hash must match exactly.
- AI disclosure and claim gate must pass before any media generation tier above text reasoning.

Add a focused test that preview approval allows deterministic preview but blocks Wan final render and AI styleframe.

## Preview MP4 pattern

Recommended minimal preview spec:

- 9:16, 540×960 or 720×1280.
- 30 fps.
- Duration follows the pilot package/shot plan, usually ~35–40s.
- Visible `PREVIEW / NOT FINAL` label throughout.
- Deterministic cards, diagrams, arrows, stamps, labels, and captions only.
- No Wan calls, no AI backgrounds, no generated fake text.
- Renderer owns all overlay text, labels, arrows, facts, numbers, and captions.

Typical local artifacts:

```text
/tmp/autoshorts_preview_v2/<candidate_id>/
  voiceover.txt
  voiceover.mp3
  edge_subtitles.srt
  word_cues_time_based.srt
  word_cues_time_based.json
  preview_silent.mp4
  preview_<candidate_id>_v2.mp4
  preview_metadata.json
```

Keep generated media out of Git.

## TTS and subtitle workflow

A safe baseline is EdgeTTS for preview voiceover:

```bash
edge-tts \
  --voice en-GB-RyanNeural \
  --rate=-3% \
  --file voiceover.txt \
  --write-media voiceover.mp3 \
  --write-subtitles edge_subtitles.srt
```

Then probe actual duration:

```bash
ffprobe -v error -show_entries format=duration \
  -of default=noprint_wrappers=1:nokey=1 voiceover.mp3
```

If real forced alignment is not available, create a transparent preview-only fallback:

1. Parse EdgeTTS sentence-level SRT cues.
2. Distribute word timings within each sentence by word length or equal timing.
3. Export `word_cues_time_based.json` and `word_cues_time_based.srt`.
4. Mark the limitation clearly: `time-based word cues; not forced alignment`.

Quality gate:

- If caption timing is massively asynchronous, do not mark the preview ready.
- If timing is usable but not final-grade, mark it as preview-ready and require forced alignment before final.

## Deterministic frame rendering pattern

For a concept preview, Python/Pillow/OpenCV is sufficient:

- Draw 9:16 dark background.
- Header: `PREVIEW / NOT FINAL`.
- Scene ID and purpose.
- Simple cards/diagram shapes.
- Renderer-owned labels (`USELESS`, `NO OWNER`, `BLOCKERS`, etc.).
- Word/pill caption at the bottom.
- Progress bar.

Use FFmpeg to mux audio and video. Preserve the planned preview duration; do not blindly use `-shortest`, because it may trim the visual outro or final takeaway hold.

Example mux shape:

```bash
ffmpeg -y \
  -i preview_silent.mp4 \
  -i voiceover.mp3 \
  -map 0:v:0 -map 1:a:0 \
  -c:v libx264 -pix_fmt yuv420p -preset veryfast -crf 24 \
  -c:a aac -b:a 160k \
  -t 38 \
  -movflags +faststart \
  preview_<candidate_id>_v2.mp4
```

## Verification before delivery

Always collect:

- MP4 path.
- Audio path.
- Subtitle/word-cue path.
- Audio duration.
- Preview duration.
- SHA256 checksum.
- Resource state used.
- Whether Wan/API/image generation/publishing occurred — should be false.

Optionally extract one mid-frame and visually inspect it for:

- `PREVIEW / NOT FINAL` visible.
- 9:16 dimensions.
- captions readable.
- concept visual understandable.
- no clipped critical text.

## Telegram delivery

If the current chat supports media delivery, include the MP4 as `MEDIA:/absolute/path/to/file.mp4` in the final response.

If Telegram/media delivery is unavailable, report:

- local MP4 path,
- SHA256,
- Telegram delivery plan,
- review text.

## Report shape

Keep the final report concise:

- git status and commit hash for previous sprint,
- pytest result,
- preview approval state,
- generated paths,
- audio/preview duration,
- known limitations,
- delivery status,
- next review commands:
  - `REVISE <candidate_id> <field> "..."`
  - `APPROVED_FOR_FINAL_RENDER <candidate_id> <version> <script_hash>`
  - `REJECT <candidate_id> "..."`

## Pitfalls

- Do not treat preview approval as final-render approval.
- Do not generate Wan/AI image assets during preview unless separately approved.
- Do not use generated media artifacts as committed source files.
- Do not hide caption limitations; say whether alignment is forced or time-based.
- Do not send an approval video if the voice/caption timing is obviously broken.
