AI Integration / Workflow May 26, 2026

When ffmpeg Concat Fails Should You Retry Whisper Per Clip or Cloud API - 2026 Decision Tree

2026 decision tree when ffmpeg concat fails—retry merge, per-clip local Whisper, or cloud API—with concat_ok and whisper_batch_allowed receipt gates.

By GamineAI Team

When ffmpeg Concat Fails Should You Retry Whisper Per Clip or Cloud API - 2026 Decision Tree

Pixel-art hero for ffmpeg concat failure Whisper path decision tree 2026

Your ffmpeg -f concat run printed Non-monotonous DTS at 02:14. The merged WAV is 0 bytes. Someone on Discord asked whether to retry concat, run Whisper on every Replay Buffer clip, or upload to the OpenAI API and hope chunking saves the night.

You already shipped the OBS Replay Buffer concat evening pipeline. You already batch-transcribe with the local Whisper playtest VOD triage workflow. concat_ok: false is not a personality test—it is a fork in the road. Pick a named path, write it to ffmpeg_concat_decision_receipt_v1.json, and only then set whisper_batch_allowed on playtest_vod_triage_receipt_v1.json.

June–July 2026 async playtest volume is high enough that teams hit this fork weekly. This AI Integration / Workflow post is the decision tree only—not a second concat tutorial, not a full Whisper install guide. It answers one search-shaped question: when merge fails, what do I do next without lying to my receipt JSON?

Non-repetition note: 16 free OBS ffmpeg Silero concat tools is a tool list; OBS zero-duration audio help is missing audio tracks; Whisper API 413 chunking help is cloud size limits after you already have audio. This URL owns path selection when concat_ok is false.

Pair with BUILD_RECEIPT, Thursday row review, course Lesson 207 — Whisper path when concat fails, preventive uniform fragments preflight (ninety-second OBS profile gate), and Lesson 258 — replay buffer uniform receipt on BUILD_RECEIPT. Forward link target: Help #5 concat fix (pairs backlog).

Who this is for and what you get

Audience You will be able to…
First-time facilitator Stop guessing after a failed concat
Solo dev Choose local vs cloud without NDA panic
Producer Require chosen_path before triage standup
Engineer Wire whisper_batch_allowed honestly in CI

Time: ~20 minutes to run the tree on one failed session folder.
Prerequisites: ffprobe on PATH; a session folder with Replay Buffer MKVs; an existing playtest_vod_triage_receipt_v1.json row (or template from the Whisper pipeline blog).

Why this matters now (June–July 2026)

  1. Replay Buffer fragments — One playtest night produces 8–20 MKVs, not one MP4. Concat fails are normal, not exceptional.
  2. Receipt culture — Teams adopted BUILD_RECEIPT rows; concat_ok without chosen_path creates false-green triage.
  3. Discord ops questions — “Should we cloud Whisper?” spikes after fest playtests when local GPU time is scarce.
  4. Privacy defaults — Uploading twelve clips because merge failed is a policy decision, not a ffmpeg accident.
  5. October deadline — Fixing path discipline in July prevents October triage collapse.

Direct answer: Log concat_ok: false, run gates D1–D6, pick reencode_concat, per_clip_local, or cloud_chunked, file ffmpeg_concat_decision_receipt_v1.json, then set whisper_batch_allowed only when that path’s verification gates pass.

Mental model — three clocks

Clock What it measures Receipt field
Merge clock Can fragments become one timeline-safe WAV? concat_ok
Path clock Which recovery lane did you choose? chosen_path
ASR clock May batch Whisper run on merged or per-clip audio? whisper_batch_allowed

Never start the ASR clock while the Path clock is blank. That is how summaries claim “we transcribed the session” when half the clips were never merged or tagged.

Beginner path — five steps when concat fails

  1. Confirm failure honestly — Open playtest_vod_triage_receipt_v1.json and set concat_ok: false. Do not delete the row.
  2. Archive ffprobe — Save ffprobe_fragments.csv per OBS ffprobe concat_ok preflight.
  3. Walk the decision tree — Answer the yes/no questions in the next section.
  4. File path receipt — Write ffmpeg_concat_decision_receipt_v1.json with chosen_path.
  5. Re-run only the ASR step — Per-clip loop, successful re-merge, or cloud upload—never all three silently.

