From ccc71987c2fd2ce5ae2365a3b7e01b941aaacc5f Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Thu, 24 Sep 2026 00:20:25 -0300 Subject: [PATCH] =?UTF-8?q?docs(C215-C219):=20planos=20do=20acervo=20de=20?= =?UTF-8?q?falas=20=E2=80=94=20fonte=20web,=20cortes,=20skill=20e=20parida?= =?UTF-8?q?de?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acervo-cortes-fonte-web-ui-design.html | 514 +++++++++++++++ docs/plans/acervo-cortes-fonte-web.md | 106 ++++ docs/plans/acervo-falas-web-ingestao.md | 89 +++ .../acervo-fonte-falas-web-ui-design.html | 587 ++++++++++++++++++ docs/plans/acervo-fonte-falas-web.md | 108 ++++ ...ervo-paridade-busca-filtros-ui-design.html | 512 +++++++++++++++ docs/plans/acervo-paridade-busca-filtros.md | 118 ++++ docs/plans/skill-catalogo-falas-web.md | 87 +++ 8 files changed, 2121 insertions(+) create mode 100644 docs/plans/acervo-cortes-fonte-web-ui-design.html create mode 100644 docs/plans/acervo-cortes-fonte-web.md create mode 100644 docs/plans/acervo-falas-web-ingestao.md create mode 100644 docs/plans/acervo-fonte-falas-web-ui-design.html create mode 100644 docs/plans/acervo-fonte-falas-web.md create mode 100644 docs/plans/acervo-paridade-busca-filtros-ui-design.html create mode 100644 docs/plans/acervo-paridade-busca-filtros.md create mode 100644 docs/plans/skill-catalogo-falas-web.md diff --git a/docs/plans/acervo-cortes-fonte-web-ui-design.html b/docs/plans/acervo-cortes-fonte-web-ui-design.html new file mode 100644 index 00000000..59270ff1 --- /dev/null +++ b/docs/plans/acervo-cortes-fonte-web-ui-design.html @@ -0,0 +1,514 @@ + + + + + + + Design — C217 · Cortes de falas na internet + + + + +
+
+
+ C217 · gate hi-fiCampanha · Comunicação +
+

+ Da fala web ao corte compartilhável +

+

+ O mesmo gesto de corte da Câmara, agora sobre o arquivo espelhado — sem criar outro + editor. +

+
+ +
+

CENA 01

+

+ Desktop · detalhe com “Cortar trecho” em destaque +

+
+
+ ← Falas na internet +
+
+
+ Arquivo espelhado · YouTube +
+
+
+
+
+ +
+

+ Selecione na transcrição ou ajuste início e fim na janela de corte. +

+
+
+ YouTube +

Título da fala publicada na internet

+

Canal/autor · dd/mm/aaaa · —:—

+

+ Transcrição · clique nas frases +

+ +
+
+
+
+
+ +
+

CENA 02

+

Diálogo existente · mínimo 5 s, sem teto

+
+
+ +
+
+ +
+

CENA 03

+

+ Estados estáticos · Processando → Pronto · Falhou +

+
+
+ Processando +

Preparando o corte…

+
    +
  1. + Arquivo localizadoConcluído +
  2. +
  3. + Recortando vídeoEm andamento +
  4. +
  5. + Publicando arquivoNa fila +
  6. +
+

+ Nada fica no ar pela metade. +

+
+
+ Pronto +

Seu corte está pronto

+

+ O arquivo já está na biblioteca e o link compartilhável está disponível. +

+
+ +
+
+
+ Falhou +
+ +
+

Não foi possível cortar o trecho

+

+ Nada foi publicado. O mesmo trecho continua selecionado e tentar de novo não cria + duplicata. +

+
+
+ +
+
+
+ +
+

CENA 04

+

Biblioteca · origem web visível

+
+
+
+
+

Biblioteca de cortes

+

+ Cortes prontos e em processamento no mesmo lugar. +

+
+ +
+
+
+ ProntoOrigem: YouTubeCriado em dd/mm/aaaa +
+

Título do corte da fala web

+

Título da fala de origem · 00:26

+

Descrição breve e editável do corte.

+
+ +
+
+
+
+
+ +
+

CENA 05

+

+ Página /corte/<id> · unlisted e noindex +

+
+
+ Jorge Solla 1313 — Mais Saúde, Mais Futuro +
+
+
+ +
+
+

Título do corte compartilhável

+

+ Fala na internet · dd/mm/aaaa · 00:26 · YouTube +

+

+ Descrição do trecho, revisada pela assessoria antes da publicação. +

+
+ +
+
+

Fonte: YouTube · Canal/autor da publicação

+

+ Página não listada — o link circula, mas não é indexada nem aparece em buscas. +

+
+
+
+
+
+ +
+

CENA 06

+

+ Mobile ~390 · detalhe e card da biblioteca +

+
+
+
+ ← Detalhe da fala +
+
+
+ YouTube · espelhado +
+ +
+

Título da fala publicada

+

Canal/autor · dd/mm/aaaa

+
+

+ Transcrição · toque para selecionar +

+ +
+
+
+
+

Biblioteca de cortes

+
+
+
+
+ ProntoYouTube +
+

Título do corte da fala web

+

Fala de origem · 00:26

