Files
gart/code/Engine/docs/01_ARCHITECTURE.md
T
João HenriqueandClaude Opus 5 dcdd73edb5 docs: varredura geral, documentação por função e regra de atualização
A documentação descrevia um sistema que não existe mais: 62/73 ferramentas
(são 74), writer.py e models.py como arquivos (viraram pacotes), 1032 testes
(são 1454), models_api.py descrito como "API FastAPI" (é ponte JSON) e o app
SwiftUI ausente por completo — 5.500 linhas que o usuário opera todo dia sem
uma linha de documentação.

Cada arquivo passa a ter uma função específica, com cabeçalho de escopo
dizendo o que cobre e o que NÃO cobre (com a seta para quem cobre). O objetivo
é ler só o necessário: doc fora do assunto custa tempo e processamento sem
entregar nada.

    01 arquitetura   camadas, duas portas de entrada, regras transversais
    02 módulos       mapa do engine, incluindo o pipeline de voz
    03 server/tools  as 74 tools, helpers e como criar uma nova
    08 app macOS     NOVO — build por swiftc, telas, ponte, etapa 5
    09 manutenção    NOVO — por onde começar, o que está aberto, sintoma→arquivo

CLAUDE.md ganha a seção "Documentação (MANDATORY)": tabela de roteamento
(qual arquivo abrir para cada tarefa) e a regra de que toda alteração de
código atualiza a doc no mesmo commit, com o mapa de o-que-mexeu → o-que-
atualizar. Doc velha engana mais que doc ausente.

O índice do 05_EXPERIENCIAS subiu para o topo: consultar "isso já quebrou
antes?" custava carregar 1.281 linhas antes de chegar na tabela.

Dívidas levantadas na varredura e registradas em 09 §2: etapa 6 ainda ignora
o phrase_review.json, offset de ~400ms do Whisper, MacApp sem teste, admin/
fora do lint, confirmações visuais pendentes no FCP, submódulo WHISPERX sujo.

Também corrigidos dois links quebrados no Engine/README que apontavam um
nível acima do certo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 22:51:33 -04:00

178 lines
8.7 KiB
Markdown

