mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 06:43:06 +00:00
Merge pull request #243 from fsolla/cursor/ops-guardrail-plans
OPS13–15 — planos: higiene de guardrails (classname / form-action / TooltipProvider)
This commit is contained in:
commit
f66381e09f
3 changed files with 304 additions and 0 deletions
103
docs/plans/form-action-guard-escada.md
Normal file
103
docs/plans/form-action-guard-escada.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Form-action guard — política na escada, não no filename
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-02
|
||||
Issue: #241 (OPS14)
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Impeccable: A — N/A (sem superfície UI; convention spec)
|
||||
Appetite: ~1 dia eng; reescrever guarda em `codebaseConventions` (+ migrar ladders expressíveis se couber no mesmo PR); sem migration
|
||||
Responsável: —
|
||||
|
||||
## Dados → decisão → apresentação
|
||||
|
||||
Dados: N/A — higiene de guardrail; sem métrica de produto.
|
||||
|
||||
## Contexto
|
||||
|
||||
Pass 2 W4d / C8 F4b: `runCampaignFormAction` / `runCampaignRedirectFormAction` unificam a escada try/catch → `mapCampaignFormActionError` → return/redirect. A guarda em `tests/unit/codebaseConventions.unit.spec.ts` só varre arquivos cujo **filename** casa `*FormActions.ts` ou `taskActions.ts`.
|
||||
|
||||
**Dodge ledgerado (P3-I / `docs/TECH-DEBT.md` / `docs/GUARDRAILS.md`):** ladders hand-rolled em `src/app/(campaign)/campanha/actions/*.ts` são invisíveis à guarda. Baseline medido no Pass 4: ~7 ladders assim (`profile` avatar×2, `leaderSupporter`, mais `password`/`auth` parcialmente bespoke). Actions novas que **usam** o wrapper (`notifications`, `webauthn`, …) passam por disciplina, não por mecanismo.
|
||||
|
||||
Agentes otimizam o gate: colocar mutação nova em `actions/foo.ts` com try/catch + `mapCampaignFormActionError` literal **não quebra o build**, embora viole a política.
|
||||
|
||||
Pedido (review 2026-08-02, item 2): **melhorar o pin** — falhar o build quando a **escada** aparece fora do wrapper, independentemente do path.
|
||||
|
||||
## Objetivos
|
||||
|
||||
- A guarda deixa de filtrar por filename `*FormActions.ts` / `taskActions.ts`.
|
||||
- Critério positivo: export/`'use server'` action sob `src/app/(campaign)` que implementa a escada (try + `mapCampaignFormActionError` **sem** passar por `runCampaign(Redirect)?FormAction`) é offender, salvo allowlist **com reason** por arquivo (ou por símbolo).
|
||||
- Allowlist inicial documenta exceções genuínas hoje (`atividades/formActions` unique-violation, `apoiadores/[id]` flatten, `taskActions` optimistic, e o que for realmente inexprimível nos wrappers — `auth`/`password` se ainda forem).
|
||||
- Ladders **expressíveis com zero delta semântico** (`profile` avatar, `leaderSupporter` se ainda raw) migram para o wrapper **neste item** ou ficam como offenders até migrar no mesmo PR — não expandir allowlist “porque o filename mudou”.
|
||||
- Atualizar linha em `docs/GUARDRAILS.md` e fechar/anotar P3-I no `TECH-DEBT.md`.
|
||||
- Guardrails: sem migration; access control inalterado; sem mudar copy de erro.
|
||||
- **Tracer bullet:** spec que flagra um fixture/`actions/*.ts` com try+mapError sem wrapper → verde após migrate ou allowlist justificada → `pnpm gate:fast`.
|
||||
|
||||
## Decisões travadas
|
||||
|
||||
- **Detecção = presença da escada (try + `mapCampaignFormActionError`), não do filename.** Opções: A) sweep AST/regex em `(campaign)/**/*.ts` | B) ESLint rule local | C) só ampliar filename para `actions/*.ts`. **Recomendação: A (convention spec)** — mesmo mecanismo da guarda atual, um PR, alinhado a P3-I. **Rejeitado:** C (ainda é proxy de path; `lib/` ou helper colocalizado escapa); B como v1 (appetite maior; Adiado com gatilho se A for dodgeable).
|
||||
- **Chamada real a `runCampaignFormAction(` / `runCampaignRedirectFormAction(` continua obrigatória** onde a escada existia — comentário nomeando o wrapper **não** passa (já é invariante atual).
|
||||
- **Não crescer os wrappers** para absorver políticas únicas (unique-violation→fieldErrors, flatten de fieldErrors, optimistic checklist). Essas ficam allowlisted com reason — precedente W4d.
|
||||
- **Migrar o que for expressível no mesmo PR** quando o custo for mecânico (<~3 call sites citados no ledger). Se um arquivo for grande/bespoke, allowlist + defer com gatilho “próxima edição do arquivo”.
|
||||
- **Kind: `chore` (OPS14).**
|
||||
- **i18n:** ids de teste em inglês.
|
||||
|
||||
## Questões em aberto
|
||||
|
||||
- **Incluir `throw` + mapError fora de try no mesmo padrão?** **Opções:** A) só try+mapError (escada clássica) | B) qualquer `mapCampaignFormActionError(` fora de arquivo que já chama o wrapper. **Recomendação:** **B** — o helper de map é o cheiro da escada hand-rolled; wrappers encapsulam o map. Verificar que nenhum call site legítimo chama mapError direto após a migração. _(assumido)_
|
||||
- **`actions/*.ts` que só re-exportam / orquestram sem mapError:** fora do radar. OK.
|
||||
|
||||
## Abordagem proposta
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
walk["walk src/app/(campaign)/**/*.ts"] --> has{"mapCampaignFormActionError( ?"}
|
||||
has -->|não| ok["ok"]
|
||||
has -->|sim| wrap{"runCampaign(Redirect)?FormAction( ?"}
|
||||
wrap -->|sim| ok
|
||||
wrap -->|não| allow{"allowlist + reason?"}
|
||||
allow -->|sim| ok
|
||||
allow -->|não| fail["build fail"]
|
||||
```
|
||||
|
||||
Componentes:
|
||||
|
||||
- **`tests/unit/codebaseConventions.unit.spec.ts`:** substituir `isGuardedActionFile` / describe W4d pelo sweep acima; allowlist `Map<path, reason>` (ou Set + comentário adjacente); manter require de call site real do wrapper.
|
||||
- **Migrações mecânicas (se couber):** `profile.ts` / `leaderSupporter.ts` → `runCampaignFormAction` (espelhar `notifications.ts` / `webauthn.ts`).
|
||||
- **Allowlist residual:** `atividades/formActions.ts`, `apoiadores/[id]/formActions.ts`, `taskActions.ts`, e auth/password se ainda inexprimíveis — reasons copiados do bloco atual + TECH-DEBT.
|
||||
- **`docs/GUARDRAILS.md`:** atualizar a linha “filename `*FormActions.ts` — dodge `actions/*.ts`”.
|
||||
- **`docs/TECH-DEBT.md`:** fechar/anotar P3-I remaining open sobre o dodge de filename.
|
||||
- **Migration:** nenhuma.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma dura. Independente de OPS13/OPS15.
|
||||
- Soft: P3-I ledger row.
|
||||
|
||||
## Não escopo
|
||||
|
||||
- Unificar políticas bespoke (unique violation, flatten) dentro dos wrappers.
|
||||
- Rotas JSON (`campaignJsonMutationRoute`) — já têm guarda própria.
|
||||
- OPS13 classname / OPS15 TooltipProvider.
|
||||
|
||||
## Rabbit holes
|
||||
|
||||
- **"Já que detecto a escada, reescrevo todos os actions do domínio."** Explode. **Mitigação:** migrar só expressíveis; allowlist o resto com gatilho.
|
||||
- **False positive em testes/helpers.** **Mitigação:** sweep só `src/app/(campaign)`; excluir `*.spec.ts`.
|
||||
- **AST completo vs regex.** Regex no estilo das outras convention specs basta; se surgir dodge por rename de mapError, ESLint depois.
|
||||
|
||||
## Adiado com gatilho
|
||||
|
||||
- **ESLint local `require-run-campaign-form-action`.** Revisitar se A for dodgeada ≥1× (rename/`mapError` indireto).
|
||||
- **Absorver unique-violation / flatten nos wrappers.** Revisitar no 3º call site da mesma política.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #241 (OPS14)
|
||||
- Review de guardrails (chat 2026-08-02) — item 2
|
||||
- `tests/unit/codebaseConventions.unit.spec.ts` — bloco formActions / W4d
|
||||
- `docs/TECH-DEBT.md` — P3-I (filename guard escapes)
|
||||
- `docs/GUARDRAILS.md` — linha FormActions
|
||||
- `src/utilities/campaignFormActionError.ts` — wrappers
|
||||
- `src/app/(campaign)/campanha/actions/{profile,leaderSupporter,password,auth,notifications,webauthn}.ts`
|
||||
- AGENTS.md — formActions como cascas sobre `runCampaignFormAction`
|
||||
98
docs/plans/matar-guarda-tooltip-provider.md
Normal file
98
docs/plans/matar-guarda-tooltip-provider.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
# Matar guarda JSX de nesting `TooltipProvider` (B102)
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-02
|
||||
Issue: #242 (OPS15)
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Impeccable: A — N/A (sem superfície UI; remover convention spec)
|
||||
Appetite: ~0,25 dia eng; apagar um `describe` + atualizar GUARDRAILS; sem migration
|
||||
Responsável: —
|
||||
|
||||
## Dados → decisão → apresentação
|
||||
|
||||
Dados: N/A — remoção de guardrail frágil; sem métrica de produto.
|
||||
|
||||
## Contexto
|
||||
|
||||
B102 (#129 / miss #133/#135): o drawer de ações rápidas monta como **irmão** do scrollport dentro de `CampaignAppScrollChrome`. `TooltipProvider` só em volta de `{children}` deixava focus→suggest (hits `priority:alta` → `CampaignHoverTooltip`) sem provider → crash da página.
|
||||
|
||||
**Fix real:** elevar o provider para envolver `CampaignAppScrollChrome` no layout `(app)`.
|
||||
|
||||
**Guarda adicionada** em `tests/unit/codebaseConventions.unit.spec.ts` (`campaign TooltipProvider wraps quick-actions chrome (B102)`): regex que exige
|
||||
|
||||
```tsx
|
||||
<TooltipProvider>
|
||||
…<CampaignAppScrollChrome>…</CampaignAppScrollChrome>…
|
||||
</TooltipProvider>
|
||||
```
|
||||
|
||||
e proíbe o nesting invertido **no source** de `layout.tsx`.
|
||||
|
||||
Problema (review 2026-08-02, item 5): o pin congela **forma JSX incidental**. Agentes satisfazem a regex com wrappers estranhos; um refactor legítimo (provider dentro de um shell component que já envolve o chrome) quebra o build sem regressão; a proteção real do crash já está (ou deve estar) nos **pins comportamentais** de focus→suggest / type→search com hits prioritários (`campaignQuickActionsDrawer` unit + e2e da miss).
|
||||
|
||||
Pedido: **matar esta guarda** — sem substituto source-shape.
|
||||
|
||||
## Objetivos
|
||||
|
||||
- Remover o `describe('campaign TooltipProvider wraps quick-actions chrome (B102)', …)` de `codebaseConventions.unit.spec.ts` por completo.
|
||||
- Confirmar que os pins comportamentais da regressão B102/miss (#133/#135) **permanecem** (unit drawer focus→suggest com hit prioritário; e2e se existir). Se algum tiver sido apagado, **restaurar** nesse PR — a remoção da guarda source só é segura com a rede comportamental viva.
|
||||
- Atualizar `docs/GUARDRAILS.md` se a guarda estiver listada; senão nota no PR + referência à Issue.
|
||||
- Guardrails: sem migration; **não** mover o `TooltipProvider` neste item (layout fica como está).
|
||||
- **Tracer bullet:** delete do describe → `pnpm gate:fast` verde → checklist dos pins comportamentais no body do PR.
|
||||
|
||||
## Decisões travadas
|
||||
|
||||
- **Delete da guarda source-shape; não “afrouxar” a regex.** Opções: A) delete | B) mover o pin para outro arquivo/componente | C) ESLint react-tree. **Recomendação: A.** O valor está no pin de crash (comportamento), não na árvore textual do layout. **Rejeitado:** B/C (mesmo cheiro / appetite).
|
||||
- **Não adicionar judgment-only substituto obrigatório** além de uma linha em GUARDRAILS/CHANGELOG se útil — o layout comentado + pins de miss bastam.
|
||||
- **Kind: `chore` (OPS15).**
|
||||
- **i18n:** N/A.
|
||||
|
||||
## Questões em aberto
|
||||
|
||||
- **Onde documentar “provider deve envolver o chrome do drawer”?** **Opções:** A) só comentário no layout | B) GUARDRAILS judgment-only | C) nada. **Recomendação:** **A** (já deve existir contexto B102 no layout); B só se a linha já existir e precise de “removido”. _(assumido)_
|
||||
|
||||
## Abordagem proposta
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
check["Ver pins unit/e2e B102"] --> del["Apagar describe nesting"]
|
||||
del --> docs["GUARDRAILS se listado"]
|
||||
docs --> gate["gate:fast"]
|
||||
```
|
||||
|
||||
Componentes:
|
||||
|
||||
- **`tests/unit/codebaseConventions.unit.spec.ts`:** remover o bloco B102 (~L671–688).
|
||||
- **Verificação:** `rg TooltipProvider|priority:alta|CampaignHoverTooltip tests/unit tests/e2e` — garantir cobertura comportamental; restaurar se faltar.
|
||||
- **`docs/GUARDRAILS.md`:** remover/ajustar linha se houver.
|
||||
- **Migration:** nenhuma.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma dura. Independente de OPS13/OPS14.
|
||||
- Soft: Issues #129 / #133 / #135 (histórico da miss) — só referência.
|
||||
|
||||
## Não escopo
|
||||
|
||||
- Mudar posição do `TooltipProvider` no layout.
|
||||
- Reabrir investigação do crash.
|
||||
- OPS13/OPS14.
|
||||
|
||||
## Rabbit holes
|
||||
|
||||
- **"Substituir por teste de árvore React renderizada do layout."** Layout é RSC/async — painel de dor; os pins do drawer já exercitam o caminho. **Mitigação:** não.
|
||||
- **Aproveitar para “limpar” outros describes do conventions.** Fora de escopo.
|
||||
|
||||
## Adiado com gatilho
|
||||
|
||||
- **Pin e2e dedicado se unit do drawer for flaky.** Revisitar só com evidência de regressão pós-remoção.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #242 (OPS15)
|
||||
- Review de guardrails (chat 2026-08-02) — item 5
|
||||
- `tests/unit/codebaseConventions.unit.spec.ts` — describe B102
|
||||
- `src/app/(campaign)/campanha/(app)/layout.tsx` — TooltipProvider atual
|
||||
- Issues #129 (B102), #133, #135 (miss)
|
||||
- `tests/unit/campaignQuickActionsDrawer.unit.spec.tsx` — pins comportamentais esperados
|
||||
103
docs/plans/remover-pins-classname.md
Normal file
103
docs/plans/remover-pins-classname.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# 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
|
||||
Loading…
Reference in a new issue