Files
gart/code/Engine/docs/09_MANUTENCAO.md
T
João HenriqueandClaude Sonnet 5 7b5aed79ee feat(voz): legenda por ênfase, forced align, IA local e correções de zoom/revisão
Trabalho da branch feat/revisao-enfases: pipeline de edição por voz ganha
alinhamento forçado (whisperx), roteirização por LLM local (Ollama), e a
etapa 5 (revisão de frases) passa a refletir de verdade o que é aplicado.

- generate_subtitles_by_emphasis: legenda comum cobre o clipe inteiro,
  legenda dinâmica só nas frases de ênfase, e a comum é desativada
  (enabled="0") onde a dinâmica cobre, em vez de nunca ser gerada ali.
- validate_subtitle_layout ignora títulos com enabled="0" — corrige falso
  positivo de colisão contra o que está desativado no lugar dele.
- Corrige zoom/marcador sendo descartado quando a borda encosta exatamente
  no início de um corte.
- Etapa 5 do Assistente: recarrega quando as decisões da IA mudam (com
  fresh=true, ignorando a revisão salva antiga) — resolve a dessincronia
  entre "ativa" na tela e o que já foi cortado no FCPXML.
- Etapa "Processar" reaplica as decisões da revisão (_phrase_actions.json)
  antes da cadeia de remoção de silêncio/legendas — antes, desativar uma
  frase na etapa 5 não tinha efeito nenhum no vídeo final.
- Etapa "Concluído" fundida em "Processar" — abrir no Final Cut/Finder
  aparece assim que termina, sem slide extra.
- Palavra clicável na etapa 5 agora funciona como toggle (clique de novo
  desfaz) e mostra a própria ênfase (sublinhado colorido + peso da fonte).
- fcpxml/forced_align.py, fcpxml/llm_local.py, ai_edit.py: alinhamento
  fonético via whisperx e roteirização local via Ollama/Gemma.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 18:26:04 -04:00

7.7 KiB

09 — Manutenção: onde mexer, o que está aberto, o que dói

Escopo: Por onde começar cada tipo de tarefa, o que está aberto e onde dói. Não cobre: Como as coisas funcionam — este doc roteia para quem explica

Este é o documento de rota. Os outros descrevem o que é; este diz o que fazer e por onde começar quando chega uma implementação, uma melhoria ou uma correção.

Última varredura: 2026-08-19 · 1.466 testes · lint zerado


1. Chegou uma tarefa — por onde começo?

A tarefa é… Comece em Não esqueça
Regra nova de edição (corte, zoom, legenda) fcpxml/<módulo> + teste Expor na tool e na ponte, senão só metade dos usuários alcança
Corrigir XML que o FCP recusa fcpxml/writer/ + dtd.py Validar contra o DTD real, não só o teste
Mudança visível na interface MacApp/Sources/ Abrir a tela — compilar não prova nada (§4)
Comando novo para o app admin/api/<assunto>.py Registrar na tabela de models_api.py
Ferramenta MCP nova server_tools/<categoria>.py Schema Tool(...) + TOOL_HANDLERS
Ajuste de análise de voz fcpxml/voice_*, emphasis.py Regerar os _voice_timeline.json de teste
"Está lento" / "está errado" e não sei onde §5 (mapa de sintomas) —

A pergunta que resolve 90% das dúvidas de lugar: essa lógica precisa saber o que é uma tool MCP ou uma tela? Se não precisa — e quase nunca precisa — ela vai para fcpxml/.


2. O que está aberto agora

Ordenado por quanto atrapalha, não por esforço.

2.1 A etapa 6 ignora a revisão de ênfases

O usuário lapida as frases na etapa 5, o _phrase_review.json é gravado — e a etapa 6 ainda processa como antes. Falta ligar: zoom e legenda dinâmica só nas frases de ênfase, legenda comum no resto. É a continuação natural do trabalho da etapa 5 e o item mais valioso da lista. → MacApp/Sources/WizardView.swift (finalizeProcessing), admin/api/subtitles.py, fcpxml/phrase_review.py (emphasis_spans já é produzido e ninguém consome).

2.2 Offset de ~400 ms no timing por palavra

O faster-whisper sem alinhamento forçado erra o início de cada palavra em ~0,4 s. Isso desloca zoom, corte e gap_before de uma vez. Há paliativo aplicado por projeto; a correção estrutural é ligar o WhisperX (ou alinhamento equivalente) em transcribe.py, o que levaria o erro para ~30 ms. Custo real: regerar todos os _transcript.json e _voice_timeline.json existentes. → 05_EXPERIENCIAS.md #14, estado parcialmente resolvido.

