Commit graph

851 commits

Author SHA1 Message Date
Francisco Solla
e08b9c497c feat(S18): cabeça do visitante proporcional à dos candidatos no card Time de você
- FaceDetector (blaze_face_full_range, Apache-2.0, lazy/on-device) mede o maior rosto no canvas do recorte; math pura frameCardPhotoOnFace escala a face à referência TEAM_CARD_FACE_REFERENCE_SIZE=103 (mediana das 5 caixas da arte-mestre).
- Piso do time CARD_TEAM_PHOTO_MIN_ZOOM=0.2 com clamp contain/cover por eixo (minZoom opcional preserva os 3 modelos S13/S14); fallback silencioso ao enquadramento S15 sem rosto/falha.
- Stub e2e estendido ('noface'); unit novo da math e da seleção do rosto; craft com retrato real 86-98px vs 103 (±20%); crítica Tier 1 certificada.

Closes #1197
2026-09-19 13:22:09 -03:00
Francisco Solla
dbd9ecdfd4 feat(S16): banner azul dinâmico no card "Time de você" — nomes longos cabendo (Closes #1195) 2026-09-19 13:05:52 -03:00
Francisco Solla
0d6518c3d1 feat(C200): separar falas por pessoa nas gravações enviadas (Closes #1167) 2026-09-19 12:32:46 -03:00
Francisco Solla
d7d4258cd7 feat(S17): controle "Harmonizar cores" no ready do card Time de você
Ajuste local de brilho/contraste/saturação (clamps fixos ≤12%, alpha byte-a-byte) para aproximar a selfie do tom da arte-mestre; variante gerada 1× no ready do useCardCutout e escolhida pelo toggle no mesmo canvas da prévia e do PNG. Sem migration/Consent/rede/persistência; os 3 modelos e o recorte intocados. Crítica do designer certificada no tier primário (artefato revalidado sem DEGRADED).
2026-09-19 10:55:18 -03:00
Francisco Solla
d0f606a55d feat(C199): gravações enviadas no acervo de comunicação (Closes #1166) 2026-09-18 23:42:30 -03:00
Francisco Solla
a8a5ed324f
C195 — Ingestão do pacote do reel na biblioteca privada (#1182)
C195 — Ingestão do pacote do reel na biblioteca privada
2026-09-18 22:30:57 -03:00
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
7079c63949 Merge remote-tracking branch 'origin/main' into C195-ingestao-do-pacote-do-reel-na-biblioteca-privada
# Conflicts:
#	src/lib/reel.ts
2026-09-18 22:01:32 -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
5afa16c33b feat(C195): ingestão do pacote do reel na biblioteca privada (Closes #1154) 2026-09-18 21:47:48 -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