diff --git a/docs/plans/central-conteudos-acoes-em-lote-ui-design.html b/docs/plans/central-conteudos-acoes-em-lote-ui-design.html new file mode 100644 index 00000000..30fe1d5d --- /dev/null +++ b/docs/plans/central-conteudos-acoes-em-lote-ui-design.html @@ -0,0 +1,1389 @@ + + + + + + + Design — C236 · Central de Conteúdos — ações em lote (DEGRADED) + + + +
+ +
+
+ + C236 · design do gate + + + DEGRADED + +
+

+ O mesmo veredito em várias peças, sem ruído na varredura +

+

+ Assessoria de comunicação na Central de Conteúdos: a leva entra, a triagem decide em + bloco. A seleção é opt-in, vale só a página visível, e o desfecho aparece com recibo + honesto — incluindo a falha parcial. +

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

Cena 1 · desktop ~1280 · repouso

+

+ A tabela de hoje não ganha checkbox permanente — o modo de seleção é opt-in +

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

Comunicação

+

Central de Conteúdos

+
+
+
+ +
+
+
+

Conteúdos

+

+ Peças que alimentam a Central pública. Rascunhos não aparecem no site. +

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

+ Em repouso, nada mais muda: sem coluna de checkbox, sem barra, sem cor nova. + Este é o único affordance para entrar no modo. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Central de Conteúdos em repouso: quatro peças com processamento, publicação, + circulação e a próxima ação de cada uma. +
PeçaProcessamentoPublicaçãoCirculaçãoPróxima ação
+
+ + + +
+

Peça publicada

+

Vídeo · 02:14 · Salvador

+
+
+
+ Pronto + + Publicado + +
+
Aberturas128
+
Downloads12
+
WhatsApp6
+
Link3
+
+
+
+ + +
+
+
+ + + +
+

Peça em rascunho

+

Card · Feira de Santana

+
+
+
+ Pronto + + Rascunho + + Sem dados — ainda não publicada + +
+ + +
+
+
+ + + +
+

Peça com falha

+

Áudio · 01:05 · Vitória da Conquista

+
+
+
+ Falhou +

Não foi possível transcrever a peça.

+
+ Rascunho + + Sem dados — ainda não publicada + +
+ + +
+
+
+ + + +
+

Peça em processamento

+

Vídeo · 03:40 · Itabuna

+
+
+
+ Processando +

Transcrevendo a peça

+
+ Rascunho + + Sem dados — ainda não publicada + +
+ + +
+
+
+ +
+

12 peças

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

Cena 2 · desktop ~1280 · seleção ativa

+

+ Checkbox por linha, “selecionar todas da página” no cabeçalho e a barra com N selecionadas +

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

Comunicação

+

Central de Conteúdos

+
+
+
+ +
+
+
+

Conteúdos

+

+ Peças que alimentam a Central pública. Rascunhos não aparecem no site. +

+
+
+ + +
+
+ +
+
+ + +
+ + +
+ + +
+ + + Modo de seleção + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Central de Conteúdos com seleção ativa: coluna de checkbox, três peças + selecionadas e a barra de ações. +
+ + + + + + PeçaProcessamentoPublicaçãoCirculaçãoPróxima ação
+ + + + + + +
+ + + +
+

Peça publicada

+

Vídeo · 02:14 · Salvador

+
+
+
ProntoPublicado +
+
Aberturas128
+
Downloads12
+
WhatsApp6
+
Link3
+
+
+
+ + +
+
+ + + + + + +
+ + + +
+

Peça em rascunho

+

Card · Feira de Santana

+
+
+
ProntoRascunhoSem dados — ainda não publicada +
+ + +
+
+ + + + + + +
+ + + +
+

Peça com falha

+

Áudio · 01:05 · Vitória da Conquista

+
+
+
+ Falhou +

Não foi possível transcrever a peça.

+
RascunhoSem dados — ainda não publicada +
+ + +
+
+ + + + +
+ + + +
+

Peça em processamento

+

Vídeo · 03:40 · Itabuna

+
+
+
+ Processando +

Transcrevendo a peça

+
RascunhoSem dados — ainda não publicada +
+ + +
+
+
+
+ + +
+
+

+ 3 selecionadas +