+ +
+ +
+
+
+
+
+
+
+ + diff --git a/docs/plans/acervo-cortes-fonte-web.md b/docs/plans/acervo-cortes-fonte-web.md new file mode 100644 index 00000000..1bad006e --- /dev/null +++ b/docs/plans/acervo-cortes-fonte-web.md @@ -0,0 +1,106 @@ +# C217 — Cortes e links compartilháveis na fonte "Falas na internet" + +Status: rascunho +Atualizado em: 2026-09-23 +Issue: #1293 +Priority: P2 +Impeccable: C — fluxo de corte em fonte nova dentro da vertical /campanha/comunicacao/acervo +Design UI: docs/plans/acervo-cortes-fonte-web-ui-design.html +Appetite: ~2–3 dias eng; um outcome verificável — a assessoria corta um trecho de uma fala da internet, o corte aparece na biblioteca e o link compartilhado abre no ponto certo, com download +Responsável: — + +## Intenção + +O acervo ganhou uma fonte nova: falas do Solla que circulam na internet (YouTube, rádio, Instagram …), trazidas pelo C215 e navegáveis pelo C216. Mas cortar, guardar na biblioteca, compartilhar por link e baixar hoje só existem para as falas da Câmara — quem acha uma fala da internet no acervo só consegue link para fora. O dono (2026-09-23): "as funcionalidades de baixar e realizar cortes (que são então disponibilizados via links compartilháveis e na biblioteca de cortes) devem também funcionar nesta sessão". Esta fatia estende o corte que já existe à fonte web, sem mecanismo novo: mesmo diálogo, mesma biblioteca, mesma página `/corte/`. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`, mais `coordinator`/`candidate`), na mesa ou em campo, montando peça a partir de uma fala que viu na internet. +- **Job principal:** cortar o trecho exato de uma fala da internet e ter o corte baixável, compartilhável e reencontrável na biblioteca — sem sair da ferramenta e sem refazer na mão. +- **Fluxo desejado:** abre a fala web no detalhe (C216) → "Cortar trecho" abre a janela de corte que já conhece (mínimo 5 s, sem teto) → confirma e acompanha Processando → Pronto → "Baixar", "Copiar link" ou "Compartilhar no WhatsApp" → o corte está na biblioteca com a origem visível e o link `/corte/` abre no ponto certo. +- **Anti-goals de produto:** não vira editor de vídeo nem segundo mecanismo de corte/player; não muda a ingestão nem a fonte (C215/C216); não cria galeria pública; não publica em rede social; não duplica a biblioteca. + +### Esboço de fluxo (C) + +```text +[detalhe da fala web (C216)] → "Cortar trecho" → janela de corte (≥5s, sem teto) +→ Processando → Pronto → [Baixar] · [Copiar link] · [Compartilhar no WhatsApp] +→ [biblioteca de cortes: mesma lista, origem visível "YouTube"/"Rádio"/"Instagram"] +→ [/corte/ unlisted + noindex: player e download] +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/acervo-cortes-fonte-web-ui-design.html` — cenas: detalhe da fala web com os gestos, diálogo "Cortar trecho", card na biblioteca com a origem e a página `/corte/`. + +```text +[detalhe da fala web] [biblioteca: card do corte] + player + transcrição título · origem (YouTube) · duração + [Cortar trecho] [Baixar] ─→ corte MP4 ─→ [Baixar] [Copiar link] [WhatsApp] +``` + +## Objetivo e aceite + +- No detalhe de uma fala da fonte web (C216), "Cortar trecho" abre a janela de corte existente e gera o corte a partir do arquivo espelhado — sem depender da plataforma de origem. +- O corte entra na mesma biblioteca `/campanha/comunicacao/acervo/cortes`, com a origem visível no card; paridade total com o corte da Câmara: download, link, editar título/descrição, apagar com confirmação, "Tentar novamente" no estado falhou e kill switch de publicação (C168/C183). +- O link compartilhado é o mesmo contrato `/corte/` (unlisted, `noindex`), com player, download, "Copiar link" e "Compartilhar no WhatsApp"; a página abre o corte certo independente da origem. +- A janela de corte é a mesma: mínimo de 5 s, sem teto (C170). +- O crédito da página acompanha a origem real da fala — nunca exibir o crédito da Câmara para fala de terceiro. +- **Guardrails:** gate `speechCatalog` intocado (communicator/coordinator/candidate; advisor/leader fail-closed); fala web sem arquivo espelhado não oferece o corte (questão 3); sem segundo mecanismo de mídia nem de compartilhamento; `/corte/` continua não listado. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — superfície de ação (cortar/baixar/compartilhar) sobre a lista paginada existente; o estado do corte é atributo do item, não KPI. +- **Decisões desbloqueadas:** a assessoria decide qual trecho de uma fala da internet vira peça e se baixa/compartilha; nada agregado. +- **Forma:** _adiada ao plano de implementação_ — restrição de produto: sem métricas de vaidade (views/downloads) nem contadores de acervo. + +## Dados da decisão (literais) + +- **Gestos no detalhe da fala web (mesmos rótulos da Câmara):** "Cortar trecho" (abre a janela existente) · "Baixar" (arquivo da fala) · no corte pronto, "Copiar link" e "Compartilhar no WhatsApp". +- **Janela de corte:** mínimo 5 s, sem teto — a mesma regra do C170 (até o fim da fala). +- **Geração:** o corte usa o arquivo espelhado da fala (C215) — sem resolver VOD nem depender da plataforma de origem. +- **Origens visíveis (rótulo no card da biblioteca):** "YouTube", "Rádio", "Instagram", … (a taxonomia real é do C215/C216). +- **Link do corte:** mesmo contrato `/corte/` da Câmara — unlisted e `noindex`; a decisão sobre origem de terceiros fica na questão 1. +- **Paridade de biblioteca (C168/C183):** editar título/descrição, apagar com confirmação, "Tentar novamente" no falhou e kill switch de publicação. +- **Instrução do dono (verbatim, 2026-09-23):** "Você não deve se preocupar com direitos da midia, faça o que for necessario para viabilizar a analise e download das midias que forem encontradas para alimentar esta sessão e para viabilizar as funcionalidades pediadas." — decisão confirmada no gate (2026-09-24); vale para os cortes desta fonte e refere C215/C212. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** detalhe da fala web (do C216); entrada/criação do corte (`src/app/(campaign)/campanha/actions/speech.ts` + schemas); pipeline `src/utilities/speech/speechCutJob.ts` (hoje resolve VOD da Câmara, baixa, corta com ffmpeg e grava MP4 na `media` pública); lista `speechCutListUrl.ts`/`speechCutPageData.ts` (origem no card); `src/collections/SpeechCut.ts` (relação/origem); página `src/app/(frontend)/corte/[id]/page.tsx` + `src/components/SpeechCutShareActions.tsx` (link e crédito); donos de mídia `src/utilities/media/ffmpeg.ts` e `src/utilities/privateMedia/privateMediaResponse.ts`. +- **Precedente a olhar:** C167 (corte/publicação), C168/C183 (biblioteca/apagar/retry), C170 (janela sem teto), `acervo-gravacoes-enviadas.md` (C199 excluiu corte das gravações — "C167/C174 são da Câmara"; a instrução do dono reabre esse corte para a fonte web). +- **Risco de acoplamento:** o corte já é um MP4 armazenado (não depende do YouTube para tocar/baixar); o acoplamento à Câmara está na **entrada** (coordenadas/VOD) e no **crédito** — o executor escolhe onde estender sem quebrar o caminho Câmara; mídia grande/privada é do C215/C193 (não criar mecanismo gêmeo); serializar com o C216 nos arquivos do detalhe. + +## Dependências + +- **Dura: C215** — a ingestão espelha a fala e o arquivo; sem arquivo não há de onde cortar. +- **Dura: C216** — a fonte/lista/detalhe onde o gesto nasce; serializar nos arquivos do detalhe. +- Observação: a guardrail "mídia de terceiro nunca é baixada" (C199/C211) é superada para esta sessão pela instrução do dono (ver literais), registrada em C215/C212. + +## Fora de escopo + +- Ingestão e espelhamento do arquivo (C215) e fonte/lista/detalhe/player da fala web (C216). +- Skill de comunicação (C218) e paridade de filtros das gravações (C219). +- Editor de vídeo, recorte fino/timeline, legendas e re-render. +- Publicação em rede social e galeria pública de cortes. +- Diarização/rotulagem de quem fala. + +## Rabbit holes de produto + +- **Editor de corte multi-trilha.** Se alguém "só completar": timeline, faixas, preview de transição. **Corte neste item:** a mesma seleção de trecho da Câmara, agora sobre o arquivo espelhado. +- **Render na nuvem / fila própria de encode.** Se alguém "só completar": worker dedicado, streaming, partes. **Corte neste item:** o pipeline de corte existente, aplicado ao arquivo da fonte web. +- **Galeria pública de cortes.** Se alguém "só completar": índice indexável, feed, perfil. **Corte neste item:** `/corte/` unlisted como hoje; sem listagem pública. +- **Segundo mecanismo de compartilhamento.** Se alguém "só completar": embed, SDK, outras redes. **Corte neste item:** "Copiar link" + "Compartilhar no WhatsApp". + +## Questões em aberto (produto) + +- **Link compartilhável de corte de origem web?** **Opções:** A) mesma página pública `/corte/` (paridade com a Câmara; risco de direitos coberto pela instrução do dono) | B) link interno autenticado só para a campanha | C) público só quando a origem for própria (canal/perfil do Solla ou material da campanha) e interno para terceiros. **Recomendação: A** — o dono pediu paridade ("links compartilháveis"); registrar o risco assumido. _(confirmado no gate, 2026-09-24)_ +- **Filtro por origem na biblioteca de cortes?** **Opções:** A) só exibir a origem no card nesta fase | B) filtro por plataforma já aqui. **Recomendação: A** — a lista hoje é q+page; filtro por origem é paridade de filtros (C219) e não é preciso para o outcome. _(confirmado no gate, 2026-09-24)_ +- **Corte de fala web sem arquivo espelhado?** **Opções:** A) gesto indisponível (só link de origem) | B) resolver/baixar sob demanda. **Recomendação: A** — a ingestão (C215) garante o arquivo; sem arquivo não há corte, e resolver sob demanda recria o acoplamento à plataforma. _(confirmado no gate, 2026-09-24)_ + +## Referências + +- GitHub Issue: — (após `pnpm agent:register`) +- Design UI (gate): `docs/plans/acervo-cortes-fonte-web-ui-design.html` +- Planos irmãos: C215 (ingestão) · C216 (fonte/lista/detalhe) · C218 (skill) · C219 (paridade de filtros); [`c168-biblioteca-cortes.md`](c168-biblioteca-cortes.md) · [`c170-corte-sem-limite.md`](c170-corte-sem-limite.md) · [`acervo-encontrar-cortes.md`](acervo-encontrar-cortes.md) · [`corte-pagina-publica-design.md`](corte-pagina-publica-design.md) · [`acervo-gravacoes-enviadas.md`](acervo-gravacoes-enviadas.md) +- Arquivos-pista: `src/collections/SpeechCut.ts` · `src/app/(campaign)/campanha/actions/speech.ts` · `src/utilities/speech/speechCutJob.ts` · `src/utilities/speech/speechCutListUrl.ts` · `src/utilities/speech/speechCutPageData.ts` · `src/lib/speechCut.ts` · `src/app/(frontend)/corte/[id]/page.tsx` · `src/components/SpeechCutShareActions.tsx` · `src/utilities/media/ffmpeg.ts` · `src/utilities/privateMedia/privateMediaResponse.ts` +- `AGENTS.md` — vertical Comunicação, gate `speechCatalog`, leader lockdown. diff --git a/docs/plans/acervo-falas-web-ingestao.md b/docs/plans/acervo-falas-web-ingestao.md new file mode 100644 index 00000000..45fa65e6 --- /dev/null +++ b/docs/plans/acervo-falas-web-ingestao.md @@ -0,0 +1,89 @@ +# C215 — Ingestão de falas da internet no acervo (descoberta, espelho e catálogo) + +Status: rascunho +Atualizado em: 2026-09-23 +Issue: #1291 +Priority: P1 +Impeccable: A — N/A (dados/ops, sem UI) +Design UI: N/A — sem UI +Appetite: ~3–4 dias de engenharia + tempo de máquina; um outcome verificável — um lote de falas encontradas na web entra no catálogo com transcrição, facetas e mídia espelhada, reexecutável sem duplicar e com relatório honesto +Responsável: — + +## Intenção + +O acervo de falas do Solla hoje só enxerga a Câmara. O que o deputado disse em vídeo no YouTube, em Reels, em rádio e em áudio solto existe na internet e não existe para a busca: a assessoria não encontra "onde ele falou de X" fora do Plenário. O dono decidiu catalogar esse material com a mesma experiência do "Falas da Câmara" — mesmas facetas, mesmos filtros — e alimentar o catálogo a partir de uma varredura da web. + +Este item entrega a esteira de ingestão: recebe um lote de achados (a descoberta é a skill do C218), baixa/espelha a mídia, transcreve, classifica e grava de forma idempotente, com relatório. A tela é o C216 e os cortes são o C217; aqui o acervo nasce e sobrevive a reexecução. + +## Persona e fluxo + +- **Persona / contexto:** coordenação técnica rodando a ingestão (uma vez no início, depois por janela); a consumidora final é a assessoria de comunicação, na tela do C216. +- **Job principal:** entregar um lote de achados da web e obter cada fala catalogada — transcrita, facetada, com mídia preservada — podendo reexecutar sem duplicar. +- **Fluxo desejado:** apontar o lote de achados (plataforma + URL + metadados que a descoberta já trouxe) → a esteira baixa a mídia, transcreve, classifica e grava → imprime relatório (achados, novos, atualizados, ignorados, falhas, tempo e custo de ASR) → a fala aparece no acervo com as mesmas facetas do "Falas da Câmara". +- **Anti-goals de produto:** não é crawler nem serviço de monitoramento (não descobre sozinho); não é CMS de mídia; não espelha nada para o público; não vira segundo cadastro de pessoa. + +## Objetivo e aceite + +- Cada fala da web vira registro com: data, duração, transcrição com timestamps, temas e alcance (mesmas facetas do "Falas da Câmara"), menções (municípios/pessoas/programas/projetos), proveniência da classificação, origem (plataforma + URL) e canal/autor. +- A mídia é espelhada para o acervo interno (player/download/cortes) e nunca vira URL pública; o arquivo é preservado. +- Reexecutar não duplica (chave natural por origem + id externo/URL canônica) nem sobrescreve curadoria manual; a ingestão aceita janela para a atualização incremental do C218. +- Relatório por execução: achados, novos, atualizados, ignorados, falhas, tempo e custo de ASR — falha não é maquiada. +- **Guardrails:** sem segundo cadastro de pessoa (menções são texto, como no C153); sem espelho público; sem PII; sem score de vaidade; sem publicação externa; não tocar o feed do site público nem a Central de Conteúdos (C211 é dono da peça; aqui é catálogo de fala); leitura restrita ao gate já existente (`canReadCommunicationCatalog`, fail-closed). + +## Dados (intenção) + +- **Vou apresentar dados?** Sim, derivado — facetas e menções alimentam a busca e os filtros do C216; aqui nenhum agregado é apresentado. +- **Decisões desbloqueadas:** a assessoria decide qual fala/trecho usar por tema, alcance, data, município citado e canal de origem. +- **Forma:** _adiada ao plano de implementação_ — restrição de produto: leitura relativa/local, sem dashboard de vaidade. + +## Dados da decisão (literais) + +- **Instrução do dono (verbatim, 2026-09-23):** "Você não deve se preocupar com direitos da mídia, faça o que for necessário para viabilizar a análise e download das mídias que forem encontradas." — supera o guardrail C212/C211-FOLLOWUP ("mídia de terceiro nunca baixada/persistida") **para este catálogo interno**. **Confirmado no gate (2026-09-24):** risco assumido e registrado. +- **Campos obrigatórios do catálogo:** data, duração, transcrição com timestamps, temas, alcance, menções (municípios/pessoas/programas/projetos), proveniência da classificação, origem (plataforma + URL), canal/autor. +- **Mídia espelhada:** privada e preservada, servida só ao acervo interno; nunca URL pública. +- **Idempotência:** chave natural por origem + id externo/URL canônica; curadoria manual nunca sobrescrita. +- **Relatório por execução:** achados · novos · atualizados · ignorados · falhas · tempo · custo de ASR. +- **Janela:** a ingestão aceita recorte temporal; a execução inicial cobre tudo que a descoberta alcançar. +- **Falha de download/transcrição:** fica fora da lista e aparece no relatório (reprocessar = rodar de novo). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** script de ingestão em `scripts/` no padrão de import idempotente; ASR em `src/utilities/ai/deepInfraTranscribe.ts`; classificação em `src/utilities/speech/speechClassifier.ts` (facetas em `src/lib/speechFacets.ts`); `src/utilities/media/ffmpeg.ts`; mídia privada em `src/utilities/privateMedia/privateMediaResponse.ts`; gate de leitura já existente. +- **Precedente a olhar:** `scripts/import-camara-speeches.mjs` (match por `sourceKey`, skip do já guardado, faceta manual preservada, `--dry-run`, `--date/--legislature/--all`, relatórios gitignored, guard de banco local + `*_CONFIRM=1`) e `src/utilities/speech/speechImport.ts` (upsert transacional); C211 (`contentPiece` com `sourceUrl`/`origin`) como vizinho que não se invade. +- **Risco de acoplamento:** `speech` é a fonte Câmara e seu `sourceKey` é identidade por contrato — a fala da web não pode quebrá-lo; `speechClassifier` e `deepInfraTranscribe` têm dono único — reusar, nunca duplicar. +- **Fatos verificados (ponto de partida):** não existe yt-dlp/gallery-dl no repo nem busca SERP no app; a pesquisa web é feita por subagentes de skill (padrão `research.json`). Ferramenta de download e destino do espelho são decisão do plano de implementação. + +## Dependências + +- Nenhuma dura — reusa ASR, classificador, ffmpeg e import idempotente já entregues (C153/C199/C211). +- C216 (tela), C217 (cortes) e C218 (skill de atualização) dependem deste. + +## Fora de escopo + +- Tela da fonte de falas na web (C216); cortes e links (C217); skill de atualização incremental (C218); paridade de filtros das gravações (C219). +- Diarização, edição de transcrição e publicação. +- Descoberta de achados (é a skill C218); publicação externa; feed do site; Central de Conteúdos. + +## Rabbit holes de produto + +- **"A ingestão descobre sozinha".** Se alguém "só completar": crawler genérico/serviço de monitoramento. **Corte neste item:** recebe lote de achados; a descoberta é C218. +- **"Baixar tudo de todos os perfis".** Se alguém "só completar": arquivo infinito e ruído. **Corte neste item:** ingere o lote que a descoberta entregar. +- **"Classificação perfeita antes de importar".** Se alguém "só completar": curadoria manual interminável. **Corte neste item:** classificação automática com proveniência + correção depois (padrão C153). +- **"Espelhar em qualidade máxima".** Se alguém "só completar": disco e tempo sem necessidade. **Corte neste item:** qualidade suficiente para transcrição/player/corte; decisão da implementação. +- **"Segundo pipeline de transcrição".** Se alguém "só completar": dois ASR, duas facetas divergindo. **Corte neste item:** donos únicos reusados. + +## Questões em aberto (produto) + +- **Direitos/ToS:** **Opções:** A) seguir a instrução do dono — scraping + download + espelho privado, com o guardrail C212/C211-FOLLOWUP registrado como superado neste catálogo | B) só caminhos oficiais — inviabiliza download/análise/cortes | C) híbrido (conta/canal próprios + anexo manual; terceiros só link). **Confirmado no gate (2026-09-24): A** — a instrução do dono prevalece; guardrail C212/C211-FOLLOWUP superado neste catálogo interno; risco assumido e registrado. +- **Plataformas v1:** **Opções:** A) YouTube + Instagram + áudio/rádio (RSS/MP3/embed) | B) + TikTok/Facebook/X. **Recomendação:** A — cobre o que existe hoje; o resto quando doer. _(confirmado no gate, 2026-09-24)_ +- **Janela da varredura inicial:** **Opções:** A) tudo que a descoberta alcançar | B) desde 2011 (janela do acervo Câmara) | C) desde 2022. **Recomendação:** A — "tudo que for encontrado", como pediu o dono. _(confirmado no gate, 2026-09-24)_ +- **Ferramenta de download e onde a mídia espelhada mora:** _adiada ao plano de implementação_ — restrição de produto: privada, preservada, servida só ao acervo; sem URL pública. _(confirmado no gate, 2026-09-24)_ +- **Falha de download/transcrição:** **Opções:** A) item fica fora da lista e aparece no relatório | B) estado "Falhou" visível com reprocessar. **Recomendação:** A nesta fase — a lista só mostra o que está pronto; reprocessar é rodar de novo. _(confirmado no gate, 2026-09-24)_ + +## Referências + +- GitHub Issue: — (após `pnpm agent:register`) +- Design UI: N/A +- `docs/plans/catalogo-falas-solla.md` (C153 — catálogo e facetas) · `docs/plans/backfill-acervo-falas.md` (C155) · `docs/plans/central-conteudos-ingestao.md` (C211) · `docs/plans/central-conteudos-varredura-instagram.md` (C212 — §Achados, decisão anti-scraping) +- Arquivos-pista: `scripts/import-camara-speeches.mjs` · `src/utilities/speech/speechImport.ts` · `src/utilities/speech/speechClassifier.ts` · `src/lib/speechFacets.ts` · `src/utilities/ai/deepInfraTranscribe.ts` · `src/utilities/media/ffmpeg.ts` · `src/utilities/privateMedia/privateMediaResponse.ts` · `src/utilities/campaignAccess.ts` +- `AGENTS.md` (convenções de access, mídia privada e gate de leitura do acervo) diff --git a/docs/plans/acervo-fonte-falas-web-ui-design.html b/docs/plans/acervo-fonte-falas-web-ui-design.html new file mode 100644 index 00000000..6af229eb --- /dev/null +++ b/docs/plans/acervo-fonte-falas-web-ui-design.html @@ -0,0 +1,587 @@ + + + + + + + Design — C216 · Falas na internet + + + + +
+
+
+ C216 · gate hi-fiCampanha · Comunicação +
+

