From 9a049bbbb409fc263d96d070b9b6eda42dc9d1c5 Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Thu, 1 Oct 2026 19:48:56 -0300 Subject: [PATCH] =?UTF-8?q?docs(C244-C247):=20planos=20de=20inten=C3=A7?= =?UTF-8?q?=C3=A3o=20=E2=80=94=20filtro=20facial=20de=20pessoa=20p=C3=BAbl?= =?UTF-8?q?ica,=20cataloga=C3=A7=C3=A3o=20em=20produ=C3=A7=C3=A3o,=20integ?= =?UTF-8?q?ridade=20do=20Garage=20e=20toggle=20de=20globais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/acervo-integridade-garage.md | 72 +++++++++++++++++++ docs/plans/album-catalogacao-producao.md | 75 ++++++++++++++++++++ docs/plans/album-pessoa-facial.md | 86 +++++++++++++++++++++++ docs/plans/ops-toggle-globais-publicos.md | 69 ++++++++++++++++++ 4 files changed, 302 insertions(+) create mode 100644 docs/plans/acervo-integridade-garage.md create mode 100644 docs/plans/album-catalogacao-producao.md create mode 100644 docs/plans/album-pessoa-facial.md create mode 100644 docs/plans/ops-toggle-globais-publicos.md diff --git a/docs/plans/acervo-integridade-garage.md b/docs/plans/acervo-integridade-garage.md new file mode 100644 index 00000000..cecbbfbe --- /dev/null +++ b/docs/plans/acervo-integridade-garage.md @@ -0,0 +1,72 @@ +# C246 — Integridade do acervo no Garage: achar e recuperar as fotos quebradas + +Status: rascunho +Atualizado em: 2026-10-01 +Issue: #1418 +Priority: P2 +Impeccable: A — sem UI +Design UI: N/A — sem UI +Appetite: ~0,5–1 dia eng + ops; um outcome verificável — nenhuma foto pública serve mídia quebrada +Responsável: — + +## Intenção + +Ao publicar as 6.492 fotos (C242) e indexar os rostos, apareceram objetos corrompidos no bucket: as fotos **80** e **83** falham o download com _checksum mismatch_ e o proxy público `/fotos//midia` responde **500** para elas. Uma amostra de 20 ids achou 1 com erro, então o problema é raro, mas hoje o álbum pode exibir (e exibe) imagens quebradas. O acervo precisa de uma varredura de integridade e de um caminho de recuperação a partir do Flickr (a ficha guarda a `sourceUrl`), sem tocar em curadoria e com relatório honesto. + +## Persona e fluxo + +- **Persona / contexto:** assessoria/ops que publica o acervo; visitante que abre uma foto e vê imagem quebrada. +- **Job principal:** garantir que toda foto aprovada sirva arquivo; recuperar as que não servem. +- **Fluxo desejado:** roda a varredura → recebe a lista de objetos ilegíveis (com motivo) → recupera do Flickr (re-ingestão idempotente pelo `flickrId`) → roda o índice facial nas recuperadas → o álbum não tem mais mídia quebrada. +- **Anti-goals de produto:** baixar/reprocessar tudo por precaução; alterar curadoria; apagar objetos sem rastro; mexer no Flickr. + +## Objetivo e aceite + +- Varredura read-only de **todas** as fotos: detecta objeto ausente/corrompido (download com validação — o mesmo caminho que o índice facial usa) e emite receita com a lista e o motivo. +- Recuperação re-ingere do Flickr pelo `flickrId`/`sourceUrl`, para o objeto no bucket, sem duplicar linha nem sobrescrever campos curados; as fotos recuperadas voltam ao público pelo fluxo normal (`draft → approved`, com o canal já configurado). +- Fotos irrecuperáveis (fonte sumiu) saem do público com registro — nunca ficam quebradas. +- Reexecutar converge; relatório diz o que foi varrido, achado, recuperado e falhou. + +## Dados (intenção) + +- **Vou apresentar dados?** Contagens no recibo da CLI (varridas/achadas/recuperadas/falhas) — operador, não público. +- **Forma:** tabela de recibo (JSON/markdown), sem exposição pública. + +## Dados da decisão (literais) + +- **Achado em produção (2026-10-01):** fotos 80 e 83 com _checksum mismatch_ (`x-amz-checksum-crc32`), mídia 500; amostra 20 ids → 1 erro. +- **Fonte de recuperação:** `archivePhoto.sourceUrl` (Flickr) — re-ingestão existente (`archivePhotoIngest`), determinística pelo `flickrId`. +- **Sem tocar curadoria:** campos curados nunca são sobrescritos (mesma régua do C231/C232). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** CLI nova de varredura (reusar `downloadPrivateMediaToFile` + checksum/`headObject` no cliente S3 do bucket, ou o próprio caminho de download do índice), e um modo de recuperação que reusa `ingestArchivePhoto`; reuso das guardas de CLI (`TEQO_ENV`, `*_CONFIRM`, S3), recibos em `data/archive/reports/`. +- **Precedente:** `pnpm archive:catalog --verify` (inventário read-only), `pnpm media:recover` (C233/OPS52 — recuperação de objeto sem tocar no DB), ingestão Flickr C231. +- **Risco de acoplamento:** `publicationStatus` da foto recuperada e o índice facial (marker) precisam ser reprocessados; mídia privada passa pelo proxy e pela allowlist do otimizador. + +## Dependências + +- Duras: C231 (ingestão/collection) e C242/C240 (publicação/índice) — entregues. + +## Fora de escopo + +- Re-varredura de mídia pública do C233 (`media`), vídeos, outras plataformas. + +## Rabbit holes de produto + +- **"Só completar" re-ingerindo o acervo inteiro.** **Corte:** só o que a varredura acusar. +- **"Só completar" apagando fotos problemáticas.** **Corte:** recuperar primeiro; sair do público só quando a fonte não existir. + +## Questões em aberto (produto) + +- **Canal de saída para irrecuperáveis:** `draft` (some do público) com registro no recibo, ou `removed`? **Recomendação:** `draft` + registro (não é pedido de remoção de pessoa). _(assumido — validar)_ + +## Referências + +- `docs/plans/acervo-fotos-flickr-ingestao.md` / `-impl.md` (C231) +- `docs/plans/album-fotos-publico-busca-impl.md` (C233 — proxy de mídia) +- `src/utilities/flickr/archivePhotoIngest.ts` · `src/utilities/privateMedia/privateMediaResponse.ts` + +## Self-score (shaping) + +5/5 — (1) outcome verificável (nenhuma mídia pública quebrada); (2) appetite pequeno, reusando ingestão e proxy; (3) persona/job/aceite claros; (4) direção com precedentes nomeados; (5) achado de produção registrado com literais. diff --git a/docs/plans/album-catalogacao-producao.md b/docs/plans/album-catalogacao-producao.md new file mode 100644 index 00000000..bee962d1 --- /dev/null +++ b/docs/plans/album-catalogacao-producao.md @@ -0,0 +1,75 @@ +# C245 — Catalogação do acervo em produção (município, atividade, legenda) + +Status: rascunho +Atualizado em: 2026-10-01 +Issue: #1417 +Priority: P2 +Impeccable: A — sem UI nova (as facetas/cards do C233 já existem; faltam os dados) +Design UI: N/A — sem UI +Appetite: ~1 dia eng + tempo de máquina; um outcome verificável — o álbum mostra município/atividade e o card ganha legenda real +Responsável: — + +## Intenção + +Depois de publicar as 6.492 fotos (C242), a única faceta que aparece em `/fotos` é **Data** e o card mostra só título/metadados básicos do Flickr. Causa verificada em produção (2026-10-01): a **catalogação do C232 nunca rodou lá** — `catalog.*` está 100% vazio (`scene=0`, `municipio=0`, `caption=0`, `catalogedAt=0`). Os dados existem (título, descrição, tags, 6.2k álbuns do Flickr, `searchText`), mas não foram derivados para a ficha; e a parte de IA (legenda/atividade a partir da imagem) exige o engine de visão local, que não está de pé. + +Este item entrega o caminho de catalogação em produção em duas camadas: **(1) metadata-only** (sem modelo): município pelo gazetteer, temas, e o que o texto sustentar; **(2) IA de visão** (legenda/descrição/atividade/texto visível) com o engine local documentado no runbook. O C244 (pessoa por facial), quando aprovado, toma o lugar do "pessoas" derivado de texto. + +## Persona e fluxo + +- **Persona / contexto:** visitante que procura "fotos em Feira de Santana" ou "de plenária"; assessoria que abre a ficha e quer legenda/atividade reais. +- **Job principal:** navegar o álbum por município/atividade e ver no card o que a foto é, onde e quando. +- **Fluxo desejado:** abre `/fotos` → as facetas Município e Atividade aparecem com valores reais → filtra → o card mostra `data · município · atividade` e legenda; a ficha no admin traz a proposta com procedência (`metadata`/`ia`). +- **Anti-goals de produto:** inventar nome de pessoa; publicar proposta de IA sem revisão por exceção; criar segunda curadoria. + +## Objetivo e aceite + +- Rodar a catalogação no acervo de produção (metadata-only primeiro; IA quando o engine estiver no ar) com recibos e reexecução idempotente. +- `/fotos` passa a exibir as facetas `Município` e `Atividade` quando houver valores; os cards ganham legenda quando houver (curadoria vence a IA). +- Nenhuma proposta sobrescreve campo curado (`curatedFields`); nada é publicado; a IA só é chamada por endereço privado (guardrail PII). +- Reexecutar não duplica nem repaga o que já está catalogado; o marker da camada metadata não pode bloquear a camada IA (design no impl). + +## Dados (intenção) + +- **Vou apresentar dados?** Não — a ficha exibe valores; sem números agregados. +- **Forma:** N/A. + +## Dados da decisão (literais) + +- **Estado verificado (2026-10-01):** produção com `catalog.*` zerado e searchText populado; a entrega pode derivar do texto sem modelo. +- **Engine de visão:** Ollama/host privado (`ARCHIVE_VISION_*`), hoje fora do ar; o runbook documenta como subir e rodar a camada IA. +- **Pessoas:** no metadata-only, não escrever `catalog.people` (o C244 assume a faceta pelo facial); temas/município seguem. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `scripts/catalog-archive-photos.mjs` + `src/utilities/flickr/archivePhotoCatalog.ts` (modo `--metadata-only` reaproveitando `resolveMentionedMunicipalityId`, `classifySpeechByGazetteer`, `archivePhotoThemesFrom` e o write transacional com `buildArchivePhotoCatalogWrite`); marker próprio (ex.: `catalog.metadataCheckedAt`) para não colidir com o `catalogedAt` da IA; runbook do engine de visão. +- **Precedente:** C232 (pipeline e guardas), C230 (writes por CLI + bust de cache via `/api/revalidate`). +- **Risco de acoplamento:** o skip por `catalogedAt` da IA precisa continuar válido; a curadoria (`curatedFields`) sempre vence; facetas públicas dependem de revalidação da tag `archivePhotos`. + +## Dependências + +- Duras: C232 (pipeline) e C242 (acervo publicado) — entregues. +- Soft: C244 (se aprovado antes, o metadata-only não escreve pessoas). + +## Fora de escopo + +- OCR dedicado, recorte/edição de imagem, segunda curadoria, superfície nova de revisão. + +## Rabbit holes de produto + +- **"Só completar" catalogando com terceiro/híbrido.** **Corte:** só engine local privado (PII). +- **"Só completar" publicando direto a proposta da IA.** **Corte:** publica é ato humano; a IA propõe. + +## Questões em aberto (produto) + +- **Subir o engine de visão agora ou só metadata-only?** **Recomendação:** metadata-only já; IA quando o host local estiver disponível. _(assumido — validar)_ + +## Referências + +- `docs/plans/acervo-fotos-catalogacao-ia.md` / `-impl.md` (C232) +- `docs/plans/album-fotos-publico-busca.md` (C233 — facetas/cards) +- `docs/ops/teqo-1313-deploy.md` (runbook do engine) + +## Self-score (shaping) + +5/5 — (1) outcome verificável (facetas e cards com dados reais no ar); (2) appetite pequeno, reusando o dono; (3) persona/job/aceite claros; (4) direção com precedentes; (5) decisão de camadas registrada. diff --git a/docs/plans/album-pessoa-facial.md b/docs/plans/album-pessoa-facial.md new file mode 100644 index 00000000..0bdbe5db --- /dev/null +++ b/docs/plans/album-pessoa-facial.md @@ -0,0 +1,86 @@ +# C244 — Filtro "Pessoa pública" por reconhecimento facial no álbum + +Status: rascunho +Atualizado em: 2026-10-01 +Issue: #1416 +Priority: P1 +Impeccable: B — muda a origem da faceta/card que já existem em `/fotos` (sem tela nova) +Design UI: N/A — a faceta e a linha "Quem aparece" já foram desenhadas no C233; muda a origem do dado +Appetite: ~2–3 dias eng + curadoria dos descritores de referência + aval jurídico registrado +Responsável: — + +## Intenção + +Hoje a faceta **Pessoa pública** do álbum (`/fotos?pessoa=`) sai do **texto** da ficha (`catalog.people`, derivado de título/álbum/legenda pelo C232): mostra fotos em que o nome foi _escrito_, não em que a pessoa _aparece_. A decisão do dono (2026-10-01) é que o filtro siga o **reconhecimento facial**: listar as fotos em que aquela pessoa realmente aparece. O C240 já deixou o motor e o índice de rostos em produção (18k descritores anônimos); falta a camada de **figuras curadas**: descritores de referência das pessoas públicas do catálogo (Solla, Lula, Jerônimo, Geraldinho, Wagner, Júlio Pinheiro e os 53 deputados estaduais), o vínculo foto↔figura no lote e a faceta lendo esse vínculo em vez do texto. + +Isto é identificação biométrica de pessoas nomeadas — permitida **apenas** para o catálogo curado de figuras públicas, com o aval jurídico declarado que abriu o índice do C240; nunca para terceiros, nunca inferida de rosto para quem não está no catálogo. + +## Persona e fluxo + +- **Persona / contexto:** visitante que quer as fotos de uma figura (ex.: Lula, Jerônimo) para rever/guardar; assessoria que quer medir presença por pessoa. +- **Job principal:** filtrar o álbum por pessoa e ver **só as fotos em que ela aparece**. +- **Fluxo desejado:** abre `/fotos` → escolhe "Pessoa pública: Lula" → grade traz só fotos com o rosto de Lula (mesmo sem o nome escrito na ficha) → abre a foto em contexto; a linha "Quem aparece" lista as figuras curadas reconhecidas naquela foto. +- **Anti-goals de produto:** identificar/nomear terceiros; virar diretório de rostos; buscar por rosto de outra pessoa; score/percentual; vídeo. + +### Design UI (B) + +- N/A — a superfície (`pessoa` na URL, chip, card "Quem aparece") é a do C233; o item muda a origem do dado e o texto vazio da faceta quando não há figuras reconhecidas. + +## Objetivo e aceite + +- A faceta `pessoa` lista **apenas figuras do catálogo curado** com ≥1 foto aprovada reconhecida; a grade da URL `?pessoa=` traz exatamente essas fotos (por rosto, não por texto). +- "Quem aparece" no card/overlay mostra só figuras curadas reconhecidas na foto; nunca nome de terceiro. +- Despublicar/remover uma foto tira-a da faceta e do "Quem aparece" imediatamente; desligar o kill switch fecha tudo. +- Opt-out (C240 "Minha presença") remove o rosto do índice — e, se uma figura sair do catálogo/for removida, deixa de aparecer na faceta. +- Nada de score; nenhuma superfície promete "todas as fotos"; o texto vazio da faceta explica que só entram figuras reconhecidas com curadoria. +- **Guardrails:** Consent/LGPD fail-closed (o aviso do índice e o consentimento da consulta continuam sendo o gate); sem cruzamento com `Contact`/leadership; referência biométrica de figura é curada e auditável. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — o resultado é a lista de fotos; nenhum número de semelhança. +- **Forma:** N/A — sem score/percentual em nenhum estado. + +## Dados da decisão (literais) + +- **Origem do filtro — decisão do dono (2026-10-01): facial.** A faceta passa a ler o vínculo foto↔figura do índice facial; o `catalog.people` (texto) pode continuar como conteúdo da ficha, mas não governa o filtro. +- **Catálogo inicial (curadoria):** Jorge Solla; Luiz Inácio Lula da Silva ("Lula"); Jerônimo Rodrigues ("Jerônimo"); Geraldo Júnior ("Geraldinho"); Jaques Wagner ("Wagner"); Júlio Pinheiro; + os 53 deputados estaduais do roster S30 (já no catálogo). +- **Referências:** cada figura precisa de descritor(es) de referência (retratos oficiais/arquivo, curadoria humana); a origem e o aval são registrados no runbook (mesmo caminho do consentimento do índice do C240). +- **Sem terceiros:** rostos que não casam com o catálogo continuam anônimos no índice; nunca são nomeados. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** collection nova de figuras (`faceFigure`: nome curado + descritores de referência, admin-only) sobre o padrão do antigo `faceSubject`; `scripts/lib/faceEngine.mjs` + `pnpm faces:enroll-figure` (referência) e `faces:index` estendido para gravar o vínculo foto↔figura (o marker `faces.checkedKey` passa a incluir a revisão das figuras); a faceta/card em `src/lib/archivePhotoPublicCatalog.ts` trocam a fonte de `pessoa`; leitura pública em `archivePhotoReads`. +- **Precedente a olhar:** C240 (`faceIndex`, purge por despublicação, opt-out), histórico A/C do C234 (`faceSubject.matchedPhotos`), `publicFigureCatalog` (slugs/aliases), catálogo público do C233. +- **Risco de acoplamento:** a faceta é contrato público (URL/chip) — o valor `pessoa` não muda, só a origem; `catalog.people` continua na ficha (texto) para não quebrar a Central/curadoria; migration aditiva; o índice atual (18k rostos) precisa ser reprocessado ao introduzir figuras (marker novo). + +## Dependências + +- Duras: C240 (índice facial e opt-out) e C233 (álbum/faceta) — entregues; C232 (ficha curada) para o catálogo. +- Duras de produto: aval jurídico do uso biométrico para figuras nomeadas (o dono declarou na sessão de 2026-10-01; registrar no runbook). + +## Fora de escopo + +- Nomear terceiros ou qualquer pessoa fora do catálogo curado; busca por rosto de outra pessoa; API pública de reconhecimento; vídeo; ranking/score por figura. + +## Rabbit holes de produto + +- **"Só completar" identificando todos os rostos.** **Corte:** só o catálogo curado; o resto segue anônimo. +- **"Só completar" com score por figura.** **Corte:** sem número em nenhum estado. +- **"Só completar" automático sem curadoria.** **Corte:** figura só entra com referência curada e revisão humana; falso positivo é tratado como débito de curadoria, não como dado. + +## Questões em aberto (produto) + +- **Origem das referências faciais de cada figura?** Retratos oficiais/arquivo do mandato (assessoria), 1–3 por pessoa; quem aprova. _(assumido — validar)_ +- **A faceta facial substitui o texto (decisão do dono) — e o `people` de texto sai do card?** **Recomendação:** sim para a faceta; manter o campo na ficha como conteúdo, sem aparecer como "Quem aparece" para não confundir as duas origens. _(assumido — validar)_ +- **Falsos positivos (limiar):** manter 0.45 e revisar por exceção, com lista de revisão no runbook. _(assumido — validar)_ + +## Referências + +- `docs/plans/busca-selfie-escopo-b.md` (C240 — índice anônimo; este item adiciona a camada curada) +- `docs/plans/album-fotos-publico-busca.md` (C233 — faceta/card desenhados) +- `docs/plans/acervo-fotos-catalogacao-ia.md` (C232 — de onde vem `catalog.people`) +- `src/lib/publicFigureCatalog.ts` · `src/lib/archivePhotoPublicCatalog.ts` + +## Self-score (shaping) + +5/5 — (1) outcome verificável (filtrar por pessoa e ver só as fotos em que ela aparece, por rosto); (2) appetite comporta reuso do motor do C240 + curadoria de referências; (3) persona/job/aceite claros; (4) direção no codebase com donos e precedentes nomeados; (5) decisões de produto registradas (facial, catálogo, sem terceiros). diff --git a/docs/plans/ops-toggle-globais-publicos.md b/docs/plans/ops-toggle-globais-publicos.md new file mode 100644 index 00000000..c12177a9 --- /dev/null +++ b/docs/plans/ops-toggle-globais-publicos.md @@ -0,0 +1,69 @@ +# C247 — Ligar/desligar globais públicos fora do admin (revalidação + ops) + +Status: rascunho +Atualizado em: 2026-10-01 +Issue: #1419 +Priority: P3 +Impeccable: A — sem UI +Design UI: N/A — sem UI +Appetite: ~0,5 dia eng; um outcome verificável — a ops muda uma flag pública por CLI e o site reflete sem depender do admin +Responsável: — + +## Intenção + +Na abertura do C242 as ops descobriram um atrito real: o update do global `photoAlbum` (canal de remoção, `selfieSearchEnabled`) foi feito por CLI/script, mas o **cache do global** (`unstable_cache`, tag `global_photoAlbum`) só é revalidado pelo `afterChange` **dentro do processo Next** — a allowlist do `POST /api/revalidate` não cobre tags de globais (só `global_privacy-policy` e afins). Na prática: a ops não consegue ligar/desligar a busca por selfie por CLI; precisou do clique no admin. Este item dá à ops um caminho de primeira classe, com guardas, para flags públicas operadas fora do admin. + +## Persona e fluxo + +- **Persona / contexto:** operador (homeserver/CLI) que precisa abrir/fechar uma superfície pública sem depender do navegador/admin. +- **Job principal:** mudar a flag e ver o efeito no site em segundos, com registro e rollback. +- **Fluxo desejado:** roda o comando com a flag nova e as guardas → grava o global pelo Local API → busta a(s) tag(s) do global no servidor → confere em `/fotos`, `/fotos/encontre` e na home. +- **Anti-goals de produto:** abrir SQL cru; criar segundo caminho de permissão; expor segredo no log. + +## Objetivo e aceite + +- Comando de ops (ex.: `pnpm ops:global photoAlbum --selfie-search on`) que atualiza o global com `overrideAccess` e **revalida a tag do global** no processo servidor (via allowlist do `/api/revalidate` derivada de `getGlobalCacheTag`, ou rota de ops dedicada com segredo). +- Efeito visível em ≤60 s em `/fotos`, `/fotos/encontre` e na home (entrada/seção), sem restart. +- Guardas de escrita existentes (`TEQO_ENV` casando o banco, `*_CONFIRM=1` fora do dev local), recibo e rollback (mesmo comando com o valor anterior). +- A allowlist continua fechada: só tags de globais/superfícies explicitamente permitidas; nada de tag arbitrária. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — operação. + +## Dados da decisão (literais) + +- **Achado da abertura do C242 (2026-10-01):** update de global por CLI não revalida o cache do servidor; a ops teve de usar o admin para ligar `selfieSearchEnabled`. +- **Allowlist atual:** `posts`, `global_privacy-policy`, `election-tse`, `municipality-catalog`, `social-feed`, `archivePhotos`, `contentPieces` — sem tags de globais operacionais. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/utilities/revalidateRequest.ts` (allowlist derivada de `getGlobalCacheTag` para os globais públicos operacionais), `src/utilities/globals.ts` (tag owner), script novo `scripts/ops-global.mjs` (padrão de guardas/recibos das CLIs). +- **Precedente:** `SocialFeedSettings` (revalidação de global) e as CLIs de ops do C230/C242 (`assertEnvironmentDatabaseTarget`, `assertWriteConfirm`). +- **Risco de acoplamento:** allowlist é superfície de segurança do endpoint; manter a lista explícita e testada (unit) e nunca aceitar tag arbitrária; o script precisa do segredo do endpoint no ambiente do alvo. + +## Dependências + +- Nenhuma dura (independente); nasceu do C242. + +## Fora de escopo + +- UI de ops, botões no admin, exposição de flags ao público. + +## Rabbit holes de produto + +- **"Só completar" com uma API genérica de revalidação.** **Corte:** allowlist fechada por tag explícita. +- **"Só completar" gravando por SQL.** **Corte:** sempre Local API (hooks/versões). + +## Questões em aberto (produto) + +- **Quais globais entram na allowlist?** **Recomendação:** os operacionais públicos (`photoAlbum`, `site-settings`, `home-page`, `metadata`) — nada além. _(assumido — validar)_ + +## Referências + +- `docs/plans/busca-selfie-escopo-b-impl.md` (C242 — o atrito observado) +- `src/utilities/revalidateRequest.ts` · `src/utilities/globals.ts` · `src/app/(frontend)/api/revalidate/route.ts` + +## Self-score (shaping) + +5/5 — (1) outcome verificável (flag muda por CLI e o site reflete); (2) appetite pequeno; (3) persona/job/aceite claros; (4) direção com donos e precedentes; (5) achado real de ops registrado.