mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
docs(audit-pass6): -impl plans P6-1, P6-2, P6-M909, P6-M895
This commit is contained in:
parent
8a1aa20ce9
commit
de70ae7e1e
4 changed files with 206 additions and 0 deletions
49
docs/plans/audit-pass6-bypass-ratchet-impl.md
Normal file
49
docs/plans/audit-pass6-bypass-ratchet-impl.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Impl: Ratchet de bypass endurecido (P6-1)
|
||||
|
||||
Status: aprovado
|
||||
Atualizado em: 2026-08-25
|
||||
Issue: —
|
||||
Intenção: docs/plans/entrega-engenharia-p6.md
|
||||
Appetite restante: herdado (guarda classe 3, spec única — entrega S)
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** Comentário de módulo (header) não zera mais o arquivo — bypass só conta como documentado com comentário per-site; arquivos novos entram pinados na contagem atual; zero mudança de runtime.
|
||||
- **O que NÃO negociar:** nenhuma mudança de comportamento, sem migration, sem dependências novas; o ratchet continua só-diminui (pins = contagem medida hoje, nunca arredondada para baixo).
|
||||
- **O que reavaliar:** a premissa "arquivos novos invisíveis" — medida: a invisibilidade vem do header rule, não do mapa; o walk já cobre todo `src/` e `pinnedUndocumented.get(path) ?? 0` já faz arquivo sem pin com N indocumentados falhar. O bug é o header zerar a contagem.
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
**Opções consideradas:** A | B | C
|
||||
**Recomendação:** A — remover o zero-by-header em `countUndocumented` (mantendo a janela de 10 linhas per-site) e pinar os arquivos recém-visíveis na contagem medida. Delta mínimo que satisfaz (a)/(b)/(c).
|
||||
**Rejeitadas:** B — apertar para "comentário contíguo imediatamente acima": rederrata ~64 arquivos, exige SUBIR pins de ~30 arquivos já pinados, violando o espírito só-diminui. C — migrar o pin map para snapshot JSON commitado: cerimônia nova sem ganho.
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`countUndocumented`** (`tests/unit/codebaseConventions.unit.spec.ts:691-704`): deletar o cálculo de `header` (linha 693) e a condição `!header.includes('bypass')` (linha 701). Documentado ⇔ `context` (10 linhas acima) contém "bypass". Atualizar a prosa do describe.
|
||||
- **`pinnedUndocumented`** (648-689): adicionar pins P6-1 (comentário "P6-1 baseline"), valores = contagem per-site medida na fase 1 (o RED da fase 1 é a medição — colar os números que o RED reportar). Os pins existentes NÃO mudam se per-site == pin atual.
|
||||
- **Migration:** sem migration. **Access/Consent:** nenhuma — guard-only. **UI:** N/A.
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Hardening do contador** — remover o header rule + atualizar a prosa; rodar o spec: `pnpm test:unit -- codebaseConventions` (bare). Esperado: RED nos arquivos recém-visíveis (`N undocumented (pin: 0)`). Negative check opcional: criar `src/utilities/__bypassProbe.ts` com 1 `overrideAccess: true` sem comentário → spec falha → deletar o probe.
|
||||
2. **Pinning** — adicionar os pins medidos na fase 1; spec GREEN.
|
||||
3. **Gates** — `pnpm gate:fast`; push via `pnpm push`.
|
||||
|
||||
## Rabbit holes / Não escopo (engenharia)
|
||||
|
||||
- **Comentários per-site nos piores arquivos** (`personDelete.ts`, `notification/*`, `Consent.ts`, `loadNamesByIds.ts`) — FORA de escopo deste pass; os pins os cobrem e o ratchet bloqueia crescimento.
|
||||
- Apertar a janela para comentário contíguo (Opção B); re-justificar bypasses; mexer no `localApiOverrideAccessConventions.unit.spec.ts`.
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- Contagem medida pelo RED da fase 1 (não estimativa); nenhum pin abaixo do medido — fase 2 confere GREEN.
|
||||
- O probe negativo é temporário e deletado na mesma fase.
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [x] Aceite de produto da intenção ainda coberto (guard hardening, runtime intocado)
|
||||
- [x] Invariantes AGENTS/engineering-standards (sem migration, sem deps, sem twin)
|
||||
- [x] Testes de domínio: a spec É o teste — RED sem hardening (fase 1), GREEN com (fase 2)
|
||||
|
||||
Self-score decision-quality: 5/5
|
||||
54
docs/plans/audit-pass6-m895-plan-data-literals-impl.md
Normal file
54
docs/plans/audit-pass6-m895-plan-data-literals-impl.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Impl: Guardrail P6-M895 — plano de intenção registra os dados literais da decisão
|
||||
|
||||
Status: aprovado
|
||||
Atualizado em: 2026-08-25
|
||||
Issue: #895
|
||||
Intenção: docs/plans/entrega-engenharia-p6.md
|
||||
Appetite restante: herdado (~0,5 dia eng, docs-only)
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** todo plano de intenção que registra uma decisão de DADOS grava os valores literais (IDs, nomes de modelo, envs, tabelas de threshold) — nunca só narrativa. O GATE de planos ganha um prompt que cobra isso.
|
||||
- **O que NÃO negociar:** classe **6 declarada judgment-only** — sem detector determinístico; nada de código/teste; não fingir que doc é guarda.
|
||||
- **O que reavaliar:** pontos de aterrissagem exatos no skill (template vs SKILL.md).
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
**Opções:** A (só template) | B (só checklist do gate) | C (ambos)
|
||||
**Recomendação: C.** O miss tem dois lados: o escritor omitiu os IDs E o gate aprovou sem eles.
|
||||
**Rejeitadas:** A (gate cego — repete a falha onde ela escapou); B (escritores sem instrução não produzem o dado).
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`.agents/skills/plan-issue/intention-template.md`**: novo bloco **"Dados da decisão (literais)"** — tabela/lista verbatim de valores a aplicar (flag→ID, lista de modelos, strings exatas, envs). Presente SEMPRE que a intenção fixa valores de dados; "N/A" explícito quando não houver.
|
||||
- **`.agents/skills/plan-issue/SKILL.md`**: Checklist e Passo 4 (GATE) ganham o prompt "decisão de dados → valores literais presentes no plano?".
|
||||
- **`docs/GUARDRAILS.md`**: linha na tabela Ativos — origem `#895`, classe `6 (judgment-only declarada)`, mecanismo `bloco "Dados da decisão (literais)" + prompt no gate`.
|
||||
- **`docs/changelog/2026-08-25-audit-pass6-m895.md`**: entrada append-only.
|
||||
- **Migration / Access / UI:** sem migration, sem access, sem UI.
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Template** — bloco + exemplo concreto do próprio miss (OPS95: tabela flag→ID do mapa).
|
||||
2. **Gate** — prompt no Checklist/Passo 4 do SKILL.md.
|
||||
3. **Ledger + changelog** — linha em GUARDRAILS.md; changelog append-only.
|
||||
4. **Gates** — `pnpm gate:fast` + docs-guards; push via `pnpm push`.
|
||||
|
||||
## Rabbit holes / Não escopo
|
||||
|
||||
- Não inventar detector de "prosa sem dados" (infalsificável; viola classe 6).
|
||||
- Não varrer `docs/plans/` retroativamente; não estender aos planos `-impl`; não reestruturar GUARDRAILS.md além da linha nova.
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- Convenção vira "bloco de cortesia": o prompt fica no GATE humano (Passo 4), não em automação; exemplo do miss nomeado.
|
||||
- Docs-only: changelog append-only em arquivo novo; nunca editar HISTORY/agregado.
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [x] `intention-template.md` com o bloco + exemplo #895 + regra N/A explícita
|
||||
- [x] SKILL.md gate cobra os literais
|
||||
- [x] GUARDRAILS.md linha classe 6 declarada, origem #895
|
||||
- [x] Changelog append-only; `pnpm gate:fast` verde
|
||||
- [x] Zero código/teste/migration — delta de comportamento nulo
|
||||
|
||||
Self-score decision-quality: 5.0 ≥ 4
|
||||
51
docs/plans/audit-pass6-m909-disarm-impl.md
Normal file
51
docs/plans/audit-pass6-m909-disarm-impl.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Impl: Guardrail P6-M909 — desarme determinístico do auto-merge da /testing-audit
|
||||
|
||||
Status: aprovado
|
||||
Atualizado em: 2026-08-25
|
||||
Issue: #909
|
||||
Intenção: docs/plans/entrega-engenharia-p6.md
|
||||
Appetite restante: 0,5 d
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** o desarme do auto-merge deixa de depender do agente lembrar a ordem — `scripts/testing-audit-disarm.mjs` chamado no passo que cria o PR (cria → desarma → verifica `null`, atômico) + fiação na skill /testing-audit.
|
||||
- **O que NÃO negociar:** o safety-net (`agent-pr-ready-automerge.yml` → `github-pr-automerge.mjs`) é intocável. PR ready (nunca draft) segue contrato. Guarda classe 3.
|
||||
- **O que reavaliar:** a Fase 5 atual da skill usa `gh pr merge --disable-auto`/`gh pr view` — scripts do repo falam REST/GraphQL com `GITHUB_TOKEN` (`github-api.mjs`, `issue.mjs`).
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
**Opções:** A (só `--pr N` desarmar) | B (fallback draft manual) | C (criar+desarmar+verificar + `--draft-on-failure`)
|
||||
**Recomendação:** C — script faz criar+desarmar (`--head/--title/--body-file`) ou desarmar PR existente (`--pr N`, para rearms pós-`synchronize`); falha de verificação converte a draft via GraphQL e sai 1. O fallback também não pode depender do agente.
|
||||
**Rejeitadas:** A (dois comandos ≠ atômico); B (a mesma ordem humana que falhou).
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`scripts/lib/github-api.mjs`** (editar o dono): `getPullRequestAutoMergeStatus(number)` GraphQL (`autoMergeRequest`, `isDraft`, `mergeable`, `mergeStateStatus`) + `convertPullRequestToDraft(nodeId)` (mutation `convertPullRequestToDraft`). Reusa: `createPullRequest`, `ensureAutoMergeDisabled` (laço desarme→re-poll), `getPullRequest`, `dieWithLabel`.
|
||||
- **`scripts/testing-audit-disarm.mjs`** (novo, plain Node): `GITHUB_TOKEN=<PAT> node … --head <b> --title <t> --body-file <r> [--draft-on-failure]` cria ready → desarma → verifica; `--pr <N>` para rearms. Pre-check de `GITHUB_TOKEN` → `dieWithLabel` exit 1 ANTES de qualquer chamada (nada armado = fail-closed por construção). Exit 0 só com `autoMergeRequest === null && !isDraft`; imprime o JSON de status para o relatório.
|
||||
- **Convention pin:** spec de convenção existente exige que a SKILL.md Fase 5 referencie o script (mecanismo classe 3). Entrada na config knip se marcado morto (família P6-G: specs não contam como usage).
|
||||
- **Migration:** sem migration. **Access/Consent:** N/A.
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Dono** — helpers GraphQL em `github-api.mjs` + pins em `tests/unit/githubApi.unit.spec.ts` (status lido; draft; idempotência via read-first). `pnpm gate:fast`.
|
||||
2. **Script + pin de convenção** — `testing-audit-disarm.mjs` (parseArgs no shape de `github-pr.mjs`; importa `dieWithLabel`).
|
||||
3. **Fiação + registro** — reescrever Fase 5 da skill (1 invocação no passo que cria o PR; `--pr N` após cada push; fallback = draft automático + registro no relatório); changelog `docs/changelog/2026-08-25-audit-pass6-m909.md`; linha em `docs/GUARDRAILS.md` Ativos (origem #909, classe 3). `pnpm gate:fast`; push via `pnpm push`.
|
||||
|
||||
## Rabbit holes / Não escopo
|
||||
|
||||
- NÃO tocar `agent-pr-ready-automerge.yml`/`github-pr-automerge.mjs`.
|
||||
- NÃO deletar `github-pr.mjs` (é P6-G, outra entrega).
|
||||
- NÃO migrar o `gh run rerun` da Fase 4; NÃO re-fiar a react-audit.
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- Mutation de desarme em PR não armado → `ensureAutoMergeDisabled` só muta quando armado (idempotente).
|
||||
- Token ausente → die antes de criar. Falha pós-criação → `--draft-on-failure` converte a draft (veto estrutural do safety-net → nunca mergeia).
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [x] Aceite da intenção coberto (desarme atômico no passo de criação)
|
||||
- [x] Invariantes (edita o dono `github-api.mjs`, não cria twin)
|
||||
- [x] Testes: pins `githubApi.unit.spec.ts` + pin de convenção da fiação na skill
|
||||
|
||||
Self-score decision-quality: 5/5
|
||||
52
docs/plans/audit-pass6-perfil-page-gate-impl.md
Normal file
52
docs/plans/audit-pass6-perfil-page-gate-impl.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Impl: P6-2 — page-gate dodge on /campanha/perfil
|
||||
|
||||
Status: aprovado
|
||||
Atualizado em: 2026-08-25
|
||||
Intenção: docs/plans/entrega-engenharia-p6.md
|
||||
Appetite restante: 0.5 dia
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** `perfil/page.tsx` passa a obter o ator pelo `requireCampaignPageActor` (P3-I), e o guard de convenção deixa de ser dodge-ável por variante de nome de `getCampaignUser*`.
|
||||
- **O que NÃO negociar:** sem migration, sem mudança de URL (`/campanha/perfil`), guard classe 3, líder "as good or better" (nunca tela em branco).
|
||||
- **O que reavaliar:** gate `noLeader` em /perfil quebraria reset de senha e self-service do líder (`redefinir-senha/page.tsx:31`, `esqueci-senha/page.tsx:20`, `actions/password.ts:137` redirecionam para `/campanha/perfil`) — **sem gate** (precedente `meus-contatos/page.tsx:16`).
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
**Opções consideradas:** A | B | C
|
||||
**Recomendação:** **C** — `requireCampaignPageActor` ganha opção `withAvatar?: boolean`; a página chama só o helper e o guard alarga o regex sem allowlist.
|
||||
**Rejeitadas:** A (mantém a chamada variante na página — exige allowlist + 1 leitura extra por request); B (manter só `getCampaignUserWithAvatar` + redirect hand-rolled — perpetua a divergência P3-I).
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`requireCampaignPageActor`** (`src/utilities/campaignPageActor.ts`): opção `withAvatar?: boolean` — `const getter = options.withAvatar ? getCampaignUserWithAvatar : getCampaignUser`. Ambos retornam `AuthenticatedCampaignUser | null`; avatar só populado em runtime. Comentário justificando (shell de perfil renderiza `avatarUrl`; avatar depth-0 vira número ID). Atualizar doc-block das gates.
|
||||
- **`perfil/page.tsx`**: `requireCampaignPageActor({ withAvatar: true })`; remove `redirect` manual, check `if (!user)` e import de `getCampaignUserWithAvatar`. VERIFICAR antes: nenhum outro `page.tsx` de `(app)` casa o regex alargado (`grep -rn "getCampaignUser[A-Za-z0-9]*(" src/app/\(campaign\)/campanha/\(app\) --include="page.tsx"`).
|
||||
- **Guard** (`tests/unit/codebaseConventions.unit.spec.ts:528-548`): regex → `/getCampaignUser[A-Za-z0-9]*\(/` + prosa atualizada; `allowlist` continua vazia.
|
||||
- **Testes:** caso unit novo no spec de gate de página/ator (`withAvatar: true` usa o getter de avatar e redireciona quando null).
|
||||
- **Migration:** sem migration. **Access/Consent:** sem mudança.
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Helper + página** — `withAvatar` + troca na página + caso unit.
|
||||
2. **Guard** — alargar regex; `pnpm vitest run tests/unit/codebaseConventions.unit.spec.ts` bare.
|
||||
3. **Gates** — `pnpm gate:fast`; push via `pnpm push`.
|
||||
|
||||
## Rabbit holes / Não escopo
|
||||
|
||||
- Migrar o layout para `requireCampaignPageActor` (layout não é route page; fora do finding).
|
||||
- Gate `noLeader` em /perfil (decisão de produto, não engenharia).
|
||||
- Derivar `getCampaignUserWithAvatar` de `getCampaignUser` via `depth` opcional (refactor além do finding).
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- Dois getters, mesmo tipo de retorno — `tsc --noEmit` valida.
|
||||
- Guard alargado pegando página futura legítima: fail-closed é desejado; saída = allowlist com razão.
|
||||
- Regressão de avatar: `withAvatar: true` preserva o comportamento atual.
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [x] Aceite de produto coberto (perfil alcançável por todos os roles autenticados)
|
||||
- [x] Invariantes AGENTS/engineering-standards (sem migration, URL intacta, prologue único)
|
||||
- [x] Testes previstos: caso unit `withAvatar` + spec de convenção verde
|
||||
|
||||
Self-score decision-quality: 5/5
|
||||
Loading…
Reference in a new issue