feat: etapa 5 do assistente — revisão de ênfases com timeline
Transforma a etapa "colar decisões" numa tela de lapidação: a sugestão da IA chega carregada e o editor afina frase a frase o que é ênfase e o que fica fora. Essa marcação é o norte da etapa 6 — só as frases com ênfase recebem zoom e legenda dinâmica; as demais ficam com legenda comum. O campo de colar o JSON sobe para a etapa 4, então a numeração das etapas não muda e a etapa 6 segue intacta. Backend (fcpxml/phrase_review.py): - build_phrase_review funde o _voice_timeline.json com as actions da IA - trim por frase que anda em fronteira de palavra; corte parcial da IA chega como trim em vez de ser arredondado fora - phrase_review_to_actions volta a cuts/zooms + emphasis_spans - merge_saved_decisions reaplica só as decisões salvas sobre uma revisão remontada da análise atual, para reprocessar a voz não ficar mascarado - resolve_source acha a mídia: o voice timeline guarda só o nome do arquivo App (SwiftUI): - layout de sala de edição: preview em cima, inspector à direita, timeline atravessando embaixo com seis trilhas rotuladas - preview enquadra no formato de entrega lido do .fcpxml (fonte horizontal, projeto vertical), com alternância para a mídia original - reprodução pula os trechos removidos e para no fim do trecho - zoom manual por trecho marcado, sem guardar escala: a forma vem das configurações de Análise de Voz no render - emoção da fala exposta por frase Correções encontradas no caminho: - VideoPlayer (AVKit) aborta em runtime no app compilado por swiftc; trocado por AVPlayerLayer (ver Engine/docs/05_EXPERIENCIAS.md #22) - teste que ainda afirmava o default zoom scale=1.3 removido do parser (#21) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e7748c2c58
commit
1bebee4359
@@ -1183,6 +1183,51 @@ o outro; percentil entrega um punhado útil nos dois casos.
|
||||
|
||||
---
|
||||
|
||||
## 21 — 2026-08-19 — Teste travado no default antigo de `zoom scale`
|
||||
|
||||
- **Sintoma:** `tests/test_voice_actions.py::test_default_scale_when_absent`
|
||||
quebrando com `KeyError: 'scale'`, sem relação com a alteração em curso.
|
||||
- **Causa raiz:** `parse_actions` deixou de carimbar `scale=1.3` quando o
|
||||
parâmetro vem ausente, justamente para que
|
||||
`server_tools/_shared.py` use o `zoom_scale` configurado pelo usuário. O
|
||||
teste continuou afirmando o default antigo, então passou a acusar como erro
|
||||
exatamente o comportamento desejado.
|
||||
- **Solução adotada:** teste reescrito para o contrato novo — um `scale`
|
||||
omitido tem que chegar ausente ao aplicador (`test_absent_scale_is_left_absent`).
|
||||
- **Aprendizado:** quando um default sai do parser e vira configuração, o teste
|
||||
que afirmava o valor antigo passa a defender o bug. Ao remover um default,
|
||||
procure o teste que o fixava no mesmo commit — senão ele fica dizendo o
|
||||
contrário do código, e a próxima pessoa perde tempo achando que quebrou algo.
|
||||
- **Estado:** `resolvido`
|
||||
|
||||
---
|
||||
|
||||
## 22 — 2026-08-19 — `VideoPlayer` (AVKit) derruba o app compilado por `swiftc`
|
||||
|
||||
- **Sintoma:** "G-ART encerrou inesperadamente" (SIGABRT) toda vez que o
|
||||
assistente entrava na etapa 5. Nada aparecia na tela antes do crash.
|
||||
- **Causa raiz:** o app é montado invocando `swiftc` direto
|
||||
(`MacApp/build_app.sh`), não pelo Xcode. Nesse modo o runtime não consegue
|
||||
resolver a superclasse Objective-C de `VideoPlayer`:
|
||||
`failed to demangle superclass of VideoPlayerView from mangled name
|
||||
'So12AVPlayerViewC'` → `getSuperclassMetadata` chama `fatalError`. É erro de
|
||||
runtime, então a compilação passa limpa e o problema só aparece ao abrir a
|
||||
view.
|
||||
- **Solução adotada:** trocar `VideoPlayer` por um `AVPlayerLayer` dentro de um
|
||||
`NSViewRepresentable` (`PlayerSurface`/`PlayerLayerView` em
|
||||
`PhraseReviewView.swift`). Só depende de AVFoundation, que linka normalmente.
|
||||
Os controles de transporte já viviam na barra da timeline, então não se perde
|
||||
nada com a chrome do AVKit.
|
||||
- **Aprendizado:** compilar limpo não prova que um componente de framework
|
||||
existe em runtime neste build. Ao usar uma view SwiftUI que embrulha uma
|
||||
classe AppKit/ObjC (AVKit, WebKit, MapKit), abra a tela de fato antes de
|
||||
concluir. Um harness pequeno (`swiftc` com os mesmos fontes + um `@main` que
|
||||
monta só aquela view e sai) reproduz o crash em segundos, sem precisar
|
||||
navegar o app inteiro até lá.
|
||||
- **Estado:** `resolvido`
|
||||
|
||||
---
|
||||
|
||||
## Resumo rápido (índice)
|
||||
|
||||
| # | Data | Problema | Estado |
|
||||
@@ -1205,5 +1250,7 @@ o outro; percentil entrega um punhado útil nos dois casos.
|
||||
| 18 | 2026-08-19 | Legendas dinâmicas geradas com `bold="0" fontFace="Bold"` não renderizam no FCP — negrito deve ser `bold="1"` (atributo) e itálico `fontFace`+`italic="1"` | `resolvido` |
|
||||
| 19 | 2026-08-19 | `output_dir` usado só como cerca de validação e nunca como destino — toda chamada entre pastas falhava acusando o caminho que ela mesma gerou | `resolvido` |
|
||||
| 20 | 2026-08-19 | `apply_voice_actions` ausente da ponte e do encadeamento do app — dava para analisar e legendar, não para cortar | `resolvido` |
|
||||
| 21 | 2026-08-19 | Teste ainda afirmava o default `zoom scale=1.3` removido do parser (agora vem do `zoom_scale` do usuário) | `resolvido` |
|
||||
| 22 | 2026-08-19 | `VideoPlayer` (AVKit) aborta em runtime no app compilado por `swiftc` — etapa 5 fechava o app; trocado por `AVPlayerLayer` | `resolvido` |
|
||||
|
||||
> Mantenha o índice acima sempre sincronizado com as entradas mais recentes.
|
||||
|
||||
Reference in New Issue
Block a user