+ Falas na internet, no mesmo acervo +

+

+ A assessoria encontra, ouve e baixa uma fala já catalogada, sabendo exatamente de onde ela + veio. +

+
+ +
+
+

CENA 01

+

+ Desktop ~1280 · lista da terceira fonte +

+
+
+
+ +
+
+
+

Acervo de falas

+

Comunicação

+
+
+
+
+

Acervo de falas

+

+ Busque nas falas da Câmara, nas gravações da equipe ou nas falas encontradas na + internet. +

+
+ +
+ +
+ +
+
+ Buscar por +
+ +
+

+ Encontra falas relacionadas pelo sentido. +

+
+
+ +
+
+
+

+ Resultados encontrados + (contagem) +

+ +
+
+
+
+ YouTubeNEEDS ASSET · THUMBNAIL DA ORIGEM +
+
+
+ YouTubedd/mm/aaaa · —:— +
+

+ Título da fala publicada na internet +

+

+ … compromisso com a saúde pública e com o atendimento de quem + mais precisa … +

+
+ SaúdeBahia +
+
+ +
+
+
+ SEM CAPA +
+
+
+ Rádiodd/mm/aaaa · —:— +
+

Entrevista sobre um tema público

+

+ … outro trecho em que o assunto buscado aparece com clareza … +

