mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 23:25:18 +00:00
50 lines
11 KiB
Markdown
50 lines
11 KiB
Markdown
# 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](https://github.com/fsolla/teqo/issues/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](https://github.com/fsolla/teqo/issues/73) | 3 | `tests/unit/testMunicipalityAllocatorConventions.unit.spec.ts` (3 regras; mutações = assign/touch/create\*/`payload.update` municipality) | PR [#93](https://github.com/fsolla/teqo/pull/93) (Pass 4) |
|
|
| Sheet compartilhada por lista — chip cells exigem `CampaignListSheetProvider`; invariante dev no overlay | [#52](https://github.com/fsolla/teqo/issues/52) | 3 + 5 | `tests/unit/sharedSheetHostConventions.unit.spec.ts`; `console.error` development-only em `CampaignCellEditOverlay` | PR [#94](https://github.com/fsolla/teqo/pull/94) (Pass 4) |
|
|
| Navegação e2e assentada — goto→goto sem settle falha o build | [#54](https://github.com/fsolla/teqo/issues/54) | 3 | `tests/unit/e2eNavigationConventions.unit.spec.ts` (settle = await expect/waitForURL/click/reload/login/catch) | PR [#95](https://github.com/fsolla/teqo/pull/95) (Pass 4) |
|
|
| Readiness de autenticador virtual antes da cerimônia WebAuthn | [#53](https://github.com/fsolla/teqo/issues/53) | 3 | mesma spec (spec com `WebAuthn.addVirtualAuthenticator` deve chamar `expectCampaignBiometricsReady(`) | PR [#95](https://github.com/fsolla/teqo/pull/95) (Pass 4) |
|
|
| Convenção de navegação e2e (goto = cold load/contrato; in-shell = continuidade) | [#54](https://github.com/fsolla/teqo/issues/54) | 6 (**judgment-only**) | parágrafo em `docs/TESTING.md` | PR [#95](https://github.com/fsolla/teqo/pull/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](https://github.com/fsolla/teqo/pull/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](https://github.com/fsolla/teqo/pull/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](https://github.com/fsolla/teqo/pull/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](https://github.com/fsolla/teqo/pull/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](https://github.com/fsolla/teqo/pull/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 / OPS14 | 3 | `codebaseConventions.unit.spec.ts` (sweep `mapCampaignFormActionError` em `(campaign)` — não filename) |
|
|
| 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` |
|
|
| PR só `docs/plans/` sem `Closes`/`Fixes`/`Resolves` | [#116](https://github.com/fsolla/teqo/issues/116) OPS12 | 4 | `scripts/lib/plansOnlyClosesGuard.mjs` + `scripts/check-plans-only-pr-closes.mjs` + job `plans-only-closes` 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 — Pass 4 fechou as 5 abertas em 2026-07-31; Pass 5 (2026-08-03) colheu **0** `kind:agent-miss` abertas. Novas entram aqui até o próximo audit.)
|
|
|
|
## Pass 5 — guardas adicionadas (não-miss)
|
|
|
|
| Guarda | Origem | Classe | Mecanismo | Status |
|
|
| ------------------------------------------------------------------------------------------ | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
|
| Push de notificação de campanha só após commit da transação; send soft-fail se a row sumiu | P5-P1 | 3 + 5 | `onPayloadTransactionCommit` em `payloadTransaction.ts`; schedule em `createCampaignNotification`; `notificationPushScheduleConventions` unit pin | vivo Pass 5 |
|