12 KiB
Changelog de contexto para agentes (fatias do AGENTS.md)
Conteúdo movido do AGENTS.md em 2026-07-30 (fatiamento do paradigma de agentes paralelos): "Known Gaps" e todos os blocos "Recently resolved". Histórico — leia só quando precisar do contexto de uma entrega passada; o sempre-presente fica no AGENTS.md. Itens novos de "Recently resolved" passam a ser registrados aqui (uma entrada curta), não no AGENTS.md.
Recently resolved (2026-08-10): B195 (Issue #591) — wizard "Registrar pedido" completo (A5, adiado no B85): o passo final saiu do stub e virou formulário funcional no shell do wizard — município no header do app (chrome municipalityLabel), sem título grande de passo (stepTitle={null} + contentFocus="none"), Tipo → Atividade (opcional) → campo único "O que você precisa?"; salvar ("Abrir demanda") → toast + retorno à origem (returnPath). Mudança de modelo da demanda: o cadastro (wizard e /demandas/nova, sem divergência) tem UM campo de texto (description required, min 2, max 4000 — constante CAMPAIGN_DEMAND_BODY_MAX_LENGTH); o título virou derivado por IA (src/utilities/ai/campaignDemandTitle.ts — generateText DeepSeek deepseek-v4-flash como o Sollinha, timeout 4s, sem key → null, prompt com rótulo do tipo) com fallback = texto truncado (src/lib/demandTitle.ts, puro: colapsa whitespace, ≤160) no create e keep-previous na edição (novo updateCampaignDemandRecord + editor inline no detalhe — recalc só quando a descrição muda; slug preservado pela invariante canônica); campaignDemandCreateSchema perdeu title (só os drafts de demanda da atividade mantêm título digitado — vertical fora de escopo, schema desacoplado). Unicidade de slug defensiva só no create das forms (ensureUniqueDemandSlug, opt-in context.campaignDemandUniqueSlug fail-closed em transação ativa — precedente skipContactPhoneInvariant): probe único da janela -2…-20 + advisory lock campaign-demand-slug:<base> contra race; activity drafts/admin mantêm a constraint estrita (contrato de rollback C90 pinado em teste). Page: branch register-demand no router + staff gate ANTES do load do escopo (gate: 'staff' → líder vai a /campanha/contatos, B43 — o 403 do scope load pré-existente virava erro não determinístico; stub WizardMunicipalitySelectedStub removido, placeholder "em breve" apagado). Bug latente corrigido no hook compartilhado useCampaignFormSuccessToast (dependência [state.message, state.status] → [state]: segundo save com a mesma mensagem — caso do editor — não disparava toast/refresh). Copy compartilhada em schemas/campaignDemand.ts; parser único parseCampaignDemandCreateFormData (utilities/demand/). Sem migration (título continua required, preenchido pelo record). Testes: unit do fallback/limites exatos; int (create deriva, colisão -2/-3, min 2, update keep-previous/skip, leader edit bloqueado, pin "sem DEEPSEEK_API_KEY" no beforeAll); e2e novo campaignRegisterDemand (fluxo completo com título na lista, back-nav à busca, lockdown de líder). Intenção registrar-pedido-wizard.md; impl registrar-pedido-wizard-impl.md.
Recently resolved (2026-08-10): OPS33 (Issue #595) — worktree next claima deterministicamente antes de criar o worktree: mesma fila/ordem e lock otimista do pnpm agent:claim, com o claim extraído para scripts/lib/agent-github.mjs (claimIssue — lock + flip + comentário; claimBriefLines — brief compartilhado; claimQueueEntry — shape para o reopen; claimTargetVerdict — decisão pura testada) e o agent-claim.mjs virou CLI fino com a mesma saída; claim falhou (fila vazia/race/--issue inválido) → motivo e saída sem worktree órfão (branch validada antes do claim; hint de falha pós-claim). --issue <N> claima a Issue direcionada (ready) ou reabre uma já claimada (in-progress — sem re-claim, idempotente; recupera também falha pós-claim); a saída imprime o brief e avisa "já claimada — NÃO rodar pnpm agent:claim". O launch do terminal agora envia /work-issue --issue <N> (prompt citado na diretiva) e a função worktree() de .agents/shell/worktree.sh passou a tokenizar a diretiva via xargs (quote-aware, nunca eval) — o valor do --prompt carrega espaço. --stay suprime cd+launch mas o claim acontece; o comando /worktree roda o mesmo script (claim incluso, sem launch). Guard -B contra reset de commits de sessão no reopen. Pool intacto (claimIssueForPool coordenado). Docs: AGENTS.md ("Per-worktree environments"), header/uso do script, .opencode/commands/worktree.md, skill worktree-next-issue (sai "read-only"), AGENT-OPS. Sem migration/dados/access/UI. Intenção worktree-next-claima-issue-deterministicamente.md; impl worktree-next-claima-issue-deterministicamente-impl.md.
Recently resolved (2026-08-10): OPS28 (Issue #584) — worktree next/plan passam a aplicar o seed mínimo além das migrations em cada banco provisionado (migrate + db:seed:minimal por banco, dev e test) — paridade com a CI, que roda o mesmo par antes do e2e: o e2e de worktree deixa de divergir do de CI (specs dependentes dos pins priority: 'alta' de salvador-ze-1/camacari — FAB suggest e campaignSavedFilters — falhavam só localmente com banco migrado cru 435×normal, o padrão que o ledger TECH-DEBT row 19 ficha como "masks real failures"). --no-migrate pula migrate e seed (o seed depende do catálogo migrado); re-provisionamento continua idempotente (upserts). Fallback sem Docker (Cursor Cloud) também roda migrate+seed nos teqo/teqo_test compartilhados (decisão de produto do gate: paridade total). Guard de regressão tests/e2e/seedParity.setup.e2e.spec.ts no projeto setup do Playwright: falha cedo com mensagem clara ("rode pnpm migrate && pnpm db:seed:minimal") se o banco de teste não estiver seedado — dependentes do setup pulam, nada de spec vermelho confuso; a evidência checada são os users do seed (MINIMAL_CAMPAIGN_USERS), deliberadamente não os pins priority: 'alta' — o cleanup dos fixtures e2e reseta priority dos municípios que toca (round-robin por sequência persistente), então pins morrem legitimamente após runs repetidas no mesmo banco de worktree e só o pnpm worktree next re-aplica (guard nunca checaria pins); scripts/worktree.mjs entrou em HIGH_RISK_EXACT (mudança no provisionador roda a suíte cheia na CI). Sem migration/access/Consent/UI. Intenção worktree-seed-minimal-paridade-e2e-ci.md; impl worktree-seed-minimal-paridade-e2e-ci-impl.md.
Recently resolved (2026-08-10): OPS34 (Issue #599) — o job e2e do CI (o mais longo da cascata, 435 s medidos no run 31412425553: ~67 s fixos + build 172 s + testes 196 s) roda agora em 2 shards paralelos (--shard=N/2, matrix fail-fast: false, build por shard — opção A da intenção validada pela medição: por shard ≈ 5–5,5 min; artefato de build compartilhado rejeitado porque os shards só começam após o build → wall maior). Cadeia de projetos do Playwright (setup → campaign → frontend → admin) + prewarm do setup viraram dev-only: playwright.config.ts ganhou isProdMode = CI || E2E_PROD=1 (mesma condição do webServer.command, agora reusada) — em prod o projeto setup sai do array (arquivo não casado = não coletado) e as dependencies zeram (famílias em paralelo contra o build de produção, onde não há compile a preaquecer); dev intocado (provado: --list mostra [setup] só sem CI; smoke e2e dev rodou setup→campaignAuth). ci-pr.yml: o job scope emite e2e_matrix/e2e_shards via novo e2eShardConfig(mode) em scripts/lib/test-affected-core.mjs (fonte única, unit-pinada: full → [1,2]/2, selected/none → [1]/1 — pagar 2 builds por 3 specs é desperdício); ci.yml hardcodeia [1,2]/2 com comentário apontando o single-source. PLAYWRIGHT_WORKERS: 2 explícito no env dos jobs e2e (aceite: explícito, default local intocado). Armadilha registrada nos workflows: flags do playwright vão sem o separador -- — pnpm repassa o -- literal ao playwright e a flag vira file pattern ("No tests found"). Specs intactas (o setup não foi removido — virou dev-only, já documentado como prewarm dev-only); sem migration/access/Consent/UI. Medição pós-merge (main, run 31418206512): job e2e 435 s → 326 s (shard 1) / 369 s (shard 2) — shard 2 = fixo 68 s + build 176 s + testes 124 s (a fase de testes caiu de 196 s seriais para 124 s — metade da suite por runner + cadeia removida; o shard 2 ainda pagou retry da flake conhecida de campaignMunicipalities; shard 1: testes ~82 s); gate completo do pipeline (checks) ~7,5 → ~6,4 min. Build passou a dominar o shard — gatilho da intenção (opção B, artefato compartilhado) reavaliável quando os testes encolherem mais. Intenção ci-e2e-paralelizar-job.md; impl ci-e2e-paralelizar-job-impl.md.
Recently resolved (2026-08-10): OPS35 (Issue #600) — modo de spec e2e full-stack sem browser (paradigma HTTP): mesma suíte (pnpm test:e2e), mesmo job/CI, mesmo servidor + DB reais, sem lançar navegador. Base nova tests/e2e/fixtures/campaignHttpTest.ts estende o test cru de @playwright/test (nunca e2eTest.ts — o guard e2eFailureGuard é auto e puxaria page/context), reusa o fixture campaign do browser (exportado como campaignFixture — ownership/cleanup in-process, zero caminho de seed paralelo) e adiciona o fixture campaignRequest(user, senha): login pelo REST real do Payload (POST /api/campaignUser/login, loginWithUsername aceita email/username) → request.newContext com o cookie canônico campaign-token (path /campanha, flags espelhando setCampaignAuthCookie; secure pelo scheme do baseURL, não pelo NODE_ENV do runner). Nomenclatura ajustada contra a letra da intenção (descoberta de execução): *.http.e2e.spec.ts não casa o testMatch /campaign.*\.e2e\.spec\.ts/ do projeto → campaign<Family>Http.e2e.spec.ts no mesmo projeto (dependência setup de prewarm já coberta). Primeira família migrada: campaignTerritories (4 specs campaignTerritoriesHttp.e2e.spec.ts, browser removido; manifesto e2e-affected atualizado — unit-pinned). Equivalências: clicks viravam GETs de URL (?sort=votes2022 → caption "Ordenado por 2022 (maior primeiro)"; ?region=Irecê → "1 território encontrado"); DOM virou HTML renderizado — com duas realidades de render registradas no header do spec: separadores RSC <!-- --> (asserções rodam sobre rendered(), comentários são transporte, não conteúdo) e o label "Cobertura" presente no flight payload (menu do picker é client component serializado mesmo fechado) — o pin "oculta por default" é a ausência do controle sortable, que resolveVisibleColumns não renderiza. RBAC leader: o redirect noLeader é redirect() pós-stream → o documento responde 200 com <meta http-equiv="refresh" content="1;url=/campanha/contatos"> (Next next-route-redirect), não 3xx — o meta é o contrato assertado (dev 307/prod 308 quando o redirect vence o stream; nunca pinar status numérico). Medição (dev server, worktree 3135, load ~68, prewarm incluído nas duas versões): família browser 56,0 s (22,9/17,5/7,9/7,7) vs HTTP 33,7 s (10,8/8,4/2,4/12,1) — −40%; o ganho é estrutural (sem login de browser, sem hidratação, sem waitForURL), a carga da máquina domina a variância. No prod build local (E2E_PROD=1, o modo do CI) a família HTTP fecha 4/4 em 3,1 s (1,4/0,9/0,5/0,3). Guard de falhas client permanece exclusivo do browser (aceite). Sem migration/access/Consent/UI/schema. Intenção e2e-full-stack-sem-browser.md; impl e2e-full-stack-sem-browser-impl.md.