+
+ + + +
+
+

+ Publicar é o veredito dominante; Despublicar é outline; Apagar é destructive + tintado (o vermelho cheio fica só no diálogo). A seleção vale só as 4 peças + desta página. +

+
+
+
+
+
+ + +
+

Detalhe · checkbox “selecionar todas da página”

+
+ + nenhuma + + + + + + parcial (indeterminate) + + + + + + todas as 4 + +
+

+ Trocar de página ou filtro zera a seleção — o header nunca representa um conjunto + invisível. +

+
+
+ + + + +
+
+

Cena 3 · mobile ~390 · repouso e seleção ativa

+

+ No celular o checkbox vive no card e a barra cabe em 390, com alvos ≥44px +

+
+ +
+ +
+

3a · repouso — sem checkbox

+
+
+ + Conteúdos +
+
+
+ + + + + +
+ +
+ +
+
+
+

Peça publicada

+ Pronto +
+
+ Publicado + Vídeo · 02:14 +
+
+
Aberturas128
+
Downloads12
+
WhatsApp6
+
Link3
+
+
+ + +
+
+ +
+
+

Peça em rascunho

+ Pronto +
+
+ Rascunho + Card +
+
+ + +
+
+
+

12 peças

+
+
+
+ + +
+

3b · seleção ativa — barra fixa no rodapé

+
+
+ + Conteúdos +
+
+ +
+ + +
+ + + Modo de seleção + + +
+ +
+ +
+
+ + + + + +
+
+

Peça publicada

+ Pronto +
+
+ Publicado + Vídeo · 02:14 +
+
+
+
+ + +
+
+ + +
+
+ + + + + +
+
+

Peça em rascunho

+ Pronto +
+
+ Rascunho + Card +
+
+
+
+ + +
+
+ + +
+
+ + + +
+
+

Peça com falha

+ Falhou +
+
+ Rascunho + Áudio · 01:05 +
+
+
+ +
+
+
+ + +
+
+
+

2 selecionadas

+ +
+
+ + + +
+
+

+ Os três botões têm 44px de altura e dividem a largura em três: nenhum label + transborda em 390. +

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

Cena 4 · diálogo sempre visível · apagar sempre confirma

+

+ O aviso de links públicos aparece só quando há publicadas na seleção +

+
+
+ +
+
+ Seleção com publicadas + +
+ + +
+
+ Seleção só rascunho/falha/processando + +
+ + +
+
+ 1 selecionada (singular — reusa o C222) + +
+
+

+ Mesmo chrome do CampaignDeleteDialog: ícone circular destrutivo, rodapé com + fundo muted/50 e borda superior, Cancelar outline e + Apagar vermelho cheio. Publicar/Despublicar em lote não têm diálogo — são o + kill switch reversível e agem direto, com recibo. +

+
+ + + + +
+
+

Cena 5 · recibos no topo da lista · nunca sucesso parcial silencioso

+

+ A lista diz o que aconteceu — e nomeia a falha quando ela existe +

+
+ +
+ +
+ +

3 peças publicadas

+ +
+ + +
+ +

3 peças despublicadas

+ +
+ + +
+ +

3 peças apagadas

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

Cena 6 · ação em andamento · spinner + disabled

+

+ Enquanto roda, a barra e o diálogo bloqueiam — sem duplo gesto +

+
+ +
+ +
+

Barra de seleção · publicando

+
+
+

3 selecionadas

+
+ + + +
+
+
+

+ O botão clicado carrega o spinner; os outros dois ficam desabilitados e os checkboxes + também. aria-busy="true" na barra. +

+
+ + +
+
+ Diálogo · apagando + +
+
+
+ + + + +
+

Notas do gate

+ +
+
+

Produto respeitado

+
    +
  • Seleção só da página visível; “selecionar todas” = as 4/25 desta página; morre ao trocar de página ou filtro.
  • +
  • Ações por linha/ficha (Abrir, Reprocessar, Apagar) intocadas — o lote não cria verbo por linha.
  • +
  • Publicar/Despublicar em lote agem sem confirmação (reversíveis) e dão recibo; Apagar sempre confirma.
  • +
  • Estados de processamento e publicação valem todos, sem filtro novo (inclusive processando/falhou).
  • +
  • Desktop (tabela) e mobile (card list) cobertos; sem edição de campos, sem agendamento, sem lixeira.
  • +
  • Sem rota pública nova: o lote é o gesto unitário repetido sobre a seleção.
  • +