+
+ +
+
+
+
+
+
+
+ +
+
+

CENA 02

+

Desktop · detalhe da fala web

+
+
+
+ ← Voltar para Falas na internet +
+
+
+ +
+
+
+ Arquivo espelhado · privado +
+
+ +
+
+

+ Origem +

+

YouTube · Canal/autor da publicação

+

Publicado em dd/mm/aaaa

+
+
+
+ YouTube +

+ Título da fala publicada na internet +

+

—:— · tema e alcance classificados

+
+

+ Transcrição · clique para posicionar +

+
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + +
  6. +
+
+
+
+
+
+
+ +
+
+

CENA 03

+

Mobile ~390 · lista e detalhe

+
+
+
+
+
+

Acervo

+

Comunicação

+
+
+
+ +
+ +
+ Assunto, tema ou município… +
+
+ Termo exato✦ Por tema +
+
+ Ano⌄Tema⌄Alcance⌄ +
+
+

+ Resultados (contagem) +

+
+
+ Instagram +
+

dd/mm/aaaa · —:—

+

Título da fala publicada

+

+ … trecho com termo destacado na transcrição … +

+ +
+
+
+
+
+ ← Detalhe da fala +
+
+
+ Arquivo espelhado +
+ +
+ YouTube +

Título da fala publicada

+

+ YouTube · Canal/autor · dd/mm/aaaa +

+
+

+ Transcrição · toque para posicionar +

+ +
+
+
+
+ +
+
+

CENA 04

+

+ Estados críticos · vazio, carregando e sem permissão +

+
+
+
+ +

Nenhuma fala encontrada

+

+ Não encontramos uma fala para esta busca com os filtros atuais. Tente outro termo ou + remova um filtro. +

+ +
+
+

Carregando falas…

+
+
+
+
+
+
+
+ +
+

Você não tem acesso a este acervo

+

+ As falas e os arquivos permanecem privados. Entre com uma conta autorizada da + comunicação. +