Success check: A teammate reading only your JSON knows why batch Whisper did or did not run.

Decision tree (D1–D6 gates)

Use these gates in order. Stop at the first branch that determines chosen_path.

Gate Question If YES If NO
D1 Is concat_ok recorded false on the triage receipt? Continue Fix honesty first—do not pick a path on a lie
D2 Does every fragment have audio with duration greater than 0? Continue Fix OBS capture—see zero-duration audio help
D3 Did concat fail with DTS/timestamp errors but fragments are otherwise valid? Candidate reencode_concat Skip to D4
D4 Do you have GPU time and NDA allows local-only processing? Candidate per_clip_local Lean cloud_chunked
D5 Is total session audio under your cloud size budget per clip after chunking? cloud_chunked viable Split clips or reencode_concat
D6 Did the chosen path pass its verification gate? Set whisper_batch_allowed per path rules below Remediation—do not transcribe yet

ASCII decision flow

concat_ok == false?
  |
  +-- NO --> (wrong article; use concat evening pipeline)
  |
  YES
  |
  +-- all fragments have audio? --NO--> fix OBS / re-capture
  |
  YES
  |
  +-- DTS/codec concat error only? --YES--> reencode_concat
  |                                      |
  |                                      +-- post_path_concat_ok? --YES--> whisper_batch_allowed true
  |
  +-- privacy requires local only? --YES--> per_clip_local
  |                                      |
  |                                      +-- all clips transcribed? --YES--> whisper_batch_allowed true (batch summaries OK)
  |
  +-- else --> cloud_chunked (per clip or chunked upload)
                 |
                 +-- API 413? --> see cloud chunking help

Path 1 — reencode_concat (retry merge with encode, not copy)

Choose when: ffprobe shows valid audio on every fragment, but ffmpeg -f concat -c copy failed with Non-monotonous DTS, Invalid data, or codec mismatch.

Do not choose when: Fragments lack audio (D2 fail) or half the folder is from a different OBS profile with incompatible channel layouts you have not normalized.

Working dev procedure

  1. Re-run normalize → concat from the concat evening pipeline Block 3, forcing encode:
ffmpeg -y -f concat -safe 0 -i concat_list.txt -ac 2 -ar 48000 -c:a pcm_s16le session_merged.wav
  1. Re-verify duration within ±2 s of fragment sum.
  2. Set on decision receipt:
{
  "chosen_path": "reencode_concat",
  "post_path_concat_ok": true,
  "whisper_batch_allowed": true
}
  1. Update triage receipt: keep original concat_ok: false on the failed attempt row; add a new row or recovery_attempt block with post_path_concat_ok: true so Thursday row review shows recovery, not overwrite history.

Common mistake: Marking concat_ok: true on the same row without noting the failed first pass—auditors cannot see you recovered.

Path 2 — per_clip_local (local Whisper per fragment)

Choose when: Merge is not worth the engineering time tonight, local GPU is available, and NDA / player consent requires audio never leaves the machine.

Tradeoffs:

Pros Cons
No cloud upload Manual loop over N files
Keeps privacy story simple Session-level summaries need merge in spreadsheet
Works when DTS is hopeless Higher operator attention

Per-clip loop (operator checklist)

For each 00N_replay_*.mkv in sort order:

  1. ffmpeg -i clip.mkv -vn -ac 1 -ar 16000 clip.wav
  2. Run local Whisper (same model table as Whisper pipeline blog).
  3. Write transcripts/00N.txt and one-line summaries/00N.md with build_id, surface, timestamp offset.
  4. Append row to batch manifest per_clip_manifest.json.

Set decision receipt:

{
  "chosen_path": "per_clip_local",
  "fragment_count": 12,
  "per_clip_transcripts_complete": true,
  "whisper_batch_allowed": true,
  "merged_audio": null,
  "notes": "No merged WAV; triage uses per-clip summaries"
}

