Lesson 207: Playtest VOD Whisper Path Decision Tree When concat_ok Fails (2026)
Direct answer: When concat_ok is false, you must pick an explicit Whisper path—do not silently run batch ASR on a broken merge. This lesson ships ffmpeg_concat_decision_receipt_v1.json with chosen_path (per_clip_local, reencode_concat, or cloud_chunked) and sets whisper_batch_allowed on playtest_vod_triage_receipt_v1.json only when the path’s verification gates pass—after Lesson 200 concat_ok and Lesson 206 facilitator contract.

Why this matters now (June 2026 post-concat stack)
June 2026 teams adopted OBS Replay Buffer concat and normalize preflight—then hit a new Discord question: “concat failed—should we Whisper each clip or pay for API?”
Wrong answers waste money and mis-file bugs:
- Per-clip Whisper with merged-timeline issue IDs (quotes don’t match facilitator timestamps).
- Cloud API on twenty clips without consent README approval.
whisper_batch_allowed: truewhileconcat_ok: false(downstream summaries lie).
The blog When ffmpeg concat fails — per-clip vs cloud API is the strategy article; this lesson is the receipt milestone for your RPG live-ops course.
Beginner path (20-minute decision)
| Step | Question | If yes → |
|---|---|---|
| 1 | Did OBS normalize preflight pass? | Retry concat once |
| 2 | Is only one fragment broken? | per_clip_local for debug; fix fragment |
| 3 | Are all fragments healthy but concat demuxer fails? | reencode_concat |
| 4 | Is legal OK for cloud + volume < API budget? | cloud_chunked |
| 5 | File ffmpeg_concat_decision_receipt_v1.json |
chosen_path set |
| 6 | Update triage receipt | whisper_batch_allowed policy below |
Time: ~20 minutes to decide; 72 minutes if you implement all three lanes in a drill.
Developer path (gates D1–D6)
| Gate | Check | Fail when |
|---|---|---|
| D1 | concat_ok recorded honestly |
false hidden as true |
| D2 | ffprobe table archived |
Missing ffprobe_fragments.csv — see OBS ffprobe concat_ok preflight |
| D3 | Path choice documented | No chosen_path |
| D4 | Path-specific verification | Lane smoke red |
| D5 | whisper_batch_allowed matches path |
Batch on per_clip_local without batch_merge_optional |
| D6 | BUILD_RECEIPT row updated | Ops column stale |
Decision tree (ASCII)
concat_ok == true?
yes → whisper_batch_allowed = true (Lesson 200)
no → ffprobe all fragments
├─ any fragment audio_stream_ok false?
│ → fix OBS ([zero-duration audio help](/help/obs-replay-buffer-export-zero-duration-audio-whisper-vod-triage-fix)); STOP
├─ single bad fragment + urgent triage?
│ → chosen_path: per_clip_local (debug only)
├─ all fragments OK, concat demuxer fails?
│ → chosen_path: reencode_concat (+genpts)
└─ consent + budget + deadline?
→ chosen_path: cloud_chunked ([API chunking help](/help/openai-whisper-api-413-payload-too-large-playtest-vod-chunking-fix))
ffmpeg_concat_decision_receipt_v1.json
{
"schema": "ffmpeg_concat_decision_receipt_v1",
"build_label": "fest-demo-2026-06-02-rc3",
"concat_ok": false,
"chosen_path": "reencode_concat",
"paths_considered": ["per_clip_local", "reencode_concat", "cloud_chunked"],
"ffprobe_table_sha256": "sha256:REPLACE",
"reencode_command": "ffmpeg -fflags +genpts -f concat ...",
"post_path_concat_ok": true,
"whisper_batch_allowed_after_path": true,
"consent_readme_present": true,
"cloud_api_used": false,
"gates": {
"D1_concat_honest": "pass",
"D2_ffprobe_archived": "pass",
"D3_path_documented": "pass",
"D4_lane_smoke": "pass",
"D5_whisper_policy": "pass",
"D6_build_receipt": "pass"
}
}
Pin under release-evidence/playtest/vod/FFMPEG_CONCAT_DECISION_RECEIPT.json.
whisper_batch_allowed policy (on triage receipt)
chosen_path |
whisper_batch_allowed |
Notes |
|---|---|---|
| (concat_ok true) | true |
Lesson 200 default |
per_clip_local |
false |
Set per_clip_transcripts_ok: true separately |
reencode_concat |
true only if post_path_concat_ok |
Re-run concat gate |
cloud_chunked |
true if consent + chunk receipt |
Log cloud_whisper_receipt_v1 |
{
"schema": "playtest_vod_triage_receipt_v1",
"build_label": "fest-demo-2026-06-02-rc3",
"concat_ok": false,
"ffmpeg_concat_decision_receipt": "release-evidence/playtest/vod/FFMPEG_CONCAT_DECISION_RECEIPT.json",
"chosen_path": "reencode_concat",
"whisper_batch_allowed": true,
"per_clip_transcripts_ok": false
}
Lane sketches
Lane A — per_clip_local
Use when one fragment is bad or you need same-night quotes without fixing merge.
for f in playtest-vod/fragments/*.mkv; do
whisper "$f" --model small --output_dir playtest-vod/per_clip_txt/
done
Honest limit: GitHub issues must tag fragment_id, not merged timeline offset.
Lane B — reencode_concat
Use when fragments pass N1–N4 but concat demuxer fails.
ffmpeg -y -fflags +genpts -f concat -safe 0 -i lists/concat.txt \
-c:a pcm_s16le -ar 48000 playtest-vod/merged_reencode.wav
Set post_path_concat_ok: true before enabling batch Whisper.
Lane C — cloud_chunked
Use only with documented consent and API chunking discipline.
- Chunk < 25 MB per request
- Log
cloud_whisper_receipt_v1.json - Never upload raw MKV without README approval
Publish gate
ALTER TABLE release_publish_gate ADD COLUMN IF NOT EXISTS
whisper_path_undocumented_blocked BOOLEAN NOT NULL DEFAULT false;
CI verify_whisper_path_decision_v1 fails when concat_ok = false and no ffmpeg_concat_decision_receipt_v1.json exists for that build_label.
Prerequisites
- Lesson 200 —
concat_okbaseline - Lesson 206 — facilitator OBS/VOD clauses
- 16 free OBS/ffmpeg/Silero tools
- Local Whisper VOD pipeline
Common mistakes
- Running batch Whisper on a failed concat “to save time.”
- Choosing cloud without updating consent README.
per_clip_localtranscripts referenced as if merged.- Fixing concat without updating
post_path_concat_ok.
Troubleshooting
| Symptom | Path |
|---|---|
| concat fails, all fragments green | reencode_concat + +genpts |
| one silent fragment | OBS audio help, then retry |
| API 413 | chunking help |
| facilitators confused | Pin decision tree in Discord README |
Mini exercise (60 minutes)
- Start with
concat_ok: falseon a test receipt. - Walk tree; pick
reencode_concat. - Produce merged WAV; flip
post_path_concat_ok. - Write both JSON receipts; verify
whisper_batch_allowed. - Add BUILD_RECEIPT column
whisper_path; link from OBS concat blog.
Continuity
- Previous: Lesson 206 — facilitator contract
- Next: Lesson 208 — Construct CORS hosting decision
- Guide: OBS normalize preflight
- Help (planned): OBS MKV concat fix (Help queue #5)
- Blog: ffmpeg concat failure decision tree
- H2 batch: Lesson 220 — facilitator concat batch receipt when multiple sessions merge into one Whisper run
- MKV gap BUILD_RECEIPT: Lesson 224 — mkv_gap_reencode_receipt when
reencode_concatis the promoted lane
FAQ
Can we always use per-clip Whisper?
Yes for debug—set whisper_batch_allowed: false and document chosen_path: per_clip_local.
Does reencode_concat count as concat_ok?
Set concat_ok false on the failed attempt; set post_path_concat_ok true on the recovery receipt row—or regenerate a green triage receipt after merge.
Cloud vs local?
Default local per facilitator contract; cloud only with consent + budget receipt.
A false concat_ok without a chosen_path is not “almost ready for Whisper”—it is an undocumented ops failure until ffmpeg_concat_decision_receipt_v1.json says otherwise.