+
+ +
+

Tokens usados

+
    +
  • --primary #c51414 no checkbox checado, no Publicar e no tint de seleção (primary/5).
  • +
  • --destructive #b42318 no Apagar do diálogo (cheio) e no Apagar da barra (tintado destructive/10).
  • +
  • --border, --input, --muted, --muted-foreground, --card, --sidebar: chrome da lista e do shell.
  • +
  • Badges de estado como já existem: verde/âmbar/vermelho de processamento e rose de publicado.
  • +
  • Inter, rounded-xl (card/lista), rounded-lg (botões), min-h-11 (44px), tabular-nums no contador.
  • +
  • Recibo de sucesso usa verde só no ícone (semântica), não como chrome.
  • +
+
+
+ +
+
+

Literais refinados (e por quê)

+
    +
  • 1 selecionada no singular, no lugar de “1 selecionadas” — segue o precedente vivo do TourComposerForm.
  • +
  • Anunciado (não literal fixado): Modo de seleção e Cancelar seleção como rótulos do affordance de entrar/sair; o plano só fixa o contador e os três verbos.
  • +
  • O corpo do diálogo, o título Apagar N peças selecionadas?, o singular Apagar esta peça? e os recibos são os literais do plano, verbatim.
  • +
+
+ +
+

NEEDS ASSET

+

+ Nenhum. Todos os ícones (checkbox, dash, lixeira, check, alerta, spinner, setas) têm + equivalente lucide e estão inline no grid 24px/stroke 2. Não há SVG próprio em + …-ui-design-assets/. Sem foto, selo, depoimento ou cobertura — não se + aplica a esta superfície. +

+
+
+ +
+

Proposta de evolução do DESIGN.md (não aplicada)

+

+ Se aprovada pelo humano, a §5 ganharia a regra do modo de seleção de lista: + checkbox opt-in (nunca permanente na varredura), tint primary/5 na linha + selecionada, e barra de ações flutuante no rodapé do conteúdo com o verbo dominante em + primary, o reversível em outline e o irreversível em destructive tintado — o + vermelho cheio permanece exclusivo do diálogo de confirmação. Como este artefato é + DEGRADED, a regra fica só como proposta; a decisão é do frontier/humano. +

+
+ +

+ DEGRADED — design não certificado; sign-off humano obrigatório no gate/PR. +

