Commit graph

843 commits

Author SHA1 Message Date
Francisco Solla
560f2e494a feat(S15): card "Time de você" — quarto modelo auto-serviço no funil público (Closes #1161) 2026-09-18 22:17:52 -03:00
Francisco Solla
7e164b637d fix(C194): port fiel ao artefato após crítica do designer (#1153)
- player mobile 226px (CTA do detalhe acima da dobra), 330px a partir de lg
- painel de downloads no mobile: CTA primário primeiro, 'Outros arquivos' depois
- cards mobile só com título/funcionalidade; data e 'Abrir reel' a partir de lg
- despublicado: aviso + publicação antes da mídia bloqueada; 'Sobre o reel' depois
- feature sem '(#cards)' na UI e data de publicação só com o dia
- 'Abrir reel' aria-hidden (o card inteiro é o link)

Design tier: openai/gpt-5.6-sol — crítica final certificada (v3, 10 capturas).
2026-09-18 21:54:37 -03:00
Francisco Solla
448f3845a2 feat(C194): biblioteca de reels na vertical Comunicação (#1153)
Lista publicados-only com capas 9:16, detalhe com player 9:16 e painel de
downloads (vídeo sem áudio primário; com áudio, mp3 e .srt quando existem;
transcrição em texto) e kill switch reversível: despublicar tira da lista e
bloqueia a mídia (C193 decision B), republicar reativa e re-carimba publishedAt.

Fiação: gate communicationCatalog (rename do speechCatalog), 3º sub-item da
vertical no nav, rule da lista no chrome, paths e loader próprios; sem
migration, sem Consent, sem tocar Media.read ou a rota de mídia do C193.

Design tier: DEGRADED — crítica final do designer indisponível no tier
primário (limite de uso); requer sign-off humano antes de push/PR.
2026-09-18 21:54:37 -03:00
Francisco Solla
c7d1fd29cc fix(C193): renomeia referência perdida do predicado da vertical de comunicação (Related #1152) 2026-09-18 18:52:38 -03:00
Francisco Solla
bdaf3c7cbb feat(C193): reel privado no CMS — modelo, upload privado e kill switch (Closes #1152) 2026-09-18 17:48:34 -03:00
Francisco Solla
45eef25b1a feat(C192): busca semântica no acervo de falas (Closes #1147)
Modo "Por tema" no acervo de falas: expansão determinística do tema via
DeepSeek (generateObject, timeout, fallback null) alimenta o motor lexical
existente (searchText/keywords OR), mantendo facetas AND, paginação por fala,
o OR de cortes do C174 e o access control intacto. Resultado de tema mostra
selo e "Por que apareceu" com trecho real (frase contínua), sem score;
degradação honesta para termo exato com aviso e vazio honesto com saídas.

- URL: mode=tema (default omitido; canonicaliza sem q), seletor otimista
- ai/expandSpeechSearchTheme + lib/speechThemeTerms (sanitiza saída do modelo)
- view model com themeMatchTerm + espelho speechMatchesSearchTerm
- UI do card de tema (selos, proveniência, ações) e aviso degradado
- sem migration/Consent/exposição pública; gate de leitura inalterado
- testes unit/int/e2e; design hi-fi estendido e certificado pelo designer
2026-09-18 17:48:28 -03:00
Francisco Solla
e5e1ae7ee8 feat(C190): dossiê Solla por tema/área + boletim modelo (skill + builder)
Terceira variante da família de dossiês: recorte pela área canônica do
acervo (SPEECH_TOPICS), com o pipeline C186/C187 generalizado para a forma
subject via THEME_UNIT (generalização aditiva; C186/C187 byte-idênticos).

- resolveSpeechTopic no dono speechFacets (fail-closed, sem slug inventado)
- themeSnapshot + extract-theme-snapshot (THEME_REPORT_CONFIRM=1, read-only)
- build-dossie-solla-tema (pack medido, PDF A4 + .md + boletim 1 página)
- skill/comando/2 subagentes (researcher por era + redator) + specs
- cenas theme-only no descritor (acervo universo/amostra, abrangência,
  lacunas, hierarquia de fontes, pills do boletim) certificadas pelo designer

Closes #1143
2026-09-18 17:02:56 -03:00
Francisco Solla
cb5854d17e feat(C187): dossiê Solla por instituição + boletim modelo (skill + builder) (Closes #1135)
Generaliza aditivamente o pipeline C186 (default município; specs verdes) via o
descritor scripts/lib/dossieUnit.mjs (municipality|institution), extrai o emit
A4/fit-guard para scripts/lib/buildPdf.mjs e a receita read-only para
scripts/lib/readOnlyExtract.mjs.

- Catálogo fail-closed src/lib/institutionCatalog.ts + institutionNameAliases.ts
  (seed UFBA/Correios/Enfermagem; escape one-off --slug/--name; dedup).
- Skill/command/subagente /dossie-solla-instituicao; eras A/B/C reusadas.
- Abrangência instituição × setor × rede nunca somada; era sem fonte vira página
  de lacuna explícita; lista capada declara "e mais N" (regra C188 no dono).
- Boletim modelo 1×A4 com fase junto ao valor, sem fontes, sem CTA; herda apenas
  fatos com fonte do dossiê (incl. falas do acervo read-only).
- Sem schema/migration/DB write; artefatos gitignored.
2026-09-17 19:25:13 -03:00
Francisco Solla
f70c5e2d0b refactor(C179): helper único da URL do thumbnail do YouTube (Closes #1093) 2026-09-17 01:30:43 -03:00
Francisco Solla
f8b0d5ecac feat(C173): pré-visualizar no player o trecho selecionado (Closes #1083) 2026-09-16 22:22:29 -03:00
Francisco Solla
b1beb07f2a fix(C182): acervo mostra o frame do meio de cada fala, não a capa da sessão (Closes #1104) 2026-09-16 21:42:36 -03:00
Francisco Solla
a84c0183b1 B203 — Sollinha começa fechado no desktop (Closes #1107) 2026-09-16 21:08:25 -03:00
Francisco Solla
20d2f03226 fix(C181): player do acervo volta a ter o YouTube in-page e espera a Câmara gerar o trecho
- restaura o embed do YouTube como superfície opt-in no SpeechDetailPlayer
  (a Câmara segue a entrada padrão; o embed nunca é a porta automática, guardrail C178)
- controle simétrico "Assistir no YouTube"/"Assistir na Câmara" no bloco de saída,
  com o ponto da fala preservado na troca (pendingSeekRef/youtubeStart)
- SPEECH_VOD_PLAYER_POLICY passa a pollAttempts: 2 / pollDelayMs: 3000 — espera
  bounded dentro do clique em vez de tratar o primeiro GERANDO como falha
- unit do resolver (pin + GERANDO→PRONTO) e do player (ida-e-volta + ponto);
  pin SSR do e2e mantendo o embed fora do HTML inicial

Closes #1103
2026-09-16 21:08:01 -03:00
Francisco Solla
9de601b7aa feat(C183): apaga um corte da biblioteca e recupera cortes falhados (Closes #1105) 2026-09-16 20:34:12 -03:00
Francisco Solla
42f2f0ecaa fix(C180): select enxuto dos loaders, teto do id in da origem e paridade busca↔VM (Closes #1097) 2026-09-16 20:27:36 -03:00
Francisco Solla
5f64321cc5 fix(C177): "Abrir fonte" do acervo só com fonte oficial (Closes #1087) 2026-09-16 20:06:18 -03:00
Francisco Solla
4b3bee7c7d fix(C172): player e link abrem no ponto certo da fala (Closes #1082) 2026-09-16 19:33:04 -03:00
Francisco Solla
b378e1a91d fix(C178): player do acervo nunca abre a parede de signin do YouTube — Câmara vira default e YouTube só a saída externa (Closes #1081) 2026-09-16 19:08:00 -03:00
Francisco Solla
f066bee92b feat(C174): encontrar cortes — navegação, na fala e na busca (Closes #1084)
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
2026-09-16 12:58:40 -03:00
Francisco Solla
01be1de7be feat(C176): página pública do corte — revisão de design (Closes #1086)
Corrige o fundo tintado (gradiente do body herdado de :root) com um
layout de segmento `data-theme="editorial"` + scroll interno, espelhando
`[type]/layout.tsx`, e porta o gate aprovado: vídeo herói, título à
esquerda, meta em relógio, prosa medida, kit WhatsApp-first responsivo,
secundárias em grade no mobile e estado indisponível redesenhado.

Extrai os botões do share kit no próprio dono (acervo/biblioteca
inalterados) e adiciona o guard e2e `data-theme="editorial"`.
2026-09-16 12:36:55 -03:00
Francisco Solla
d199c6b006 feat(C175): miniatura do trecho na listagem de falas (Closes #1085) 2026-09-16 12:36:35 -03:00
Francisco Solla
ed9dfd3e85 fix(C171-F1): troca para a Câmara preserva o ponto clicado na transcrição (Closes #1052) 2026-09-15 23:50:24 -03:00
Francisco Solla
046b51e38b fix(C169): corte do acervo resolve o trecho com a Câmara instável e falha dizendo o porquê (Closes #1045) 2026-09-15 22:37:41 -03:00
Francisco Solla
83f30dfc82 fix(C171): player do acervo toca ou oferece a saída em um clique — nunca beco de signin (Closes #1047) 2026-09-15 22:27:28 -03:00
Francisco Solla
c010cf815b feat(C170): acervo sem teto de corte — 5 s até o fim da fala (Closes #1046) 2026-09-15 22:17:01 -03:00
Francisco Solla
28c3b3a0fe fix(B32-B34-F1): clamp nunca esconde todos os chips + key warning do head (Closes #1042) 2026-09-15 21:55:30 -03:00
Francisco Solla
8dece9cd32 fix(C165-F1): fecha município nulo/fora da carteira no access de update da atividade (Closes #1030)
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
2026-09-15 13:48:17 -03:00
Francisco Solla
2e2813fe8c fix(C168): reconhece o 404 do /corte/<id> pelo status, não por instanceof
No build de produção o erro do findByID atravessa a fronteira de módulo e o\ninstanceof APIError falha, virando 500 no id inexistente (pego no e2e do CI).\nO contrato é o status: 404 = não encontrado -> notFound(); o resto falha alto.
2026-09-15 12:56:51 -03:00
Francisco Solla
77216481d8 feat(C168): biblioteca de cortes no acervo (origem, download, compartilhar, editar texto)
Lista + detalhe em /campanha/comunicacao/acervo/cortes: busca por título/descrição,\norigem da fala, player do MP4, edição de título/descrição e kill switch de\npublicar/despublicar no mesmo /corte/<id>. Gate speechCatalog fail-closed para\nadvisor/leader. Sem collection/migration nova.
2026-09-15 12:56:51 -03:00
Francisco Solla
897154b58b feat(campaign): C165 — importa eventos do Google como atividades sem município (Closes #1010) 2026-09-15 11:54:21 -03:00
Francisco Solla
352801853f feat(C167): corta o trecho [início,fim] do acervo e publica o arquivo numa página compartilhável
Seleção do C166 ganha "Cortar vídeo": título/descrição por IA (editáveis, com fallback determinístico), job assíncrono com ffmpeg por re-encode exato e polling dos quatro passos, e página pública unlisted /corte/<id> (noindex, OG, crédito CC BY) servindo o mesmo MP4. Collection speechCut com access canReadSpeechCut (advisor/leader negados) e kill switch por status; ffmpeg entra só no runner da imagem com FFMPEG_PATH para teste.
2026-09-15 10:24:36 -03:00
Francisco Solla
bbd147fffb fix(C163): vídeo do acervo ancorado no trecho da Câmara, com folga 2026-09-15 10:24:27 -03:00
Francisco Solla
68efa6eef6 fix(C163): vídeo do acervo abre no início da fala (speechAt − sessão) 2026-09-15 10:24:27 -03:00
Francisco Solla
93416cd5ef feat(C166): seleciona trecho do acervo e compartilha link no ponto + WhatsApp (#1013) 2026-09-15 07:51:44 -03:00
Francisco Solla
0c0725835b feat(B202): totais do recorte no rodapé da lista de municípios (Closes #1005) 2026-09-15 07:37:45 -03:00
Francisco Solla
fc6846ebea fix(C164): registra canal de push normalizando expiration string na borda
O events.watch serializa o expiration (int64 epoch ms) como string JSON;
o client tipava number|null e o motor lancava RangeError: Invalid time
value no new Date(...).toISOString(), gravando pushChannelError sem
persistir o canal.

- parseGoogleWatchExpiration (borda do client) normaliza string|number
  para number|null com teto do range do Date; malformado cai no fallback
  de PUSH_CHANNEL_TTL_SECONDS, nunca lanca.
- pushChannelError ganha a causa do fetch (error.cause) preservada no
  teto de 500 chars.
- Unit: stub de transporte modela /watch (string real) + matriz do
  parser; int: caminho number->ISO, fallback null->now+TTL e causa.

Closes #1009
2026-09-15 06:52:50 -03:00
Francisco Solla
6854ede261 refactor(C162): dono único da elegibilidade VOD, start inicial do YouTube e mídia em early-returns (simplify) 2026-09-14 07:09:58 -03:00
Francisco Solla
940e32e28d fix(C162): mantém CamaraVodVideo interno (knip exports:error) 2026-09-14 07:09:58 -03:00
Francisco Solla
fbe67f0358 feat(C162): player do acervo resolve o trecho sob demanda e YouTube vira default (Closes #999) 2026-09-14 07:09:58 -03:00
Francisco Solla
dd8daa2420 feat(C159): Sollinha na assessoria de comunicação — chat escopado ao acervo (Closes #983) 2026-09-14 05:45:28 -03:00
Francisco Solla
e7369839aa feat(C160): link oficial do acervo vira PDF direto do Diário (#988)
- puros: classify/parse da URL legada (dc_20b/dc_20, montaPdf), build do PDF
  direto com #page, cache key por publicação, plano de reparo e fallback
- camaraFetch: resolveOfficialPdfUrl segue o redirect via .leg.br (fail-closed)
  e probeLink generalizado (Range + contentType)
- import: normaliza officialTextUrl no write path (cache <out>/diario por
  publicação; falha preserva PDF direto anterior, senão null)
- novo modo --repair-links [--dry-run] com guard CAMARA_IMPORT_CONFIRM fora de
  alvo local, relatório de cobertura e idempotência
2026-09-14 05:00:18 -03:00
Francisco Solla
9928fb183e feat(C158): Sollinha sugere trechos de falas do acervo para vídeos (Closes #982) 2026-09-14 03:41:59 -03:00
Francisco Solla
4f5f32dfef refactor(C155): simplify pós-review — backoff no camaraFetch, runLegislature e ajustes de guard/relatório 2026-09-14 01:54:55 -03:00
Francisco Solla
aa540ba9e1 feat(C155): backfill 54ª–57ª com cobertura por legislatura, guard de escrita e verificação de VOD 2026-09-14 01:54:55 -03:00
Francisco Solla
3e062749fa feat(C154): vertical de comunicação — papel communicator e acervo pesquisável
Papel communicator com nav própria e gate speechCatalog; acervo em
/campanha/comunicacao/acervo com busca normalizada (destaque no trecho),
filtros de ano/tema/alcance/fase/município/duração em URL canônica e
paginação por discurso via speech.searchText (GIN trgm + backfill).
Detalhe com player nativo no trecho, transcrição clicável, baixar/abrir
fonte e fallback sem VOD. Resolve o débito do C153 (Sollinha fora da
vertical) e corrige o parser de keywords oficiais no dono.

Closes #956
2026-09-13 13:46:58 -03:00
Francisco Solla
7ca708a3cb fix(C153): colisão de sourceKey, match de município e reclassificação limpa
Chave sufixada por hash de conteúdo para falas distintas que compartilham
data/tipo/fase (caso real 2026-06-17T17:16); keywords oficiais deixam de
alimentar o gazetteer de lugares; nomes ambíguos (Saúde, Wagner, Santana...)
exigem contexto de lugar; teste de nav do communicator; plano com prova viva
e changelog.
2026-09-13 02:08:55 -03:00
Francisco Solla
aca3ea6188 feat(C153): catálogo de falas do Solla — schema, access, import idempotente e busca
Collections speech/speechSegment no grupo Comunicação, papel communicator
(leitura restrita) e índice trigram normalizado para a busca por segmento.
Import idempotente da Câmara (discurso→evento→trecho→VOD→ASR) com facetas
gazetteer+LLM, proveniência e preservação de curadoria manual; parser de
quem presidia; reusa a lógica pura do piloto C152 via scripts/lib.

Related #955
2026-09-13 02:08:55 -03:00
Francisco Solla
b03b7bd969 feat(OPS103): staging no homeserver com verify único e aprovações separadas (Closes #968) 2026-09-12 22:48:22 -03:00
Francisco Solla
8e0366d3ba feat(S14): cards personalizados — ajustes de fidelidade e experiência
A home abre o mesmo compositor do /cards ali mesmo (dialog no desktop,
drawer no mobile) e perde o CTA: os três modelos viram botões e nada
navega. A seção sobe para imediatamente antes da captura de novidades.
O nome no card e no tile alinha à esquerda com o SOU (x=213) via leftX
+ drawCardName extraído; o tile passa a desenhar SEU NOME com o próprio
pipeline real (canvas transparente sobre a base). Modal sem o vão
interno (p-0 sm:p-0) e ajuda legível no tema campaign-site
(--muted-foreground). Remove a variante link e o cardModelHref sem call
site. Unit atualizado (+ drawCardName) e e2e com alinhamento por pixel;
sem migration, sem PII em rede.
2026-09-12 21:01:15 -03:00
Francisco Solla
7990c79b3e refactor(campaign): C150 — simplify (catch/sessão do picker, leitura única, webcal morto) + changelog e débito C156 2026-09-12 21:01:12 -03:00