# Isolar a porta do e2e por worktree (e2e não deve disputar a porta 3000) Status: rascunho Atualizado em: 2026-08-09 Issue: #464 Priority: P1 Model: composer-2.5 Impeccable: A — N/A (sem superfície de usuário; infra de dev/teste) Canvas UI: N/A — sem UI Appetite: ~0,5 dia eng; um outcome verificável (dois e2e em paralelo em worktrees diferentes não colidem) Responsável: — ## Intenção O provisionamento por worktree (`pnpm worktree next` / `plan`) isolou o **banco** de teste corretamente — cada worktree ganha `teqo_wt_test` — mas o **e2e em si continua caindo sempre na porta `3000`**. O script grava `PLAYWRIGHT_BASE_URL` no `.env.local` (que o `playwright.config.ts` **não lê**), e omite do `.env.test.local` (que ele lê). Resultado: quando dois agentes rodam `pnpm test:e2e` em worktrees paralelos, os dois sobem `pnpm dev` na mesma porta `3000` → um trava com porta ocupada e os dois disputam CPU do mesmo dev server. Os registros do repo (“dois worktrees com dev server ativo”, “load ~40–58”, “contenção do sandbox com múltiplos dev servers em paralelo”) são a assinatura disso rondando as entregas. Faltou meia linha. ## Persona e fluxo - **Persona / contexto:** agente (ou humano) de paralelismo rodando a suíte e2e como gate entrega, enquanto outros worktrees estão vivos no mesmo host. - **Job principal:** rodar `pnpm test:e2e` no meu worktree sem depender do que outros worktrees estão fazendo no host. - **Fluxo desejado:** cada worktree roda e2e contra o **seu** banco de teste (`teqo_wt_test`) **e na sua** porta (`3100+slot`) → dois runs paralelos não se veem. - **Anti-goals de produto:** não criar autenticação/rota/DB novo; não mexer em contrato de URL público; não virar “runner distribuído”. ## Objetivo e aceite - Rodar a suíte e2e em dois worktrees diferentes ao mesmo tempo, no mesmo host, termina **sem** `EADDRINUSE` / sem um run falar com o servidor do outro. - O run e2e de cada worktree usa o banco e a porta derivados do slot do próprio worktree — nada de `3000` como queda. - O dev server do e2e (webServer do Playwright) continua amarrado ao banco de **teste**, nunca ao banco dev ou prod. ## Dados (intenção) - **Vou apresentar dados?** Não — sem superfície de dados; é isolamento de ambiente de teste. ## Direção no codebase (hipótese) - **Áreas prováveis:** `scripts/worktree.mjs` (bloco de escrita do `.env.test.local` no `provision`); `playwright.config.ts` (`baseURL` já lê `PLAYWRIGHT_BASE_URL`, com fallback `3000` — o que precisa é a variável chegar lá). - **Precedente a olhar:** `tests/helpers/assertTestDatabase.ts` já aceita `teqo__test`; `.env.test.local` já carrega `NEXT_PUBLIC_SITE_URL` na porta do slot — só a `PLAYWRIGHT_BASE_URL` ficou de fora. - **Risco de acoplamento:** porta do e2e = porta do dev do worktree (já derivada e determinística); não inventar um segundo domínio de porta só para o e2e. ## Dependências - Nenhuma. ## Fora de escopo - Isolar o Vercel Blob compartilhado entre e2e de worktrees paralelos (upload com chaves determinísticas por fixture) — comportamento pré-existente, overwrite silencioso; abrir item próprio se virar problema medido. - Isolamento do caminho _sem Docker_ (fallback Cursor Cloud): já documentado que degrada para `teqo/test` e porta compartilhada — não é o alvo deste item. - Qualquer mudança nos contratos de URL/rota ou no próprio `playwright.config.ts` além do necessário para a variável chegar. ## Rabbit holes de produto - **“Isolar também o Blob / o tmp / os workers”** — escopo explode para uma conta de runner gigante. **Corte neste item:** só a porta; Blob/tmp viram item próprio se medirem conflito real. - **“Reescrever o fluxo de env do playwright”** — não precisa: a variável certa já existe e o config já a lê com antecedência. ## Questões em aberto (produto) - **Apontar o e2e para a porta do dev do worktree (`3100+slot`) ou para uma porta distinta?** **Opções:** A) reusar a porta do slot do worktree (já provisionada, determinística, e o `.env.test.local`/`NEXT_PUBLIC_SITE_URL` já apontam nela) | B) segunda faixa de portas só para e2e. **Recomendação:** A — o domínio de colisão já é único (`slot`), duplicar a faixa só cria segundo estado a reconciliar. _(assumido — validar com o dono do provisionamento)_ ## Referências - GitHub Issue #464 - `playwright.config.ts:11-27` — só carrega `.env.test` + `.env.test.local`; `baseURL = PLAYWRIGHT_BASE_URL ?? http://localhost:3000` - `scripts/worktree.mjs:250-279` — `.env.local` recebe `PLAYWRIGHT_BASE_URL` (linha ~256); `.env.test.local` **não** - `.agents/skills/local-database/SKILL.md` — documenta o que o provisionamento escreve (e replica o gap) - Registros do sintoma em vários planos: “dois worktrees com dev server ativo”, “contenção do sandbox com múltiplos dev servers em paralelo”