diff --git a/docs/CHANGELOG-AGENTS-HISTORY.md b/docs/CHANGELOG-AGENTS-HISTORY.md index 6941bcff..b2be8a80 100644 --- a/docs/CHANGELOG-AGENTS-HISTORY.md +++ b/docs/CHANGELOG-AGENTS-HISTORY.md @@ -5,13 +5,9 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente --- -**OPS90 — skills e docs: codificar a pirâmide de testes unit→int→e2e-com-benefício (2026-08-24):** meta-chore de guias de agente, sem código de produto/schema/CI. A ordem de preferência unit primeiro → int para fronteiras Payload/DB → e2e só com benefício real por fluxo ficou explícita nos donos certos: âncora canônica nova "This repo: the three layers" na skill `test-driven-development` (mapeia a pirâmide às camadas `tests/unit|int|e2e` com fixtures e aponta a política OPS72 por referência); linha das 3 camadas do `codebase-map.mdc` reescrita com a ordem; parágrafo "Level preference (pyramid)" em `docs/TESTING.md`; preferência de nível enunciada no §Executar da `execution-pipeline.md` (compartilhada por `work-issue`/`agent-work-issue`) e como bullet no Passo 4 do `work-issue`; revisão ganha o critério de nível em `code-review-and-quality` (Step 2 + checklist) e `improve-code-quality` (exit checklist); `browser-testing-with-devtools` rotula verificação em browser como caso legítimo de "e2e com benefício real". Política OPS72 intacta byte-a-byte (gate local discricionário, CI `selected`, full só no verify do deploy); sem % de cobertura, sem proibição de e2e, sem guard novo; `ci-cd-and-automation`/`engineering-audit`/`AGENTS*` intocados (sem lacuna real). Débitos: 6 achados de simplify absorvidos no diff; contradição stale do tracker Forgejo já coberta pela Issue #841. - **OPS89 — variantes do provider Vercel AI Gateway movidas do repo para a config global do opencode (2026-08-24):** fecha o ciclo aberto pela OPS78/OPS82: as variantes low/high/max dos dois DeepSeek V4 Flash (`deepseek-v4-flash` e `-0731`) saíram do `opencode.json` do repo e voltam a ser preferência de máquina no global `~/.config/opencode/opencode.jsonc` (aplicação manual pelo dono — nada commitado; auth continua em `~/.local/share/opencode/auth.json`). O repo fica mínimo: só `$schema` + `mcp.penpot` — o mesmo princípio "edit the owner, don't twin" da OPS82, agora para o próprio `provider.vercel` (o anti-goal original da OPS78 de não commitar config de opencode no repo prevalece). Config-only + prosa: `-32` linhas de config; docblock de `OPENCODE_PRESET_MODEL` (`scripts/lib/worktree.mjs`) e prosa de `worktree-next-issue/SKILL.md` passam a apontar para a config global; a constante (model ID) e os pins de `worktree.unit.spec.ts` ficam intactos — o launch de `pnpm worktree next` não muda. No mesmo diff: "Forgejo" → "GitHub" na linha reescrita da skill (rastro stale pós-cutover); a varredura ampla do resíduo virou a OPS91 (#841). Verificação: `pnpm gate:fast` verde (256 arquivos/2443 testes), JSON estrito validado, grep sem ref viva a `provider.vercel` fora do docblock atualizado; aceite final do TUI condicionado ao global aplicado pelo dono (`opencode debug config`, `--variant max`, Ctrl+T). -**OPS88 — verify do CI (PR e deploy): um Postgres com reset determinístico, um build, migrate/seed sem repetição (2026-08-24):** o `checks` do PR e o `verify` do deploy reconstruíam o mesmo estado até 4× por run (dois containers Postgres `postgres-int`/`postgres-build`, dois migrates explícitos, dois seeds, dois builds — cada build re-rodando migrate embutido; o build default `.next` nem era servido por nada). Agora: **um Postgres por run** com reset determinístico entre fases — script novo `pnpm db:reset` (`scripts/db-reset.mjs`: `DROP SCHEMA public CASCADE` → `CREATE SCHEMA public` → `pnpm migrate` → `pnpm db:seed:minimal`, guard fail-closed por construção: só host local E nome `teqo(_)?_test`, sem escape `ALLOW_REMOTE_DB` — um DROP não pode herdar o override remoto dos seeds) — e **um build por run** quando build+e2e rodam juntos (o e2e continua servindo o `.next-e2e`; o build default só roda quando é o único build da run; no `verify` do deploy ele saiu de vez, pois o e2e full sempre roda lá). Contrato do nome `_test` extraído para `TEST_DATABASE_NAME_RE` em `scripts/lib/cli.mjs` (fonte única com `assertTestDatabase.ts`); `scripts/db-reset.mjs` entra no `HIGH_RISK_EXACT` **e** no `BUILD_SURFACE_EXACT` (um PR só no reset arma o próprio step no CI), `scripts/lib/cli.mjs` entra no `HIGH_RISK_EXACT`; o mirror local `gate:ci` ganha o reset antes do build (paridade CI↔local, mesma condição do YAML); `deploy` no homeserver intocado (migrate-before-build OPS66 preservado — o migrate embutido do build vira no-op aceito). Docs canônicos (`TESTING.md`, `AGENT-OPS.md`) atualizados para o setup único. Contabilização honesta: ciclos de estado 4→2, Postgres 2→1, builds 2→1, migrates executados 4→3 (residual = no-op embutido), seeds 2→2. Verificação: guards fail-closed (3 recusas), reset sobre resíduo real (tabela junk somada → baseline 435 municípios + seed minimal de volta), idempotência (re-execução), suite int **full** verde pós-reset (830 tests); `pnpm lint`/`tsc`/`format:check`/`knip`/`check:cycles`/`test:unit` (2445) verdes. - -**OPS88 — verify do CI (PR e deploy): um Postgres com reset determinístico, um build, migrate/seed sem repetição (2026-08-24):** o `checks` do PR e o `verify` do deploy reconstruíam o mesmo estado até 4× por run (dois containers Postgres `postgres-int`/`postgres-build`, dois migrates explícitos, dois seeds, dois builds — cada build re-rodando migrate embutido; o build default `.next` nem era servido por nada). Agora: **um Postgres por run** com reset determinístico entre fases — script novo `pnpm db:reset` (`scripts/db-reset.mjs`: `DROP SCHEMA public CASCADE` → `CREATE SCHEMA public` → `pnpm migrate` → `pnpm db:seed:minimal`, guard fail-closed por construção: só host local E nome `teqo(_)?_test`, sem escape `ALLOW_REMOTE_DB` — um DROP não pode herdar o override remoto dos seeds) — e **um build por run** quando build+e2e rodam juntos (o e2e continua servindo o `.next-e2e`; o build default só roda quando é o único build da run; no `verify` do deploy ele saiu de vez, pois o e2e full sempre roda lá). Contrato do nome `_test` extraído para `TEST_DATABASE_NAME_RE` em `scripts/lib/cli.mjs` (fonte única com `assertTestDatabase.ts`); `scripts/db-reset.mjs` entra no `HIGH_RISK_EXACT` (harness de teste) e o mirror local `gate:ci` ganha o reset antes do build (paridade CI↔local); `deploy` no homeserver intocado (migrate-before-build OPS66 preservado — o migrate embutido do build vira no-op aceito). Contabilização honesta: ciclos de estado 4→2, Postgres 2→1, builds 2→1, migrates executados 4→3 (residual = no-op embutido), seeds 2→2. Verificação: guards fail-closed (3 recusas), reset sobre resíduo real (tabela junk somada → baseline 435 municípios + seed minimal de volta), idempotência (re-execução), suite int **full** verde pós-reset (830 tests); `pnpm lint`/`tsc`/`format:check`/`knip`/`check:cycles`/`test:unit` (2445) verdes. +**OPS90 — skills e docs: codificar a pirâmide de testes unit→int→e2e-com-benefício (2026-08-24):** meta-chore de guias de agente, sem código de produto/schema/CI. A ordem de preferência unit primeiro → int para fronteiras Payload/DB → e2e só com benefício real por fluxo ficou explícita nos donos certos: âncora canônica nova "This repo: the three layers" na skill `test-driven-development` (mapeia a pirâmide às camadas `tests/unit|int|e2e` com fixtures e aponta a política OPS72 por referência); linha das 3 camadas do `codebase-map.mdc` reescrita com a ordem; parágrafo "Level preference (pyramid)" em `docs/TESTING.md`; preferência de nível enunciada no §Executar da `execution-pipeline.md` (compartilhada por `work-issue`/`agent-work-issue`) e como bullet no Passo 4 do `work-issue`; revisão ganha o critério de nível em `code-review-and-quality` (Step 2 + checklist) e `improve-code-quality` (exit checklist); `browser-testing-with-devtools` rotula verificação em browser como caso legítimo de "e2e com benefício real". Política OPS72 intacta byte-a-byte (gate local discricionário, CI `selected`, full só no verify do deploy); sem % de cobertura, sem proibição de e2e, sem guard novo; `ci-cd-and-automation`/`engineering-audit`/`AGENTS*` intocados (sem lacuna real). Débitos: 6 achados de simplify absorvidos no diff; contradição stale do tracker Forgejo já coberta pela Issue #841. **OPS83 — desbloquear deploy: estabilizar os e2e do verify sem reduzir cobertura; AgendaFeed volta a rodar em prod (2026-08-24):** o deploy manual (`deploy.yml`) estava bloqueado pelo job `verify` (run #15: 1 failed + 7 flaky + 2 skipped + 1 did-not-run). Causas estudadas e corrigidas por reescrita de specs (settle/poll/hermeticidade/escopo de locator) — **nenhum** `test.flaky`, nenhuma remoção de cobertura, nenhuma mudança de workers/retries, zero mudança de app/contrato/acesso: (1) kill switch da home — o poll de server-HTML convergia enquanto a seção renderizada ainda mostrava o link do Instagram; passou a pollar o **DOM rendered** escopado a `[data-home-section="contents"]` (`expectSectionCardCount`, usado também no sibling de fallback IG); (2) section-hidden — o revalidate `tag=posts` era engolido por `.catch`; agora o POST é **assertado** e a convergência ganha orçamento explícito (não bump cego); (3) SavedFilters strict-mode — o link 'Municípios' agora é escopado ao container `[data-slot="sidebar"]` (2º match = bottom nav, #669 absorvida); (4) People — gate `S:` + settle do stream antes de asserir rows (testes 15, pós-search e C118); (5) Municípios:642 — poll DOM da liderança específica em vez de `.first()` no stream; (6) Municípios:386 B176 — `settleMunicipalityStream` entre remove-chip e o próximo clique de opção; (7) Newsletter:222 — `toHaveURL(/#novidades/)` sem `$` (o `?e2e=scroll-…` é legítimo); (8) DemandVisibility:62 — `.goto` com cache-buster para a asserção de 404 do peer (a cache RSC servia a demanda acessível após a troca de cookie). **AgendaFeed (Decision B):** os 2 `test.skip(isProdMode)` foram **removidos** — o build e2e agora inlina `NEXT_PUBLIC_SITE_URL=https://feed.e2e.teqo.test` (`.test` TLD, passa o fail-closed `requireProductionDNSOrigin`), o diálogo gera o link canônico e os testes asserem o **path** e buscam via `campaign.baseURL + path`; confirmado que share usa `window.location.origin`, webauthn é desacoplado via request-host e webhooks usam `campaign.baseURL` — nenhum outro e2e depende do origin. Escopo config: `playwright.config.ts` (default do webServer env em prod), `deploy.yml` e `ci-pr.yml` (env do build-for-e2e + do passo de testes). Verificação: specs afetadas verdes em dev mode (2×) e AgendaFeed verde em `E2E_PROD=1`; `pnpm lint`/`tsc`/`format:check`/`knip`/`check:cycles`/`test:unit` (2443) verdes; PR em main com auto-merge.