+ +
+
+
+
+ + diff --git a/docs/plans/acervo-fonte-falas-web.md b/docs/plans/acervo-fonte-falas-web.md new file mode 100644 index 00000000..37ca6a51 --- /dev/null +++ b/docs/plans/acervo-fonte-falas-web.md @@ -0,0 +1,108 @@ +# C216 — Terceira fonte do acervo: "Falas na internet" + +Status: rascunho +Atualizado em: 2026-09-23 +Issue: #1292 +Priority: P1 +Impeccable: C — fluxo novo na vertical `/campanha/comunicacao/acervo` (terceira fonte + detalhe próprio) +Design UI: docs/plans/acervo-fonte-falas-web-ui-design.html +Appetite: ~3–4 dias eng; um outcome verificável — a assessoria alterna para "Falas na internet", busca/filtra como no acervo da Câmara e assiste/baixa a fala encontrada +Responsável: — + +## Intenção + +O acervo cobre duas coisas: o que a Câmara publica e o que a equipe envia. Falta o que o Solla fala fora disso — YouTube, Instagram, rádios, podcasts — material espalhado, sem transcrição pesquisável e sem lugar único. O C215 descobre e cataloga esse material (download, transcrição e classificação automática); este item é a cara disso no acervo: a terceira fonte "Falas na internet", com a mesma busca e os mesmos filtros do "Falas da Câmara" e um detalhe com player, transcrição clicável, download e link para a origem. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`) — e `coordinator`/`candidate` — na mesa garimpando matéria-prima com prazo curto, ou em campo procurando no celular o que o Solla já disse sobre um tema. +- **Job principal:** achar uma fala do Solla publicada na internet sobre um assunto/município, ouvir e baixar o arquivo, e saber de onde ela veio para poder citar. +- **Fluxo desejado:** abre o acervo → alterna para "Falas na internet" → busca (termo ou tema) e filtra (ano, tema, alcance, duração, municípios citados) → resultados com trecho destacado e chip da origem → abre o detalhe → player da mídia espelhada no trecho + transcrição clicável por segmento → "Baixar" e "Abrir na origem" (com plataforma, canal/autor e data). +- **Anti-goals de produto:** não é editor de vídeo nem publicação; não expõe o acervo publicamente; não cria cadastro de pessoa; não busca _dentro_ da internet (a descoberta é do C215); não mistura as fontes numa lista única. + +### Esboço de fluxo (C) + +```text +[acervo /campanha/comunicacao/acervo] → alternador: "Falas da Câmara" | "Gravações enviadas" | "Falas na internet" + → busca com destaque + facetas (ano, tema, alcance, duração, municípios) com paridade da Câmara + → abre o detalhe → player da mídia espelhada + transcrição clicável + "Baixar" + "Abrir na origem" + → [outcome: a fala da internet achada, assistida e baixada, com a origem identificada] +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/acervo-fonte-falas-web-ui-design.html` (+ assets em `docs/plans/acervo-fonte-falas-web-ui-design-assets/`) — a produzir pelo designer. +- Por que C: fluxo novo na vertical do acervo (terceira fonte, detalhe próprio com player/link externo e estados), mesmo sem rota de topo nova. Design hi-fi obrigatório no gate e fonte de verdade do port. + +## Objetivo e aceite + +- O alternador do acervo passa a ter três fontes: "Falas da Câmara" | "Gravações enviadas" | "Falas na internet", com a ativa marcada (`aria-current`) e a troca preservando o contrato de URL da fonte. +- "Falas na internet" tem paridade de busca e filtros com "Falas da Câmara" no que a fonte tiver: busca textual com destaque, `mode=termo|tema` (semântica), ano, tema, alcance, duração, municípios citados, contagem e paginação; a lista mostra o trecho com `` e a contagem. +- Detalhe da fala: player da mídia espelhada (arquivo privado servido autenticado), transcrição clicável por segmento (clique posiciona o player), "Baixar" o arquivo, "Abrir na origem" e atribuição visível (plataforma + canal/autor + data). +- Lista com chip da origem ("YouTube", "Rádio", …) e capa: thumbnail da origem quando a ingestão a capturar; senão, placeholder. +- Estados: vazio (sem resultado), carregando e sem permissão; **sem** estado de processamento por item — a lista mostra o que está pronto e as falhas ficam no relatório da ingestão (C215). +- Acesso: mesmo gate fail-closed do acervo (`communicator` + `coordinator`/`candidate`; `advisor`/`leader` negados); a mídia nunca é pública. +- Mobile utilizável (a assessoria trabalha em campo). +- **Guardrail de direitos de mídia (decisão assumida):** o dono instruiu, verbatim, "Você não deve se preocupar com direitos da mídia, faça o que for necessário para viabilizar a análise e download das mídias que forem encontradas para alimentar esta sessão e para viabilizar as funcionalidades pedidas." Isto supersede a anotação "nunca mídia de terceiro" de C212/C211-FOLLOWUP-OEMBED e vale como premissa do C215; **confirmado no gate (2026-09-24)** — risco assumido. + +## Dados (intenção) + +- **Vou apresentar dados?** N/A — resultados de busca não são métrica nem agregado; não desbloqueiam decisão numérica. +- **Decisões desbloqueadas:** N/A — a escolha da persona ("qual fala usar") é qualitativa. +- **Forma:** N/A — restrição de produto: nenhum score de relevância/similaridade exposto como número. + +## Dados da decisão (literais) + +- **Rótulo da fonte:** "Falas na internet" (terceira opção do alternador, ao lado de "Falas da Câmara" e "Gravações enviadas"). +- **Faceta de origem na lista:** chip com a plataforma ("YouTube", "Rádio", "Instagram", …) — vocabulário exato vem do C215. +- **Ações do detalhe:** "Baixar" (arquivo) · "Abrir na origem" (link para o vídeo/post/áudio original) · transcrição clicável. +- **Atribuição/identificação da origem:** plataforma + canal/autor + data. +- **Parâmetro de URL da fonte:** valor decidido na implementação seguindo o padrão `?source=` do C199 (sem quebrar o contrato congelado da Câmara, `speechListUrl`). _(adiado à implementação)_ +- **Estados:** vazio (sem resultado) · carregando · sem permissão; sem estado de processamento por item nesta fase. +- **Acesso:** mesmo gate do acervo, fail-closed (`canReadCommunicationCatalog`/`communicationCatalog`); mídia nunca pública. +- **Dependência dura:** C215 (ingestão: descoberta, download, transcrição, classificação). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/app/(campaign)/campanha/(app)/comunicacao/acervo/` (página + sub-rota de detalhe), `src/components/campaign/recording/AcervoSourceToggle.tsx` (terceira opção), `src/utilities/recordings/recordingListUrl.ts` (gêmeo do contrato da nova fonte; hoje `parseAcervoSource` é binário fail-closed), `src/components/campaign/speech/` (`SpeechAcervoFilters.tsx`, lista/card, player), `src/utilities/speech/` (`speechListUrl.ts`, `speechPageData.ts`, `speechViewModels.ts`), `src/utilities/privateMedia/privateMediaResponse.ts` (precedente de servir arquivo privado). +- **Precedente a olhar:** C199 (segunda fonte + contrato de URL próprio no `?source=enviadas`), C192 (`mode=termo|tema`), `gravacoes/[id]/arquivo`, C200 (faceta nova como recorte na mesma tela). +- **Risco de acoplamento:** (1) o contrato da lista da Câmara (`q|mode|year|topic|scope|phase|municipality|duration|page`) está congelado — a fonte nova tem o dele (como o C199 fez), sem renomear params existentes; (2) o detalhe da Câmara é acoplado (VOD da Câmara, `SpeechDetailPlayer`) — a fonte web não tem VOD, o player é da mídia espelhada; (3) o regex genérico de detalhe do chrome (`src/lib/campaignPageChrome.ts`) já mordeu `cortes`/`gravacoes` — escolher rota que não colida; (4) nav de Comunicação pinada (4 itens) e C184/#1106 mexem nela — nada de item de nav novo. + +## Dependências + +- **C215 (dura):** sem o catálogo (mídia espelhada + transcrição + classificação) não há o que listar; o desenho pode ser validado antes com dados de amostra. +- **C153/C154/C199 (entregues):** base do acervo e alternador de fonte. +- **C184/#1106 (soft):** conflito de nav/chrome — serializar. +- **C217/C218 (futuros):** cortes e skill de atualização; não bloqueiam. + +## Fora de escopo + +- Ingestão/descoberta, download, transcrição e classificação (C215). +- Cortes e links compartilháveis (C217); skill de atualização (C218). +- Paridade das gravações (C219). +- Diarização, edição de transcrição, publicação externa. +- Merge das fontes numa busca global única; item novo de nav. + +## Rabbit holes de produto + +- **Merge multi-fonte numa lista única.** Se alguém "só completar": ranking entre fontes, dedupe, busca global. **Corte neste item:** alternador dentro do acervo. +- **Segundo cadastro de pessoa.** Se alguém "só completar": transformar canal/autor em `Contact`. **Corte neste item:** atribuição é texto de origem. +- **Editor de vídeo.** Se alguém "só completar": cortar/legendar/remixar. **Corte neste item:** player + transcrição + download; corte é o C217. +- **Dashboard de vaidade.** Se alguém "só completar": views, alcance, KPIs. **Corte neste item:** sem métrica de audiência. +- **Espelhar tudo em qualidade máxima.** Se alguém "só completar": baixar/guardar versão original de tudo. **Corte neste item:** o que o C215 catalogar; nada de biblioteca de masters. + +## Questões em aberto (produto) + +- **A fonte entra no mesmo alternador ou em rota separada?** **Opções:** A) terceira opção no mesmo alternador (recomendado) | B) rota separada. **Recomendação:** A — é o mesmo job no mesmo lugar; rota separada fragmenta o acervo. _(confirmado no gate, 2026-09-24)_ +- **Capa do card?** **Opções:** A) thumbnail da origem quando a ingestão a capturar; senão placeholder | B) sem capa. **Recomendação:** A — a lista da Câmara já usa imagem e a leitura fica mais rápida; o C215 fornece a thumb. _(confirmado no gate, 2026-09-24)_ +- **Mostrar a origem já na lista?** **Opções:** A) sim, chip "YouTube"/"Rádio"/… | B) só no detalhe. **Recomendação:** A — a assessoria escolhe a peça já sabendo de onde a fala veio. _(confirmado no gate, 2026-09-24)_ +- **Item sem transcrição (ASR falhou)?** **Opções:** A) fora da lista, só no relatório da ingestão | B) listado com aviso e só link de origem. **Recomendação:** A nesta fase — a fonte web nasce para busca; item sem texto só ruído. _(confirmado no gate, 2026-09-24)_ +- **Valor do parâmetro de URL da fonte?** **Opções:** A) decidido na implementação seguindo o padrão `?source=` do C199 | B) travar agora. **Recomendação:** A — mesma convenção do alternador atual. _(adiado à implementação)_ + +## Referências + +- GitHub Issue — (após `pnpm agent:register`) +- Design UI (gate): `docs/plans/acervo-fonte-falas-web-ui-design.html` (+ assets em `docs/plans/acervo-fonte-falas-web-ui-design-assets/`) +- Planos irmãos: `docs/plans/acervo-gravacoes-enviadas.md` (C199, precedente direto de fonte) · `docs/plans/acervo-videos-comunicacao.md` (C154) · `docs/plans/acervo-separacao-por-pessoa.md` (C200, formato de plano C de acervo) · `docs/plans/acervo-busca-semantica.md` (C192) +- Arquivos-pista: `src/app/(campaign)/campanha/(app)/comunicacao/acervo/page.tsx` · `src/components/campaign/recording/AcervoSourceToggle.tsx` · `src/utilities/recordings/recordingListUrl.ts` · `src/components/campaign/speech/` · `src/utilities/speech/speechListUrl.ts` · `src/utilities/speech/speechPageData.ts` · `src/utilities/privateMedia/privateMediaResponse.ts` · `src/lib/campaignPageChrome.ts` +- `AGENTS.md` — RBAC de `/campanha`, acervo interno e leader lockdown diff --git a/docs/plans/acervo-paridade-busca-filtros-ui-design.html b/docs/plans/acervo-paridade-busca-filtros-ui-design.html new file mode 100644 index 00000000..6a941736 --- /dev/null +++ b/docs/plans/acervo-paridade-busca-filtros-ui-design.html @@ -0,0 +1,512 @@ + + + + + + + Design — C219 · Paridade de busca e filtros + + + + +
+
+
+ C219 · gate hi-fiCampanha · Comunicação +
+

