teqo-backup/docs/plans/remover-pins-classname.md
Francisco Ignácio Fontoura Solla 8a60ab1ec8 docs(plans): register OPS13–15 guardrail hygiene chores
Classname/token pin removal, form-action ladder guard, kill TooltipProvider JSX nesting pin.
2026-08-02 13:40:25 -03:00

103 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Remover pins de className / tokens Tailwind literais
Status: registrado
Atualizado em: 2026-08-02
Issue: #240 (OPS13)
Priority: P2
Model: composer-2.5
Impeccable: A — N/A (sem superfície UI; só testes de convenção / pin unitário)
Appetite: ~0,5–1 dia eng; editar specs unitárias; sem migration; sem mudança de produto obrigatória
Responsável: —
## Dados → decisão → apresentação
Dados: N/A — higiene de guardrails de teste; sem métrica de produto.
## Contexto
Review de guardrails (2026-08-02): vários unit specs congelam **strings completas de `className`**, sequências Tailwind e tokens hex de CSS. Exemplos vivos:
- `tests/unit/campaignComponents.unit.spec.ts` — `className="h-svh min-h-0 overflow-hidden print:h-auto print:overflow-visible"`; sticky `sticky left-0 z-20…min-w-56…`; `--sidebar: #fafaf9` / foreground hex
- `tests/unit/campaignHomeActionButton.unit.spec.tsx` — `w-[5.5rem]`, `gap-0`, `px-4`
- `tests/unit/campaignHomeLayout.unit.spec.tsx` — `-mx-4`, `w-[calc(100%+2rem)]`, `grid-rows-[0fr]`, `opacity-0`
- `tests/unit/campaignWizardShell.unit.spec.tsx` — `pt-2` vs `pt-3`, `pb-6`
- `tests/unit/campaignQuickActionsDrawer.unit.spec.tsx` — `-mx-4`, `w-[calc(100%+2rem)]`
- `tests/unit/homeSearchResultsLayout.unit.spec.tsx` — `flex-col` / `md:grid-cols-2` / `lg:grid-cols-3`
O intent original (shell fixa + scroll no content pane; coluna Município sticky; touch target; contraste da sidebar) é legítimo. O **mecanismo** (literal de utilitários) empurra agentes a: (a) não mexer no layout com bug real; (b) satisfazer a string e colocar o comportamento em outro arquivo; (c) “passar” o gate sem preservar a invariante.
Pedido: **remover** esses pins de classname/token e, onde a invariante ainda importa, **substituir por pin comportamental** (`data-slot`, role/ARIA, presença de região de scroll, não-presença de `title=` onde deve ser texto acessível, etc.).
## Objetivos
- Nenhum unit spec sob `tests/unit/` exige igualdade/substring de uma **lista completa de utilitários Tailwind** (ex. string multilasse colada do JSX) nem hex de token CSS como prova de layout.
- Invariantes que ainda valem ficam pinadas por **contrato estável**: `data-slot`, `data-*` de domínio, roles/ARIA, uso de constantes exportadas (`HOME_SEARCH_*_CLASS` **como símbolo**, sem reassertar o conteúdo da constante), ou comportamento renderizado (texto acessível, overflow scrollport presente).
- Specs que só existiam para congelar spacing/sizing cosmético (`pt-2` vs `pt-3`, largura exata do botão) **somem** ou viram assert do contrato exportado, sem re-listar utilities.
- Atualizar `docs/GUARDRAILS.md` / nota curta se alguma linha citar esses pins; entrada no ledger se P4-H-adjunto não se aplicar.
- Guardrails: sem migration; sem mudança de UI obrigatória neste PR (só testes/docs). Se um pin comportamental exigir `data-slot` novo no shell, é permitido e mínimo.
- **Tracer bullet:** apagar o `toContain('className="h-svh…')` em `campaignComponents` → substituir por assert em `data-slot="campaign-content-scroll"` + overflow no scrollport (já parcialmente presente) → `pnpm gate:fast` verde.
## Decisões travadas
- **Remover literais de className/token; não “afrouxar” para regex parcial da mesma string.** Opções: A) delete puro | B) delete + pin comportamental onde havia invariante de produto | C) manter e documentar judgment-only. **Recomendação: B.** A sozinho perde cobertura real (shell scroll / sticky / a11y). C perpetua o incentivo a shortcut. **Rejeitado:** C; “só comentar o expect”.
- **Constantes exportadas (`HOME_SEARCH_*_CLASS`) podem continuar sendo referenciadas por identidade (`toBe(CONST)`), sem `toContain('rounded-md')` adjacente que recongele o conteúdo.** Se o spec hoje compara `className === CONST` **e** ainda lista utilities, manter só a igualdade ao símbolo. **Rejeitado:** expandir pins para o valor string da constante.
- **Hex de `--sidebar*`:** provar contraste/tema via token name (`text-sidebar-foreground`) ou snapshot de contrato de tema se existir; não o valor `#fafaf9`. **Rejeitado:** pin de palette hex em unit (design tokens mudam sem bug).
- **Sticky Município:** pinar `data-slot` / sticky via atributo estável ou teste de presença da célula sticky sem a sequência `z-20…min-w-56…`. **Rejeitado:** regex da class completa.
- **Kind: `chore` (OPS13).** Engenharia de guardrail, não feature de `/campanha`.
- **i18n:** ids de teste/data-slot em inglês; copy pt-BR intocada.
## Questões em aberto
- **Incluir também asserts `min-h-11` / `min-w-11` (touch target)?** **Opções:** A) remover junto (são classname) | B) manter como proxy de touch target até haver pin computed-style/e2e. **Recomendação:** **A neste item** — o produto já tem regra em `campanha-edit-where-you-see`; o literal Tailwind é o mesmo cheiro. Se regressão de touch aparecer, e2e/comportamental depois. _(assumido)_
- **`campaignCompositionCleanup` `w-full` no submit?** **Opções:** A) no escopo | B) fora (é um assert pontual de form). **Recomendação:** **A** se for `className` literal; fora se for só layout smoke sem lista de utilities. _(assumido: incluir se for toContain de utility)_
## Abordagem proposta
```mermaid
flowchart LR
audit["Listar expects className/token"] --> classify{"Invariante de produto?"}
classify -->|não| delete["Apagar expect"]
classify -->|sim| replace["Pin data-slot / ARIA / símbolo"]
delete --> gate["gate:fast"]
replace --> gate
```
Componentes:
- **Auditoria mecânica:** `rg "className|toMatch\\(/sticky|--sidebar: #" tests/unit` — checklist no PR; cada hit classificado delete vs replace.
- **`tests/unit/campaignComponents.unit.spec.ts`:** remover strings de layout/sidebar hex/sticky utilities; conservar `data-slot="campaign-content-scroll"`, `data-scope`, badges semânticos, a11y de prioridade/classe territorial (`sr-only` vs `title` — esse pin é de **conteúdo acessível**, não de classname de layout; **manter**).
- **Home / wizard / drawer / search layout specs:** cortar expects de spacing/bleed/grid utilities; onde B115/B116 etc. dependem de contrato, apontar para constante exportada ou `data-slot` já existente.
- **`docs/GUARDRAILS.md`:** se alguma linha referenciar pin de classname, atualizar; senão só o PR das Issues.
- **Migration:** nenhuma.
## Dependências
- Nenhuma dura. Independente de OPS14/OPS15.
- Soft: issues de UI mobile (B115/B116) podem conflitar em specs de home — rebase trivial; não bloqueia registro.
## Não escopo
- Reescrever o shell visual / redesign.
- Matar pins de **comportamento** (`data-pending`, `aria-busy`, `data-slot` semântico, texto acessível vs `title`).
- OPS14 (form-action por política) e OPS15 (TooltipProvider nesting).
- ESLint banindo Tailwind arbitrary values.
## Rabbit holes
- **"Já que mexo no spec, refatoro o layout".** Explode appetite. **Mitigação:** só testes (+ `data-slot` mínimo se faltar âncora).
- **Substituir classname por snapshot HTML enorme.** Mesmo cheiro. **Mitigação:** asserts pontuais de contrato.
- **Computed style em jsdom.** Frágil e barulhento. **Mitigação:** não neste item; data-slot/ARIA bastam.
## Adiado com gatilho
- **Pin e2e de scroll/sticky real.** Revisitar se regressão de shell voltar após remoção dos literais.
- **Lint `no-restricted-syntax` contra `toContain('min-h-` em tests.** Só se agentes reintroduzirem o padrão ≥2×.
## Referências
- GitHub Issue #240 (OPS13)
- Review de guardrails (chat 2026-08-02) — item 1
- `tests/unit/campaignComponents.unit.spec.ts` (shell + sticky + sidebar)
- `tests/unit/campaignHomeLayout.unit.spec.tsx`, `campaignHomeActionButton.unit.spec.tsx`, `campaignWizardShell.unit.spec.tsx`, `homeSearch*.unit.spec.tsx`, `campaignQuickActionsDrawer.unit.spec.tsx`
- `docs/GUARDRAILS.md` — escada de determinismo
- AGENTS.md / engineering-standards — gates; não congelar incidental syntax