Commit graph

1636 commits

Author SHA1 Message Date
Francisco Solla
331cb3aac7 docs(bug-fix): registra merge, deploy e verificação em prod do fix #1433
Some checks failed
Deploy / preflight (push) Has been cancelled
Deploy / verify (push) Has been cancelled
Deploy / deploy staging (teqo-staging) (push) Has been cancelled
Deploy / requeue when main advanced (push) Has been cancelled
Deploy / deploy production (teqo-1313) (push) Has been cancelled
2026-10-02 22:51:17 -03:00
Francisco Solla
8e32c7cee7 fix(storage): desliga checksum automático de upload no client S3 (Garage multipart) (C246-hotfix)
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
O adapter storage-s3 usa multipart acima de 50 MB e o Garage grava um x-amz-checksum-crc32 errado; o SDK valida no GET e toda leitura do objeto falhava (500 nas fotos 80/83, panorâmicas de 54 MB — conteúdo correto). requestChecksumCalculation: WHEN_REQUIRED no client do plugin; a leitura segue validando o checksum que o objeto tiver e a varredura de integridade segue como checagem honesta. Os dois objetos foram reescritos com PUT único (checksum correto) no ops: canário 2/2 e URLs públicas 200 com 53.762.718 bytes.
2026-10-02 20:01:24 -03:00
Francisco Solla
afc22e5bf3 docs(bug-fix): post-mortem e changelog das chaves AVIF presas no otimizador 2026-10-02 18:55:54 -03:00
Francisco Solla
c15f09531a feat(fotos): miniaturas AVIF pré-geradas do álbum público (C248)
Derivada AVIF 720px q60 armazenada como objeto-irmão determinístico de cada
foto aprovada (flickr-<id>-grade.avif), servida direto quando o cliente
negocia Accept: image/avif; fallback JPEG on-the-fly em ausência/falha, heal
preguiçoso via after(), warm no afterChange da aprovação e backfill
pnpm archive:thumbnails idempotente com recibo e guardas *_CONFIRM.

Sem migration, sem UI, sem mudança de URL pública ou pull-down.
Closes #1424
2026-10-02 17:40:41 -03:00
Francisco Solla
4feea40c01 docs(archive): verificação do canário por GET no runbook (HEAD não valida checksum) 2026-10-02 17:37:39 -03:00
Francisco Solla
255751f5ce fix(archive): teto de 15 min no download do reparo e caminhos do runbook (C246-followup)
O canário 80/83 abortou no download do Flickr: original de ~54 MB (panorâmica 7952px) a ~260 KB/s no link direto do homeserver leva ~3,5 min, acima do teto de 2 min herdado do C231. ARCHIVE_INTEGRITY_DOWNLOAD_TIMEOUT_MS vira 15 min (exportada e pinada no unit); falha de download segue failed retentável. Runbook §C246 usa ~/archive-reports (o /srv do texto original não existe/grava) e ganha docker pull do migrator (a limpeza pós-deploy remove a tag local).
2026-10-02 17:37:39 -03:00
Francisco Solla
a3a49c3462 feat(archive): preflight de integridade antes de aprovar drafts (C249)
O pnpm archive:publish passa cada draft elegível pelo inspectPrivateMediaObject do C246 (download pelo caminho da rota pública + decode sharp) antes de qualquer payload.update: objeto missing/corrupt fica fora do lote, é nomeado no recibo como skippedBroken (stage + motivo) e o comando sai 1 — no plan (read-only) e no apply. A fila seleciona filename além de id; o lote vira o seam exportado runArchivePublishBatch (temp por foto removido no finally) com guard isDirectRun, e o puro scripts/lib/archivePublishPlan.mjs ganha skippedBroken/skippedBrokenCount no summary e as linhas do recibo. scripts/publish-archive-photos.mjs entra no SCRIPTS_SPEC_PINNED (high-risk exato: unit/int full + e2e curado). Guardas do publish intactas; sem S3 num alvo não-local o probe classifica tudo missing (fail-closed). Sem migration, sem UI. Runbook C242/C246 e changelog atualizados; unit do summarize/format, int do lote real (íntegro aprovado, corrompido decode, removido missing, plan sem escrita) e impl plan em docs/plans/acervo-publish-preflight-integridade-impl.md.
2026-10-02 17:25:03 -03:00
Francisco Solla
ac39c81765 style(docs): separa as seções C244/C246 no runbook após o rebase
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-10-02 10:53:39 -03:00
Francisco Solla
dcf8e85a9d feat(archive): varredura e reparo de integridade do acervo no Garage (C246)
Adiciona a CLI pnpm archive:integrity: varredura read-only de todas as archivePhoto (download + decode pelo mesmo caminho da rota pública e do índice facial; sai 1 enquanto houver mídia quebrada approved) e --apply que re-ingere do Flickr pelo flickrId, substitui o objeto na mesma chave via payload.update filePath (sem tocar curadoria/status) e rebaixa a draft as irrecuperáveis (removed intocado).