whisper_batch_allowed: true here means you may run your batch summary script over per-clip outputs—it does not mean concat_ok became true.

Facilitator README snippet

## When concat fails
1. Set concat_ok false on the triage receipt.
2. Do NOT upload VODs to cloud unless producer approves.
3. Run per-clip Whisper loop; file ffmpeg_concat_decision_receipt_v1.json.
4. Post daily note with fragment indices, not "the session."

Path 3 — cloud_chunked (API Whisper with chunking discipline)

Choose when: Local GPU is unavailable, you need fastest text tonight, and consent docs allow cloud transcription for this playtest cohort.

Do not choose when: Only failure mode is fixable merge (Path 1 is cheaper and keeps data local). Do not choose when 413 Payload Too Large is likely without a chunk plan—read Whisper API 413 chunking help first.

Cloud path steps

  1. Extract 48 kHz WAV per clip (same as local path extract).
  2. Chunk to under API limit (often 24–25 MB per request depending on account).
  3. Upload chunks with filename prefix 001_, 002_ preserving order.
  4. Stitch transcript text files with headers:
### Fragment 003 — 2026-05-26T19:14:22 — build rc4
<transcript>
  1. File decision receipt:
{
  "chosen_path": "cloud_chunked",
  "cloud_provider": "openai_whisper",
  "chunk_count": 28,
  "consent_doc_version": "playtest-vod/README.md#cloud",
  "whisper_batch_allowed": true,
  "concat_ok": false
}

Cost discipline: Cloud is for time, not laziness. If Path 1 succeeds in under 30 minutes, prefer local merge.

Outbound reference: OpenAI Whisper API documentation for current limits and formats.

Proof table — map path to receipt columns

Path concat_ok chosen_path whisper_batch_allowed Required proof artifact
Happy merge (not this article) true null or omitted true session_merged.wav
reencode_concat false on attempt 1 reencode_concat true after post_path_concat_ok session_merged.wav + encode log
per_clip_local false per_clip_local true when all clips done per_clip_manifest.json
cloud_chunked false cloud_chunked true when chunks stitched cloud_stitch_index.md

Add these columns to your spreadsheet triage board if JSON feels heavy for non-dev producers.

ffmpeg_concat_decision_receipt_v1.json (full example)

{
  "schema": "ffmpeg_concat_decision_receipt_v1",
  "build_id": "nextfest-oct-2026-rc4",
  "surface": "playtest_invite",
  "session_folder": "playtest-vod/inbox/2026-05-26_session-rc4",
  "concat_ok": false,
  "chosen_path": "per_clip_local",
  "decision_gates": {
    "D1_concat_ok_false_logged": "pass",
    "D2_fragment_audio_present": "pass",
    "D3_dts_error_only": "fail",
    "D4_local_allowed": "pass",
    "D5_cloud_budget": "skipped",
    "D6_path_verification": "pass"
  },
  "fragment_count": 11,
  "per_clip_transcripts_complete": true,
  "whisper_batch_allowed": true,
  "operator": "facilitator-east",
  "decided_at_utc": "2026-05-26T22:15:00Z",
  "notes": "Concat copy failed DTS; per-clip faster than third merge attempt before standup"
}

Store beside playtest_vod_triage_receipt_v1.json in the same receipts/ folder.

Working dev path — CI and batch scripts

Guardrail sketch (fail closed)

Pseudologic your nightly job should enforce:

if receipt.concat_ok == false:
    require ffmpeg_concat_decision_receipt_v1.json
    require receipt.chosen_path in ALLOWED_PATHS
    if receipt.whisper_batch_allowed == true:
        assert path_verification_passed(receipt.chosen_path)
else:
    allow batch whisper on session_merged.wav

Aligns with Lesson 207 verify_whisper_path_decision_v1 intent.

Batch script branch (Python outline)

