# Qualidade e gates da V2 — o que os números provam

> Fontes: `V2/LINT_BASELINE.md`, `V2/TEST_BASELINE.md`, `phpstan.neon`, `phpunit.xml`,
> `composer.json`, `tests/`. Nada foi executado; os números são os declarados pelo projeto.

## 1. Os quatro gates

| Gate | Número declarado | Comando | Escopo |
|---|---|---|---|
| PHPUnit | **650 testes / 2107 asserções / 0 erros / 0 falhas / 9 skipped** (`TEST_BASELINE.md:11-22`) | `vendor/bin/phpunit --no-coverage` | `tests/` (V1 + V2) |
| Playwright | **89/89** (`TEST_BASELINE.md:40-48`) | `npx playwright test` | `tests-e2e/` |
| PHPStan | **nível 9, 0 erros** (`LINT_BASELINE.md:6-13`) | `composer v2:analyse` | `V2/` |
| php-cs-fixer | dry-run 0 (`LINT_BASELINE.md:38-46`) | `composer v2:lint` | `V2/`, Blade excluído |

## 2. O que cada número realmente garante

**PHPUnit.** Cobre regressão de comportamento conhecido — não é uma suíte de segurança. A
distribuição mostra onde está a confiança:

| Área | Testes (exemplos) | Cobre |
|---|---|---|
| `tests/Unit/V2/Services/**` | FormularioDinamico (validação, scoring, diagnóstico, renderer, export), ExcelImporter, conversores DOCX/HTML→AST | regra de serviço |
| `tests/Unit/V2/Modules/**` | PermissionService, GestaoPermissoes (roles/permissions/regressão), Legislacao (model/scopes/files/seeder), LandingSections | unidade de módulo |
| `tests/Feature/V2/**` | Notícias (CMS/portal/paginação), Legislação (CMS/import/categoria/portal), Licitações, Ouvidoria, BasicPage (home/contato), RBAC e2e | fluxo HTTP |
| `tests/Feature/V1/**` | legado | fora do escopo V2 |

**O que não está coberto de forma sistemática:** RBAC por verbo/rota (há um teste e2e de acesso por
módulo, não uma matriz rota×permissão), CSRF, upload malicioso, XSS de conteúdo rico, headers de
segurança, e **nenhum teste** para `SupportConfigs` e `TransparenciaFiscal`.

**Os 9 skipped são intencionais** (`TEST_BASELINE.md:22`) — o baseline manda tratar **novo** skip como
regressão. É a política certa.

**Playwright.** 89 cenários, mas o login de avaliação depende de `X-CMS-AI-Token` com fallback
hardcoded no `playwright.config.js` (`TEST_BASELINE.md:59-72`). O verde prova o fluxo; não prova que
um humano consegue autenticar, nem que o canal de IA está desligado em produção.

**PHPStan nível 9.** O “0 erros” é real **dentro da configuração**, mas a configuração contém ~60
blocos de `ignoreErrors` (`phpstan.neon:18-260`), incluindo `Cannot call method .+ on mixed`,
`#Access to an undefined property object::\$#` e supressões por arquivo em `CmsAuthenticate.php`,
`SidebarComposer.php`, `V2AuditLogger.php`. Nível 9 mede consistência de tipos internos; os padrões
suprimidos são justamente os que pegariam `mixed` em fronteira de dados (request/DB). **Não é um
atestado de correção.**

**php-cs-fixer.** Formata, não analisa; Blade fica fora por desenho — logo, a camada de view (onde
está a maior parte do HTML/a11y) não tem gate de estilo.

## 3. Baseline como contrato

O acerto metodológico do V2 é tratar o baseline como **contrato explícito** (`TEST_BASELINE.md:9-13`):
contagens, comando exato, o que é skip intencional e o que é regressão. O V7 já segue a mesma ideia
(`make check` com cobertura mínima e “duas vezes seguidas”); o que vale importar é a **tabela de
clusters corrigidos** (`:24-41`), que documenta a causa de cada vermelho antigo.

## 4. Lacunas de gate que o V7 não deve repetir

| Lacuna | Evidência | Efeito |
|---|---|---|
| PHPStan com supressões amplas | `phpstan.neon:18-260` | 0 erros deixa de significar “sem `mixed` em fronteira” |
| E2E autenticado por token de avaliação | `TEST_BASELINE.md:59-72` | verde não representa o login real |
| Sem gate de acessibilidade bloqueante | sniff advisory (`:80-88`) | regressão visual/a11y passa |
| Sem teste de RBAC por rota/verbo | `tests/Feature/V2/Rbac/` tem um fluxo, não matriz | fail-open do middleware não é pego |
| Sem teste de XSS/HTML | nenhum caso de `Blade::compileString`/`{!! !!}` | RCE/XSS de Blade-em-DB não é pego |
| `SupportConfigs` e `TransparenciaFiscal` sem teste | inventário de testes | módulos críticos sem rede |
| Cobertura não é medida (sem `--coverage`) | `TEST_BASELINE.md:16` | “650 testes” não diz o que é coberto |

## 5. Regras de estilo que valem manter

- `declare(strict_types=1)` como **primeira** instrução em 100% dos `.php` não-Blade — o V7 já exige
  (ADR-008); o V2 prova que é sustentável em base grande.
- Proibição explícita de sintaxe acima do alvo (arrow fn, typed properties, `match`, enums) —
  `LINT_BASELINE.md:14`. No V7 o alvo é 8.4; a lição é a **declaração explícita do alvo**, não a
  proibição em si.
- Baseline numérico versionado e revalidado a cada PR (`README.md:35`).

## 6. O que medir no V7 ao portar código daqui

1. **Cobertura real** por serviço portado (o V7 já tem piso de 90%).
2. **PHPStan sem supressão nova** — cada `ignoreErrors` precisa de justificativa e prazo.
3. **Teste de contrato** para o que for portado: parsing/normalização (Excel), scoring (formulários),
   preparação de seções (landing), índice/upsert (search).
4. **Determinismo**: o V2 usa `time()` em nome de arquivo, `random()` em UUID de banco e `date()` em
   logs — no V7, injetar `Clock`/`IdGen` (ADR-001).