+
+
+ + + diff --git a/docs/plans/central-conteudos-acoes-em-lote.md b/docs/plans/central-conteudos-acoes-em-lote.md new file mode 100644 index 00000000..1c42df4b --- /dev/null +++ b/docs/plans/central-conteudos-acoes-em-lote.md @@ -0,0 +1,116 @@ +# C236 — Central de Conteúdos — publicar, despublicar e apagar em lote + +Status: rascunho +Atualizado em: 2026-09-29 +Issue: #1388 +Priority: P2 +Impeccable: B — encaixe na lista existente da Central de Conteúdos (`/campanha/comunicacao/conteudos`): seleção múltipla + barra de ações +Design UI: docs/plans/central-conteudos-acoes-em-lote-ui-design.html +Appetite: ~1–1,5 dia eng; um outcome verificável — o mesmo veredito editorial aplicado a várias peças num gesto +Responsável: — + +## Intenção + +A Central de Conteúdos resolveu o garimpo: a peça entra, é catalogada e publicada/despublicada por um gesto — mas o kill switch mora só na ficha, e apagar é uma confirmação por linha. O uso real chega em blocos: um evento despeja dezenas de peças, uma importação traz uma leva de posts, e a assessoria precisa dar o **mesmo veredito** a várias delas ("essas cinco vão para a pública", "essas três não servem"). Hoje são N decisões iguais custando N navegações. + +O pedido humano é direto: "selecionar vários para publicar/despublicar/apagar". O C222 (`docs/plans/central-conteudos-apagar-peca.md`) declarou "sem lote" como anti-goal — mas o próprio Fora de escopo dizia "lote é item próprio se o uso pedir". **Este item é esse item próprio: a reabertura do anti-goal é de propósito**, do mesmo modo que o C222 reabriu o "sem delete" do C211. O lote não é semântica nova: é o gesto unitário existente repetido sobre a seleção, com recibo honesto. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`; `coordinator`/`candidate` também), na mesa ou no celular, logo depois de uma leva de peças entrar — quando decidir caso a caso atrapalha a triagem. +- **Job principal:** aplicar o mesmo veredito — publicar, despublicar ou apagar — a várias peças da tela num gesto, sem abrir ficha por ficha. +- **Fluxo desejado:** abre a lista → marca as peças da página (checkbox na tabela, card no celular) → a barra aparece com `N selecionadas` → `Publicar`/`Despublicar` agem na hora com recibo; `Apagar` pede confirmação (avisando os links públicos quando houver publicadas na seleção) → a lista atualiza e diz o que aconteceu. +- **Anti-goals de produto:** não vira planilha (sem edição de campos em lote); não é lote global (cross-page/"todos os filtrados"); não é pipeline (sem job assíncrono/progresso); não mexe na semântica do gesto unitário; não cria rota pública nenhuma. + +### Esboço de fluxo (B) + +```text +[/campanha/comunicacao/conteudos] → marcar peças da página (checkbox na tabela, card no celular) +→ barra "N selecionadas" · Publicar | Despublicar | Apagar +→ Publicar/Despublicar: age na hora, lista atualiza, recibo "N peças publicadas/despublicadas" +→ Apagar: confirmação (avisa links públicos das publicadas) → recibo "N peças apagadas" +[outcome: o mesmo veredito em várias peças num gesto, com recibo honesto e sem ficha por ficha] +``` + +### Design UI (B) + +- Design UI (gate): `docs/plans/central-conteudos-acoes-em-lote-ui-design.html` — cenas na tabela (~1280) e no card list (~390), barra de seleção, confirmação em massa e recibos; a forma do affordance é do design. +- Design tier: DEGRADED (opencode-go/deepseek-v4.1-flash; frontier `openai/gpt-5.6-sol` sem quota) — sign-off humano obrigatório no PR. + +## Objetivo e aceite + +- Selecionar várias peças **da página visível** (as 25 do filtro/página atual), com a seleção visível e contada na barra; "selecionar todas" = todas as da página; a seleção morre ao trocar de página ou filtro. +- A barra de ações só existe com seleção ativa e oferece `Publicar`, `Despublicar` e `Apagar`; as ações por linha/ficha continuam exatamente como estão (o lote não cria publicar/despublicar por linha). +- `Publicar` e `Despublicar` em lote agem sem confirmação (são reversíveis) e dão recibo; `Apagar` em lote sempre confirma — o diálogo avisa que, havendo publicadas, seus links públicos deixam de funcionar, e sempre que a ação não pode ser desfeita. +- Nunca sucesso silencioso parcial: o recibo diz quantas peças foram afetadas e quantas falharam; a falha de uma peça não reverte as demais (é o mesmo gesto unitário, repetido) e a lista reflete o desfecho. +- O lote respeita a elegibilidade do gesto unitário, sem regra nova: peça `processando` ou `falhou` publica/despublica/apaga como no unitário (apagar `processando` continua sendo a saída para job travado). +- Existe no celular (card list) e no desktop (tabela) — a assessoria usa os dois. +- **Quem pode:** a mesma audiência da vertical (`communicator`, `coordinator`, `candidate`); `advisor`/`leader` negados (fail-closed). Nada de papel novo. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — é o mesmo gesto de estado do item, repetido; nenhum painel, contador de vaidade ou telemetria. +- **Decisões desbloqueadas:** a assessoria decide o destino editorial de várias peças de uma vez (o que vai à pública, o que sai, o que morre); nenhuma leitura agregada nova. +- **Forma:** _adiada ao plano de implementação_ — restrição de produto: sem métrica de exclusão/ação em lote, sem dashboard, sem auditoria exposta. + +## Dados da decisão (literais) + +- **Barra de seleção:** contador `N selecionadas`; ações `Publicar` · `Despublicar` · `Apagar`. +- **Confirmação de apagar em massa:** título `Apagar N peças selecionadas?` (singular reusa o C222: `Apagar esta peça?`); botões `Cancelar` / `Apagar`. +- **Corpo (há publicadas na seleção):** `Os links públicos das peças publicadas da seleção deixam de funcionar para quem já recebeu. Esta ação não pode ser desfeita.` +- **Corpo (nenhuma publicada):** `Esta ação não pode ser desfeita.` +- **Recibos:** `3 peças publicadas` · `3 peças despublicadas` · `3 peças apagadas`; falha parcial: `2 de 3 peças apagadas. 1 falhou.` +- **Estados:** processamento `processando` | `pronto` | `falhou`; publicação `rascunho` | `publicado` — o lote vale em todos, como no unitário. +- **Rota interna:** `/campanha/comunicacao/conteudos` (lista). Nenhuma rota pública nova. +- **Nota de comportamento (herdada do unitário):** publicar peça sem arquivo nem link a deixa `publicado` mas fora da Central pública (é o `contentPieceIsPublic` de sempre); apagar publicada quebra o link `/conteudos/` já distribuído — daí o aviso. +- **Acesso:** `communicator`, `coordinator`, `candidate`; `advisor`/`leader` negados (fail-closed). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** página `src/app/(campaign)/campanha/(app)/comunicacao/conteudos/page.tsx`; `src/components/campaign/content/ContentPieceTable.tsx` e `ContentPieceCardList.tsx` (a lista é renderizada 2×: card no mobile, tabela no desktop); actions `src/app/(campaign)/campanha/actions/contentPieces.ts` (`setContentPiecePublishedForActor`, `deleteContentPieceForActor`, hoje uma peça cada) e as rotas `.../conteudos/[id]/publicacao/route.ts` / `.../[id]/apagar/route.ts`; `src/components/campaign/shared/CampaignDeleteDialog.tsx`. +- **Precedente a olhar:** `src/components/campaign/tour/TourComposerForm.tsx` (checkbox + contador `N selecionadas`, único precedente real de seleção no `/campanha`); FD2 (`docs/plans/field-desk-ux-pos-critique.md` §Fase 1) desenhou checkbox por linha + barra com contador para a fila de prioridade e nunca implementou — referência de desenho, não de código; `CampaignTable` **não tem API de seleção** — o "como" fica para o plano de implementação. +- **Risco de acoplamento:** a lista tem dois corpos (card/tabela) exibidos por breakpoint — a seleção precisa existir nos dois; toda escrita via Local API já busta a tag `contentPieces` por hook (`afterChange`/`afterDelete`) e o lote herda se escrever pelo Local API; o job de processamento tolera a row sumida; `ContentEvent` de circulação nunca é limpo; não tocar nas rotas públicas (S27). + +## Dependências + +- Nenhuma dura — C211 (Central interna) e C222 (apagar uma peça) entregues; S27 é o contrato público a respeitar. +- Suave: C213 (contadores de circulação) segue intocado — o lote não limpa nem recalcula eventos. + +## Fora de escopo + +- Cross-page / "todos os resultados do filtro" — a seleção não sobrevive à navegação de página/filtro. +- Publicar/despublicar por linha na lista (o lote não muda a ação rotineira por linha). +- Lixeira/desfazer/restauração; agendamento; edição de campos em lote; seleção em outras listas (a fila FD2 segue item próprio). +- Progresso/job assíncrono, fila/retomada/cancelamento — o lote é uma ação curta de mesa. +- Mudar a semântica do gesto unitário: publicação (slug canônico, `publishedAt` e arquivo preservados) e exclusão (mídia privada exclusiva sai best-effort; `ContentEvent` nunca é limpo). +- Central pública (S27): nada muda além do efeito que publicar/despublicar/apagar já têm. + +## Rabbit holes de produto + +- **"Já que seleciona, seleciona todos os filtrados / entre páginas."** Se alguém "só completar": seleção persistente, dedupe, contagem global, confirmação sobre um conjunto que ninguém vê. **Corte neste item:** só a página visível; a seleção morre ao navegar. +- **"Já que apaga muito, faz um job com progresso."** Se alguém "só completar": fila, retomada, cancelamento, tela de acompanhamento. **Corte neste item:** ação curta com recibo honesto; falha parcial nomeada. +- **"Já que publica em lote, agenda por data."** Se alguém "só completar": agendamento e calendário editorial. **Corte neste item:** publicar é agora. +- **"Já que tem barra, edita campos em lote."** Vira spreadsheet mode. **Corte neste item:** só os três verbos. +- **"Já que publicar não confirma, apagar também não."** **Corte neste item:** o reversível age; o irreversível confirma. + +## Questões em aberto (produto) + +- **Escopo da seleção?** **Opções:** A) peças da página visível (as 25 do filtro atual); "selecionar todas" = a página | B) cross-page/"todos os resultados do filtro". **Recomendação:** A — B é rabbit hole (seleção invisível, dedupe, confirmação sobre conjunto que ninguém vê). _(assumido — validar no gate)_ +- **Confirmação vale para qual ação?** **Opções:** A) só `Apagar` confirma (com aviso de links públicos), `Publicar`/`Despublicar` agem direto com recibo | B) todas confirmam | C) nenhuma confirma. **Recomendação:** A — publicar/despublicar são o kill switch reversível; apagar é a família irreversível do C222. _(assumido — validar no gate)_ +- **Falha parcial: tudo-ou-nada ou honesta?** **Opções:** A) cada peça é o mesmo gesto unitário — falha de uma não reverte as outras, e o recibo nomeia (`2 de 3 peças apagadas. 1 falhou.`) | B) lote transacional (uma falha cancela tudo). **Recomendação:** A — espelha o "falha de um não derruba os outros" do C211 e evita esconder o que já aconteceu. _(assumido — validar no gate)_ +- **Elegibilidade no lote?** **Opções:** A) a mesma do unitário, sem filtro novo (inclusive `processando`/`falhou`) | B) bloquear estados no lote. **Recomendação:** A — o lote é o gesto unitário repetido; regra nova criaria duas verdades. _(assumido — validar no gate)_ +- **Onde mora o affordance da barra?** **Opções:** A) barra só quando há seleção, sem poluir a varredura rotineira | B) checkbox sempre visível com barra fixa. **Recomendação:** A — o "como" (posição, fixa vs. inline) é do design; o produto fixa só que a rotina não ganha ruído. _(assumido — validar no gate)_ + +## Referências + +- GitHub Issue: #1388 +- Design UI (gate): `docs/plans/central-conteudos-acoes-em-lote-ui-design.html` +- Anti-goal reaberto: `docs/plans/central-conteudos-apagar-peca.md` (C222, "sem lote"; Fora de escopo: "lote é item próprio se o uso pedir") · `docs/plans/central-conteudos-ingestao.md` (C211) +- Precedentes: `docs/plans/field-desk-ux-pos-critique.md` (FD2 §Fase 1) · `src/components/campaign/tour/TourComposerForm.tsx` +- Arquivos-pista: `src/app/(campaign)/campanha/(app)/comunicacao/conteudos/page.tsx` · `src/components/campaign/content/ContentPieceTable.tsx` · `ContentPieceCardList.tsx` · `src/app/(campaign)/campanha/actions/contentPieces.ts` · `.../conteudos/[id]/publicacao/route.ts` e `.../[id]/apagar/route.ts` · `src/components/campaign/shared/CampaignDeleteDialog.tsx` · `CampaignTable.tsx` · `src/lib/campaignRoles.ts` +- Testes a tocar: `tests/int/contentPiece.int.spec.ts` · `tests/unit/contentPieceDeleteDialog.unit.spec.tsx` · `tests/e2e/campaignSpeechAcervo.e2e.spec.ts` +- `AGENTS.md` — vertical Comunicação, fail-closed, mídia privada/S3, contrato de cache + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável (o mesmo veredito em várias peças num gesto, com a lista e a pública refletindo); (2) appetite ~1–1,5 dia declarado e o escopo cabe (seleção da página visível; cross-page, job e agendamento cortados); (3) persona, job e aceite em linguagem de usuário, com reabertura do anti-goal e literais fixados, sem jargão de stack; (4) direção no codebase é hipótese com precedentes nomeados, sem contrato; (5) zero decisão dura de engenharia (forma da barra, mecanismo do lote e transporte ficam para o plano de implementação; aqui só se fixa produto).