Autonomous engineering-audit 2026-07-31 (precheck: gh-doctor OK, pool desligado). Delta anchor Pass 3 (880 files in 3 days). Baseline green (tsc/lint/knip/cycles; 774 files madge). - IMPROVE-CODE-QUALITY-PLAN: Pass 4 section — 1 P0 (globals Boolean(user) -> PR #91), 1 P1 (seed-posts dieWithLabel -> PR #92), 5 misses -> 5 guardrails (PRs #93-#95, #83 verified+closed), decisions D1-D6. - TECH-DEBT: rows 33/34 verified fixed and closed (P3-A/P3-B); 17/19/23/ 35/40/45 updated with measured counts and trigger status; 15 new rows with evidence (homeSearch twins, notification write path, wizard drawers, B14-class labels import, bypass-header dodge, dev-mode chip failure with instrumentation, god modules, fixture honesty...). - docs/plans/entrega-engenharia-p4.md: waves P4-A..P4-L, guard map (9 new guards, 2 hardened, judgment-only residue declared), 12 defer+trigger, 6 rejected look-alikes, execution rules. - docs/GUARDRAILS.md (new, OPS2 scope): one row per guardrail — origin, determinism class 1-6, mechanism, status; active, precedents, queue. - CHANGELOG-AGENTS: one delivery entry per convention. Aikido not run (MCP unavailable in this Cloud env — ledger row noted). Closes #43
9.3 KiB
9.3 KiB
Guardrails
Ledger dos guardrails determinísticos colhidos de kind:agent-miss (fluxo pnpm agent:file-miss → harvest no engineering-audit → guarda programática) e dos endurecimentos de guarda existentes. Uma linha por guarda: origem, classe na escada de determinismo, mecanismo, status.
Classes (escada do Pass 3 D6 / skill engineering-audit passo 4b): 1 tipo (estado ruim irrepresentável) · 2 ESLint · 3 spec de convenção · 4 análise estática em CI (knip/madge) · 5 pin comportamental · 6 doc/convenção (judgment-only declarado — não fingir que doc é guarda).
Ativos
| Guarda | Origem | Classe | Mecanismo | Status |
|---|---|---|---|---|
agent:ship exige stamp de /simplify casado com HEAD; PR Ready + auto-merge + watch até MERGED |
#83 | 3 (script + hooks) | scripts/agent-ship.mjs, .cursor/hooks/guard-pr-create.mjs (bloqueia gh pr create manual), .cursor/hooks/pr-merge-watchdog.mjs (re-engata com PR aberto) |
vivo desde 2026-07-31 (PR #89); miss fechada no Pass 4 |
Alocador de municípios em specs — sem slug fixo + mutação; sem municipio=<slug> em e2e; regex de nome de catálogo ancorada |
#73 | 3 | tests/unit/testMunicipalityAllocatorConventions.unit.spec.ts (3 regras; mutações = assign/touch/create*/payload.update municipality) |
PR #93 (Pass 4) |
Sheet compartilhada por lista — chip cells exigem CampaignListSheetProvider; invariante dev no overlay |
#52 | 3 + 5 | tests/unit/sharedSheetHostConventions.unit.spec.ts; console.error development-only em CampaignCellEditOverlay |
PR #94 (Pass 4) |
| Navegação e2e assentada — goto→goto sem settle falha o build | #54 | 3 | tests/unit/e2eNavigationConventions.unit.spec.ts (settle = await expect/waitForURL/click/reload/login/catch) |
PR #95 (Pass 4) |
| Readiness de autenticador virtual antes da cerimônia WebAuthn | #53 | 3 | mesma spec (spec com WebAuthn.addVirtualAuthenticator deve chamar expectCampaignBiometricsReady() |
PR #95 (Pass 4) |
| Convenção de navegação e2e (goto = cold load/contrato; in-shell = continuidade) | #54 | 6 (judgment-only) | parágrafo em docs/TESTING.md |
PR #95 (Pass 4) |
| Update de globals públicos nunca "qualquer autenticado" | P0 do Pass 4 (sem issue) | 3 | tests/unit/globalAccessConventions.unit.spec.ts ban Boolean(user) em src/globals |
PR #91 (Pass 4) |
| Loaders de notificação tipados pelo ator (recipientID arbitrário irrepresentável) | P0 adjacente do Pass 4 | 1 | assinatura (payload, user: CampaignUser) + overrideAccess: false sob canReadOwnNotifications |
PR #91 (Pass 4) |
Die-helpers da CLI importados onde usados; DAY_MS single-source |
P1 do Pass 4 (sem issue) | 3 | tests/unit/scriptCliConventions.unit.spec.ts |
PR #92 (Pass 4) |
src/lib não type-importa @/utilities/** (direção única também para tipos) |
dodge do Pass 3 (suggestionCatalog) | 2 | ESLint no-restricted-imports allowTypeImports: false na zona src/lib |
PR #92 (Pass 4) |
Local API com user sempre declara overrideAccess; import dinâmico de módulos server banido em utilities |
guarda ausente (medida baseline 59/0) | 3 | tests/unit/localApiOverrideAccessConventions.unit.spec.ts |
PR #92 (Pass 4) |
Precedentes vivos (anteriores ao primeiro harvest)
| Guarda | Origem | Classe | Mecanismo |
|---|---|---|---|
| Vocabulário banido (Praça/Núcleo/Plano de Ação, accent-tolerant) | C13 / W4f / P3-K | 3 | codebaseConventions.unit.spec.ts |
server-only em utilities acopladas (sweep payload/next/*) |
Pass 2 W2 / P3-K | 3 | codebaseConventions.unit.spec.ts |
Escadas de formActions nos wrappers (runCampaignFormAction/Redirect) |
W4d / C8 F4b | 3 | codebaseConventions.unit.spec.ts (filename *FormActions.ts — dodge actions/*.ts ledgerado) |
| Ratchet de bypass admin não documentado | P3-E | 3 | codebaseConventions.unit.spec.ts (por arquivo, só diminui) |
| Mensagens de recusa como constantes + correspondência throw↔safelist | P3-A | 3 | codebaseConventions.unit.spec.ts:216-263 |
as never banido |
Pass 1 | 2 | ESLint no-restricted-syntax |
src/lib não importa utilities/ (valores) |
Pass 2 W2 | 2 | ESLint no-restricted-imports |
| 0 ciclos de import | Pass 2 | 4 | madge (pnpm check:cycles) |
| Dead code (arquivos/deps/exports em erro) | Pass 2 W4b | 4 | knip em CI |
migration-lock (≤1 PR aberto tocando schema) |
agentes paralelos | 4 | job em ci-pr.yml |
| Seed mínimo obrigatório com migration (contrato manifest) | OPS fluxo PR | 3 + 5 | tests/unit/seedMinimalManifest.unit.spec.ts + job CI migrate→seed→int |
| Regex de template ancorada em e2e | P3-C | 3 | codebaseConventions.unit.spec.ts (ampliada para literais no Pass 4) |
| Consent fail-closed por chave estável | D3/Onda 0 | 5 | pins int submitWhatsapp/liderança/apoiador |
Misses colhidas aguardando guarda (fila do harvest)
(nenhuma — todas as 5 abertas em 2026-07-31 foram classificadas: 4 com guarda shippada + 1 com guarda já viva. Novas kind:agent-miss entram aqui até o próximo audit.)