Dono da leitura ganha inspectPrivateMediaObject e isPrivateMediaMissingError (S3 NoSuchKey/404 + ENOENT local; checksum nunca é missing); archivePhotoIngest ganha repairArchivePhotoObject e withdrawArchivePhotoFromPublic; decisão do reparo em scripts/lib/archiveIntegrityRepair.mjs com deps injetadas e puro de CLI/recibo em scripts/lib/archiveIntegrityPlan.mjs. Sem migration, sem UI. Guardas: ARCHIVE_INTEGRITY_CONFIRM + TEQO_ENV exato + 4 S3_* (em qualquer modo no alvo não-local) + FLICKR_API_KEY. Runbook C246, changelog e unit/int/e2e afetado.
2026-10-02 10:53:39 -03:00
Francisco Solla
930db3eb02 feat(C245): catalogar o acervo em produção por camadas — metadados primeiro
A catalogação do C232 nunca rodou em produção: catalog.* zerado nas 6.492
fotos publicadas e o engine de visão fora do ar. O pnpm archive:catalog
ganha --metadata-only: deriva município (gazetteer) e temas do texto já
ingerido, sem engine e sem mídia, grava catalog.metadataCheckedAt
(migration aditiva) e não marca catalogedAt — a fila da IA segue aberta.
Nunca escreve catalog.people (C244 assume a faceta por facial).

A passada de IA passa a carimbar os dois markers; a fila de metadados exclui
linha já catalogada pela IA (não rebaixa o source); o --verify relata as duas
camadas com exit pela selecionada; o --apply de metadados dispensa S3_* e
engine. Runbook §C245: metadados → revalidate archivePhotos → IA.