# 01 — Arquitetura do Sistema (G-ART / fcp-mcp-server)
> **Escopo:** Como o sistema é dividido em camadas e onde cada responsabilidade mora.
> **Não cobre:** Detalhe módulo a módulo (→ 02) · ferramentas MCP (→ 03) · app (→ 08)
> Referência canônica de como o sistema está dividido. Leia antes de qualquer
> mudança de código. Se algo aqui divergir do código, **o código está certo e
> este documento está velho** — corrija-o no mesmo commit.
Última varredura: 2026-08-19 · 74 ferramentas MCP · 1.454 testes · versão `0.6.35`
---
## 1. Visão de cima (camadas)
O sistema lê, analisa e reescreve **FCPXML** do Final Cut Pro. Ele opera *fora*
do FCP: você exporta o XML, o programa processa como dados estruturados e
devolve um XML para importar. Nada é patcheado, nenhuma API privada é usada.
São **quatro camadas**, e o ponto importante é que existem **duas portas de
entrada diferentes** para o mesmo motor:
```
┌──────────────────────────┐ ┌──────────────────────────────┐
│ MacApp/ (SwiftUI) │ │ Cliente MCP (Claude) │
│ O app que o usuário usa │ │ Conversa, decide a edição │
└───────────┬──────────────┘ └───────────────┬──────────────┘
│ subprocesso + JSON-lines │ JSON-RPC (stdio)
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────────┐
│ admin/models_api.py │ │ server.py + server_tools/ │
│ + admin/api/ │ │ 74 tools, dispatch, schemas │
│ 37 comandos da ponte │ │ NÃO tem lógica de timeline │
└───────────┬──────────────┘ └───────────────┬──────────────┘
└───────────────┬────────────────────┘
▼
┌───────────────────────────────────┐
│ fcpxml/ — O ENGINE │
│ Núcleo puro Python, desacoplado. │
│ Não conhece MCP nem o app. │
│ É onde quase tudo mora. │
└───────────────────────────────────┘
```
**A regra que sustenta tudo:** nem `server.py` nem `admin/api/` implementam
lógica de timeline. Os dois validam entrada, chamam o engine e formatam a
saída. Toda regra de negócio é testável sem MCP e sem app.
**Por que duas portas.** O MCP existe para o julgamento editorial — qual tomada
usar, onde dar zoom — que é conversa com uma IA. A ponte existe para o que o
usuário faz sozinho no app — transcrever, configurar, processar. As duas caem
no mesmo engine, então uma correção ali vale para as duas.
---
## 2. Regras transversais (valem em todo o código)
| Conceito | Regra |
|----------|-------|
| **Tempo** | `TimeValue`, fração racional `"600/2400s"`. **Nunca float para tempo.** |
| **Tempo de decisão** | Ações de voz usam sempre segundos da **mídia original**, nunca pós-corte. |
| **I/O paths** | Sempre via `_validate_filepath` / `_validate_output_path` (sandbox). |
| **Nome de saída** | Nunca sobrescrever o original: `generate_output_path()` gera `_suffix`. |
| **Segurança XML** | Sempre `defusedxml` via `safe_xml.py`. Nunca `xml.etree` direto para ler. |
| **Deps opcionais** | `librosa`/`ffmpeg`/`huggingface_hub` importados **lazy**, degradam com `None`. |
| **Idioma** | Comunicação com o usuário em português. Código e comentários em inglês. |
| **Validação** | `./Engine/run_after_fix.sh` **sempre** após cada correção. |
| **App** | Alterou `MacApp/`? Compile e rode: `./MacApp/build_app.sh --run`. |
---
## 3. Fluxo de um request
### Pela porta MCP (Claude decidindo a edição)
```
Cliente MCP ──JSON-RPC──► server.py
│ TOOL_HANDLERS[nome]
▼
server_tools/<categoria>.py
│ _shared/: valida path, parseia projeto
▼
fcpxml/ (parser → writer → safe_xml)
▼
projeto_<suffix>.fcpxml (original intocado)
```
### Pela porta do app (usuário operando)
```
MacApp ──Process + argv JSON──► admin/models_api.py
│ handlers[comando]
▼
admin/api/<assunto>.py
│ shared.emit() devolve JSON-lines
▼
fcpxml/ (ou chama um handler do server)
▼
arquivo gerado + caminho de volta ao app
```
A saída da ponte é **JSON-lines**: um documento JSON por linha, para que
comandos longos transmitam progresso enquanto rodam. Toda escrita passa por
`admin/api/shared.py::emit`, que serializa o acesso a stdout — dois comandos
escrevendo ao mesmo tempo entrelaçariam documentos.
---
## 4. Dual-mode: XML + Live
- **Modo XML (principal):** exporta FCPXML, processa como dados, reimporta.
- **Modo Live (`fcpxml/live.py`):** *push* do FCPXML direto para o FCP em
execução via Apple events oficiais (`Open Document`). Leitura de bibliotecas
via AppleScript read-only.
**Assimetria estrutural:** import é scriptable, mas a Apple não oferece export
programático. Round-trips sempre voltam pelas ferramentas XML.
---
## 5. Onde está cada responsabilidade
| Responsabilidade | Fica em |
|------------------|---------|
| Modelos de dados (tempo, clips, markers, QC, legendas) | `fcpxml/models/` |
| Parse FCPXML → objetos | `fcpxml/parser.py` |
| Edição e escrita de FCPXML | `fcpxml/writer/` |
| Geração de timeline nova | `fcpxml/rough_cut.py` |
| Comparação de timelines | `fcpxml/diff.py` |
| Export cross-NLE (Resolve, FCP7) | `fcpxml/export.py` |
| Silêncio e beats | `fcpxml/media_intel.py` |
| Transcrição Whisper | `fcpxml/transcribe.py` |
| Diarização (quem falou) | `fcpxml/diarize.py` |
| Ênfase acústica | `fcpxml/emphasis.py`, `fcpxml/voice_features.py` |
| Timeline de voz (o JSON que a IA lê) | `fcpxml/voice_timeline.py` |
| Decisões de edição (cut/zoom/text/marker) | `fcpxml/voice_actions.py` |
| Revisão de frases da etapa 5 | `fcpxml/phrase_review.py` |
| Layout de legendas e métricas de fonte | `fcpxml/text_layout.py`, `font_metrics.py`, `collision.py` |
| Gestão de modelos Whisper | `fcpxml/model_manager.py` |
| Controle Live do FCP | `fcpxml/live.py` |
| Segurança XML | `fcpxml/safe_xml.py` |
| Validação contra DTDs da Apple | `fcpxml/dtd.py` |
| Transporte MCP (74 tools) | `server.py` + `server_tools/` |
| Ponte com o app (37 comandos) | `admin/models_api.py` + `admin/api/` |
| Interface do usuário | `MacApp/Sources/` |
---
## 6. Mapa de dependências
```
MacApp/ ──► admin/models_api.py (subprocesso, por caminho)
admin/api/ ──► fcpxml/* e, para algumas operações, server.py
server.py ──► server_tools/*
server_tools/* ──► server_tools/_shared/ ──► fcpxml/*
fcpxml/writer/ ──► fcpxml/models/, safe_xml, dtd, text_layout, collision
fcpxml/models/ ──► fcpxml/text_layout (só o pacote subtitles)
fcpxml/__init__.py ──► reexporta a API pública
```
**A seta que não existe, e não deve existir:** `fcpxml/` nunca importa de
`server_tools/`, de `admin/` ou de qualquer coisa que saiba o que é uma tool.
Se você precisar disso, a lógica está no lugar errado.
---
## 7. Criando algo novo — por onde começar
| Você quer… | Comece por |
|-----------|-----------|
| Uma **ferramenta MCP** nova | Função pura em `fcpxml/` + teste. O handler em `server_tools/` fica fino. |
| Um **comando do app** novo | Mesmo caminho, e exponha em `admin/api/<assunto>.py` + tabela em `models_api.py`. |
| Uma **tela** nova | `MacApp/Sources/`, consumindo comandos que já existem na ponte. |
| Uma **regra de edição** nova | `fcpxml/` sempre. Se você está escrevendo `if` sobre timeline fora de `fcpxml/`, pare. |
O trabalho principal é **sempre** no engine. As camadas de cima são finas de
propósito: é o que permite testar 1.454 casos sem abrir o app nem subir o MCP.