chore(fase0): higiene do repositório + corrige gitignore que escondia fcpxml/models/
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>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0fdfe33613
commit
d13f643ebc
@@ -51,6 +51,9 @@ que merece entrada.
|
||||
| 31 | 2026-08-24 | Revisão de falantes ("Quem fica na edição") salvava certo, mas etapa 4 (Revisão de frases) lia a timeline crua, ignorando falantes mutados/linhas riscadas | `resolvido` |
|
||||
| 32 | 2026-08-24 | Separar legendas dinâmicas de convencionais por role: `<title>` aceita `role` (CDATA), NÃO `videoRole` — este último é DTD-inválido para títulos e quebra a validação | `resolvido` |
|
||||
| 33 | 2026-09-22 | Legenda comum sobreposta à composição dinâmica em `generate_subtitles_by_emphasis`; regenerar acumulava títulos em vez de substituir | `resolvido` |
|
||||
| 34 | 2026-09-22 | `ClipDeAjuste` gerava wrapper `<adjustment>` inválido no DTD; `code/WHISPERX` era 2,6 GB de backup órfão que inflava o lint quando rodado com `--exclude` explícito | `resolvido` |
|
||||
| 35 | 2026-09-22 | Indexação RAG (`admin/update_rag.py`) abortava a transação inteira ao achar um chunk que estoura o contexto do modelo de embedding | `resolvido` |
|
||||
| 36 | 2026-09-23 | `.gitignore` com regra `models/` solta escondia do git o pacote inteiro `fcpxml/models/` (dados do engine), não só o cache do Whisper | `resolvido` |
|
||||
|
||||
> Mantenha o índice acima sempre sincronizado com as entradas mais recentes.
|
||||
|
||||
@@ -1732,3 +1735,161 @@ conjunto de títulos por cima do anterior em vez de substituí-lo.
|
||||
skipped, 1 falha e 1 erro de ambiente sem relação com a mudança (WhisperX/
|
||||
`extract_pitch` ausente, torchcodec sem libs de sistema); lint dos arquivos
|
||||
alterados limpo.
|
||||
|
||||
---
|
||||
|
||||
### Entrada 34 — 2026-09-22: `<adjustment>` inválido no DTD e `WHISPERX` órfão inflando o lint
|
||||
|
||||
**Sintoma 1:** `fcpxml/writer/adjustment.py` (`ClipDeAjuste`, código de uma
|
||||
sessão anterior não commitado) montava
|
||||
`<clip><adjustment><filter-video .../></adjustment></clip>` para camadas de
|
||||
ajuste. Nada usava o módulo ainda (sem chamada em `server_tools`/
|
||||
`admin/api`), mas ficava pronto para alguém reusar do jeito errado.
|
||||
|
||||
**Causa 1:** o DTD real da Apple (`FCPXMLv1_13.dtd`) não define nenhum
|
||||
elemento `<adjustment>`. A produção real de `<clip>` é
|
||||
`(note?, %timing-params;, %intrinsic-params;, (spine|(%clip_item;)|caption)*,
|
||||
(%marker_item;)*, audio-channel-source*, (%video_filter_item;)*,
|
||||
filter-audio*, metadata?)` — ou seja, `filter-video`/`filter-audio` são
|
||||
filhos diretos do `<clip>`, sem wrapper, e nessa ordem (vídeo antes de
|
||||
áudio).
|
||||
|
||||
**Solução 1:** `ClipDeAjuste.criar()` agora anexa os filtros direto no
|
||||
`<clip>`, ordenados com vídeo antes de áudio
|
||||
(`sorted(filtros, key=lambda f: f.tag != "filter-video")`). Teste de
|
||||
regressão novo: `tests/test_writer_adjustment.py` (sem wrapper, ordem
|
||||
correta, um `<effect>` por `uid` em `resources`).
|
||||
|
||||
**Sintoma 2 (achado ao investigar o mesmo módulo):** um `ruff check .
|
||||
--exclude docs/` rodado manualmente no início desta sessão acusou **510
|
||||
erros** — muito acima do que a suíte normalmente reporta.
|
||||
|
||||
**Causa 2:** `code/WHISPERX` era uma pasta `.git` solta de **2,6 GB** dentro
|
||||
de `code/` (não um submodule registrado — sem `.gitmodules`), contendo
|
||||
cópias/backups congelados do próprio projeto, incluindo uma cópia inteira e
|
||||
antiga de `fcp-mcp-server-main` dentro de si mesma. O `pyproject.toml` já
|
||||
excluía `WHISPERX/` do lint por padrão (`[tool.ruff] exclude = ["docs/",
|
||||
"WHISPERX/"]`), mas passar `--exclude docs/` na linha de comando
|
||||
**sobrescreve** esse `exclude` em vez de complementá-lo — foi assim que o
|
||||
lint passou a varrer os 2,6 GB de código velho lá dentro. Confirmado por
|
||||
grep que só 3 arquivos no código ativo referenciam "WHISPERX", todos em
|
||||
comentários explicativos (`fcpxml/diarize.py`, `tests/test_diarize.py`,
|
||||
`admin/api/shared.py`) — nenhum import ou caminho real dependia da pasta.
|
||||
|
||||
**Solução 2:** pasta movida para `~/Archives/G-ART-WHISPERX-backup` (fora do
|
||||
workspace git), copiada com `rsync -a --no-perms` e conferida com
|
||||
`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 em `code/`).
|
||||
|
||||
**Aprendizado:** (1) um wrapper de elemento "que faz sentido conceitualmente"
|
||||
não substitui checar o DTD real antes de escrever o gerador — o padrão do
|
||||
projeto (`dtd.py`, DTDs em `bm/*/FCPXMLv1_13.dtd`) existe exatamente para
|
||||
isso. (2) uma flag de linha de comando como `--exclude` em ferramentas de
|
||||
lint tipicamente **substitui** a config do projeto, não a estende — rodar
|
||||
`ruff check .` sem flags (herdando `pyproject.toml`) é o comando correto
|
||||
para refletir o gate real; qualquer variação manual com `--exclude` pode
|
||||
mentir sobre o estado do lint. (3) uma pasta de backup improvisada dentro do
|
||||
diretório ativo do projeto (mesmo que "só para não perder nada") é dívida
|
||||
que cresce sem ninguém perceber — 2,6 GB não apareceram de uma vez.
|
||||
|
||||
**Estado:** `resolvido` — `tests/test_writer_adjustment.py` (3 testes)
|
||||
passando; `admin/` trazido ao lint gate no mesmo commit (ver
|
||||
`09_MANUTENCAO.md` §2.3); suíte completa 1543 passando, 8 skipped, 1 falha
|
||||
+ 1 erro pré-existentes de outro trabalho em andamento (sem relação com
|
||||
esta correção).
|
||||
|
||||
### Entrada 35 — 2026-09-22: chunk grande demais derrubava a indexação RAG inteira
|
||||
|
||||
**Sintoma:** `admin/update_rag.command` (primeira indexação completa do
|
||||
G-ART, banco `rag_gart` recém-provisionado) morria sempre no mesmo ponto com
|
||||
`requests.exceptions.HTTPError: 500 Server Error` na chamada ao Ollama —
|
||||
sempre logo após imprimir `code/fcpxml/export.py`, ou seja, no arquivo
|
||||
seguinte na ordem alfabética.
|
||||
|
||||
**Causa raiz:** `code/fcpxml/font_metrics.py` é uma tabela de larguras de
|
||||
glifo (`METRICS = {...}`), texto extremamente denso em tokens (muitos
|
||||
números/pontuação curtos) — um chunk de ~4900 caracteres (dentro do limite
|
||||
`CHUNK_MAX_CHARS = 5000`) virou 2653 tokens no tokenizer do
|
||||
`nomic-embed-text`, estourando o contexto de 2048 tokens do servidor Ollama
|
||||
local (`llama.cpp`: "input length exceeds the context length"). Reproduzido
|
||||
isolando o arquivo e chamando `/api/embeddings` chunk a chunk — 6 dos 9
|
||||
chunks falhavam. `CHUNK_MAX_CHARS` mede caracteres, não tokens; assume
|
||||
implicitamente ~1 token por poucos caracteres, o que não vale para conteúdo
|
||||
não-prosa (tabelas numéricas, JSON denso).
|
||||
|
||||
Segundo problema, apontado por que a primeira tentativa não recuperou nada:
|
||||
`admin/update_rag.py::index()` roda a varredura inteira (centenas de
|
||||
arquivos) em **uma única transação**, com `commit()` só no fim e
|
||||
`rollback()` em qualquer exceção — um único chunk problemático em um único
|
||||
arquivo descartava a indexação inteira, mesmo que os outros 300+ arquivos
|
||||
já tivessem embedado e inserido com sucesso.
|
||||
|
||||
**Solução:** `_embed()` agora detecta essa resposta específica do Ollama
|
||||
(`ChunkTooLarge`, checado por `500` + `"context length"` no corpo) e o loop
|
||||
principal captura essa exceção por chunk, pula só aquele chunk (aviso em
|
||||
stderr) e continua o arquivo — sem abortar a transação. Não trunca nem
|
||||
reduz `CHUNK_MAX_CHARS` globalmente (afetaria todo o corpus por causa de
|
||||
poucos arquivos atípicos); a lacuna fica só nos poucos chunks realmente
|
||||
grandes demais, e o resto do arquivo ainda fica pesquisável.
|
||||
|
||||
**Aprendizado:** um limite de chunk em caracteres é uma aproximação, não uma
|
||||
garantia de contexto — arquivos de dados brutos (tabelas, mapeamentos
|
||||
numéricos, JSON/CSV embutido em `.py`) tokenizam bem mais denso que prosa ou
|
||||
código comum e podem violar o limite do modelo mesmo dentro do teto de
|
||||
caracteres. Uma indexação em lote sobre centenas de arquivos não deve ficar
|
||||
tudo-ou-nada numa única transação: uma falha isolada e recuperável (chunk
|
||||
específico, arquivo específico) deve ser contida ali, não descartar o
|
||||
trabalho inteiro já validado.
|
||||
|
||||
**Estado:** `resolvido` — indexação completa rodou até o fim: 304 arquivos,
|
||||
1702 chunks, 0 removidos. Também nesta sessão: criada a pasta `rag/` na raiz
|
||||
(schema, busca híbrida `search.py`/`search_gart.sh`, `SETUP.md`) — ver
|
||||
`rag/README.md` para a divisão de responsabilidades com `admin/update_rag.py`.
|
||||
|
||||
---
|
||||
|
||||
### Entrada 36 — 2026-09-23: `.gitignore` escondia `fcpxml/models/` inteiro do git
|
||||
|
||||
**Sintoma:** ao investigar por que um `git diff` de um arquivo recém-editado
|
||||
(`fcpxml/models/timeline.py`, durante a correção da Entrada 34) não mostrava
|
||||
nada, `git status` também não listava o arquivo como modificado nem como
|
||||
untracked — como se ele simplesmente não existisse para o git.
|
||||
|
||||
**Causa:** `.gitignore` tinha a regra solta `models/` (comentada como
|
||||
"WhisperX models cache", pensada para ignorar o cache de ~11 GB de modelos
|
||||
Whisper baixados em `code/models/`). Uma regra sem `/` inicial no
|
||||
`.gitignore` casa com **qualquer diretório com esse nome em qualquer
|
||||
profundidade** — não só `code/models/`, mas também `code/fcpxml/models/`, o
|
||||
pacote de data classes (`TimeValue`, `Clip`, `Timeline`, `Marker`, etc.) que
|
||||
sustenta todo o engine. Confirmado: `git ls-tree -r HEAD` não tem nenhum
|
||||
`fcpxml/models.py` nem `fcpxml/models/` em nenhum commit do histórico — o
|
||||
pacote inteiro (1.234 linhas, 7 módulos) só existia em disco, sem nenhuma
|
||||
proteção de versionamento, desde que a divisão de `models.py` em pacote foi
|
||||
feita (sessão anterior, nunca commitada).
|
||||
|
||||
**Risco:** qualquer operação que limpa arquivos não rastreados
|
||||
(`git clean -fd`, reinstalar do zero, trocar de máquina via `git clone`)
|
||||
apagaria essa base sem chance de recuperação — nenhum commit para reverter.
|
||||
|
||||
**Solução:** regra trocada para `/code/models/` (ancorada na raiz do repo,
|
||||
só o cache real), preservando `whisper/` (sem uso hoje, mas inofensiva) e
|
||||
tudo mais. Confirmado com `git check-ignore -v`: `fcpxml/models/timeline.py`
|
||||
não é mais ignorado; `code/models/models--Systran--faster-whisper-base`
|
||||
continua ignorado. `fcpxml/models/` passou a aparecer como `??` no
|
||||
`git status` — visível, pronto para ser commitado quando o dono do trabalho
|
||||
revisar.
|
||||
|
||||
**Aprendizado:** regra de `.gitignore` sem `/` inicial (ex.: `models/`) casa
|
||||
em qualquer profundidade da árvore — é fácil escrever pensando só no caso
|
||||
que motivou a regra (um cache na raiz) e esquecer que o mesmo nome de pasta
|
||||
pode existir, com sentido completamente diferente, dentro do código-fonte.
|
||||
Regra de bolso: nomes de pasta genéricos (`models/`, `build/`, `cache/`,
|
||||
`data/`) no `.gitignore` deveriam quase sempre vir ancorados (`/caminho/
|
||||
exato/`), a menos que a intenção seja mesmo ignorar toda ocorrência do nome
|
||||
em qualquer lugar da árvore.
|
||||
|
||||
**Estado:** `resolvido` — regra corrigida, `fcpxml/models/` confirmado
|
||||
visível ao git (não commitado ainda; fica para quem já está com esse
|
||||
trabalho em andamento decidir quando commitar). Nenhum código alterado,
|
||||
só o `.gitignore`.
|
||||
|
||||
Reference in New Issue
Block a user