- scripts/worktree.mjs: provision() aplica migrate + db:seed:minimal nos bancos dev e test (paridade com a CI, que roda o par antes do e2e); --no-migrate pula os dois (o seed depende do catálogo migrado); fallback sem Docker também migra+seeda o teqo/teqo_test compartilhado (com warning de sobrescrita dos pins). - Guard de regressão tests/e2e/seedParity.setup.e2e.spec.ts no projeto setup: falha cedo com mensagem clara se o banco de teste não estiver seedado; evidência = users do seed (MINIMAL_CAMPAIGN_USERS), não os pins de priority — o cleanup dos fixtures e2e reseta priority por round-robin persistente. - scripts/lib/test-affected-core.mjs: scripts/worktree.mjs em HIGH_RISK_EXACT. - Docs: AGENTS.md, skill local-database, CHANGELOG-AGENTS.md, impl plan. Closes #584
8.4 KiB
Impl: Worktrees provisionam os bancos e2e sem o seed mínimo — e2e diverge da CI
Status: aprovado Atualizado em: 2026-08-10 Issue: #584 Intenção: docs/plans/worktree-seed-minimal-paridade-e2e-ci.md Appetite restante: herdado (~0,5 dia eng; um outcome verificável)
Leitura da intenção
- Outcome: um worktree recém-provisionado (
nexteplan) rodapnpm test:e2ecom o mesmo resultado da CI nos specs dependentes de dados do seed (campaignMunicipalitiesFAB suggest,campaignSavedFilterse os que tocampriority/expectedVotes/campaignGoals); a CI continua sendo a fonte canônica (nada do que este item faz muda o que a CI executa); o seed roda idempotente e protegido pelo guard de banco local; re-provisionamento não duplica nem corrompe. - O que NÃO negociar: não alterar specs e2e para "aceitar dados ausentes" (o provisão é o defeito); nunca rodar seed contra banco não-local; CI intocada; guard de regressão sem enfraquecer specs.
- O que reavaliar: a hipótese de "Direção no codebase" aponta
scripts/worktree.mjs+seed-minimal.mjs+ manifest + setup e2e — confirmada na exploração; a mecânica real das falhas foi verificada no código (FAB suggest filtrapriority === 'alta'emrankHomeSearchSuggestMunicipalities; o recorte?priority=altanasce vazio sem os pins; o nome sugerido vem deformatMunicipalityActiveFiltersSummary(state)— o fluxo quebra porque o recorte vazio derruba a linha 49 do spec).
Abordagem recomendada
flowchart LR
A[provision worktree] --> B[runMigrate dev]
B --> C[runSeedMinimal dev]
C --> D[runMigrate test]
D --> E[runSeedMinimal test]
E --> F[env files + porta do slot]
F --> G[e2e igual à CI]
Opções consideradas: A | B | C
Recomendação: A — rodar pnpm db:seed:minimal dentro de provision() em scripts/worktree.mjs, logo após cada runMigrate, para os DOIS bancos (dev e test), reusando o mesmo padrão de env (DATABASE_URL + PAYLOAD_SECRET explícitos) e o mesmo script npm da CI (pnpm db:seed:minimal — idempotente por upsert, guard assertLocalDatabase já embutido). --no-migrate pula migrations e o seed (o seed depende do catálogo migrado). Re-provisionamento (next num worktree existente) roda tudo de novo — migrate e seed são idempotentes, o aceite "não duplica nem corrompe" vale por construção.
Rejeitadas:
- B — seedar só o banco de teste (test-only): corrige o e2e mas deixa o
pnpm devdo worktree divergente (FAB suggest vazio no navegador manual) e cria dois contratos de provisionamento; o custo de seedar o dev é o mesmo. - C — documentar no AGENTS.md "rode o seed manualmente no worktree": trata o sintoma no papel; o ambiente padrão de entrega continua divergente e o agente segue aprendendo a ignorar o e2e vermelho (o padrão exato do ledger TECH-DEBT row 19).
Componentes / mudanças
runSeedMinimal(scripts/worktree.mjs): irmã derunMigrate—execFileSync('pnpm', ['db:seed:minimal'], { cwd: dir, env: { ...process.env, DATABASE_URL, PAYLOAD_SECRET }, stdio: 'inherit' }). O script npm já carregatsx/esm+seed-loader; o seed fazloadCliEnv()semoverride, então os env explícitos vencem.provision()(scripts/worktree.mjs):migrate dev → seed dev → migrate test → seed test;skipMigratepassa a pular os dois (mensagem atualizada).- Fallback sem Docker (
writeFallbackEnvpath): decisão Q1 aprovada no gate — paridade total (opção A):migrate + seed:minimaltambém noteqo/teqo_testcompartilhados (lerPAYLOAD_SECRETdo main env nesse branch;--no-migratepula igualmente). - Guard de regressão (Q2 da intenção, decisão aprovada no gate — opção B, setup e2e): spec novo
tests/e2e/seedParity.setup.e2e.spec.tsno projetosetupdo Playwright (o match/setup\.e2e\.spec\.ts/pega o arquivo; projetosetuproda primeiro e os projetos dependentes pulam se ele falhar): bootagetPayload({ config })(padrão já usado nos fixtures) e falha com mensagem clara ("rodepnpm migrate && pnpm db:seed:minimal— oupnpm worktree nextpara reprovisionar") se o banco de teste não estiver seedado. Evidência checada =MINIMAL_CAMPAIGN_USERS(users sintéticos do seed), deliberadamente NÃO os pins depriority: 'alta': o cleanup dos fixtures e2e resetaprioritydos municípios tocados (round-robin por sequência persistente —campaignE2EFixtures.ts), então pins morrem legitimamente após runs repetidas no mesmo banco de worktree e não são evidência indelével; os users do seed nunca são deletados pelo cleanup (que só deleta o que os fixtures criaram). Mensagem clara em vez de spec vermelho confuso. (Sem extensão extra do manifest unit — o pin existente de slugs fica como está.) HIGH_RISK_EXACT(scripts/lib/test-affected-core.mjs): adicionarscripts/worktree.mjs— mudança no provisionador deve rodar a suíte cheia na CI, não só o diff.- Docs: AGENTS.md "Per-worktree environments" (migrations → migrations + seed mínimo, paridade com a CI); header/uso do
scripts/worktree.mjs(--no-migrateagora pula migrate+seed);.agents/skills/local-database/SKILL.md(linhas 32/34, mesmo contrato); entrada curta emdocs/CHANGELOG-AGENTS.md. - Migration: nenhuma (sem schema/dados novos).
- Access / Consent: nenhum (o seed já faz
provisionOnda0ConsentAndPrivacy+ chaves fail-closed — intocado). - UI: Impeccable A — N/A (sem UI).
Dados → forma (se aplicável)
Não aplicável — infra de provisionamento; o "dado" é a paridade de estados entre ambientes, verificada pelo guard do setup (pin alta no banco de teste) e pelo e2e real.
Fases verificáveis
- Tracer — provisionamento (quota principal):
runSeedMinimal+ chamadas noprovision()(Docker path) +--no-migrate→ verificação manual num banco de teste recém-criado (seed aplicado, idempotência em re-execução). Fallback sem Docker segue a decisão do gate (Q1). - Guard —
seedParity.setup.e2e.spec.tsno projetosetup(falha com mensagem clara contra banco não-seedado — incluindo banco nunca-migrado, via try/catch com a mesma mensagem; verde com seed) +HIGH_RISK_EXACT. - Gates —
pnpm gate:fastna iteração; depoispnpm test:e2e -- tests/e2e/campaignSavedFilters.e2e.spec.ts+ o spec do FAB suggest contra o banco do worktree seedado (reprodução real das duas falhas da intenção);pnpm test:int(unit+int);pnpm check:cycles/format:check/knip; entrega compnpm push.
Rabbit holes / Não escopo (engenharia)
- Não tocar em nenhum spec e2e existente (o único arquivo de teste novo é o guard).
- Não mudar o CI (
ci.yml/ci-pr.ymljá rodammigrate → seed:minimal— nada a fazer). - Não alterar o
seed-minimal.mjsnem o manifest (já idempotentes e corretos). - Não mexer nos bancos compartilhados
teqo/teqo_testno fluxo Docker (fora do contrato de worktree). - Não adicionar lock/transação ao seed para o caso de dois fallbacks seedarem o mesmo
teqo_testem paralelo (fallback é degradado; colisão de upsert find-before-create é raça rara e ruidosa — documentar no impl, não engenhar). - Gap observado (não deste item): o fallback não grava
PAYLOAD_SECRETno.env.local/.env.test.localgerados — o seed receberá o secret explícito no env; o gap do dev no fallback é pré-existente e fica fora de escopo.
Riscos e mitigação
- Seed adiciona ~10–30 s por banco no provisionamento (boot do Payload + upserts): aceitável — migrations já levam ~30 s cada; é one-time por banco e idempotente.
- Re-execução em worktree existente:
nextre-rodaprovision(); migrate+seed idempotentes → sem duplicação (upsert por chave estável/slug/email/phone). - Guard do setup com banco compartilhado do fallback: se dois fallbacks rodarem e2e no mesmo
teqo_test, o guard lê estado do banco — o seed é idempotente; risco residual documentado (raça find-before-create) e ruidoso se ocorrer. - E2E novo no projeto
setuppode afetar a duração do setup: boot do payload ~2–5 s; aceitável (o setup já prewarms 13 rotas).
Aceite de engenharia
- Aceite de produto da intenção ainda coberto (e2e do worktree = CI; CI intacta; idempotência)
- Invariantes AGENTS/engineering-standards (local-only via
assertLocalDatabase; nenhum schema/access/Consent tocado) - Testes previstos: guard e2e (falha clara + verde), unit do manifest estendido, reprodução real dos 2 specs que falhavam