+ Mesmos gestos para encontrar gravações +

+

+ “Gravações enviadas” ganha busca por termo ou tema, facetas, chips ativos, contagem e + ordenação — Pessoa continua exclusiva desta fonte. +

+
+ +
+

CENA 01

+

+ Desktop ~1280 · filtros completos e resultados +

+
+
+ +
+
+
+

Acervo de falas

+

Comunicação

+
+
+
+
+
+

Acervo de falas

+

+ Busque nas falas da Câmara ou nas gravações da equipe. +

+
+ +
+ +
+ +
+ +
+
+
+ Buscar por +
+ +
+
+

+ Encontra gravações relacionadas pelo sentido. +

+
+
+ +
+
+ Ativos: +
+
+
+

+ Gravações encontradas + (contagem) +

+ +
+
+
+
+ +
+
+
+

Título da gravação enviada

+ Pronto +
+

dd/mm/aaaa · —:—

+

+ … trecho em que saúde aparece na transcrição da gravação … +

+
+ SaúdeNome da pessoa +
+
+ +
+
+
+ +
+
+
+

Outra gravação enviada

+ Pronto +
+

dd/mm/aaaa · —:—

+

+ … resultado relacionado ao tema buscado, com contexto + suficiente para decidir … +

+
+ +
+
+
+
+
+
+
+ +
+

CENA 02

+

Mobile ~390 · barra e lista

+
+
+
+

Acervo

+

Comunicação

+
+
+
+ +
+ +
+ Palavra, trecho ou tema… +
+
+ Termo exato✦ Por tema +
+
+ Ano⌄Tema: Saúde⌄Alcance⌄ +
+
+ Município⌄Duração⌄Pessoa⌄ +
+
+ Saúde ×Pessoa: Nome… × +
+
+
+

+ Resultados (contagem) +

+ +
+
+
+ +
+
+

Título da gravação

+ Pronto +
+

dd/mm/aaaa · —:—

+

+ … trecho com termo destacado na transcrição … +

+ +
+
+
+
+ +
+

CENA 03

+

Vazio honesto · limpar ou trocar o modo

+
+
+
+ +
+

Nenhuma gravação encontrada para este tema

+

+ Não encontramos uma gravação que corresponda ao sentido desta busca com os filtros + atuais. Não vamos preencher a lista com resultados pouco relacionados. +

+
+ +
+
+
+
+ +
+

CENA 04

+

Sem permissão · fail-closed

+
+
+
+ +
+

Você não tem acesso a este acervo

+

+ As gravações, transcrições e filtros permanecem privados. Entre com uma conta + autorizada da comunicação. +

+ +
+
+
+ +
+

CENA 05

+

Carregando · contexto preservado

+
+
+
+
+
+
+
+
+
+

Atualizando resultados…

