30 KiB
Impl: Minha colinha — o estadual escolhido na colinha de voto
Status: aprovado (modo --auto) Atualizado em: 2026-09-23 Issue: #1272 Intenção: docs/plans/cards-colinha.md Appetite restante: herdado — ~1–1,5 dia eng (3 fases somam ≤1,3 dia; sem migration; o único peso novo é 1 asset copiado byte-a-byte)
Leitura da intenção
- Outcome: o estúdio de cards ganha o sexto modelo
Minha colinha: o visitante escolhe um estadual na MESMA lista de S30 e recebe uma colinha 9:16 (PNG 1080×1920) com o topo aprovado (foto do grupo + lockup + faixaJORGE SOLLA 1313e as marcas menores), a linha legal vertical na borda esquerda e seis linhas de voto — cinco fixas (DEPUTADO FEDERAL Jorge Solla 1313,SENADOR Jaques Wagner 130,SENADOR Rui Costa 133,GOVERNADOR Jerônimo 13,PRESIDENTE Lula 13) e a do estadual preenchida com nome de urna + cinco dígitos, um por caixa — cada uma com o selo verdeCONFIRMA. - O que NÃO negociar:
- 100% no aparelho: sem nome do visitante, sem foto, sem upload, sem persistência/analytics; os cinco modelos existentes intocados além do badge.
- Um único editor/fluxo: sexto item do MESMO
CardsStudio/CardComposer;#cards,/cardse?model=minha-colinhacontinuam. - Catálogo de estaduais = o de S30 (
src/lib/stateDeputyCatalog.ts, 53 entradas): um estadual, uma linha; sem escolha não há download; o seletor S30 é reusado sem tocar na superfície entregue. - Fidelidade ao gate: topo, linha legal vertical na borda esquerda e corpo de linhas seguem
docs/plans/cards-colinha-ui-design.html(cenas 1–5). - Escolha por toque e teclado; sem página/rota por colinha; a nota de privacidade precisa permanecer verdadeira (a existente fala de nome/foto).
- O que reavaliar (hipóteses da intenção):
- “O
CardComposerramifica porkind”: confirmado (CardComposer.tsx:206-208e ternários ao longo do arquivo); a colinha é o primeirokindnovo desde S13 e o branch fica isolado — sem flag extra dentro dokind:'team'. - “Catálogo e assets são os de S30”: confirmado — reuso puro; nenhuma entrada/asset de estadual nasce aqui.
- “Pipeline
renderX → preview canvas → PNG downloadreaproveitado”: confirmado — o render novo (renderColinhaCard) mora no dono único (cardRender.ts) e usaCardPreviewCanvas/cardCanvas/cardFileName. - “NEEDS ASSET do topo”: resolvido no gate — o topo é composição medida a partir do kit (
team-card-base.png+marca-negativa-completa.png+team-card-front.png); não há asset-mestre novo nem script. - “
CardModelTile/galeria”: o tile já cai noImagecompreviewSrcparakinddesconhecido (só osizesacompanha as seis colunas); a galeria passa a seis colunas.
- “O
Abordagem recomendada
flowchart LR
H["home #cards / rota /cards"] --> S["CardsStudio — ilha única"]
S --> G["CardModelGallery — 6 tiles + 6 dots"]
G -->|"tile Minha colinha"| C["CardComposer — branch kind:'colinha' (passo único)"]
C --> SEL["StateDeputySelect — S30, intocado"]
SEL --> CAT["stateDeputyCatalog — 53 entradas (S30)"]
C --> RC["renderColinhaCard — cardRender.ts (dono único)"]
MOD["cardColinha.ts — COLINHA_* + colinhaVoteRows"] --> RC
AST["team-card-base + team-card-front + marca-negativa (kit)"] --> RC
RC --> PV["prévia canvas compartilhada"]
PV --> DL["Baixar minha colinha — PNG 1080×1920"]
TILE["public/cards/modelo-colinha.jpeg — cópia byte-a-byte"] --> G
Opções consideradas: A) sexto modelo no estúdio existente com composição canvas portada do gate + seletor de S30 reusado | B) usar o modelo-colinha.jpeg como fundo e sobrepor só a linha do estadual | C) asset-mestre novo gerado por script sharp + render de camadas.
Recomendação: A — o outcome é um modelo no estúdio existente; portar o gate classe-a-classe mantém a fidelidade aprovada, usa só o kit oficial e reaproveita catálogo/seletor/preview/download; cabe no appetite (um render novo, nenhuma infra).
Rejeitadas: B porque o modelo aprovado não tem slot para o nome dinâmico (a linha do estadual está queimada e o rótulo não comporta nome variável); C porque cria mestre novo não aprovado e um script para um asset quando o gate já define a composição.
Decisões de engenharia
-
Sexto modelo —
kind:'colinha'novo + flagstateDeputyPicker: truede S30. Opções: A) novokind:'colinha'+stateDeputyPicker:true| B) reusarkind:'team'| C) uma entrada por estadual (53 modelos). Recomendação: A — o fluxo não tem foto/recorte/nome (nada da esteira S15), mas reusa o eixo do catálogo de S30; okinddiscrimina os branches de composer/render eisCardModelId/?model=cobrem o id de graça. Rejeitadas: B porque arrastaria janela de foto/recorte/harmonia/nome para um fluxo que não tem nenhum (branch por flag extra dentro doteam); C porque explode galeria/pins/URL. -
Render — composição canvas pura portada classe-a-classe do gate (não o
modelo-colinha.jpegcomo fundo). Opções: A) portar a composição do gate (medidas em px, canvas puro) | B)modelo-colinha.jpegcomo fundo + linha do estadual desenhada por cima | C) mestre novo por script sharp + camadas. Recomendação: A — a doutrina do estúdio porta o artefato aprovado e a intenção diz que o topo é “definida no design hi-fi e montada a partir do kit oficial”; omodelonão tem slot para o nome dinâmico (rótulo queimado). Rejeitadas: B porque o nome/dígitos não têm onde entrar; C porque é mestre novo não aprovado + script, quando o gate já define a composição. -
Módulos —
src/lib/cardColinha.tspuro +renderColinhaCardno dono do render. Opções: A) módulo puro novo (COLINHA_*, tabela fixa,colinhaVoteRows) + renderer emsrc/lib/cardRender.ts| B) tudo dentro docardRender.ts| C) renderer standalone em módulo próprio. Recomendação: A — o layout/tabela é conhecimento próprio, testável sem canvas; o renderer fica no dono único de prévia/export (um call site), como S13–S30. Rejeitadas: B porque espalha a tabela de linhas no arquivo de desenho; C porque seria um segundo dono de render (twin). -
Geometria — px medidos do gate em 1080×1920, constantes
COLINHA_*pinadas em unit; candidato shrink-to-fit em uma linha. Opções: A) portar os valores medidos do gate em px | B) recalcular percentuais/cqwem runtime | C) desenhar na escala 900×1600 do tile. Recomendação: A — canvas não tem CSS; os valores do gate em 1080×1920 são a régua (re-medir no browser se algo divergir ao portar). Valores:- topo: y
0 → 710,4(37% de 1920), fundo#148fc2; foto do grupoteam-card-base.png(1080×1440) em cover, desenhada em(0, −335,62, 1080, 1440)com clip no bloco. - caixa da marca:
(32,4; 21,29; 529,19×134,97); fundo gradiente linear 125°#e4102f0→52% e#184e9252→100% (linha CSS: dir(sin125°, −cos125°), comprimento|w·sinθ| + |h·cosθ|, stops viacreateLinearGradient); lockuppublic/campaign-kit/marca-negativa-completa.png(1037×595) contido → rect desenhado(226,4; 48,29; 141,1×80,97)(o padding percentual do gate resolve contra o bloco de 1080 = 27px, não contra a caixa; não recalcular o contain a partir de “13,23”). - faixa vermelha:
(0; 504,39; 1080×206,0), fundo#e4102f; artepublic/cards/team-card-front.png(1080×1440) recortada nas linhas de origem1232,36 → 1438,36, desenhada com clip emdy = 504,39 − 1232,36 = −727,97. - linha legal vertical: box
(7,55; 748,79; 15,66×1132,81); textoFEDERAÇÃO BRASIL DA ESPERANÇA - FE BRASIL (PT-PC DO B - PV) | CNPJ CANDIDATO: 68.430.467/0001-05;700 15,66px, letter-spacing ~0,31, cor#333, rotacionada −90° (lê de baixo para cima). - corpo:
(51,83; 710,39; 1028,17×1209,61); padding topo 34,56 / lados 35,64 / base 32,4; gap entre linhas 34,56; centralizado verticalmente; cada uma das 6 linhas min-height 108; grid da linha =30% | 1fr | autocom gap 21,6 (coluna do rótulo ≈287,07). Derivado: primeira linha em y ≈ 905,88 e passo 142,56 (6×108 + 5×34,56 = 820,8 no miolo de 1142,65). - rótulo do cargo:
900 27px(line-height 1,02), caixa alta,#171717, quebrasDEPUTADO\nFEDERALeDEPUTADO\nESTADUAL, uma linha nos outros quatro. - candidato:
900 26,46px,#e4102f, gap ~9,6 acima; shrink-to-fit em UMA linha dentro da coluna de 287px, piso 18px — rejeitadas a quebra em duas linhas com altura variável (o CSS do gate quebra; o ritmo fixo das 6 linhas é melhor no canvas) e candidatos de duas linhas fixas. - caixas de dígito:
59,39×73,44, borda5,94#111, raio6,48, fundo branco, dígito900 46,44pxcentrado; gap 8,1; vazia = borda#9a9a9a, fundo#fafafa, dígito invisível. - pill CONFIRMA: raio cheio, fundo
#009647, padding17,28×21,6,900 21,6pxbranco; vazia = 30% de opacidade (fill#0096474d, semglobalAlphano subset). - posições: CONFIRMA na borda direita da linha (coluna
auto); dígitos alinhados à esquerda na coluna do meio. Rejeitadas: B porque canvas não interpreta CSS e a conversão runtime reintroduz erro de medição; C porque a régua aprovada é 1080×1920 (o tile 900×1600 é só arte de galeria).
- topo: y
-
CardDrawContextganharoundRect(fill-only). Opções: A) adicionarroundRectreal e compor bordas com dois preenchimentos (externo na cor da borda, interno no fill) | B)stroke/lineWidthno subset | C) cantos com arcos manuais. Recomendação: A — método real, subset mínimo e fill-only; caixas (borda 5,94), pill e estados vazios saem de doisroundRectpreenchidos; o recorder falso registra a op. Pela geometria medida o subset ganha também os membros reaisclip(recortes do topo/faixa),createLinearGradient(caixa da marca) eletterSpacing(linha legal). Rejeitadas: B porque stroke centrado exigiria meia-borda na geometria e polui o subset; C porque reinventaroundRect. -
Composer — passo único, CTA baixa direto da prévia compartilhada. Opções: A) sem
result: CTABaixar minha colinhabaixa direto do canvas da prévia; desabilitado até estadual + imagens prontas;Gerando…durante | B) dois passos compose→result como os outros modelos | C) dois CTAs (criar + baixar). Recomendação: A — não há nome/foto para confirmar; as cenas 2 e 5 do gate mostram um único CTA; evita estado novo. Rodapé fiel ao gate: dialog =Cancelar+ primário (cena 2); drawer = só o primário full-width (cena 5). Prévias: compacta pré-escolha (cena 2, 145px) e grande pós-escolha (cena 3 desktop 405px / cena 5 mobile 300px) — no branch da colinha omax-h-[38dvh]do S15 não se aplica (o 9:16 precisa da largura da cena 3 e rola com o corpo); os demais modelos ficam intocados. Rejeitadas: B porque adiciona tela de confirmação sem conteúdo novo; C porque não existe no design. -
Tile — cópia byte-a-byte do asset aprovado; badge
NOVOmuda de modelo. Opções: A) copiardocs/plans/cards-colinha-ui-design-assets/modelo-colinha.jpegparapublic/cards/modelo-colinha.jpeg(900×1600, sha256 pinado) | B) derivativo via script sharp | C) referenciar o arquivo dedocs/plans/nosrc. Recomendação: A — precedente S30;docs/não é servido em produção; um asset não justifica script. O badgeNOVOsai detime-do-estaduale entra emminha-colinha(literal assumido, gate cena 1). Rejeitadas: B (script para 1 arquivo; mestre novo não aprovado); C (não é servido pelo Next). -
Galeria — seis tiles na mesma fileira. Opções: A)
lg:grid-cols-6mantendolg:gap-4+ dicaDeslize para ver os seis modelos(os dots já derivam deCARD_MODELS.length) | B) manter 5 colunas e esconder o 6º no scroll | C) extrair carrossel/dots genérico. Recomendação: A — o gate cena 1 desenha seis colunas; dots e contagem já são derivados; nada de abstração nova./cardspassa aEscolha um dos seis modelos, personalize e baixe para compartilhar.e o doc-comment da home (CampaignCardsSection.tsx:5) “five”→“six”. Rejeitadas: B viola o gate; C abstração sem segundo consumidor. -
Entrada do modelo.
id:'minha-colinha',kind:'colinha',label:'Minha colinha',badge:'NOVO',stateDeputyPicker:true,assetSrc:'/cards/team-card-base.png'(foto do grupo),overlaySrc:'/cards/team-card-front.png'(arte da faixa),lockupSrc:'/campaign-kit/marca-negativa-completa.png'(novo campo opcional deCardModel),previewSrc:'/cards/modelo-colinha.jpeg',width:1080,height:1920, semphotoWindow. -
Copy do composer — literais do gate + nota nova; seletor S30 intocado. Opções: A) portar os literais das cenas 2/3/5 e criar constante nova em
cardCopy.ts| B) reusarCARD_PHOTO_PRIVACY_NOTE| C) reescrever a copy. Recomendação: A — a nota existente fala de “nome e foto” (falsa aqui: nada é digitado/enviado); a nova é o literal do gate.StateDeputySelecte sua dica seguem intocados (superfície S30 não é tocada). Rejeitadas: B porque a frase não corresponde ao fluxo sem foto; C porque o gate é a fonte. -
Case dos textos. Opções: A) rótulos UPPERCASE; fixos em Title Case como o gate/modelo; estadual UPPERCASE; vazio
Escolha abaixo| B) tudo UPPERCASE | C) estadual em Title Case como no catálogo. Recomendação: A — fidelidade literal (cena 3/4:JULIO PINHEIRO; fixosJorge Solla,Jaques Wagner,Rui Costa,Jerônimo,Lula); o catálogo guarda o nome de exibição e a colinha aplicatoLocaleUpperCase('pt-BR'). Rejeitadas: B muda os fixos aprovados; C diverge do gate. -
Testes — estender os pins e o spec
frontend; manifesto sem mudança. Opções: A) atualizarcardModels/cardRender, criarcardColinha.unit.spec.tse estendertests/e2e/frontend.e2e.spec.ts| B) spec e2e novo separado | C) só unit. Recomendação: A — o harness/probes do estúdio já vivem no specfrontend;scripts/lib/e2e-affected-manifest.mjsNÃO muda (o prefixosrc/lib/cardjá casacardColinha.ts,src/components/cardscasa o composer epublic/é ignorado); int não se aplica (sem Payload/DB/access/escrita multi-collection). Rejeitadas: B fragmenta o harness e duplica setup; C não cobre o aceite visual (prévia/download/troca).
Componentes / mudanças
src/lib/cardColinha.ts(novo, puro, client-safe): geometriaCOLINHA_*(topo, marca, faixa, legal, corpo, linha, rótulo, candidato, dígito, confirmar; cores e pesos),COLINHA_LEGAL_TEXT, tabela fixa das 5 linhas ecolinhaVoteRows(deputy: StateDeputyCatalogEntry | null)→ 6 linhas na ordem do gate (federal, estadual, 2× senador, governador, presidente), comofficeLines,candidate,digits(por caractere) e o marcador de estado vazio (5 slots +Escolha abaixo+ CONFIRMA esmaecido).src/lib/cardRender.ts(editar):CardDrawContextganharoundRect(+clip,createLinearGradient,letterSpacing— membros reais exigidos pela geometria medida);renderColinhaCard(ctx, model, args)desenha na ordem medida — fundo branco → topo (fundo, foto recortada, caixa da marca com gradiente, faixa recortada) → linha legal rotacionada → 6 linhas (rótulo, candidato shrink-to-fit, caixas de dígito, pill) — reusandoCardMeasureText;createCardMeasureganha peso opcional com default 700 (S13–S30 intocados) para medir o candidato em 900.src/lib/cardModels.ts(editar):CARD_MODEL_IDScom 6 ids;kindganha'colinha';CardModelganhalockupSrc?: string; entrada de S31 (Decisão 9) e remoção dobadgedetime-do-estadual.src/components/cards/CardComposer.tsx(editar):isColinhaModel; branch de carregamento (foto do grupo + faixa + lockup;previewSrcfica só no tile) e de render no canvas; semuseCardCutout/nome/harmonia no fluxo; título/eyebrow/descrição por estado; seletor S30 reusado; caixaLinha conferida; nota nova; CTA único (Decisão 6) chamando ohandleDownloadexistente.src/components/cards/cardCopy.ts(editar): constante nova da nota de privacidade da colinha (A escolha é processada neste aparelho. Nenhum nome, foto ou cadastro é solicitado.).src/components/cards/CardModelGallery.tsx(editar):lg:grid-cols-6+lg:gap-4, dicaDeslize para ver os seis modelos, doc-comment “five”→“six”.src/components/cards/CardModelTile.tsx(editar só osizes): okind:'colinha'cai noImagecompreviewSrc(fall-through já existente); osizesde 5 para 6 colunas (167px).src/app/(frontend)/(home)/cards/page.tsx(editar): introEscolha um dos seis modelos, personalize e baixe para compartilhar..src/app/(frontend)/(home)/CampaignCardsSection.tsx(editar): doc-comment “five”→“six”.public/cards/modelo-colinha.jpeg(novo): cópia byte-a-byte do asset aprovado (900×1600, sha25676505492fb243c67313d237e58926afbd4d0847c00ab3bb43c090859cbdf18c8).- Testes (editar/novo):
tests/unit/cardModels.unit.spec.ts(6 ids, pin do modelo novo +lockupSrc, badge movido),tests/unit/cardRender.unit.spec.ts(recorder falso comroundRect/clip/gradiente; ordem e medidas dorenderColinhaCard; estado vazio),tests/unit/cardColinha.unit.spec.ts(novo,// @vitest-environment node: pins deCOLINHA_*,colinhaVoteRowsfixo/preenchido/vazio, sha256 + 900×1600 do tile viasharp),tests/e2e/frontend.e2e.spec.ts(loop de 6 tiles + badge emminha-colinha; 6 dots +seis modelos; describe novoCards personalizados (S31 — Minha colinha)). scripts/lib/e2e-affected-manifest.mjs: sem mudança —src/lib/cardjá casacardColinha.ts,src/components/cardscobre composer/galeria e assets empublic/são ignorados pelo manifesto.docs/changelog/2026-09-23-s31-minha-colinha.md(novo).- Migration: sem migration — nenhuma collection/global/field toca o schema;
push:falseintocado. - Access / Consent: não se aplica — nenhuma superfície Payload, nenhum opt-in; o fluxo é 100% client-side e a escolha não sai do aparelho.
- UI: Impeccable B — shape (gate cenas 1–5) → craft (port classe-a-classe das medidas) → critique (a11y toque/teclado, mobile 390, contraste das caixas, copy) → polish. Shells/tokens reusados:
CardsStudio,ui/dialog,ui/Drawer,CardPreviewCanvas,StateDeputySelect,--pt-red/--campaign-*; alvos ≥44px;role=status/role=alertherdados. Crítica final (c) dodesigner: 1ª passada DEGRADED com 2 ajustes — tipografia do canvas devia ser o stack do gate, não a display da campanha, e a descrição não devia ocupar o cabeçalho do drawer mobile (cena 5) — ambos aplicados (COLINHA_FONT_FAMILYno desenho/medição; descrição só no dialog) e certificados na 2ª passada (Design tier: openai/gpt-5.6-sol).
Dados → forma (se aplicável)
Não se aplica (data-presentation Q3): nenhum KPI, mapa ou série; a única “forma” é a geometria do card. A escolha do estadual é insumo local da imagem — nunca dado coletado, apresentado ou enviado (medição de uso é S32).
Fases verificáveis
- Núcleo puro + modelo + tile — quota ~0,5 dia.
cardColinha.ts(geometria + tabela + builder);renderColinhaCard+ membros novos do subset nocardRender.ts;cardModels.ts(6º modelo,lockupSrc, badge movido); cópia byte-a-byte do jpeg; unit pins (cardModels,cardColinha,cardRender). Prova:pnpm gate:fastverde;sha256sum public/cards/modelo-colinha.jpeg docs/plans/cards-colinha-ui-design-assets/modelo-colinha.jpegidênticos; unit da colinha verde (geometria, linhas, 900×1600). - Composer + galeria + copy — quota ~0,5 dia. Branch
kind:'colinha'noCardComposer(passo único, CTA direto, prévias 145/300/405,Linha conferida, nota nova); galeria 6 colunas/dica/dots; intro/cardse doc-comment da home. Prova:pnpm gate:fastverde;?model=minha-colinhano browser: estado vazio (Escolha abaixo, 5 caixas vazias, CONFIRMA esmaecido, CTA desabilitado), escolha por busca/↑↓/Enter, prévia com nome + 5 dígitos, CTA habilitado,Baixar minha colinha;/cardscom 6 tiles e dica dos seis. - Gates + e2e + changelog — quota ~0,3 dia. e2e (loop 6 tiles + badge; 6 dots +
seis modelos; describe S31); changelog;pnpm gate:fast; e2e da superfície;pnpm push(pre-push rodagate:ci). Prova:pnpm test:e2e --no-deps -- tests/e2e/frontend.e2e.spec.ts -g "Minha colinha"verde (prévia vazia + CTA off, seleção por teclado, prévia preenchida, download realcard-jorge-solla-minha-colinha.pngcom assinatura PNG, troca mantendo a escolha); fixture de console-error intacta.
Rabbit holes / Não escopo (engenharia)
- PDF/A4 ou impressão em casa (intenção, Questão 1) — só PNG 9:16; A4 vira item próprio se o produto pedir.
- Nome do visitante/“feito por você” (Questão 2) — a colinha é o produto.
- Segundo editor/estúdio, rota/página por colinha, editor de linhas (reordenar/remover cargos),
?estadual=. - Analytics de uso/abandono (S32); qualquer medição da escolha.
- CMS/collection/migration; ler
stateDeputy/Contact; qualquer superfície Payload. - Re-harmonização/segundo estilo de card; 53 modelos (a colinha é uma só); compartilhamento direto em redes.
- Redesenhar o topo/arte-mestre fora do gate; tipografia nova; otimização/prebuild de assets ou script de build (um asset = cópia byte-a-byte).
- Tocar nas artes-mestre (
team-card-base.png,team-card-front.png, kit) e nos cinco modelos existentes além do badge; mexer noStateDeputySelect/dica de S30.
Explicitamente fora (descartes e defers com gatilho do simplify)
- Descartado — ternários por
kindno composer (revisores 1/2): a dívida é a F2 do #1277 (escala-dry-pos-s30.md), que já absorvecanAdvance/adjustable/eyebrow/title/estágios de prévia; nada a duplicar aqui. - Descartado — identificadores PT (
colinha/isColinhaModel/kind:'colinha'): literal do gate auto-aprovado no plano (palavra do domínio, como os enums depost.type). - Descartado — pins de geometria no unit/e2e e
sizes167px: duplo pin intencional da composição (as constantes já são pinadas emcardColinha.unit); osizesfoi medido (166,7px para 6 colunas do contêiner de 1080). - Descartado — pureza ≤2 (
colinhaVoteRowsmutável/refs compartilhadas,Recordinline,drawColinhaToprecebendoCardModel): sem bug e sem 2º consumidor. - Defer —
lockupSrcopcional: gatilho = 2º campo required porkindou 2º consumidor delockupSrc(entra junto com a união discriminada deCardModel). - Defer — dígitos/
ballotNumber(5 fixo): gatilho = catálogo ganhar código ≠5 dígitos ou layout parametrizado pela contagem. - Defer — teste do caminho de falha do download: gatilho = próxima mexida no caminho de download/erro do estúdio.
- Re-defer — par JULIO default morto/duplicado (S30 P6+P10, #1277): o gatilho do S30 (“o S31 revisita o contrato”) disparou, mas a condição não se cumpriu — os defaults seguem mortos e sem 2º consumidor; o S31 só acrescentou
lockupSrc. Novo gatilho: 2º consumidor do par default ou modelo que precise de default real (não ilustrativo). - Já resolvido no simplify (não reabrir):
downloadErrorrenderizado no compose da colinha (alert novo), doc depreviewSrc, plano/codebase-map,Linha conferidaderivada decolinhaVoteRows(fim do rótulo/case duplicados), splice de classe, guardwidth <= 0,drawColinhaDigit(empty), altura da pill calculada 1×,capAt,pickJulioByKeyboardiçado, nota de privacidade asserida no e2e.
Riscos e mitigação
- Fidelidade do topo vs
modelo-colinha.jpeg: o port segue as medidas do gate + crítica do designer (c) + UAT; os númerosCOLINHA_*ficam pinados em unit e a divergência gate × modelo é literal assumido (fonte canônica = gate). Gatilho: crítica do designer reprovar → ajustar só as constantes. - Nomes longos do catálogo (53): shrink-to-fit em uma linha com piso 18px; unit pina o builder/geometria e o UAT cobre o pior caso (
Artur Barachisio Lisbôa,Coletivo de Enfermagem); se um nome ainda estourar no piso, o candidato quebra em duas linhas apenas nessa linha (revisitar a Decisão 4). - Badge
NOVOmovido quebra pins: unit + e2e atualizados no mesmo PR (literal assumido). - Medida do candidato em 900:
createCardMeasuremede em 700; o peso opcional (default 700) entra junto para o shrink medir o que desenha — sem tocar S13–S30. - Regressão nos modelos S13–S30: subset só ganha membros; nenhum call site antigo muda; unit/e2e dos cinco modelos seguem verdes; o
max-h-[38dvh]do S15 fica intocado (o branch da colinha tem o próprio enquadramento). - Prévia 9:16 no dialog: sem o teto de altura do S15 a prévia usa a largura da cena 3 e rola com o corpo; se o UAT achar o dialog alto demais, reduzir a largura pós-escolha (constante da Decisão 6), nunca a fidelidade das linhas.
- Peso do asset novo (~250KB): aceito; cópia byte-a-byte sem script e sem tocar no bundle JS.
Aceite de engenharia
- Aceite de produto da intenção ainda coberto: 6º modelo
Minha colinhana home e/cards(#cards,/cards,?model=minha-colinha); escolha do estadual na lista de S30 por toque/teclado; prévia com nome de urna + 5 dígitos (um por caixa) e as 5 linhas fixas intocadas; PNG 1080×1920 baixado do mesmo estúdio; 100% no aparelho (sem nome/foto/upload); fidelidade ao gate (topo, linha legal vertical, corpo); sem página/rota por colinha. - Invariantes AGENTS/engineering-standards: sem migration/collection/Consent;
src/libpuro/client-safe (cardColinhasemutilities/); copy pt-BR/identificadores em inglês; semas never; knip sem órfãos; artes-mestre intocadas;pnpm gate:fast+ e2e da superfície +pnpm pushverdes. - Testes de domínio previstos: unit dos módulos puros (6 ids/badge/
lockupSrc, pins deCOLINHA_*,colinhaVoteRowspreenchido/vazio, render no recorder falso comroundRect/clip, sha256 + 900×1600 do tile) obrigatório; e2e no specfrontend(6 tiles + badge, 6 dots +seis modelos, describe S31 com prévia vazia + CTA desabilitado, busca/teclado, prévia preenchida, download PNG, troca mantendo a escolha); int não se aplica — sem Payload/DB/access nem escrita multi-collection neste fluxo (client-side + assets estáticos).
Literais assumidos (auto-aprovados)
- Modelo: id
minha-colinha, labelMinha colinha,kind:'colinha',stateDeputyPicker:true,badge:'NOVO'(movido detime-do-estadual),assetSrc:'/cards/team-card-base.png',overlaySrc:'/cards/team-card-front.png',lockupSrc:'/campaign-kit/marca-negativa-completa.png',previewSrc:'/cards/modelo-colinha.jpeg',1080×1920, semphotoWindow. - Tile:
public/cards/modelo-colinha.jpeg= cópia byte-a-byte dedocs/plans/cards-colinha-ui-design-assets/modelo-colinha.jpeg(900×1600; sha25676505492fb243c67313d237e58926afbd4d0847c00ab3bb43c090859cbdf18c8). - Linhas fixas (ordem e literais):
DEPUTADO FEDERAL · Jorge Solla · 1313(4 caixas) ·DEPUTADO ESTADUAL · <nome> · <5 dígitos>(5 caixas) ·SENADOR · Jaques Wagner · 130·SENADOR · Rui Costa · 133·GOVERNADOR · Jerônimo · 13·PRESIDENTE · Lula · 13; todas comCONFIRMA. - Legal:
FEDERAÇÃO BRASIL DA ESPERANÇA - FE BRASIL (PT-PC DO B - PV) | CNPJ CANDIDATO: 68.430.467/0001-05. - Case: rótulos UPPERCASE; fixos em Title Case (
Jorge Solla,Jaques Wagner,Rui Costa,Jerônimo,Lula); estadual UPPERCASE (gateJULIO PINHEIRO); vazioEscolha abaixo. - Copy do composer: eyebrow
Minha colinha; pré-escolha títuloEscolha seu estadual+ descriçãoA linha de deputado estadual será preenchida na hora.; pós-escolha título dialogPronta para levar com você/ drawerPronta para baixar+ descriçãoConfira o estadual escolhido. As demais escolhas já vêm preenchidas no modelo oficial.; aviso pré-escolhaEscolha um estadual para baixar./A linha vazia será preenchida com o nome e os cinco dígitos.; pós-escolhaLinha conferida+DEPUTADO ESTADUAL · <NOME MAIÚSCULO> · <5 dígitos>; CTABaixar minha colinha/Gerando…; nota novaA escolha é processada neste aparelho. Nenhum nome, foto ou cadastro é solicitado. - Galeria:
lg:grid-cols-6comlg:gap-4; dicaDeslize para ver os seis modelos; intro/cardsEscolha um dos seis modelos, personalize e baixe para compartilhar.; badgeNOVOno modelo novo (assert e2e acompanha). - Geometria: constantes
COLINHA_*com os valores da Decisão 4 (fonte canônica = gate em 1080×1920; o gate ×modelodivergente fica sinalizado para a crítica do designer). - Prévias: 145px pré-escolha; 300px mobile / 405px desktop pós-escolha; rodapé dialog
Cancelar+ primário, drawer só primário full-width.
Self-score decision-quality: 5/5
- Decisões caras com rejeitadas: modelo/kind, estratégia de render, módulos, geometria (e o candidato em uma linha), subset do contexto, fluxo do composer, tile/badge, galeria, entrada, copy, case e harness de testes — todas com Opções/Recomendação/Rejeitadas.
- Cabe no appetite: 3 fases ≤1,3 dia, sem migration/infra; o único peso novo é 1 asset copiado byte-a-byte (~250KB), já previsto na intenção.
- Rabbit holes nomeados: PDF/A4, nome do visitante, segundo editor/rota, editor de linhas, analytics, CMS, 53 modelos, redesenho do topo, script de asset, tocar nas artes-mestre.
- Depth check: reusa
CardsStudio/shells,CardComposer,StateDeputySelect/stateDeputyCatalog,CardPreviewCanvas/cardCanvas/cardFileName, o donocardRendere o padrão de cópia byte-a-byte + sha256 de S30; nada de abstração especulativa. - Intenção preservada: aceite de produto intacto (6º modelo, escolha S30, prévia preenchida, PNG 1080×1920, 100% local, 5 modelos intocados além do badge); a engenharia só resolveu forma (kind novo, render portado, módulo puro, branch single-step).