2.3 MacApp/ não tem teste automatizado

5.500 linhas de Swift sem uma asserção. A rede hoje é o harness manual (§4) e o olho do usuário. Não é para sair criando suíte de UI — mas lógica pura que foi parar na camada de tela (cálculo de trim, mapeamento de tempo) deveria descer para o Python, onde já existe rede.

2.4 admin/ fica fora do lint

run_after_fix.sh roda o ruff de dentro de code/, então admin/ — 1.751 linhas de código que o app depende para funcionar — nunca é verificado. Incluir mexe no gate, então é decisão consciente, não esquecimento.

2.5 Confirmações visuais pendentes no FCP

Várias entradas do 05_EXPERIENCIAS.md estão marcadas como resolvidas no XML — testes verdes, DTD válido — mas pendentes de importação real no Final Cut. 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.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.


3. Onde o código ainda é grande (e onde isso não é problema)

Quatro arquivos foram divididos (writer.py, models.py, models_api.py, _shared.py): 6.685 linhas concentradas viraram 43 módulos.

O que sobrou grande, e o diagnóstico honesto de cada um:

Arquivo Linhas Vale dividir?
fcpxml/text_layout.py 901 Não. É diagramação — um assunto coeso.
fcpxml/rough_cut.py 798 Não. É geração de timeline, um assunto.
fcpxml/model_manager.py 748 Talvez: mistura catálogo, download e config.
server_tools/voice.py 754 Talvez, se crescer mais.
MacApp/TranscriptionView.swift 843 Sim, quando for mexer nela.
MacApp/WizardView.swift 808 Sim: sete etapas num switch só.

Critério, não número: divida quando o arquivo tiver assuntos que não se falam. Um arquivo grande de um assunto só é mais fácil de ler que seis arquivos pequenos que você precisa abrir juntos. Código picado sem motivo atrapalha tanto quanto arquivo gigante.


4. Checklist antes de dar algo por pronto

cd code && ./Engine/run_after_fix.sh        # lint zerado + 1.466 testes
admin/run_app.command                       # se mexeu no app (padrão de revisão)

E, além do script:

  • Mexeu na interface? Abriu a tela? Compilar não prova que roda — VideoPlayer compilava e abortava (05_EXPERIENCIAS.md #22).
  • Mexeu em XML? Importou no FCP? DTD válido ≠ renderiza certo.
  • Dividiu ou moveu módulo? Procure patch('<módulo>. e imports relativos dentro de funções — é o que quebra em silêncio (#23).
  • Criou teste fora de code/tests/? Confirme que a contagem total subiu. Teste fora de testpaths não roda e dá falsa sensação de rede (#24).
  • Problema estrutural ou erro recorrente? Registre em 05_EXPERIENCIAS.md com o índice atualizado.
  • Documentação divergiu? Corrija no mesmo commit. Doc velha engana mais que doc ausente.

5. Mapa de sintomas → onde olhar

Sintoma Suspeite de Arquivo
FCP recusa o arquivo ao importar id inválido, ordem de filhos, timebase writer/validation.py, dtd.py
Título importa mas não aparece Template/uid Motion que não resolve writer/titles.py
Corte no lugar errado Tempo pós-corte usado como se fosse original voice_actions.py (shift_after_cuts)
Zoom no lugar errado Idem, ou offset de timing do Whisper §2.2
Legenda sobrepondo Layout ou conteúdo antigo no arquivo collision.py, text_layout.py
"Ênfase" apontando para palavra à toa Falta renormalizar após o corte refine_voice_timeline
App diz que falta librosa/pyannote uv run com cwd errado PythonBridge.swift (§3 do doc 08)
App crasha com ModuleNotFoundError: server_tools sys.path de admin/api/ mal calculado 05_EXPERIENCIAS.md #25
Tela do app fecha o programa Componente de framework que só falha em runtime 05_EXPERIENCIAS.md #22
Comando existe no MCP mas não no app Falta expor na ponte admin/api/, #20

6. Convenções que não são negociáveis

Estão em 01_ARCHITECTURE.md §2 e valem repetir as três que mais custaram:

  1. Tempo é fração racional. Float para tempo produz drift que só aparece depois de dez operações encadeadas.
  2. Ação de voz é sempre em tempo da mídia original. Nunca pós-corte.
  3. Original nunca é sobrescrito. Toda saída ganha sufixo.

Documentos relacionados