def whisper_entry(receipt, decision):
    if receipt["concat_ok"]:
        return transcribe_merged(receipt["merged_audio"])
    path = decision["chosen_path"]
    if path == "reencode_concat" and decision.get("post_path_concat_ok"):
        return transcribe_merged(receipt["merged_audio"])
    if path == "per_clip_local":
        return transcribe_per_clip_manifest(decision["per_clip_manifest"])
    if path == "cloud_chunked":
        raise RuntimeError("Cloud path must not run in unattended batch without explicit flag")
    raise RuntimeError("concat_ok false but no valid chosen_path")

Why cloud is gated: Unattended upload is a policy event, not a build step.

Cost and time comparison (honest bands)

Numbers vary by GPU and clip length; use bands for planning, not quotes.

Path Operator time (11 clips) Money Privacy
reencode_concat 25–45 min $0 Local
per_clip_local 40–90 min $0 electricity Local
cloud_chunked 20–40 min API $ Cloud

When operator time is the bottleneck and merge is likely fixable, try Path 1 twice before Path 3.

Failure modes and remediation

Symptom Wrong conclusion Correct path
0-byte merged WAV “Whisper broken” reencode_concat or per_clip_local
Chipmunk audio after merge “Whisper hallucinating” reencode_concat with wrong rate
API 413 on upload “game too long” chunk per clip; see help
Mixed OBS profiles in folder “concat impossible” split session folders by profile
whisper_batch_allowed true with no transcripts “done” D6 fail—remediation

Three-surface tagging reminder

When filing summaries, keep surface aligned with playtest isolation:

  • playtest_invite — Steam Playtest key cohort
  • fest_public — Next Fest library install
  • internal — team dogfood

Path choice does not change surface. A per-clip loop still tags each fragment row.

Tooling cross-links (not a tool list)

Use the 16-tool concat prep list for stack inventory. Use this tree when concat_ok is already false and you must decide what happens next.

Tool role When in this tree
ffprobe D2 fragment proof
ffmpeg encode concat Path 1
faster-whisper Path 2
OpenAI API Path 3
jq Validate receipt JSON in CI

Producer-facing one-pager (paste into contract)

From multi-channel facilitator contract teams already require audio gate proof. Add one bullet:

  • If concat fails: facilitator files ffmpeg_concat_decision_receipt_v1.json within 4 hours and notifies #playtest-ops with chosen_path—no cloud upload without producer reply.

That single bullet prevents midnight API uploads.

Scenario walkthrough A — DTS error on eleven MKV fragments

Context: Tuesday playtest, build_id rc4, eleven Replay Buffer saves, ffmpeg -f concat -c copy exits with Non-monotonous DTS.

D1: Receipt row already shows concat_ok: false from operator—pass.
D2: ffprobe_table.csv shows audio on all eleven—pass.
D3: Error log mentions DTS only—reencode_concat candidate.
D4: Local GPU free—Path 1 preferred over per-clip.
D5: Skipped—cloud not needed.
D6: Re-encode merge duration 1388 s vs sum 1390 s—pass.

Actions: Operator runs encode concat from normalized WAV list, updates decision receipt with post_path_concat_ok: true, runs single Whisper pass on session_merged.wav. Do not flip original concat_ok on failed row.

Standup sentence: “Merge failed on copy; we re-encoded concat, merged WAV verified, batch Whisper allowed.”

Scenario walkthrough B — two OBS profiles in one folder

Context: Facilitator changed OBS sample rate mid-session; fragments mix 44100 and 48000.

D3: Copy concat fails—expected.
Path choice: If normalize-then-encode still fails after splitting folders by profile, use per_clip_local rather than a third merge attempt past 45 minutes.

Lesson: The tree is not “retry until magic.” Splitting bad inputs is valid remediation.

Scenario walkthrough C — NDA blocks cloud, GPU busy rendering trailer

Context: Art team needs the workstation; merge failed; standup in 90 minutes.

Path: per_clip_local on laptop #2 while desktop renders. File per_clip_manifest.json with eleven rows. Producer merges summaries in spreadsheet manually.

Receipt: whisper_batch_allowed: true with note “summary merge manual.”

concat_ok vs whisper_batch_allowed — do not conflate

