From 4b54cbfbe2a4c645ea1f6098fac306ce437fa86b Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Tue, 25 Aug 2026 01:51:06 -0300 Subject: [PATCH] test(ops96-audit): mover 4 specs puros de int para unit (relationship, schemaPrimitives, assertTestDatabase, petition-page-layout) --- docs/plans/ops96-skill-testing-audit-impl.md | 204 ++++++++++++++++++ eslint-legacy-ignores.mjs | 2 +- knip.json | 8 +- scripts/testing-audit-metrics.mjs | 6 +- .../assertTestDatabase.unit.spec.ts} | 0 .../petition-page-layout.unit.spec.ts} | 0 .../relationship.unit.spec.ts} | 0 .../schemaPrimitives.unit.spec.ts} | 0 .../unit/testingAuditMetricsCore.unit.spec.ts | 8 +- 9 files changed, 222 insertions(+), 6 deletions(-) create mode 100644 docs/plans/ops96-skill-testing-audit-impl.md rename tests/{int/assertTestDatabase.int.spec.ts => unit/assertTestDatabase.unit.spec.ts} (100%) rename tests/{int/petition-page-layout.int.spec.ts => unit/petition-page-layout.unit.spec.ts} (100%) rename tests/{int/relationship.int.spec.ts => unit/relationship.unit.spec.ts} (100%) rename tests/{int/schemaPrimitives.int.spec.ts => unit/schemaPrimitives.unit.spec.ts} (100%) diff --git a/docs/plans/ops96-skill-testing-audit-impl.md b/docs/plans/ops96-skill-testing-audit-impl.md new file mode 100644 index 00000000..31bb2a03 --- /dev/null +++ b/docs/plans/ops96-skill-testing-audit-impl.md @@ -0,0 +1,204 @@ +# Impl: Skill `/testing-audit` — auditoria autônoma da suíte de testes com implementação das melhorias + +Status: rascunho +Atualizado em: 2026-08-25 +Issue: #898 +Intenção: docs/plans/ops96-skill-testing-audit.md +Appetite restante: herdado (~1–2 dias eng) — ~½ dia de construção (Fases 0–3) + uma noite de execução governada com tetos duros ~6h (Fases 4–5) + +## Leitura da intenção + +- **Outcome:** disparo `/testing-audit` à noite; pela manhã existe UM relatório que explica toda a noite: retrato honesto da suíte (contagens/tempos por camada — unit ~221 / int ~96 / e2e ~44 inventariado estaticamente), duplicatas prováveis, candidatos mover/reforçar/remover cada um com disposição + justificativa, melhorias seguras JÁ aplicadas como código (cada passo provou suíte verde ANTES e DEPOIS), passos revertidos registrados e propostas não executadas documentadas. Entrega = UM PR **ready** (não draft), **sem auto-merge armado**, CI green e mergeable; descrição do PR = relatório final; o relatório também vive como artefato commitado referenciado pelo PR; fixes em commits separados quando possível (preferência, não requisito duro); diff revisável em pedaços lógicos. +- **O que NÃO negociar:** intocáveis absolutos — testes de consentimento/LGPD fail-closed, access control/RBAC, lockdown de liderança (nunca remover nem enfraquecer autonomamente); OPS72/`ci-scope.mjs` + `scripts/lib/e2e-affected-manifest.mjs` intocáveis (nenhum gate, workflow ou política de seleção e2e muda); remoção autônoma só com PROVA FORTE (na dúvida vira proposta no relatório); teto temporal fixo (auditoria termina, implementação começa); ferramentas só first-party; relatório é artefato de aceite; changelog append-only no mesmo PR; nenhuma % de cobertura vira regra dura; sem rewrite da suíte e sem segundo cadastro de métricas. +- **O que reavaliar:** teto de 6 melhorias aplicadas é hipótese (a primeira noite calibra); formato do relatório após a primeira execução; se durações e2e reais serão um dia necessárias (hoje deliberadamente "não medido"); se o piloto do protocolo na Fase 3 já consome parte da cota noturna. + +## Abordagem recomendada + +```mermaid +flowchart TD + A["Fase 0: baseline verde unit+int"] --> B["Fase 1: tracer
skill + comando + guard"] + B --> C["Fase 2: motor de métricas baratas
script versionado + cobertura atrás de flag"] + C --> D["Fase 3: protocolo na SKILL.md
rubrica, provas antes/depois, tetos, fecho/desarme"] + D --> E["Fase 4: execução noturna
inventário paralelo Task x3 → rubrica → loop de melhorias"] + E -->|"AFTER falho (≤10min/1 retry)"| R["revert do commit + registra"] + R --> E + E --> F["Fase 5: fecho
relatório + changelog + push único + CI green"] + F --> G["DESARME automerge
sempre o ÚLTIMO passo"] + G --> H{"autoMergeRequest === null?"} + H -->|sim| I["PR ready, mergeable, desarmado"] + H -->|não| J["fallback fail-closed:
draft + registro no relatório"] +``` + +### Decisões de engenharia + +**D1 — Forma da skill.** + +- **A)** SKILL.md única com fases sequenciais executadas pelo próprio agente (estilo `engineering-audit`, 182 linhas). +- **B)** Decomposição pesada em sub-agentes Task para tudo (estilo `agent-work-issue`, padrão explorador→escritor→revisores→capturador). +- **C)** Híbrido: fases sequenciais definidas na SKILL.md; inventário por camada delegado a leitores paralelos **read-only** via Task (unit/int/e2e estático); loop de implementação estritamente sequencial no agente principal. + +**Recomendação: C.** A máquina roda à noite sem humano: os leitores paralelos cortam o tempo de parede da fase mais mecânica e são seguros porque não escrevem nada (cada achado vem com caminho+linha e é validado contra o fonte antes de virar disposição); o loop de melhorias precisa de continuidade de estado (provas verde encadeadas, commits incrementais) e não paraleliza sem corromper a prova. SKILL.md alvo: ~150–180 linhas, frontmatter mínimo `{name, description}`. + +**Rejeitadas:** B (custo de orquestração acima do appetite; implementadores paralelos invalidariam as provas encadeadas); A puro (noite mais longa no inventário, desperdiça a única paralelização segura). + +**D2 — Coleta de métricas.** + +- **A)** Reporters JSON nativos parseados ad-hoc a cada execução (`node -e` efêmero ou leitura manual). +- **B)** Script versionado `scripts/testing-audit-metrics.mjs`: roda os runners com `--reporter=json --outputFile` para arquivo temporário e normaliza contagens por camada + specs mais lentas numa tabela compacta markdown/json. +- **C)** Tudo manual pelo agente lendo saídas dos runners. + +**Recomendação: B**, com teste unitário próprio para a função pura de normalização (`tests/unit/testingAuditMetrics.unit.spec.ts`). Repetível entre noites, barato (~100 linhas), knip-safe — verificado que `knip.json` tem `scripts/*.mjs` como entry, então o script novo não é órfão. Unit roda com DATABASE_URL inválido proposital (`test:unit`), int exige `teqo_test` (`assertTestDatabase`) — o script apenas orquestra os scripts existentes. E2E entra como inventário estático (parse dos spec files: contagem de `test(`/`describe(`, tags, fixtures), nunca execução (ver D4/riscos). + +**Rejeitadas:** A (não repetível; joga fora o trabalho toda noite); C (queima tokens, propenso a erro de leitura, não é auditável por teste). + +**D3 — Cobertura (@vitest/coverage-v8).** + +- **A)** Instalar como devDependency NESTE PR, pinada na mesma versão major/minor do vitest instalado, acionável APENAS por flag documentada na skill (`pnpm vitest run --config ./vitest.unit.config.mts --coverage`); acrescentar `@vitest/coverage-v8` ao `ignoreDependencies` do `knip.json` preventivamente (o plugin só carrega sob `--coverage`; knip flaggaria como dependência não usada e deixaria o gate vermelho durante a noite). +- **B)** Instalar sob demanda na primeira execução (skill instrui `pnpm add -D @vitest/coverage-v8`). +- **C)** Não instalar. + +**Recomendação: A.** Determinística: o PR entregue já sai com o comando funcionando e os gates previsíveis à noite. O ajuste no `knip.json` é whitelist declarativa de dependência invocada por flag — mesmo padrão das entradas existentes (`tailwindcss-animate`, `tw-animate-css`, `shadcn`, `eslint-config-next`) — e NÃO enfraquece check algum; nenhum gate/script passa a exigir ou reportar cobertura; nenhuma % vira regra (corte da intenção preservado). + +**Rejeitadas:** B (worktree sujo no meio da noite, risco de esquecer o commit, comando documentado mas inoperante no PR entregue, surpresa de knip às cegas); C (rejeitada pela própria intenção — decidiu SIM atrás de flag; motivo registrado: diagnóstico barato e first-party do ecossistema vitest, opcional por construção). + +**D4 — Protocolo verde antes/depois + tetos.** + +- **Prova padrão de cada passo:** `pnpm test:unit` + `pnpm test:int` verdes ANTES e DEPOIS da edição (int roda contra `teqo_wt_test`, já provisionada neste worktree — validar conexão na Fase 0; unit roda com DATABASE_URL inválido por design). Passos confinados a arquivos unit podem provar unit-only, mas o bloco de fechamento roda o par completo uma vez. +- **Categorias seguras de melhoria:** **mover** (spec na camada errada realocado dentro da mesma suíte — ex.: teste puro vivendo em arquivo int); **reforçar** (assertion faltante dentro de escopo já testado); **remover** SOMENTE com prova forte: duplicata demonstrada (diff das assertions mostra comportamento idêntico ao teste gêmeo citado) ou teste morto de feature removida do codebase (referência morta verificada). Na dúvida → proposta no relatório. +- **Intocáveis (nunca remover/enfraquecer):** consentimento/LGPD fail-closed, access control/RBAC (`src/utilities/access/*`), lockdown de liderança. Duplicata aparente envolvendo intocável vira proposta sempre. +- **Evidência:** linhas-resumo literais dos runners ("Test Files X passed", "Tests Y passed") + hash curto do commit + timestamp, gravadas por passo na tabela de evidências do relatório. JSON bruto é efêmero (fora do git). +- **Tetos duros:** budget global da noite **6h**; máx **6 melhorias aplicadas**; **30min por passo** incluindo provas; AFTER falho → debug ≤10min/1 retry, senão `git reset --hard HEAD~1` e registrar como "revertido" com motivo; auditoria termina antes de implementar; estourou teto → candidato vira proposta. + +**Recomendação:** exatamente o acima. +**Rejeitadas:** provar só com unit (regressões de int ficariam invisíveis — melhorias movem specs entre camadas); provar rodando build/e2e a cada passo (custo proibitivo); sem teto (viola o corte explícito da intenção "auditoria termina, implementação começa"). + +**D5 — Desarme do auto-merge (verificado no fonte).** +Todo PR ready OPEN base main nasce ARMADO: `.github/workflows/agent-pr-ready-automerge.yml` dispara em opened/reopened/synchronize/ready_for_review/converted_to_draft e `decideAutomergeAction` (`scripts/lib/github-pr-flow.mjs`) arma automerge em qualquer ready OPEN base main (único veto estrutural = draft fora de `cursor/*`). Cada novo push REARMA via synchronize. Sequência obrigatória de fecho: + +1. Push único com tudo (relatório, changelog, melhorias) — minimiza rearms; o hook `.husky/pre-push` roda `gate:push` (gate-ci sem e2e + docs-guards) como validação gratuita pré-push. +2. Aguardar o run do workflow de automerge **deste SHA final** terminar (terá armado o automerge no synchronize). +3. `gh pr merge --disable-auto`. +4. Verificar: `gh pr view --json isDraft,autoMergeRequest,mergeable,mergeStateStatus` → esperado `{false, null, MERGEABLE, CLEAN}`. +5. **Fallback fail-closed:** se `--disable-auto` falhar ou `autoMergeRequest` persistir não-nulo → converter para draft (`gh pr ready --undo`; draft fora de `cursor/*` é veto estrutural, exit 0) e registrar no relatório que o humano vira ready pela manhã. Draft protegido é preferível a main mergeado sem querer. + +**Recomendação:** sequência acima, executada SEMPRE como último passo da noite. +**Rejeitadas:** entregar draft e virar ready de manhã (viola o aceite explícito — ready não draft — e o desarme resolve a causa real); confiar no humano para desarmar (viola aceite); não fazer nada (PR se auto-mergeia sozinho assim que o CI ficar verde, durante a noite). **Regra derivada:** qualquer push posterior ao desarme rearma — portanto NUNCA rebasar/repushar após o desarme (ver Riscos). + +**D6 — Relatório: localização e forma.** + +- **A)** `docs/plans/ops96-skill-testing-audit-report.md`. +- **B)** `docs/testing-audits/.md` (diretório dedicado, chaveado por data). +- **C)** Artefato fora do repo (gist/comentário de issue). + +**Recomendação: B**, convenção definida dentro da SKILL.md para reuso por execuções futuras; esta entrega grava `docs/testing-audits/.md`. Regra "descrição do PR = relatório": o corpo do PR contém o relatório integral (ou versão condensada com ponteiro para o artefato, se ultrapassar limites razoáveis de UI). Template embutido na SKILL.md com seções fixas: sumário executivo; metodologia e tetos respeitados; retrato por camada (unit/int com contagens+durações medidas; e2e inventário estático com durações "não medido — execução noturna proibida"); tabela de disposições (id, camada, arquivo, tipo mover/reforçar/remover/manter, prioridade alta/média/baixa, prova, decisão aplicada/proposta/revertida); evidências verde antes/depois por passo; passos revertidos com motivo; propostas não executadas; estado final do PR. Pedaços lógicos do diff: commits separados por scaffolding (tracer / métricas / protocolo+deps) e 1 commit por melhoria aplicada; relatório+changelog no(s) commit(s) finais. + +**Rejeitadas:** A (acopla saída recorrente ao diretório de planos por ops; polui `docs/plans/` nas próximas noites); C (quebra o aceite "relatório vive como artefato no repo"). + +**D7 — Guard de comandos e espelho.** +Atualizar o array pinado `['work-issue', 'plan-issue']` em `tests/unit/opencodeCommands.unit.spec.ts` para incluir `'testing-audit'` e criar `.opencode/commands/testing-audit.md` no formato stub existente: frontmatter com `description:` (TUI) e `model: deepseek/deepseek-v4-flash`; corpo curto que carrega a skill `testing-audit` pelo nome exato, aponta a fonte canônica `.agents/skills/testing-audit/SKILL.md` (sem transcrever) e passa `$ARGUMENTS`. O guard exige: arquivo existe, skill existe, `` `testing-audit` `` literal, `$ARGUMENTS`, `.agents/skills/testing-audit/SKILL.md` literal, frontmatter válido — é o tracer da Fase 1. + +### Componentes / mudanças + +1. **`.agents/skills/testing-audit/SKILL.md`** (~150–180 linhas, frontmatter `{name, description}`): objetivo; fases 0–5; rubrica de disposições + prioridades; protocolo verde antes/depois com evidências; categorias seguras + prova forte para remoção; lista de intocáveis; tetos duros; instruções dos leitores paralelos Task (read-only, citação obrigatória caminho:linha); fecho noturno completo incluindo a sequência de desarme D5 verbatim; template do relatório; apontamentos explícitos: pirâmide das 3 camadas CITADA de `test-driven-development` §144–198 + `docs/TESTING.md` (não duplicada); declaração explícita de que NÃO herda o contrato auto-merge de `engineering-audit`; ci-scope/e2e-affected intocáveis. +2. **`.opencode/commands/testing-audit.md`**: espelho stub no formato D7. +3. **`tests/unit/opencodeCommands.unit.spec.ts`**: array ganha `'testing-audit'`. +4. **`scripts/testing-audit-metrics.mjs`**: orquestra reporters JSON nativos, normaliza contagens/durações, emite tabela markdown + json opcional. +5. **`tests/unit/testingAuditMetrics.unit.spec.ts`**: testa a normalização (fixtures de payload vitest JSON). +6. **`package.json` + lockfile**: devDependency `@vitest/coverage-v8` (versão casa com vitest instalado). +7. **`knip.json`**: `ignoreDependencies` += `@vitest/coverage-v8`. +8. **`docs/testing-audits/.md`**: relatório da primeira execução noturna (artefato de aceite). +9. **`docs/changelog/-ops96-testing-audit.md`**: entrada append-only (exigência docs-guards). +10. **Melhorias aplicadas**: até 6 commits, um por passo, cada um com provas registradas. + +## Fases verificáveis + +**Fase 0 — Preparação e baseline (antes de qualquer edição).** + +- Validar worktree: deps instaladas, `DATABASE_URL` do `.env.test.local` aponta para `teqo_wt_test` (nunca produção — guards locais intactos). +- Rodar `pnpm test:unit` e `pnpm test:int` → verdes; registrar contagens baseline (esperado ~221/~96) no futuro relatório. +- **Verificação:** baseline verde registrado; nenhum arquivo modificado ainda. + +**Fase 1 — Tracer: skill + comando + guard.** + +- Criar SKILL.md esqueleto (fases nomeadas), espelho `.opencode/commands/testing-audit.md`, adicionar `'testing-audit'` ao array do guard. +- **Verificação:** `pnpm test:unit opencodeCommands` verde com os 3 comandos pinados; commit próprio. + +**Fase 2 — Motor de métricas baratas.** + +- `scripts/testing-audit-metrics.mjs` + spec de normalização; devDependency `@vitest/coverage-v8` + entrada em `knip.json.ignoreDependencies`; comando de cobertura documentado na SKILL.md (flag only). +- **Verificação:** script roda na suíte atual e emite tabela ~221 unit / ~96 int com specs mais lentas; spec novo verde; `pnpm exec knip` sem novos alertas; commit próprio. + +**Fase 3 — Protocolo de execução segura dentro da SKILL.md.** + +- Escrever rubrica, provas antes/depois com evidências, categorias seguras, prova forte de remoção, intocáveis, tetos, regra "e2e read-only", fecho/desarme D5, template do relatório. +- Piloto opcional (se tempo): aplicar 1 melhoria trivial seguindo o protocolo à risca, para validar o mecanismo antes da noite. +- **Verificação:** checklist de autossuficiência — um agente lendo SOMENTE a SKILL.md consegue executar a noite inteira sem contexto extra; `pnpm lint` + `pnpm typecheck` verdes. + +**Fase 4 — Execução noturna governada (a skill rodando sobre a suíte real).** + +- Inventário paralelo via Task ×3 leitores read-only (unit/int/e2e estático), ≤45min, achados com caminho:linha. +- Consolidação + rubrica ≤30min: cada candidato recebe disposição (mover/reforçar/remover/manter/proposta) + justificativa + prioridade. +- Loop sequencial de melhorias: ≤6 passos, 30min cada, provas verde antes/depois por passo, 1 commit por passo; AFTER falho → ≤10min/1 retry → revert + registro. +- **Verificação:** cada melhoria = commit com evidências no relatório; `git diff origin/main` NÃO toca ci-scope/e2e-affected/workflows/husky nem paths intocáveis; zero edições em arquivos e2e; tetos respeitados. + +**Fase 5 — Fecho noturno.** + +- Finalizar `docs/testing-audits/.md`; changelog append-only; `pnpm lint && pnpm format:check && pnpm typecheck && pnpm exec knip && pnpm check:cycles && pnpm test:unit && pnpm test:int` no SHA final. +- Push único (hook roda `gate:push`); abrir PR ready base main; colar relatório como descrição; aguardar CI green no SHA final (monitorar; flake aparente → rerun 1×; quebra real → fix-forward ≤2 ciclos). +- **Desarme (ÚLTIMO passo):** sequência D5 completa; verificar `{isDraft: false, autoMergeRequest: null, mergeable: MERGEABLE}`. +- **Verificação:** `gh pr view --json isDraft,autoMergeRequest,mergeable,mergeStateStatus` confirma ready + desarmado + mergeable; fallback draft só se desarme falhar, com registro explícito no relatório. + +## Rabbit holes / Não escopo (engenharia) + +- **Rodar Playwright/e2e à noite — nem full, nem smoke.** Custo alto + política OPS72 + flake noturno. E2E é inventariado estaticamente (contagens, estrutura, tags) com durações marcadas "não medido"; qualquer mudança em spec e2e é proposta, nunca edição autônoma. +- **Não criar segundo cadastro/dashboard de métricas históricas.** O script gera tabela pontual para o relatório; sem persistência além do artefato markdown. +- **Não tocar** `ci-scope.mjs`, `e2e-affected-manifest.mjs`, workflows, husky, gates, seleção e2e — nem "só para arrumar" algo visto no caminho (vira proposta no relatório). +- **Não registrar Issues no tracker** (propostas vivem apenas no relatório; captura de débitos é decisão humana posterior). +- **Não perseguir % de cobertura** como meta ou regra; flag diagnóstica apenas. +- **Não reescrever/mover testes em massa**; remoção autônoma só com prova forte; intocáveis nunca, nem com prova. +- **Não rebasar após o desarme** (rearma automerge); conflito com main é registrado para ação humana. +- **Ferramentas só first-party:** reporters nativos vitest/playwright + `@vitest/coverage-v8`. Nada de libs third-party de análise de suíte. +- **Não implementar agendamento/cron** para a skill disparar sozinha; o disparo é humano (`/testing-audit`). + +## Riscos e mitigação + +| Risco | Mitigação | +| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Rearme automático do automerge a cada `synchronize` | Push único ao fecho; desarme SEMPRE último passo; verificação explícita de `autoMergeRequest === null`; fallback fail-closed draft; regra "não repushar após desarme". | +| CI flaky overnight bloqueia "green" da manhã | Máxima prova local pré-push (`gate:push` roda cascata sem e2e no hook); pós-push: 1 rerun se flake aparente, ≤2 ciclos de fix-forward; esgotado → registrado no relatório como pendência conhecida (não corrompe main porque automerge está desarmado). | +| knip flagga `@vitest/coverage-v8` e deixa o gate vermelho à noite | Whitelist preventiva em `knip.json.ignoreDependencies` (D3-A); validado na Fase 2 com `pnpm exec knip`. | +| `test:int` sem DB do worktree disponível | Fase 0 valida `teqo_wt_test` antes de tudo (worktree já provisionado). Se falhar: melhorias restritas a provas unit-only e int vira verificação adiada REGISTRADA no relatório (fail-closed honesto). | +| Conflito com main ao amanhecer (main avançou durante a noite) | NÃO rebasar após o desarme (rearmaria); registrar no topo do relatório "main avançou; rebasar é passo humano". | +| Melhoria "segura" quebra comportamento não coberto pelos testes | Provas antes/depois por passo; categorias restritas (mover/reforçar/remover-com-prova); revert barato (commit isolado); teto de tentativas. | +| Tempo estoura / noite não cabe tudo | Tetos duros por fase; auditoria termina antes de implementar; excedentes viram propostas; hard stop: se faltar tempo, pular direto ao fecho com o que há. | +| Leitor Task alucina achados | Leitores read-only obrigados a citar caminho:linha; consolidador valida cada achado contra o fonte antes de virar disposição; implementação nunca delegada. | +| PR auto-mergeia durante janela entre CI green e desarme | Janela minimizada: desarme imediatamente após o run do workflow do SHA final terminar; monitoramento ativo nessa janela; fallback draft. | + +## Aceite de engenharia (checklist) + +- [ ] `.agents/skills/testing-audit/SKILL.md` existe, autossuficiente, cita OPS90 §144–198 + `docs/TESTING.md` sem duplicá-los, declara explicitamente que NÃO herda o contrato auto-merge de `engineering-audit`, e contém a sequência de desarme D5 verbatim. +- [ ] `.opencode/commands/testing-audit.md` stub no formato do guard: frontmatter `description:` + `model: deepseek/deepseek-v4-flash`, `$ARGUMENTS`, aponta `.agents/skills/testing-audit/SKILL.md`. +- [ ] Guard `tests/unit/opencodeCommands.unit.spec.ts` inclui `'testing-audit'` e passa. +- [ ] Script de métricas versionado + spec de normalização verde; `pnpm exec knip` limpo. +- [ ] `@vitest/coverage-v8` instalado (versão casa com vitest), acionável só pela flag documentada; `knip.json.ignoreDependencies` ajustado; nenhum gate/script usa ou exige cobertura. +- [ ] Relatório `docs/testing-audits/.md` commitado: retrato por camada (unit/int medidos; e2e inventário estático), disposições com justificativa, evidências verde antes/depois por melhoria, reverts registrados, propostas restantes; mesma versão (ou condensado + ponteiro) como descrição do PR. +- [ ] Cada melhoria aplicada em commit próprio quando possível; diff revisável em pedaços lógicos. +- [ ] `git diff origin/main` NÃO toca `ci-scope.mjs`, `e2e-affected-manifest.mjs`, `.github/workflows/`, `.husky/` nem política de seleção e2e. +- [ ] Intocáveis intactos: consentimento/LGPD fail-closed, access control/RBAC, lockdown de liderança. +- [ ] Zero edições em arquivos e2e nesta execução. +- [ ] Changelog append-only `docs/changelog/-.md` presente no mesmo PR (docs-guards verdes). +- [ ] PR ready (não draft), CI green no SHA final, mergeable; `autoMergeRequest === null` verificado via `gh pr view` — ou fallback draft registrado com motivo no relatório. +- [ ] Tetos respeitados: ≤6 melhorias aplicadas, ≤30min/passo, ≤2 ciclos de correção pós-push, budget ~6h. +- [ ] `pnpm lint`, format check, typecheck, `pnpm exec knip`, `pnpm check:cycles`, `pnpm test:unit`, `pnpm test:int` verdes no SHA final. + +## Self-score decision-quality + +| Pergunta | Nota | Justificativa | +| -------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Decisões caras têm Opções/Recomendação/Rejeitadas? | 5 | D1–D7 todas deliberadas; as caras de reverter (forma da skill, protocolo de provas, desarme, cobertura) com alternativas e motivos de rejeição explícitos. | +| Cabe no appetite (~1–2 dias eng)? | 4 | Construção enxuta reusando padrões existentes + execução noturna amarrada por tetos duros; −1 pela variância inerente à primeira execução real. | +| Rabbit holes nomeados? | 5 | Lista própria + todos os cortes da intenção preservados (teto temporal, prova forte para remover, e2e read-only, ferramentas first-party, relatório como aceite). | +| Depth check (reuse > invenção)? | 4 | Reusa guard/comando existentes, reporters nativos, padrões engineering-audit/agent-work-issue, scripts de gate; −1 pelo pequeno script de métricas novo (justificado pela repetibilidade). | +| Intenção satisfeita? | 5 | Outcome integral coberto: relatório único explicando a noite, melhorias com provas antes/depois, reverts e propostas documentados, PR ready sem automerge armado, anti-goals respeitados. | + +**Média: 4.6 ≥ 4 — gate de qualidade satisfeito.** diff --git a/eslint-legacy-ignores.mjs b/eslint-legacy-ignores.mjs index c911ab2c..819daf80 100644 --- a/eslint-legacy-ignores.mjs +++ b/eslint-legacy-ignores.mjs @@ -47,5 +47,5 @@ export const legacyCamelCaseFilenameIgnores = [ 'src/lib/schemas/campaign-login.ts', 'src/lib/schemas/petition-form.ts', 'src/lib/schemas/whatsapp-form.ts', - 'tests/int/petition-page-layout.int.spec.ts', + 'tests/unit/petition-page-layout.unit.spec.ts', ] diff --git a/knip.json b/knip.json index 6c792908..f3e67b35 100644 --- a/knip.json +++ b/knip.json @@ -19,7 +19,13 @@ "server-only": ["tests/helpers/serverOnly.ts"] }, "ignoreBinaries": [], - "ignoreDependencies": ["tailwindcss-animate", "tw-animate-css", "shadcn", "eslint-config-next", "@vitest/coverage-v8"], + "ignoreDependencies": [ + "tailwindcss-animate", + "tw-animate-css", + "shadcn", + "eslint-config-next", + "@vitest/coverage-v8" + ], "rules": { "exports": "error", "types": "error", diff --git a/scripts/testing-audit-metrics.mjs b/scripts/testing-audit-metrics.mjs index 9f4be9ee..c0ee0176 100644 --- a/scripts/testing-audit-metrics.mjs +++ b/scripts/testing-audit-metrics.mjs @@ -14,8 +14,8 @@ * e2e-inventory: static count of describe/test blocks per spec file — durations * are deliberately absent because running Playwright overnight is forbidden. */ -import { readdirSync, readFileSync } from 'node:fs' import { spawnSync } from 'node:child_process' +import { readdirSync, readFileSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' @@ -62,7 +62,9 @@ const runVitestLayer = async (layer) => { try { report = JSON.parse(result.stdout.slice(jsonStart)) } catch (error) { - console.error(`[metrics] relatório JSON inválido: ${error instanceof Error ? error.message : error}`) + console.error( + `[metrics] relatório JSON inválido: ${error instanceof Error ? error.message : error}`, + ) process.exit(2) } const summary = summarizeVitestReport(report) diff --git a/tests/int/assertTestDatabase.int.spec.ts b/tests/unit/assertTestDatabase.unit.spec.ts similarity index 100% rename from tests/int/assertTestDatabase.int.spec.ts rename to tests/unit/assertTestDatabase.unit.spec.ts diff --git a/tests/int/petition-page-layout.int.spec.ts b/tests/unit/petition-page-layout.unit.spec.ts similarity index 100% rename from tests/int/petition-page-layout.int.spec.ts rename to tests/unit/petition-page-layout.unit.spec.ts diff --git a/tests/int/relationship.int.spec.ts b/tests/unit/relationship.unit.spec.ts similarity index 100% rename from tests/int/relationship.int.spec.ts rename to tests/unit/relationship.unit.spec.ts diff --git a/tests/int/schemaPrimitives.int.spec.ts b/tests/unit/schemaPrimitives.unit.spec.ts similarity index 100% rename from tests/int/schemaPrimitives.int.spec.ts rename to tests/unit/schemaPrimitives.unit.spec.ts diff --git a/tests/unit/testingAuditMetricsCore.unit.spec.ts b/tests/unit/testingAuditMetricsCore.unit.spec.ts index 5aaa787f..b1bb202c 100644 --- a/tests/unit/testingAuditMetricsCore.unit.spec.ts +++ b/tests/unit/testingAuditMetricsCore.unit.spec.ts @@ -49,7 +49,9 @@ describe('summarizeVitestReport', () => { it('falls back to summed durations when the payload lacks timestamps', () => { const payload = { - testResults: [{ name: '/x/y.unit.spec.ts', assertionResults: [{ title: 't', duration: 120 }] }], + testResults: [ + { name: '/x/y.unit.spec.ts', assertionResults: [{ title: 't', duration: 120 }] }, + ], } expect(summarizeVitestReport(payload).rows[0].durationMs).toBe(120) @@ -96,6 +98,8 @@ describe('renderE2EInventoryTable', () => { { file: 'tests/e2e/x.e2e.spec.ts', describes: 1, tests: 4 }, ]) - expect(table).toContain('| tests/e2e/x.e2e.spec.ts | 1 | 4 | não medido — execução noturna proibida |') + expect(table).toContain( + '| tests/e2e/x.e2e.spec.ts | 1 | 4 | não medido — execução noturna proibida |', + ) }) })