fix(voz): frases desativadas em sequência deixavam fatias sobrando no corte

phrase_review_to_actions() cortava cada frase desativada isoladamente
(start..end da própria frase) — quando várias seguidas estavam desativadas,
a pausa ENTRE elas não pertencia a nenhuma frase e sobrevivia como um
clipe minúsculo (0,1-0,5s) na timeline final. Confirmado no projeto
Mastopexia real: 29 cuts individuais geravam mais de uma dezena de fatias
sub-segundo; agrupar frases desativadas consecutivas num único cut (do
início da primeira ao fim da última) reduziu para 3 cuts e 4 fatias
residuais (menores, provavelmente do padding do remove_media_silence —
registrado como dívida separada em 09_MANUTENCAO.md §2.5).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
João Henrique
2026-08-21 18:49:13 -04:00
co-authored by Claude Sonnet 5
parent fd791e116a
commit 8257155fd3
4 changed files with 113 additions and 10 deletions
+35
View File
@@ -1459,3 +1459,38 @@ o outro; percentil entrega um punhado útil nos dois casos.
> borda que respire. Regra prática: só cortar rente ao timestamp quando a
> borda encosta em silêncio real (`gap_before` grande) ou em conteúdo que
> também será descartado; encostando em fala mantida, sempre recuar.
---
### 2026-08-21 — Frases desativadas em sequência deixavam fatias de 0,1-0,5s sobrando
- **Sintoma:** usuário viu, no Final Cut, um clipe minúsculo sobrando entre
dois clipes normais na timeline (projeto Mastopexia, confirmado por
screenshot). Investigação achou 29 `cut`s individuais no
`_phrase_actions.json` gerado pela etapa 5, e a timeline final saiu com
mais de uma dezena de fatias de 0,1-0,5s entre clipes.
- **Causa:** `phrase_review_to_actions()` (`fcpxml/phrase_review.py`) gerava
**um `cut` por frase desativada**, cobrindo só `[phrase.start, phrase.end]`.
Quando duas ou mais frases seguidas estão desativadas, a pausa **entre**
elas nunca pertence a nenhuma frase — não é coberta por nenhum `cut` — e
sobrevive como um clipe próprio, minúsculo, que ninguém pediu para manter.
- **Correção:** `phrase_review_to_actions()` agora agrupa frases desativadas
**consecutivas** (`flush_inactive_run()`) e emite um único `cut` cobrindo do
início da primeira ao fim da última do grupo, absorvendo as pausas entre
elas. Uma frase ativa no meio ainda quebra o grupo — cuts continuam
separados quando há conteúdo mantido entre eles.
- **Validação:** `tests/test_phrase_review.py` ganhou
`test_consecutive_inactive_phrases_merge_into_one_cut`,
`test_inactive_run_at_the_end_still_flushes` e
`test_isolated_inactive_phrases_stay_separate_cuts`. No projeto Mastopexia
real, 29 cuts individuais viraram 3 cuts mescladas; a contagem de fatias
sub-segundo na timeline final caiu de mais de uma dezena para 4 (resíduo
menor, provavelmente do padding do `remove_media_silence` na emenda entre
clipes — não investigado a fundo nesta sessão, ver `09_MANUTENCAO.md`).
- **Estado:** `resolvido` (a causa principal); a sobra residual do
`remove_media_silence` continua como dívida separada.
> **Aprendizado:** "cortar cada frase desativada" não é a mesma coisa que
> "cortar o trecho desativado" quando frases se sucedem sem conteúdo mantido
> entre elas — a pausa entre duas coisas descartadas também precisa ser
> descartada, e ninguém a cobre por definição se o corte for por frase.
+10 -1
View File
@@ -59,7 +59,16 @@ Várias entradas do `05_EXPERIENCIAS.md` estão marcadas como resolvidas *no XML
XML válido não é o mesmo que XML que renderiza como o esperado. Ao mexer em
legenda, zoom ou keyframe, a confirmação final é abrir no FCP.
### 2.5 Submódulo `WHISPERX` com conteúdo modificado e não commitado
### 2.5 `remove_media_silence` deixa fatias sub-segundo nas emendas entre clipes
Mesmo depois de corrigir o merge de cortes consecutivos (`05_EXPERIENCIAS.md`
#28), sobraram 4 clipes de 0,07-0,23s no projeto Mastopexia real, todos bem
na emenda entre dois clipes vizinhos — mesma família do #6 (clipe-fantasma de
1 frame por padding sem vizinho na borda), mas não confirmado se é a mesma
causa raiz. Não investigado a fundo ainda.
→ `fcpxml/writer/cut.py` (`cut_clip_ranges`, `min_keep_seconds`), padding do
`remove_media_silence`.
### 2.6 Submódulo `WHISPERX` com conteúdo modificado e não commitado
Está fora dos commits de propósito, porque ninguém verificou o que mudou lá
dentro. Precisa ser olhado e resolvido — ou commitado, ou revertido.