Field Meaning Common bug
concat_ok Did merge produce one verified timeline? Set true after per-clip because “we have text”
whisper_batch_allowed May automated batch ASR/summary run proceed? True while zero transcripts exist
chosen_path Which recovery lane when merge failed? Omitted entirely

Audit sentence for Thursday row review:concat_ok false + chosen_path set + whisper_batch_allowed true only after D6.”

Spreadsheet columns for producers (no JSON required)

Column Example
session_id 2026-05-26_rc4
concat_ok false
chosen_path per_clip_local
whisper_batch_allowed true
fragment_count 11
blocker none
owner Alex
standup_note Per-clip transcripts in summaries/

JSON remains source of truth for engineers; spreadsheet is the human dashboard.

PowerShell variant — batch ffprobe table export

Windows facilitators without bash loops:

$rows = @()
Get-ChildItem *.mkv | Sort-Object Name | ForEach-Object {
  $dur = ffprobe -v error -show_entries format=duration -of csv=p=0 $_.Name
  $rows += [pscustomobject]@{ file=$_.Name; duration_sec=$dur; pass_o1=([double]$dur -gt 0) }
}
$rows | Export-Csv ffprobe_table.csv -NoTypeInformation

Attach ffprobe_table.csv to decision receipt as fragment_proof.

Silero VAD optional gate (when clips are huge)

From the 16-tool list, Silero VAD can mark speech regions before Whisper spend on menu idle fragments.

Optional gate V1: If more than 40% of a clip is non-speech, tag triage_priority: low in per-clip summary—still transcribe, but do not block standup on that fragment.

This does not change chosen_path; it changes summary ordering.

Reencode_concat debug checklist (second attempt discipline)

Before abandoning Path 1:

  1. Confirm concat_list.txt uses sorted norm_*.wav only.
  2. Confirm no absolute paths with unescaped quotes on Windows.
  3. Try pcm_s16le encode, not copy.
  4. Compare merged duration to CSV sum.
  5. Listen to seconds 0–5 and last 5 for truncation.

Log each attempt in decision receipt merge_attempts[] array—auditors see discipline.

Per-clip manifest schema (minimal)

{
  "schema": "per_clip_manifest_v1",
  "build_id": "rc4",
  "clips": [
    {
      "index": 1,
      "source_mkv": "001_replay_2026-05-26_19-02.mkv",
      "transcript": "transcripts/001.txt",
      "summary": "summaries/001.md",
      "whisper_model": "medium",
      "status": "complete"
    }
  ]
}

Batch summary scripts read this instead of guessing filenames.

Cloud path consent README paragraph

Add to playtest-vod/README.md:

## Cloud transcription
Cloud Whisper is **opt-in per session**. Facilitator must receive written approval in #playtest-ops with build_id and retention days. Default path when concat fails is **per_clip_local** unless producer selects cloud_chunked.

Link README version in consent_doc_version field.

Anti-patterns that recreate October triage pain

  1. Deleting failed merge outputs — keep logs for DTS errors.
  2. Running cloud on entire session zip without chunk plan—413 and policy risk.
  3. Transcribing before build_id confirmed — tag fragments wrong.
  4. Mixing playtest_invite clips with fest_public in one folder—surface lies.
  5. Setting whisper_batch_allowed in spreadsheet only — JSON must match for CI.

Integration with local Whisper pipeline gates T1–T6

After path selection, resume Whisper pipeline at the correct entry:

chosen_path Enter pipeline at
reencode_concat + post_path_concat_ok T2 extract merged WAV
per_clip_local T3 per-clip loop (custom)
cloud_chunked T4 cloud stitch then T5 summary

Gate T5 surface still applies—Playtest vs fest_public must match isolation playbook.

Weekly ops ritual (15 minutes)

Every Friday with Friday Block 5 energy:

  1. Count sessions with concat_ok: false.
  2. Count how many have ffmpeg_concat_decision_receipt_v1.json.
  3. If gap greater than zero, README or facilitator contract needs another sentence.
  4. Pick one failed session for 15-minute tree drill so new volunteers learn paths.

