docs: a vps-fresh-onboarding entrou no CI — as frases que a davam como fora venceram

O PR #983 tirou a `vps-fresh-onboarding.spec.ts` da `FORA_DO_CI` e a pôs
para rodar na `SPECS_PARTE_4` do `e2e.yml` (matrix `parte: [1, 2, 3, 4]`;
o agregador obrigatório `e2e` tem `needs: [e2e-alcance, e2e-parte]`).
Medido em origin/main @ af6730f0f: a `FORA_DO_CI` lista só
`inbox-tempo-real` e `cadastro-sem-confirmacao-de-email`.

Com isso, venceram as afirmações de que a jornada de instalação fresca
segue sem gate e de que `e2e` verde não a prova:

- CLAUDE.md (item `e2e` dos checks obrigatórios): a frase vira histórico
  datado e a pergunta passa a ser respondida pelo comando python que o
  próprio item já traz, amarrado ao `e2e-cobertura-completa.test.ts`.
- AGENTS.md (Limitações conhecidas): o item carrega o comando que mede a
  `FORA_DO_CI` e o histórico em uma frase. Também a linha "`e2e` roda
  três partes", que venceu no mesmo PR, vira comando.
- docs/current-state.md §4.1 e docs/harness-audit.md: são retratos
  datados, então ganham nota de atualização em vez de reescrita.

A ressalva que continua verdadeira fica escrita em todos: PR que não
alcança o `e2e` (scripts/pr-alcanca-o-e2e.sh) pula as partes, e ali o
verde não prova tela nenhuma.