Closes #1417
2026-10-02 10:17:49 -03:00
Francisco Solla
539138db0a docs(ops): runbook e changelog do ops:global (C247) 2026-10-02 10:10:16 -03:00
Francisco Solla
269b3d9e3b feat(ops): CLI ops:global para flags de globais públicos (C247)
Grava um único campo do global via Local API e busta a tag no processo Next vivo pelo POST /api/revalidate (allowlist ampliada com REVALIDATE_PHOTO_ALBUM_CACHE_TAG), com guardas de escrita, plan/apply/verify, recibo com rollback e int pin do update parcial.
2026-10-02 10:10:16 -03:00
Francisco Solla
d8020607b9 docs(C244): impl plan, runbook, AGENTS-public e changelog 2026-10-02 09:35:43 -03:00
Francisco Solla
8a87f5f81b docs(plan): C248 — miniaturas AVIF pré-geradas do álbum público (Related #1424) 2026-10-02 09:24:47 -03:00
fsolla
048df6f828 docs: registra merge, verify e staging do fix #1415 no post-mortem
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-10-01 20:50:34 -03:00
Francisco Solla
ff969ec8e4 docs(bug-fix): registra o PR #1421 no post-mortem 2026-10-01 20:41:37 -03:00
Francisco Solla
3c3af5c6bc docs(bug-fix): post-mortem e changelog das imagens lentas da home 2026-10-01 20:41:37 -03:00
Francisco Solla
9a049bbbb4 docs(C244-C247): planos de intenção — filtro facial de pessoa pública, catalogação em produção, integridade do Garage e toggle de globais 2026-10-01 20:28:53 -03:00
fsolla
8db841f778 docs: registra o PR #1415 no post-mortem e no changelog 2026-10-01 19:38:07 -03:00
fsolla
14e0197df0 docs: post-mortem e changelog do verify (refresh do live preview x hash #novidades) 2026-10-01 19:38:07 -03:00
Francisco Solla
ab441d36df docs(changelog): S45 — cards verticais na Central de Conteúdos 2026-10-01 19:17:06 -03:00
Francisco Solla
fcc47bb111 docs(plan): S45 — plano de implementação e crítica visual do designer 2026-10-01 19:17:06 -03:00
Francisco Solla
0a8b0774d3 feat(S44): home divulga a Plenária da Vitória (agenda pré-live, embed ao vivo e kill switch)
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-10-01 17:47:30 -03:00
Francisco Solla
8d61b4183f docs(plan): S45 — central de conteúdos — cards verticais no catálogo e na seção da home (Related #1410) 2026-10-01 17:19:23 -03:00
Francisco Solla
33a1d10c09 docs(plan): S44 — Home — seção da Plenária da Vitória (divulgação e acesso) (Related #1408) 2026-10-01 15:24:24 -03:00
fsolla
94d1ca3364 docs: registra o PR #1407 no post-mortem e no changelog 2026-10-01 14:14:37 -03:00
fsolla
f2b5ec0e5c docs: formata o post-mortem do fix do verify (prettier) 2026-10-01 14:14:37 -03:00
fsolla
90768be1cf fix(e2e): clique no dia do calendário pelo contrato data-day — desbloqueia o verify (C104, miss #55)
O verify do deploy falhava nas 3 tentativas no e2e C104: o clique do dia
de término usava getByRole(name: "2 de Outubro de 2026"), e o matcher de
nome do Playwright é substring + case-insensitive — casava também os dias
12 e 22 do mesmo grid (strict mode violation) sempre que hoje+1 caía em
dia 01–09 do mês (02/10 no run de 2026-10-01).

O C104 passa a clicar via calendarDaySelector ([data-day="DD/MM/YYYY"], o
contrato do Calendar.tsx) e o guard miss #55 no e2eNavigationConventions
bane o padrão antigo em todos os specs, com teste do contrato do helper;
TESTING.md, changelog e post-mortem registram a miss.

Related #1406
2026-10-01 14:14:37 -03:00
Francisco Solla
cd4942d9e2 feat(C242/C243): abre a busca por selfie a qualquer visitante (escopo B) + seção na homepage
O escopo A/C do gate (PR #1370) é superado por decisão do dono (2026-10-01, aval jurídico declarado): o índice vira anônimo (archivePhotoFace, foto + descritor 128-d, sem nome/vínculo), o enrollment por pessoa morre (faceSubject/faces:enroll removidos) e qualquer visitante encontra as próprias fotos aprovadas.

- faces:index persiste os descritores por foto (transação substitui as linhas + marker = modelo); desaprovar/remover/deletar foto apaga os descritores (hooks + FK cascade)
- POST /api/fotos/selfie casa o vetor da consulta contra o índice em memória (TTL 60 s) e devolve só a interseção com o read aprovado do C233, sem score/nome de terceiro; leave-index apaga os descritores que casarem
- Consentimentos seguem fail-closed: busca-selfie-fotos (consulta) e busca-selfie-indice (aviso público do índice), textos versionados em scripts/lib/faceConsentTexts.mjs e provisionados por pnpm seed:face-consents
- pnpm archive:publish aprova o acervo em lote (draft -> approved; removed nunca) com guardas e recibo
- C243: seção condicional SelfieSearchHomeSection (port do design hi-fi, cenas 390/1280) entre a Central e a newsletter; sem engine/captura na home e sem CTA morto quando fechada
- docs: planos C242/C243, AGENTS-public, runbook §C242, changelog

Provas: gate:fast 457 arquivos/5.055 testes; int full 109/1.075; e2e frontendFotosSelfie 9/9; knip verde.
2026-10-01 12:54:47 -03:00
Francisco Solla
77e7b0efde docs(plan): S43 — Home — escolher o estadual da dobradinha, montar e compartilhar a colinha (Related #1404) 2026-10-01 12:41:44 -03:00
Francisco Solla
ca843fb4bb fix(C230): fallback da catalogação dá título semântico, não placeholder
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
Quando a sugestão por IA falhava (timeout de 8s) ou a peça não tinha
texto, o fallback preservava o título provisório `Instagram · <código>`
para sempre. Agora isContentPieceLinkTitle (dono em src/lib) identifica o
placeholder e o fallback gera título determinístico (tipo + cidade +
temas); o caminho sem texto faz o mesmo em vez de deixar o placeholder,
a sugestão da IA que ecoa o placeholder é descartada, e título editado
pela assessoria continua intocado.
2026-10-01 02:29:19 -03:00
Francisco Solla
3d269725f8 feat(C230): expurgo de peças fora do período eleitoral na Central
O rascunho pré-campanha que o --publish-existing ressuscita precisa sair
do catálogo de vez: o novo CLI content:instagram:prune faz hard delete da
peça e da mídia privada (linha, arquivo e still do C226), então uma
importação futura não a recria. Compartilha o mesmo núcleo de corte da
retirada (data civil na Bahia, peça sem data no feed nunca é tocada) e
espelha as guardas dos irmãos: --before obrigatório, TEQO_ENV casando o
nome exato do banco, CONTENT_INSTAGRAM_PRUNE_CONFIRM=1 e recibos JSON.

Testes: planejador/parser/recibo em unit e guardas do CLI em subprocesso.
Runbook e changelog atualizados.
2026-10-01 02:29:19 -03:00
Francisco Solla
20d3781e4b docs(C240): plano + design hi-fi — carrossel do Instagram como conteúdo de primeira classe (Related #1399) 2026-10-01 01:44:27 -03:00
Francisco Solla
449ef72190 fix(S42): corpo do card da home com min-w-0 (paridade com o artefato)
Some checks failed
Deploy / preflight (push) Has been cancelled
Deploy / verify (push) Has been cancelled
Deploy / deploy staging (teqo-staging) (push) Has been cancelled
Deploy / requeue when main advanced (push) Has been cancelled
Deploy / deploy production (teqo-1313) (push) Has been cancelled
Crítica visual (trigger c, tier gpt-5.6-sol): o título longo em 390 px
precisava da coluna do grid sem min-width intrínseco para quebrar como na
referência. Capturas da crítica certificada em
docs/plans/central-conteudos-secao-home-share-filtro-ui-design-critique/.
2026-09-30 01:09:07 -03:00
Francisco Solla
862da74fbe feat(S42): seção da Central compartilha a peça e abre /conteudos já filtrada
A seção S39 era só vitrine: quem via a peça do seu território tinha de ir
até o catálogo para compartilhar ou recortar. O card agora abre a MESMA
folha do S27 (mensagem de voto por tipo, contador C213, sem sair da home) e
as tags com faceta honesta — mais a fileira Tipo | Cidade | Região — levam
a /conteudos já filtrada pelo construtor canônico; nada filtra a amostra
local e as tags sem faceta (Mais recente, origem) continuam estáticas.

As facetas da fileira são derivadas no server (contentPieceCatalogFacets,
mesmo vocabulário do catálogo) e o lean ContentPieceHomeItem ganha só
sourceUrl, com a folha S27 estreitada ao que lê; classes novas são
home-scoped — CONTENT_PIECE_TAG e /conteudos ficam intactos. Sem migration,
Consent ou analytics novos.

Closes #1391
2026-09-30 01:09:07 -03:00
Francisco Solla
3201b7a93f feat(C237): vetor da fala inclui o sumário/keywords oficiais
A Fase 5 pós-deploy do C229 mediu o corpus real e o aceite 'impeachment'
falhava: a 222 (votação do impeachment de Dilma, 17/04/2016) ficava em #841
porque o índice só embutia o ASR — e a fala nunca pronuncia 'impeachment';
a relevância dela mora no sumário/keywords oficiais da Câmara.

O plano do índice passa a carregar metadataText (sumário — ou título no web
— + keywords, incluído no hash de idempotência) e o vetor da fala vira
normalize(média das unidades + 2·metadata), calibrado no corpus real
(w=2: 222 em #8; w=1: #25). A metadata é vetorizada no mesmo lote do
provedor mas não vira unidade armazenada nem evidência; sem migration.

Related #1395
2026-09-29 22:53:41 -03:00
Francisco Solla
5eb8fd75ef feat(C230): lote da Central — publicar rascunhos da janela e retirar pré-campanha
--publish-existing no content:instagram:import (publica rascunhos prontos da
janela, mais antigo primeiro) e CLI novo content:instagram:withdraw (despublica
por corte civil na Bahia, com as datas vindas do feed oficial). Plumbing
compartilhado dos dois em scripts/lib/instagramContentCli.mjs; teto do feed
passa ao da edge (10K) com early-stop por data; guardas C155/C195/C231, testes
unit das guardas e do planejador, runbook e changelog.
2026-09-29 22:51:25 -03:00
Francisco Solla
39933fc004 feat(C237-C239): colunas emparelhadas e motion determinístico no gerador de gráficos
- C237 (CENA 02F): --paired desenha duas colunas zero-based por categoria
  (inicial cinza, recente vermelha, valência positiva compartilhada), com
  legenda de períodos, valor sobre cada barra e rótulo sob o par; até 4
  categorias; design DEGRADED com sign-off humano de 2026-09-29.
- C238/C239 (CENAS 02G/02H): --motion gera MP4 H.264 local (6s @ 30fps,
  frames determinísticos por seek + ffmpeg do repo) para o par emparelhado,
  a coluna de 2 períodos e o número-âncora; C238 com sign-off humano de
  2026-09-30 e C239 aguardando gate.
- Superfície: CLI, SKILL.md, hi-fi e specs novos (chartMotion/
  chartMotionRender; SCRIPTS_SPEC_PINNED sincronizado).

Design tier: DEGRADED (inline, tier 4 — frontier sem quota).
2026-09-29 22:37:02 -03:00
Francisco Solla
10327a7451 feat(C236): publicar, despublicar e apagar em lote na Central de Conteúdos
A lista /campanha/comunicacao/conteudos ganha um modo de seleção opt-in
que envolve os dois corpos (tabela e card list) com um estado client
compartilhado, chaveado pela URL canônica (a seleção morre em
página/filtro e nunca cresce para além da página visível). Com seleção
ativa, a barra flutuante aplica o mesmo veredito unitário à seleção:
Publicar/Despublicar agem direto com recibo honesto; Apagar sempre
confirma no CampaignDeleteDialog reusado (novo caminho onConfirm
aditivo), avisando os links públicos só quando a seleção carrega
publicadas.

O transporte é uma rota única (POST .../conteudos/lote,
campaignJsonMutationRoute, teto de 50 ids) que itera server-side as ações
donas: cada peça mantém a própria transação, o gate fresco e a limpeza
best-effort de mídia; a falha de uma nunca reverte as demais e o recibo
separa afetadas x falhas (2 de 3 peças apagadas. 1 falhou.).

Sem migration, sem Consent novo, sem rota pública (S27) e sem mudar a
semântica do C222. Cobertura: int do lote (papéis, dedupe, mídia, evento,
tag, falha parcial, schema), unit do builder/barra/seleção e e2e HTTP.

Design tier: DEGRADED (artefato de origem sem certificação frontier) —
crítica do designer aplicada no escopo do item; entrega bloqueada para
sign-off humano antes do PR. Related #1388
2026-09-29 22:26:26 -03:00
Francisco Solla
ce055ad3d8 docs(plan): S42 — Home — seção da Central de Conteúdos: compartilhar a peça no card e filtro que abre /conteudos já filtrado (Related #1391) 2026-09-29 22:05:43 -03:00
Francisco Solla
8608aeb317 feat(C235): importa qualquer janela de publicações do perfil na Central
A importação do perfil oficial deixa a janela fixa de 12 mídias e ganha o recorte por período (desde; até opcional), com prévia honesta (novas · já estavam · total) e confirmação antes de criar; "Recentes" segue o default e o clique único. O planner puro de janela/dedupe passa ao dono em src/lib (CLI re-exporta) e a varredura usa o teto de páginas derivado de maxResults, com early-stop por data e corte denunciado (truncated). Sem migration/Consent; tudo Rascunho; fail-closed de credencial intacto.

Design tier: DEGRADED (central-conteudos-importar-janela-ui-design) — port classe-a-classes das cenas 01–08 com sign-off humano explícito (2026-09-29); a crítica de paridade do designer no tier primário não pôde rodar por quota.
2026-09-29 13:23:01 -03:00
Francisco Solla
fa1bf52ccd style(plan): C236 — formata design HTML para o gate de push (Related #1388) 2026-09-29 11:06:57 -03:00
Francisco Solla
90a9d0039a docs(plan): C236 — Central de Conteúdos publicar/despublicar/apagar em lote (Related #1388) 2026-09-29 11:06:57 -03:00
Francisco Solla
5a3fec1e78 style(C235): formata o plano e o design hi-fi com prettier 2026-09-29 10:34:13 -03:00
Francisco Solla
432d5a10e2 docs(C235): plano + design hi-fi — importar qualquer janela de publicações do perfil (Related #1386) 2026-09-29 10:34:13 -03:00
Francisco Solla
35eb2ed432 feat(C230): importação em lote do Instagram para a Central (CLI)
CLI operacional `content:instagram:import`: lê o feed oficial do perfil,
filtra a janela por dias (default 60), deduplica pela identidade do post e
processa cada novidade inline pelo pipeline C220 (download, transcrição,
catalogação); --publish publica ao final o que terminou pronto, mais antigo
primeiro, e revalida a Central pública. Guardas C155/C195/C231 (TEQO_ENV +
nome exato do banco, confirmação explícita, S3_* obrigatórias, dry-run padrão).
2026-09-29 09:51:46 -03:00
Francisco Solla
ad2b165e5e fix(C231): EXIF do acervo volta ao mapper e ganha backfill --refresh-metadata
A API do Flickr responde raw/clean como { _content } e o mapper só aceitava
string — as 6.492 fotos do backfill gravaram exif: []. archivePhotoExifEntries
desembrulha os dois shapes (contentScalar também substitui o unwrap ad-hoc do
description) e o CLI ganha o modo --refresh-metadata, que re-busca o EXIF das
linhas existentes e atualiza só o que mudou: write-only no campo exif, sem S3,
guardas de confirmação/TEQO_ENV e recibo atualizadas/inalteradas/falhas.
Runbook §C231 documenta a operação. Closes #1383.
2026-09-29 09:11:49 -03:00
Francisco Solla
59a6480df8 docs: registra o PR #1382 no post-mortem e no changelog
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-28 19:36:12 -03:00
Francisco Solla
722cd6cf94 fix(C199): upload de gravações fatiado em 16 MiB — escapa do 413 do edge
O diálogo "Enviar gravação" mandava o arquivo inteiro num único XHR e a
produção vive atrás do Cloudflare Tunnel, cujo edge responde 413 para
qualquer request body acima de ~100 MB ANTES do app ver o corpo (probe
read-only: POST de 150 MB cortado após ~3,2 MB). Um .mp4 de 6 GB de
plenária nunca chegava à rota — o C199-large havia removido só o teto do
app, não o do proxy.

O upload agora é fatiado ponta a ponta: o start bodyless cria a row e a
sessão em disco (`recording-upload-<id>` com estado + arquivo anexado), o
diálogo envia partes de 16 MiB em ordem estrita com progresso agregado e
o último byte do tamanho declarado finaliza a mídia privada e o job. Cada
parte faz heartbeat do `updatedAt` contra o reaper de 1 h, o start faz
preflight de disco (statfs + margem), falha de parte aborta a sessão e o
delete do usuário/reaper limpam o diretório. Sem migration e sem schema.

Regressão: protocolo int nas rotas start/chunk/abort (multi-parte, fora
de ordem, tamanho excedido, seam multipart, falha S3, reaper), guarda
unit do orçamento do edge, guardas e2e das rotas. Post-mortem e entrada
de changelog em docs/.
2026-09-28 19:36:12 -03:00
Francisco Solla
9e9864f420 feat(C234): busca por selfie no álbum público — índice A/C consentido, selfie on-device
- /fotos/encontre + POST /api/fotos/selfie: só o vetor 128-d, sem imagem, sem score e
  sem nomes de terceiros; fail-closed pela flag photoAlbum.selfieSearchEnabled (default
  false) e pelos Consents por chave estável (busca-selfie-fotos/busca-selfie-indice, não
  seedados — a superfície nasce fechada até o aval jurídico/DPIA).
- Índice A/C do gate (PR #1370): só quem aderiu é indexado; descriptors do acervo são
  transitórios. Collection faceSubject (admin-only, sem vínculo com Contact), vínculos
  matchedPhotos e marker faces.checkedKey no archivePhoto (modelo + enrolledAt).
- Engine @vladmandic/face-api nos dois lados: browser lazy com modelos same-origin
  (copy-face-vision-assets no prebuild/predev/Docker) e CLI node-wasm sem tfjs-node.
  CLIs ops-only faces:enroll / faces:index --apply|--verify com guardas C231/C232.
- Opt-out self-service por reconhecimento (leave-index) + canal de remoção do C233;
  rate limit próprio (namespace selfie:<hash>) e bounded body extraído do beacon.
- UI portada classe-a-classe do design estendido (paridade certificada, tier primário);
  e2e frontendFotosSelfie (manifest+curado+projeto, engine stubada) e canário do engine
  real; runbook §C234, contrato em AGENTS-public.md e changelog.
- Migration aditiva add_face_subject (SQL revisado); hard-stops aprovados na sessão.
2026-09-27 20:04:41 -03:00