Engine and platform notes (merge failures are not engine bugs)

Godot, Unity, and Construct do not cause ffmpeg DTS errors—OBS fragment encoding does. Do not open engine tickets when this tree applies.

Symptom location Owner
OBS fragment encoding Facilitator + this tree
Gameplay soft-lock Engineering
Steam branch mismatch BUILD_RECEIPT

Extended FAQ — search phrasing

What does Non-monotonous DTS mean for playtest VOD concat

It means fragment timestamps cannot be stitched with stream copy. Re-encode concat (Path 1) or per-clip Whisper (Path 2) is expected—not a reason to skip receipts.

Is whisper_batch_allowed the same as concat_ok

No. You can have concat_ok: false and whisper_batch_allowed: true only when chosen_path verification completed (for example per-clip transcripts all exist).

Should facilitators decide cloud alone

No. Default per_clip_local when in doubt. Cloud requires producer approval documented in consent_doc_version.

How long should path selection take before standup

Target 15 minutes for D1–D6 with existing fragments. If you exceed 45 minutes without chosen_path, escalate to producer with receipt partial—do not silently upload.

Does Lesson 207 replace this blog post

No. Lesson 207 is the course milestone with BUILD_RECEIPT wiring; this article is the standup-facing strategy tree with scenarios, manifests, and facilitator contract language.

Copy-paste standup templates (three lanes)

reencode_concat: “Merge copy failed on build_id {id}; re-encoded concat passed D6; batch Whisper on merged WAV allowed; receipt filed.”

per_clip_local: “Merge failed; running per-clip Whisper on {n} fragments; whisper_batch_allowed true after manifest complete; no cloud.”

cloud_chunked: “Merge failed; producer approved cloud_chunked for {n} chunks; consent {version}; retention {days} days; receipts attached.”

Paste the matching sentence into #playtest-ops so producers do not re-ask which lane you chose.

Key takeaways

  1. concat_ok: false demands a named chosen_path—never silent batch Whisper.
  2. reencode_concat is first when fragments are healthy but copy-concat failed.
  3. per_clip_local preserves privacy when merge is not worth tonight.
  4. cloud_chunked is a time trade, not a default—check consent and 413 limits.
  5. whisper_batch_allowed follows path verification (D6), not wishful thinking.
  6. File ffmpeg_concat_decision_receipt_v1.json beside triage receipts for audit trails.
  7. This article complements—not replaces—the concat evening and Whisper triage pipelines.

FAQ

Should I retry ffmpeg concat or skip straight to per-clip Whisper

Retry merge with encode (Path 1) when ffprobe shows audio on every fragment and the error is timestamp or codec related. Skip to per-clip when you have already failed two disciplined merge attempts or standup is in under an hour and local GPU is free.

Does per-clip local mean concat_ok should be true

No. Keep concat_ok: false on the failed merge attempt. Set chosen_path: per_clip_local and whisper_batch_allowed: true only after every clip has a transcript file listed in your manifest.

When is cloud API the right answer

When local GPU time is unavailable, consent allows cloud processing, and chunk sizes fit API limits—or when fragments are few and upload cost is negligible. It is wrong when Path 1 would succeed in one encode pass.

What is post_path_concat_ok

A field on the decision receipt meaning Path 1 recovery produced a verified merged WAV after an initial concat_ok: false. Do not overwrite the failed attempt; add recovery metadata for auditors.

How does this relate to playtest_vod_triage_receipt_v1.json

Triage receipt tracks session ingest and merge. Decision receipt tracks what you did when merge failed. Batch scripts should read both before setting whisper_batch_allowed.

Can I run cloud and local on the same session

Pick one path per session folder per night. Mixing paths without documentation recreates the “which transcript is canonical?” fights this tree prevents.

Next step

Tonight when concat fails:

  1. Set concat_ok: false.
  2. Run D1–D6.
  3. Write ffmpeg_concat_decision_receipt_v1.json.
  4. Only then run Whisper—merged, per-clip, or cloud—matching chosen_path.

Your triage board stays honest. Your October fest self stays out of refund-driven fire drills.