Fase 0 do roteiro de reestruturação (Engine/docs/10_MAPA_REESTRUTURACAO.md): move code/WHISPERX (2,6 GB de backups órfãos, sem uso ativo, sem .gitmodules) para ~/Archives/G-ART-WHISPERX-backup fora do workspace git; traz admin/ para o gate de lint de run_after_fix.sh; corrige fcpxml/writer/adjustment.py, que gerava um wrapper <adjustment> inexistente no DTD 1.13 (filtros agora vão direto no <clip>, na ordem exigida), com teste de regressão novo. Achado à parte: .gitignore tinha uma regra solta "models/" (pensada só para o cache do Whisper em code/models/) que também escondia do git todo o pacote fcpxml/models/ — nunca commitado, sem proteção nenhuma. Corrigida para /code/models/, ancorada na raiz. Docs atualizados no mesmo commit (02_MODULES, 09_MANUTENCAO, 10_MAPA_REESTRUTURACAO, 05_EXPERIENCIAS #34 e #36), conforme a regra do CLAUDE.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
194 lines
10 KiB
Markdown
194 lines
10 KiB
Markdown
# 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-09-22 · 1.543 testes passando (+1 falha pré-existente em `test_forced_align.py` e +1 erro pré-existente em `test_refine_voice_timeline_tool.py`, ver §2.6) · lint zerado em `code/` e em `admin/` (fora de server.py/ai_edit.py/fcpxml/analise.py, pré-existentes — outro trabalho em andamento na branch)
|
|
|
|
---
|
|
|
|
## 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 `resolve_actions` não tolera margem no encosto de zoom/marker contra um corte
|
|
Um `zoom`/`marker` cuja borda cai exatamente em cima do `start`/`end` de um
|
|
`cut` é descartado como "apontando para material cortado" — mesmo quando a
|
|
intenção era ficar bem ao lado. Contornado manualmente no projeto Mastopexia
|
|
(recuando as bordas na mão); a correção estrutural é dar a `resolve_actions`
|
|
uma margem de tolerância (meio frame) antes de considerar uma ação "dentro"
|
|
do corte. → `fcpxml/voice_actions.py` (`resolve_actions`/`shift_after_cuts`),
|
|
`05_EXPERIENCIAS.md` #27.
|
|
|
|
### 2.2 `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.3 ~~`admin/` fica fora do lint~~ — resolvido em 2026-09-22
|
|
`run_after_fix.sh` agora roda um segundo passo (`ruff check --config
|
|
pyproject.toml ../admin/`) com a mesma config do engine. Precisou de
|
|
`# noqa: E402` em 6 imports de `admin/models_api.py`/`admin/models_gui.py`
|
|
(padrão `sys.path.insert` antes do import local, convenção já usada no
|
|
projeto). Lint de `admin/` está zerado.
|
|
|
|
### 2.4 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.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 ~~`fcpxml/writer/adjustment.py` gerava um wrapper `<adjustment>` inválido~~ — resolvido em 2026-09-22
|
|
`ClipDeAjuste` embrulhava filtros num `<clip><adjustment>...</adjustment></clip>`,
|
|
que não existe no DTD real da Apple. Corrigido para anexar
|
|
`filter-video`/`filter-audio` direto como filhos do `<clip>` (na ordem que o
|
|
DTD exige: vídeo antes de áudio). Teste de regressão em
|
|
`tests/test_writer_adjustment.py`. Segue sem uso em `server_tools`/`admin/api`
|
|
— só deixou de estar pronto pra alguém reusar do jeito errado.
|
|
→ `05_EXPERIENCIAS.md` #34.
|
|
|
|
### 2.7 `test_refine_voice_timeline_tool.py` quebrado: `voice_timeline.extract_pitch` ausente
|
|
`TestRefineVoiceTimelineHandler::test_max_zooms_caps_the_list` tenta
|
|
`monkeypatch.setattr(vt, "extract_pitch", ...)` mas `fcpxml/voice_timeline.py`
|
|
não tem mais (ou nunca teve, nesta branch) essa função. Pertence ao trabalho
|
|
de análise de voz já em andamento nesta branch (`voice_timeline.py`
|
|
modificado, não commitado) — não investigado a fundo, só registrado aqui
|
|
para não se perder.
|
|
→ `fcpxml/voice_timeline.py`, `tests/test_refine_voice_timeline_tool.py`.
|
|
|
|
### 2.8 ~~Submódulo `WHISPERX` com conteúdo modificado e não commitado~~ — resolvido em 2026-09-22
|
|
Não era um submódulo git registrado (sem `.gitmodules`) — era uma pasta
|
|
`.git` solta de 2,6 GB dentro de `code/`, com cópias/backups congelados do
|
|
próprio projeto (`WHISPERX_backup_88476/`, uma cópia inteira e antiga de
|
|
`fcp-mcp-server-main`). Só 3 referências no código ativo, todas em
|
|
comentários (`fcpxml/diarize.py`, `tests/test_diarize.py`,
|
|
`admin/api/shared.py`), nenhum import ou caminho dependia dela. Além do
|
|
peso morto, ela também inflava qualquer lint rodado com `--exclude`
|
|
explícito (que sobrescreve o `exclude` do `pyproject.toml`) — foi assim que
|
|
um `ruff check . --exclude docs/` chegou a acusar 510 erros, quase todos
|
|
dentro dela. Movida para `~/Archives/G-ART-WHISPERX-backup` (fora do
|
|
workspace git), copiada e verificada (`diff -rq`) antes de remover o
|
|
original. `WHISPERX/` também saiu do `exclude` do ruff em
|
|
`code/pyproject.toml` — não faz mais sentido excluir um caminho que não
|
|
existe mais dentro de `code/`.
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
```bash
|
|
cd code && ./Engine/run_after_fix.sh # lint zerado + 1.498 testes
|
|
admin/run_app.command # se mexeu no app (padrão de revisão)
|
|
admin/run.command # app + atualização incremental da RAG
|
|
rag/search_gart.sh "consulta" # busca híbrida no índice RAG (ver rag/README.md)
|
|
```
|
|
|
|
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/marker sumindo perto de um corte | Borda encostando exatamente no `cut` | §2.1 |
|
|
| 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
|
|
|
|
- [01 Arquitetura](01_ARCHITECTURE.md) — camadas e onde cada coisa mora
|
|
- [02 Módulos](02_MODULES.md) — mapa do engine, módulo a módulo
|
|
- [03 Server/Tools](03_SERVER_TOOLS.md) — as 77 ferramentas MCP
|
|
- [04 Testes & Workflow](04_TESTS_AND_WORKFLOW.md)
|
|
- [05 Experiências](05_EXPERIENCIAS.md) — o que já quebrou e por quê
|
|
- [06 Boas Práticas](06_BOAS_PRATICAS.md)
|
|
- [08 App macOS](08_APP_MACOS.md) — o app e o Assistente
|