+
+
+
+
+
+
+
+ + diff --git a/docs/plans/acervo-paridade-busca-filtros.md b/docs/plans/acervo-paridade-busca-filtros.md new file mode 100644 index 00000000..775f8f3c --- /dev/null +++ b/docs/plans/acervo-paridade-busca-filtros.md @@ -0,0 +1,118 @@ +# C219 — Paridade de busca e filtros entre as fontes do acervo + +Status: rascunho +Atualizado em: 2026-09-23 +Issue: #1295 +Priority: P2 +Impeccable: B — encaixe na tela existente do acervo (barra de filtros e facetas da fonte de gravações) +Design UI: docs/plans/acervo-paridade-busca-filtros-ui-design.html +Appetite: ~2–3 dias eng; a assessoria filtra "Gravações enviadas" por ano, duração, tema, alcance e município citado, e busca por tema como na Câmara, com o mesmo comportamento de filtros +Responsável: — + +## Intenção + +O dono percebeu o desnível: "o 'Gravações enviadas' não está hoje com todas as funcionalidades de pesquisa e filtro que temos para 'Falas da Câmara'". As duas fontes vivem no mesmo acervo, mas a experiência é desigual — a Câmara tem busca por termo/tema, ano, duração e facetas de conteúdo; as gravações têm só busca textual e pessoa. Quem garimpa uma plenária enviada trabalha com menos instrumentos do que quem garimpa um discurso de plenário. + +Este item fecha as lacunas da fonte de gravações e deixa registrado o contrato que **toda** fonte do acervo deve cumprir — a fonte nova ("Falas na internet", C216) nasce com ele. Paridade é do conjunto de capacidades, não de facetas idênticas: "Pessoa" continua exclusiva das gravações. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`) — e `coordinator`/`candidate` — na mesa, sob prazo curto, garimpando fala em plenárias/debates enviados pela equipe; busca também acontece em campo. +- **Job principal:** achar a gravação/trecho sobre um assunto, tema, ano ou município com os mesmos gestos que já usa nas falas da Câmara. +- **Fluxo desejado:** + 1. Abre o acervo e alterna para "Gravações enviadas". + 2. Digita o assunto e escolhe termo exato ou por tema (como na Câmara). + 3. Restringe por ano, duração, tema, alcance e município citado; combina filtros e vê a contagem. + 4. Vê os chips dos filtros ativos, limpa um ou todos, reordena. + 5. Abre a gravação e assiste/baixa (fluxo atual intocado). + 6. Vazio honesto quando nada serve; gravação sem transcrição segue visível, fora dos filtros de conteúdo. +- **Anti-goals de produto:** não unifica as fontes numa lista única; não vira curadoria de taxonomia; não cria cadastro de pessoa; não redesenha a barra da Câmara; não classifica conteúdo de terceiros (C211 é outro dono). + +### Esboço de fluxo (B) + +```text +[fonte "Gravações enviadas"] → busca (termo | tema) + ano + duração + tema + alcance + município + → lista com trecho destacado, contagem, chips ativos e ordenação + → abre a gravação → player/transcrição/baixar (como hoje) + → vazio honesto: limpar filtros | trocar modo +[outcome: achar a gravação certa com os mesmos gestos da Câmara] +``` + +### Design UI (B) + +- Design UI (gate): `docs/plans/acervo-paridade-busca-filtros-ui-design.html` +- Por que B: as capacidades já existem na tela; o item estende a barra de filtros e a lista da fonte de gravações na linguagem da Câmara, sem rota nova. Design hi-fi obrigatório no gate e fonte de verdade do port. + +```text +[Câmara] busca [termo|tema] · Ano · Tema · Alcance · Município · Fase · Duração +[Enviadas] busca [termo|tema] · Ano · Tema · Alcance · Município · Duração · Pessoa +``` + +## Objetivo e aceite + +- Contrato de paridade do acervo cumprido por toda fonte, no que for aplicável: busca textual com destaque; contagem; paginação; busca semântica `mode=termo|tema`; filtro por data/ano; filtro por duração; facetas de conteúdo quando houver classificação; ordenação; estados vazio/carregando/sem permissão. +- "Gravações enviadas" ganha: ano (data da gravação), duração, busca por tema (`mode=tema`) e facetas Tema/Alcance/Município citado — derivadas por classificação automática com proveniência (`classifiedBy`), sobre a transcrição já existente. +- Mesma experiência de filtros da Câmara: chips dos ativos, limpar, contagem, paginação preservada no deep link. +- Classificação é automática e revisável; nunca inventa — falha degrada para o que existir e é sinalizada; combina com os filtros existentes (`q`, Pessoa) sem regressão. +- **Guardrails:** sem segundo cadastro de pessoa ("Pessoa" continua rótulo, C200); gate fail-closed do acervo intocado; acervo interno; sem score/vaidade. + +## Dados (intenção) + +- **Vou apresentar dados?** N/A — resultados e facetas de busca são recorte editorial, não métrica nem agregado. +- **Decisões desbloqueadas:** N/A — a escolha ("qual gravação/fala serve") é qualitativa. +- **Forma:** N/A — sem superfície de dados; restrição de produto: proveniência é rótulo auditável, nunca score numérico na UI. + +## Dados da decisão (literais) + +- **Contrato de paridade (capacidades):** busca textual com destaque do termo · contagem de resultados · paginação · busca semântica `mode=termo|tema` · filtro por data/ano · filtro por duração · facetas de conteúdo (tema, alcance, municípios citados) quando a fonte tiver classificação · ordenação · estados vazio/carregando/sem permissão. +- **Faceta exclusiva não quebra paridade:** "Pessoa" permanece só em "Gravações enviadas"; o contrato é do conjunto de capacidades, não de facetas idênticas. +- **Rótulos novos nas gravações:** "Ano" · "Duração" · "Tema" · "Alcance" · "Município citado"; buckets de duração idênticos à Câmara ("Até 2 min" · "2 a 5 min" · "Mais de 5 min" · "Sem duração"). +- **Ano:** derivado da data da gravação já informada no envio (`recordedAt`) — nunca um segundo campo digitado. +- **Proveniência:** mesmos valores da Câmara — `gazetteer` | `llm` | `manual` (campo `classifiedBy`) na fonte de gravações. +- **Modo de busca:** `mode=termo` é o default (nunca serializado; deep-links atuais intactos) e `mode=tema` é explícito, como na Câmara. +- **Ordenação (rótulos):** "Mais recentes" (default) · "Duração (maior)" · "Duração (menor)". +- **Papéis/gate:** mesmo gate de leitura do acervo (`communicator` + `coordinator`/`candidate`; `advisor`/`leader` negados, fail-closed). +- **URL:** a fonte mantém `?source=enviadas` e ganha os novos params no seu contrato; o contrato da Câmara não muda. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/utilities/recordings/` (`recordingListUrl.ts`, `recordingListFilters.ts`, `recordingPageData.ts`, `recordingViewModels.ts`), `src/components/campaign/recording/` (barra de filtros e lista), `src/collections/Recording.ts` (facets + proveniência), `src/utilities/speech/speechClassifier.ts` (dono único — reusar, não duplicar), `src/utilities/ai/expandSpeechSearchTheme.ts` (ponte de tema por corpus), `src/lib/speechFacets.ts` (taxonomia única). +- **Precedente a olhar:** `SpeechAcervoFilters.tsx` + `speechListUrl.ts`/`speechListFilters.ts` (C154/C192) para a experiência e o contrato; C200 (Pessoa como rótulo derivado); import da Câmara (`scripts/import-camara-speeches.mjs`) para o padrão de classificação com proveniência. +- **Risco de acoplamento:** o contrato de `source=enviadas` sustenta deep-links (`q|person|page`) — não quebrar; classificar a transcrição existente sem tocar diarização/rótulos (C200); um só dono de classificador e taxonomia; gate fail-closed intocado. + +## Dependências + +- **Nenhuma dura.** +- **Soft (serialize): C216** — a fonte nova nasce com o contrato; se ambos estiverem em voo, serializar nos componentes de filtros do acervo (mesmos arquivos). + +## Fora de escopo + +- Fonte web "Falas na internet" (C215/C216) — o contrato vale; a implementação é de lá. +- Cortes/clipes (C217) e a skill do acervo (C218). +- Diarização e edição de transcrição (C200 / itens próprios). +- Merge das fontes numa lista única / busca global. +- Classificação de conteúdo de terceiros na Central de Conteúdos (C211). + +## Rabbit holes de produto + +- **Unificar as fontes numa busca só.** Se alguém "só completar": lista Câmara+gravações+web, paginação multi-coleção, ranking entre fontes. **Corte neste item:** cada fonte mantém sua lista; paridade é de capacidades. +- **Redesenhar a barra de filtros da Câmara.** Se alguém "só completar": shell novo e migração de todos os filtros. **Corte:** a Câmara é a referência; muda-se a fonte de gravações. +- **Classificar por segmento/falante.** Se alguém "só completar": tema por trecho, timeline por pessoa. **Corte:** classificação no nível da gravação, como a fala é a unidade da Câmara. +- **Segundo cadastro de pessoa.** **Corte:** "Pessoa" continua rótulo (C200). +- **Dashboard de vaidade.** **Corte:** nada de métrica de busca/uso. + +## Questões em aberto (produto) + +- **Classificar as gravações para ter tema/alcance/municípios?** **Opções:** A) sim, classificação automática com proveniência | B) não, só filtros genéricos (ano/duração/semântica). **Recomendação:** A — sem classificação não há paridade real de facetas; a proveniência mantém tudo auditável. _(confirmado no gate, 2026-09-24)_ +- **Ordenação?** **Opções:** A) data (mais recente primeiro) + duração (maior/menor) | B) só data. **Recomendação:** A — achar o trecho longo/curto é gesto recorrente de quem monta peça. _(confirmado no gate, 2026-09-24)_ +- **Busca semântica nas gravações?** **Opções:** A) estender a ponte de tema ao corpus de gravações | B) só busca literal. **Recomendação:** A — é a paridade pedida; a ponte já existe e degrada sozinha. _(confirmado no gate, 2026-09-24)_ +- **Gravação sem transcrição (processando/falhou)?** **Opções:** A) fica fora dos filtros de conteúdo e visível como hoje | B) esconder da lista. **Recomendação:** A — estado honesto (como no C199); esconder faz o arquivo sumir sem explicação. _(confirmado no gate, 2026-09-24)_ +- **Ano da gravação?** **Opções:** A) derivar da data já informada | B) criar campo próprio. **Recomendação:** A — uma fonte de verdade da data; campo próprio criaria dupla digitação. _(confirmado no gate, 2026-09-24)_ + +## Referências + +- GitHub Issue: — (após `pnpm agent:register`) +- Design UI (gate): `docs/plans/acervo-paridade-busca-filtros-ui-design.html` +- Planos irmãos: `docs/plans/acervo-videos-comunicacao.md` (C154) · `docs/plans/acervo-gravacoes-enviadas.md` (C199) · `docs/plans/acervo-separacao-por-pessoa.md` (C200) · `docs/plans/acervo-busca-semantica.md` (C192) +- Arquivos-pista: `src/utilities/recordings/recordingListUrl.ts` · `recordingListFilters.ts` · `recordingPageData.ts` · `src/components/campaign/recording/` · `src/components/campaign/speech/SpeechAcervoFilters.tsx` · `src/utilities/speech/speechClassifier.ts` · `src/utilities/ai/expandSpeechSearchTheme.ts` · `src/lib/speechFacets.ts` · `src/collections/Recording.ts` +- `AGENTS.md` — RBAC de `/campanha`, acervo interno e leader lockdown diff --git a/docs/plans/skill-catalogo-falas-web.md b/docs/plans/skill-catalogo-falas-web.md new file mode 100644 index 00000000..24db7ce7 --- /dev/null +++ b/docs/plans/skill-catalogo-falas-web.md @@ -0,0 +1,87 @@ +# C218 — Skill catalogo-falas-web: atualização incremental do catálogo + +Status: rascunho +Atualizado em: 2026-09-23 +Issue: #1294 +Priority: P2 +Impeccable: A — N/A (skill/docs, sem UI) +Design UI: N/A — sem UI +Appetite: ~1–2 dias eng; um outcome verificável — rodar a skill atualiza o catálogo desde a última execução bem-sucedida e devolve o recibo, sem duplicar +Responsável: — + +## Intenção + +O catálogo de falas já tem como ingerir mídia (C215), mas alguém precisa descobrir o que apareceu novo na internet desde a última rodada — e hoje isso é trabalho manual, sem registro de onde parou. Esta skill transforma a atualização numa operação repetível: lê a data da última execução, faz a descoberta web do que surgiu desde então, monta o lote de achados e chama a esteira de ingestão do C215, devolvendo um recibo curto. É a resposta à ideia do dono (2026-09-23): "atualizar essa sessão fazendo um novo scraping a partir da data que foi feito o último". + +Sem isso, cada atualização recomeça do zero (ou do que a memória de quem opera lembrar) e o catálogo envelhece entre entregas da comunicação. + +## Persona e fluxo + +- **Persona / contexto:** agente/coordenação técnica (não a assessoria); roda na workstation/worktree, como as skills de conteúdo dos dossiês. +- **Job principal:** dar um comando e ter o catálogo atualizado desde a última execução, sabendo o que entrou, o que foi ignorado e o que falhou. +- **Fluxo desejado:** `/catalogo-falas-web` → a skill lê a data da última execução (primeira rodada: varredura inicial completa) → descobre o que apareceu desde então → cura falsos positivos → entrega o lote à ingestão (C215) → imprime o recibo (período, achados, novos, ignorados, falhas, custo/tempo). +- **Anti-goals de produto:** não é serviço de monitoramento; não é tela (sem UI); não decide faceta manualmente (transcrição/classificação é do C215); não promete cobertura exaustiva da web. + +## Objetivo e aceite + +- Rodar a skill atualiza o catálogo desde a última execução bem-sucedida e devolve o recibo curto — sem duplicar e sem reprocessar o que já está no catálogo. +- Primeira execução (sem data anterior) faz a varredura inicial completa do que for encontrado; as seguintes são incrementais. +- Achado duvidoso (ex.: falso positivo de "fala do Solla") fica marcado como "revisar" e não é ingerido até confirmação. +- A skill reporta o que encontrou **e o que ficou de fora**; falha de um achado não derruba o lote (sucesso parcial com motivo no recibo). +- **Guardrails:** a decisão sobre descoberta/download é a do C215 (instrução do dono sobre direitos, confirmada no gate) — a skill segue o mecanismo que o C215 definir, sem inventar um caminho paralelo; nenhuma segunda esteira de transcrição/classificação; estado da última execução é o único estado novo que este item cria. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — o recibo (período, contagens, falhas, custo/tempo) é insumo operacional de quem roda a skill, não superfície de usuário. +- **Decisões desbloqueadas:** N/A — a decisão é operacional: quando a comunicação precisa do acervo atualizado, quem opera roda a skill. +- **Forma:** N/A. + +## Dados da decisão (literais) + +- **Ideia do dono (verbatim, 2026-09-23):** "Crie uma skill que permita atualizar essa sessão fazendo um novo scraping a partir da data que foi feito o último [scraping]." +- Nome da skill: `catalogo-falas-web`; wrapper de comando: `/catalogo-falas-web`. +- Recorte temporal: **desde a data da última execução bem-sucedida**; sem data anterior, varredura inicial completa. +- Recibo (campos literais): período coberto, achados, novos, ignorados, falhas (com motivo) e custo/tempo. +- A análise automática (transcrição/classificação) é da ingestão (C215); a skill **pode** corrigir/curar o que a descoberta achou errado (ex.: falso positivo) antes de ingerir — nunca classifica faceta manualmente. +- Operação por agente/coordenação técnica; **sem UI**. +- Reexecutar não duplica nem reprocessa o que já está no catálogo. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `.agents/skills/catalogo-falas-web/SKILL.md` + wrapper fino `.opencode/commands/catalogo-falas-web.md`, no padrão das skills de conteúdo (`dossie-solla-{cidade,tema,instituicao}`, `briefing-capacitacao-solla`, `relatorio-cidade`, `reels-tutoriais`, `graficos-dados`); descoberta web por subagente com JSON datado, como o `research.json` dos dossiês. +- **Precedente a olhar:** `dossie-solla-cidade` (research por subagente + pastas `data/` gitignored + recibo curto datado), `reels-tutoriais` (`sourceHash` em `reelPackageIngest.ts`), import da Câmara com janela explícita (`pnpm camara:import --date`, `scripts/import-camara-speeches.mjs`, `scripts/lib/camaraSpeeches.mjs`, skip por estado em `speechImport.ts`). +- **Fatos verificados (a revalidar):** não há watermark de última execução no repo — o estado hoje é JSON por execução com `researchedAt`/`consultedAt`, recibos datados, saídas `-…` e changelog; a pesquisa web é feita por subagentes de skill (nunca por serviço do app — não há SERP no app nem yt-dlp no repo). +- **Risco de acoplamento:** não criar segunda esteira de ASR/classificação nem segundo estado de catálogo; a ingestão é a do C215 e a descoberta não compete com a varredura oficial do Instagram/YouTube (C211/C212) — a decisão de mecanismo é a do C215. + +## Dependências + +- **C215 (dura)** — sem a esteira de ingestão a skill não tem o que orquestrar. **C216/C217 não bloqueiam.** + +## Fora de escopo + +- A esteira de download/transcrição/classificação (C215), a tela (C216) e os cortes (C217). +- Paridade das gravações (C219); agendamento recorrente/infra de fila; monitoramento contínuo de redes. + +## Rabbit holes de produto + +- **"Virar serviço de monitoramento 24/7."** Se alguém "só completar": agendador, fila, alerta em tempo real. **Corte neste item:** rodada manual sob demanda; recorrência é conversa separada. +- **"Crawling irrestrito."** Se alguém "só completar": varrer a web inteira e perfis que não são do Solla. **Corte:** fontes/plataformas do escopo do C215, com queries pelo nome do deputado e variações. +- **"Segunda esteira de ASR/classificação."** Se alguém "só completar": transcrever e classificar dentro da descoberta. **Corte:** a skill entrega o lote; análise é do C215. +- **"Prometer cobertura exaustiva."** Se alguém "só completar": afirmar que nada escapou. **Corte:** o recibo declara período, achados e limites — o que ficou de fora é reportado, não escondido. + +## Questões em aberto (produto) + +- **Onde mora o estado da última execução?** **Opções:** A) arquivo gitignored em `data/` (padrão das famílias de skill) | B) registro em banco | C) derivar do próprio catálogo (última data importada). **Recomendação:** A — segue o precedente das skills de conteúdo e não cria schema; o formato exato é decidido na implementação. _(confirmado no gate, 2026-09-24)_ +- **Recorte temporal do incremental?** **Opções:** A) desde a última execução bem-sucedida | B) janela fixa (ex.: últimos 30 dias) com dedupe. **Recomendação:** A — "a partir da data que foi feito o último", na voz do dono; janela fixa reintroduz reprocessamento. _(confirmado no gate, 2026-09-24)_ +- **Quem aciona?** **Opções:** A) manual (humano/agente rodando a skill, como os dossiês) | B) agendado. **Recomendação:** A — agendamento recorrente está fora de escopo; quando atualizar é decisão de quem opera. _(confirmado no gate, 2026-09-24)_ +- **O que fazer com achados duvidosos?** **Opções:** A) a skill marca "revisar" e não ingere até confirmação | B) ingere tudo e a curadoria corrige depois. **Recomendação:** A — evita lixo no catálogo e é barato neste volume; o duvidoso aparece no recibo. _(confirmado no gate, 2026-09-24)_ +- **Fontes de descoberta v1?** **Opções:** A) mesmas plataformas do C215 (YouTube, Instagram, áudio/rádio), com queries por nome do deputado e variações | B) recorte menor, monitorando veículo a veículo. **Recomendação:** A — manter o escopo do C215; ampliar é item próprio. _(confirmado no gate, 2026-09-24)_ + +## Referências + +- GitHub Issue: — (após `pnpm agent:register`) +- Design UI (gate): N/A — sem UI +- Abrir primeiro: `.agents/skills/dossie-solla-cidade/SKILL.md` (padrão de research por subagente + recibo) e `.agents/skills/reels-tutoriais/SKILL.md` (ingestão idempotente por hash) +- `docs/plans/acervo-falas-web-ingestao.md` (C215 — mecanismo de descoberta/download e decisão sobre direitos) +- `scripts/import-camara-speeches.mjs` / `scripts/lib/camaraSpeeches.mjs` / `src/utilities/speech/speechImport.ts` — janela explícita e skip por estado +- `AGENTS.md` — convenções de skills do repo