# Static active-word captions + controlled final pilot render

Session learning from the first TrueTraceShorts pilot (`AI Output Autopsy / Meeting Summary Decision Target`). Use this for final-near preview/final render work where the user reviews voiceover, subtitle feel, Wan/background quality, and anti-AI-slop risk.

## Caption style correction

The user explicitly rejected two subtitle behaviours:

1. **One word shown alone** — too nervous / teleprompter-like.
2. **Sliding word window where all visible words change at once** — still too jumpy.
3. **Subtitles that are only approximately timed to the voiceover** — irritating when listening and reading simultaneously. For final-near previews, use forced alignment or provider word-boundary events when available; for EdgeTTS, request `boundary='WordBoundary'` and render highlights from those offsets instead of evenly distributing words over sentence SRT blocks.

Required default style for this user's AutoShorts/TrueTraceShorts videos:

```text
static phrase segment + active-word highlight
```

Rules:

- Keep the subtitle phrase segment static on screen.
- Show at least 3 words at once; ideal is 4–7 words when the phrase allows it.
- Prefer two-line static phrase segments when the phrase is long enough; this reduces nervous one-line churn and lets the active word move inside a calmer block.
- Words stay in the same positions during the segment.
- Only the currently spoken word highlights / pulses.
- The highlight moves left-to-right through the fixed phrase.
- Replace the whole phrase only at the next sentence/phrase boundary.
- Do not default to one-word-only captions except for a deliberate hook/impact frame.
- Do not use hectic windows where all words change at once every word.
- For Chatterbox HTTP voices, do not evenly distribute word timing over the whole script. Chatterbox does not expose provider WordBoundary events; extract word timestamps from the rendered voiceover with forced alignment / faster-whisper `word_timestamps=True`, then render the active-word highlight from those measured word cues.
- When forced-alignment words lack reliable punctuation, map aligned words back to the source script token positions and use source punctuation / phrase breakers for segment boundaries. Do not allow blocks to cross sentence boundaries merely because the ASR word text omitted punctuation; QA a real subtitle frame and re-render if a phrase reads like a sentence splice.
- When mapping source tokens to ASR word positions, normalize hyphenated source words such as `toll-road` into separate tokens if the aligner emits them separately; otherwise punctuation boundaries drift by one word.
- Do not treat colon-only labels such as `Rule:` as a hard segment break if doing so creates a one-word caption. Either merge the label with the following phrase (`RULE, TRUST YOUR...`) or rewrite the script to avoid the label punctuation.
- QA seconds must fall inside the measured audio/video duration; avoid stale frame timestamps from longer template videos.
- For silent viewers, captions must be understandable as reading text, not just word-highlighting decoration. If subtitle blocks change too quickly, extend scene/video duration or slow the subtitle pacing rather than forcing dense text into a short runtime. The user explicitly approved the `erf-007` readable revision pattern: sentence-by-sentence TTS chunks, small pauses, fewer longer sense blocks, and 46s instead of a rushed 36s. See `references/readable-silent-short-captions.md` for the durable implementation pattern.
- Prefer sentence-complete or clause-complete blocks. Do not leave a single orphan word on the next subtitle page; if a sentence would create a 1-word tail, rebalance the previous block, merge a short label with the following phrase, or slightly extend the segment/video.
- When a sentence is longer than a readable block, split at natural clause boundaries, keeping each block meaningful on its own and on screen long enough for no-audio comprehension.
- Caption renderer must have a hard width guard: measure actual rendered word widths, wrap greedily within mobile safe width, allow a 3-line fallback for long sentence-complete blocks, and continue shrinking font size until the line fits. Do not leave the font at a large default when no 2-line size fits; this caused the `erf-009` 0:25 subtitle overflow.
- QA exact timestamps where long captions appear, not only template QA seconds. Extract an exact frame if the user reports a timestamp.
- See `references/readable-silent-shorts-captions.md` for the accepted `erf-007`/`erf-008` silent-readable baseline, QA checklist, and implementation notes.

Implementation pattern:

```text
word cues → phrase segments of 3–7 words → fixed layout per segment → active_word_index selects highlight only
```

Logic tests to add for any renderer implementation:

- static caption segment contains multiple words
- active word changes within the same segment
- segment text remains stable while highlight moves
- no one-word-only caption mode as default when enough words exist

## Preview/final render gate sequence

Use approval states as resource gates, not as vague comments:

- `APPROVED_FOR_PREVIEW_RENDER` permits TTS, subtitle alignment, deterministic animatic/preview MP4, and Telegram delivery of that preview only.
- `APPROVED_FOR_FINAL_RENDER` permits exactly the approved final render resource tier for the hash/version-bound candidate.
- Publishing/platform APIs remain blocked until a separate manual-posting approval.
- AI image/keyframe generation remains blocked unless separately approved.

Before final render, verify:

- candidate_id matches
- version matches
- script_hash matches
- claim gate valid
- AI disclosure valid
- resource gate allows only the intended render tier
- publishing and platform API tiers still block

## Wan/background policy for this class

For a controlled pilot final render, Wan may generate only a **text-free visual motion/background layer**. Deterministic renderer must own:

- captions
- labels
- arrows
- stamps such as `USELESS`
- mechanism diagrams
- factual claims / UI-like text
- final takeaway text

Wan negative prompt must include variants of:

```text
readable text, words, subtitles, captions, numbers, logos, watermark, brand names, UI text, fake letters
```

If constrained to exactly one Wan render, it is acceptable to create one short text-free Wan background clip and loop/upscale/compose it under deterministic overlays, but label that limitation clearly in the review package. Do not silently imply that every scene was separately generated.

## Viewer-friendly ending / solution gate

If the user says the ending feels confusing, rushed, or does not really solve the viewer's problem, revise before any further polish. Do not leave the fix as a compressed expert phrase.

For broad/non-technical viewers, the final third should answer in plain steps:

1. What should the viewer stop doing right now?
2. What exact safe action should they take instead?
3. How can they verify the situation without trusting the suspicious button/link/email?
4. What short rule should they remember?

Example for a calendar-login trap:

```text
Close the invite.
Open your calendar or work app from the normal icon or trusted bookmark.
If the meeting is real, it will still be there.
Rule: trust your normal path, not the button sent to you.
```

Avoid vague endings like `Open the service yourself` unless the video immediately explains what that means in everyday language.

## Review package checklist

After final pilot render, produce:

- final MP4 path
- SHA256
- duration, resolution, fps
- audio path and measured duration
- subtitle/caption path
- render manifest
- Wan prompt plan/history/log
- claim gate result
- AI disclosure result
- resource gate result
- known limitations, especially forced-alignment status and any looped background layer
- draft social copy and manual posting pack marked draft-only
- explicit note: no posting, no platform API, no second final render without approval

## Pitfall

Do not treat a caption-style correction as a one-off `/tmp` script patch. Integrate the behaviour into the actual renderer/caption library and commit tests so the next render starts from the corrected style.