Só documentação: não muda comportamento para quem opera VPS, então não
leva fragmento em .changes/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
melgarafael
2026-09-19 02:19:37 -03:00
co-authored by Claude Opus 5
parent af6730f0fc
commit 21017b8a83
4 changed files with 51 additions and 12 deletions
+18 -8
View File
@@ -169,8 +169,10 @@ gh api repos/melgarafael/DeskcommCRM/branches/main/protection \
--jq '.required_status_checks.contexts|join(", ")'
```
`e2e` roda três partes em paralelo; as specs de fora estão declaradas, **com motivo escrito**, em
`FORA_DO_CI` dentro de `.github/workflows/e2e.yml`. Leia em vez de supor:
`e2e` roda as partes da sua matrix em paralelo (quantas:
`git show origin/main:.github/workflows/e2e.yml | grep -E '^ +parte: \['` — esta linha dizia
"três" até o PR #983 acrescentar a quarta); as specs de fora estão declaradas, **com motivo
escrito**, em `FORA_DO_CI` dentro de `.github/workflows/e2e.yml`. Leia em vez de supor:
```bash
git show origin/main:.github/workflows/e2e.yml | grep -A4 'FORA_DO_CI:'
@@ -379,12 +381,20 @@ itens envelhecem em ritmos diferentes, e o cabeçalho passava a mentir por todos
(O SHA `789dfa6`, que ficava aqui, ficou para trás — meça com
`git rev-list --count 789dfa6..origin/main`.)
- **As specs E2E fora do CI são exatamente as declaradas em `FORA_DO_CI`** — hoje
`vps-fresh-onboarding` é a P0 entre elas —, e o `e2e` **é** check obrigatório. Ou seja: um PR
que quebre o `e2e` não entra — mas a jornada de
instalação fresca, que é o produto que se vende, continua sem gate. Se você mexeu nela, a
prova é sua. O número e a contagem que ficavam aqui eram de uma fotografia de agosto, e o
disco já tinha mudado desde então.
- **As specs E2E fora do CI são exatamente as declaradas em `FORA_DO_CI`**, e o `e2e` **é** check
obrigatório: um PR que quebre o `e2e` não entra. Quais ficam fora, meça:
```bash
git show origin/main:.github/workflows/e2e.yml | \
python3 -c "import sys,re; y=sys.stdin.read(); print(sorted({s for _,c in re.findall(r'(FORA_DO_CI):\s*>-\n((?:[ ]{8,}.*\n)+)',y) for s in re.findall(r'[a-z0-9-]+\.spec\.ts',c)}))"
```
Até 2026-09-19 a `vps-fresh-onboarding` — a P0, a jornada de instalação fresca, que é o
produto que se vende — estava nessa lista e seguia sem gate; desde o PR #983 ela roda na
`SPECS_PARTE_4`. O gate vale só em PR que alcança o `e2e` (regra em
`scripts/pr-alcanca-o-e2e.sh`): o que pula as partes sai com `e2e` verde sem ter provado tela
nenhuma, a da instalação fresca inclusive. O número e a contagem que ficavam aqui eram de uma
fotografia de agosto, e o disco já tinha mudado desde então.
- Rate limit HTTP: `lib/auth/rate-limit.ts` cobre **login, signup, recuperação de senha e
aceite de convite** (contando por IP **e** por identificador hasheado); `checkRateLimit` cobre
o webhook de captação e o dispatcher de IA. **Crons e MCP seguem sem.** Meça antes de agir:
+1 -1
View File
@@ -435,7 +435,7 @@ Checks **obrigatórios** na branch protection da `main` (verificado na configura
python3 -c "import sys,re; y=sys.stdin.read(); print(sorted({s for _,c in re.findall(r'(FORA_DO_CI):\s*>-\n((?:[ ]{8,}.*\n)+)',y) for s in re.findall(r'[a-z0-9-]+\.spec\.ts',c)}))"
```
Esta frase já dizia "a **única** de fora é `vps-fresh-onboarding`" e estava errada: em 2026-09-04 a variável listava **duas** (`inbox-tempo-real` entrou depois). É o mesmo defeito que o parágrafo acima descreve — afirmação de estado que envelhece —, cometido na frase seguinte à que o denuncia. O que continua verdade e é o que importa: `vps-fresh-onboarding` é a **P0** da doutrina de QA Visual, então `e2e` verde **não** prova a jornada de instalação fresca, que é o produto que se vende.
Esta frase já dizia "a **única** de fora é `vps-fresh-onboarding`" e estava errada: em 2026-09-04 a variável listava **duas** (`inbox-tempo-real` entrou depois). É o mesmo defeito que o parágrafo acima descreve — afirmação de estado que envelhece —, cometido na frase seguinte à que o denuncia. E a frase que a substituiu envelheceu do mesmo jeito: afirmava que `e2e` verde **não** prova a jornada de instalação fresca, porque a `vps-fresh-onboarding` — a **P0** da doutrina de QA Visual — estava fora. Valeu até 2026-09-19; desde o PR #983 ela roda na `SPECS_PARTE_4`. Em vez de uma terceira frase de estado, a pergunta que importa — *o `e2e` verde cobre a instalação fresca?* — se responde com o comando acima: se `vps-fresh-onboarding` não está na saída, ela roda, porque `tests/unit/e2e-cobertura-completa.test.ts` reprova spec que não esteja nem numa `SPECS_PARTE_*` nem na `FORA_DO_CI`. A ressalva do começo do item continua de pé: em PR que pula as partes, o verde não prova tela nenhuma — a da instalação fresca inclusive.
**Não confie em `grep` no arquivo inteiro.** `grep -oE '[a-z0-9-]+\.spec\.ts' .github/workflows/e2e.yml | sort -u | wc -l` conta quem é CITADO, não quem é INVOCADO: a `FORA_DO_CI` é uma variável YAML como as outras e entra na conta. (Até 2026-08-14 este parágrafo culpava "menções em comentários", e isso é falso — medido, o conjunto de specs citadas fora de variável é **vazio**.) O que roda são as `SPECS_PARTE_*`:
+14 -1
View File
@@ -169,6 +169,18 @@ protection em 2026-08-13 e saiu desta lista em 2026-08-14.)*
### 4.1 Os E2E quase não rodam no CI 🟠 — parcialmente resolvido em 2026-07-30
> **Atualização (2026-09-19, PR #983):** a `vps-fresh-onboarding` saiu da `FORA_DO_CI` e passou
> a rodar no CI, na `SPECS_PARTE_4` do `e2e.yml`, sozinha numa parte. Tudo abaixo que a dá como
> fora, ou que conclui que "`e2e` verde não prova a instalação fresca", é registro de antes
> dessa data. Uma ressalva continua valendo: PR que não alcança o `e2e` (regra em
> `scripts/pr-alcanca-o-e2e.sh`) pula as partes, e ali o verde não prova tela nenhuma. O que
> fica fora hoje não se lê deste documento — meça:
>
> ```bash
> git show origin/main:.github/workflows/e2e.yml | \
> python3 -c "import sys,re; y=sys.stdin.read(); print(sorted({s for _,c in re.findall(r'(FORA_DO_CI):\s*>-\n((?:[ ]{8,}.*\n)+)',y) for s in re.findall(r'[a-z0-9-]+\.spec\.ts',c)}))"
> ```
>
> **Atualização (2026-08-14 @ `741c4ec8`):** `e2e.yml` roda **45 das 46 specs**, e o `e2e` **é
> check obrigatório** na branch protection desde 2026-08-08 (junto com `verify`,
> `build-and-size`, `invariants` e `imagens-ok` — **cinco**). A única spec fora é
@@ -192,7 +204,8 @@ O que continua fora (2026-08-14): **1 das 46 specs Playwright**. A
rodar** no `e2e.yml`. Mas a `vps-fresh-onboarding.spec.ts` — a jornada que a doutrina de QA
Visual classifica como o caminho mais crítico do produto — continua fora, porque exige WAHA +
Redis + Resend + Nuvemshop no runner. Regressão nela passa sem detecção (issue #63), e é por
isso que **`e2e` verde não prova a instalação fresca**.
isso que **`e2e` verde não prova a instalação fresca**. *(Superado em 2026-09-19 pelo PR #983 —
ver a atualização no topo desta seção.)*
O `e2e` **é** check obrigatório desde 2026-08-08; um PR que o quebre não entra na `main`.
+18 -2
View File
@@ -53,7 +53,7 @@ verificados por leitura de arquivo, config e workflow.
| H2 — Reproduzível | ✅ | Quickstart no README, `docs/SETUP.md`, `.nvmrc` (22), `packageManager` fixo, `pnpm-lock.yaml`, `docker-compose.yml`, `install.sh` do kit self-host, `baseline.sql` |
| H3 — Verificável | ✅ | `lint` + `typecheck` + `test:unit` + `build`; CI roda os 3 primeiros em PR |
| H4 — Preparado para agentes | ✅ | `CLAUDE.md` doutrinal forte; `AGENTS.md` **criado nesta auditoria**; documentação técnica extensa; **e o CI roda o gate de isolamento RLS** (job `invariants` → `pnpm test:db`) |
| H5 — Automação avançada | ⚠️ **parcial** | CI confiável e ambiente isolado ✅ (Postgres efêmero pg15, worktrees, gov-loop com maker≠checker e hash-check). Falta: **1 das 46 specs E2E fora do CI** (45 rodam via `e2e.yml`, **obrigatório desde 2026-08-08**; a de fora é `vps-fresh-onboarding`, que é justamente a P0), `format:check` fora do CI, e o comando único local (`gov:verify`) não cobre `test:db`/`test:e2e`. *(Números recontados em 2026-08-14 @ `741c4ec8`; a redação anterior — "4 das 32, não-obrigatório" — apodreceu.)* |
| H5 — Automação avançada | ⚠️ **parcial** | CI confiável e ambiente isolado ✅ (Postgres efêmero pg15, worktrees, gov-loop com maker≠checker e hash-check). Falta: **1 das 46 specs E2E fora do CI** (45 rodam via `e2e.yml`, **obrigatório desde 2026-08-08**; a de fora é `vps-fresh-onboarding`, que é justamente a P0), `format:check` fora do CI, e o comando único local (`gov:verify`) não cobre `test:db`/`test:e2e`. *(Números recontados em 2026-08-14 @ `741c4ec8`; a redação anterior — "4 das 32, não-obrigatório" — apodreceu.)* *(Nota de 2026-09-19: a `vps-fresh-onboarding` deixou de estar fora — desde o PR #983 roda na `SPECS_PARTE_4`. O que fica fora hoje: ver a nota logo abaixo de "O que separa de H5".)* |
**Por que H4 e não H5:** a instrução da auditoria é explícita — não atribuir nível só
porque os arquivos existem, avaliar se o processo está implementado. Aqui está: o gate de
@@ -67,6 +67,17 @@ como o caminho mais crítico do produto. E `pnpm gov:verify`, o comando único q
naturalmente usa como critério de pronto, **não** inclui `test:db` nem `test:e2e`: o CI
pega o que ele deixa passar, mas só depois do push.
> **Nota de 2026-09-19 (PR #983):** a `vps-fresh-onboarding.spec.ts` citada acima como fora do
> CI passou a rodar na `SPECS_PARTE_4` do `e2e.yml`. Em PR que alcança o `e2e` (regra em
> `scripts/pr-alcanca-o-e2e.sh`), o verde agora cobre a jornada de instalação fresca; em PR
> que pula as partes, continua não provando tela nenhuma. O parágrafo acima é retrato de antes
> e fica como está. O que fica fora hoje não se lê deste documento — meça:
>
> ```bash
> git show origin/main:.github/workflows/e2e.yml | \
> python3 -c "import sys,re; y=sys.stdin.read(); print(sorted({s for _,c in re.findall(r'(FORA_DO_CI):\s*>-\n((?:[ ]{8,}.*\n)+)',y) for s in re.findall(r'[a-z0-9-]+\.spec\.ts',c)}))"
> ```
**O que puxa este projeto para cima e é incomum num CRM open-source:** doutrina escrita e
específica (`CLAUDE.md`), Definition of Done de 13 itens, **56 arquivos de invariantes de
banco**, gate de install+update do `baseline.sql` num Postgres descartável rodando em CI,
@@ -93,7 +104,7 @@ Legenda: ✅ existente e funcional · ⚠️ existente mas incompleto · ❌ nã
| 10 | Checagem de tipos | ✅ | `pnpm typecheck` (`tsc --noEmit`, TS 6 estrito), roda no CI |
| 11 | Testes unitários | ✅ | 221 arquivos `*.test.ts(x)`; `pnpm test:unit` no CI |
| 12 | Testes de integração | ✅ | **56 arquivos** de invariantes em `tests/invariants/` + `tests/api/`. Excluídos do `test:unit` de propósito (`vitest.config.ts:12`) e rodados pelo job `invariants` do CI via `pnpm test:db` |
| 13 | Testes E2E | ⚠️ | 20 specs Playwright. **10 rodam no CI** (`e2e.yml`, ainda não-obrigatório), incluindo o P0 `vps-webhook-outbound-ssrf`; o P0 `vps-fresh-onboarding` continua fora (issue #63) |
| 13 | Testes E2E | ⚠️ | 20 specs Playwright. **10 rodam no CI** (`e2e.yml`, ainda não-obrigatório), incluindo o P0 `vps-webhook-outbound-ssrf`; o P0 `vps-fresh-onboarding` continua fora (issue #63) *(Nota de 2026-09-19: desde o PR #983 ela roda na `SPECS_PARTE_4` — ver a nota logo abaixo de "O que separa de H5".)* |
| 14 | Comando único de verificação | ⚠️ | `pnpm gov:verify` = `typecheck && lint && test:unit`. **Omite `test:db` e `test:e2e`** — verde localmente não significa verificado. O CI cobre `test:db`, mas só depois do push |
| 15 | CI executando verificações | ✅ | `ci.yml` tem 2 jobs: `verify` (typecheck + lint + test:unit) e **`invariants` (`pnpm test:db` — isolamento RLS + invariantes de governança, em job paralelo com timeout de 20min)**. Falta E2E e `format:check`. `perf.yml` faz build + bundle size; `publish-image.yml` publica no GHCR |
| 16 | Proteção contra secrets | ⚠️ | `.gitignore` cobre `.env*` (exceção só para os `.example`) e o Sentry tem `beforeSend` que higieniza PII. **Sem** gitleaks/trufflehog no CI, **sem** pre-commit hook |
@@ -123,6 +134,11 @@ doutrina classifica como o caminho mais crítico do produto, e
`vps-webhook-outbound-ssrf.spec.ts` é a única prova automatizada do guard de SSRF. Rodar
em PR pode ser lento; um workflow nightly + trigger manual já elimina a regressão silenciosa.
> **Nota de 2026-09-19:** as duas specs que este item cita entraram no CI obrigatório, em PR — não
> num nightly: a `vps-webhook-outbound-ssrf.spec.ts` entrou antes (item 13 da tabela acima), e a
> `vps-fresh-onboarding.spec.ts` entrou no PR #983, na `SPECS_PARTE_4`. O que ainda fica fora:
> ver a nota logo abaixo de "O que separa de H5".
### 2. Renomear/reforçar o comando único 🟠 · custo: 2 linhas
Duas opções: (a) `gov:verify` passa a incluir `test:db` (exige Docker em toda máquina de