Skip to content

fix(régua): prova de mordida que não morde passa a REPROVAR - #416

Merged
rubenmarcus merged 1 commit into
mainfrom
fix/mutacao-cega-reprova
Aug 22, 2026
Merged

fix(régua): prova de mordida que não morde passa a REPROVAR#416
rubenmarcus merged 1 commit into
mainfrom
fix/mutacao-cega-reprova

Conversation

@rubenmarcus

Copy link
Copy Markdown
Member

Summary

  • cinco réguas anunciavam "portão cego" e saíam com zero;
  • as cinco passam a usar o padrão que o telemetry-check já tinha: o caso entra na lista de falhas;
  • régua nova MC1 varre tools/eval/ e impede a volta.

Evidência

A casa tem uma lei — régua que não morde não existe — e quem demonstra a mordida é o modo --mutante=. Só que cinco réguas faziam isto:

if (MUT && !falhas.length)
  console.log(`✗ MUTAÇÃO '${MUT}' não acendeu nenhuma cláusula — portão cego (lei 3)`);
process.exit(falhas.length ? 1 : 0);

Com a lista de falhas vazia — que é exatamente o caso do portão cego — o processo sai com zero. Quem roda a mutação num laço e confere o código de saída, que é o jeito óbvio de automatizar a lei, vê verde justo na hora em que a régua se mostrou cega.

A prova da mordida tinha o mesmo defeito que ela existe para caçar.

Atingidas: armas-check, docs-autoria-check, entrada-check, preload-check, replaycam-check. O telemetry-check já fazia certo (falhas.push('mutacao-cega')) e serviu de padrão — não inventei um sexto jeito de fazer a mesma coisa.

A MC1 aceita as duas formas que a casa usa (empurrar nas falhas ou levar uma flag até o exit) e recusa só a terceira, que é imprimir o aviso e sair pelo falhas.length. Sete réguas auditadas; o mutante exit-cego remove o falhas.push de uma delas e reprova.

Issue

Achado enquanto eu resolvia conflito nos PRs #400/#375/#372/#399. O defeito irmão — eval:docsautoria reprovando branch de PR com autor novo — está no #415, da outra sessão; este PR não encosta nele.

Risk

  • low - docs/tooling/text only
  • medium - UI/site/runtime path touched
  • high - gameplay/render/backend/anti-cheat touched

Só o código de saída de cinco réguas. Nenhuma cláusula de julgamento mudou.

Validation

  • npm run check:deploy - 31/31
  • eval:mutcega verde e o mutante exit-cego reprovando
  • sintaxe das cinco réguas conferida

Limite declarado

Não mexe nas cláusulas das réguas, só em como elas terminam. E não trata do eval:docsautoria — é o #415.

Bot notes

  • ok to label safe-automerge
  • needs needs-staging
  • needs needs-human-gameplay
  • needs needs-human-backend

🤖 Generated with Claude Code

A casa tem uma lei - régua que não morde não existe - e quem demonstra a mordida é
o modo `--mutante=`. Cinco réguas imprimiam

    ✗ MUTAÇÃO 'x' não acendeu nenhuma cláusula — portão cego (lei 3)

e logo abaixo chamavam `process.exit(falhas.length ? 1 : 0)`. Com a lista de
falhas VAZIA - que é exatamente o caso do portão cego - o processo saía com ZERO.
Quem roda a mutação num laço e confere o código de saída, que é o jeito óbvio de
automatizar a lei, via verde justo na hora em que a régua se mostrou cega.

A prova da mordida tinha o mesmo defeito que ela existe para caçar.

As cinco passam a seguir o padrão que o telemetry-check já usava: o portão cego
entra na lista de falhas. Não inventei um sexto jeito de fazer a mesma coisa.

A MC1 varre `tools/eval/` e aceita as duas formas que a casa usa - empurrar nas
falhas ou levar uma flag até o exit -, recusando só a terceira, que é imprimir o
aviso e sair pelo `falhas.length`. Sete réguas auditadas. O mutante `exit-cego`
remove o `falhas.push` de uma delas e reprova.

Achado enquanto eu resolvia conflito nos PRs; o defeito irmão do
`eval:docsautoria` está no #415, da outra sessão.

Agent: Claude Opus 5 (Claude Code)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
csbrasil Ready Ready Preview Aug 22, 2026 12:44am

Request Review

@csbrasil-BOT csbrasil-BOT added the target:main PR apontando para a branch main label Aug 22, 2026
@csbrasil-BOT

Copy link
Copy Markdown
Collaborator

csbrasil-bot classification

Note

@rubenmarcus abriu 14 arquivo(s) · +96 −21, base main.

O que mudou

área arquivos + amostra
📚 docs 7 +13 −13 ARCH.generated.md, README.md, STATUS.md
🧪 arnês 6 +79 −5 armas-check.mjs, docs-autoria-check.mjs, entrada-check.mjs
📦 outros 1 +4 −3 package.json

Labels

label por quê
target:main vai direto pra main, sem fila de integração

Ações do bot

@rubenmarcus
rubenmarcus merged commit c1ca5b8 into main Aug 22, 2026
20 checks passed
rubenmarcus added a commit that referenced this pull request Aug 22, 2026
Dos 13 arquivos em conflito, 12 eram gerados e vieram da main, re-derivados
depois. O único de verdade era o package.json, resolvido por união: `eval:mutcega`
que a main ganhou no #416 mais `eval:animsdesvio` deste PR.

E o #416, que acabou de entrar, mordeu este PR na porta: o `anims-desvio-check.mjs`
nasceu com o mesmo defeito das outras cinco réguas - anunciava "portão cego" e
saía por `falhas.length`, que ali é zero por definição, então a prova de que a
régua morde sairia VERDE justo quando ela não mordesse. Aplicado o padrão da casa:
o caso entra na lista de falhas.

Nenhum arquivo de animação, de código ou de asset foi tocado.

Agent: Claude Opus 5 (Claude Code)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
rubenmarcus added a commit that referenced this pull request Aug 22, 2026
Dos 10 arquivos em conflito, 9 eram gerados e vieram da main, re-derivados
depois. O package.json não trazia régua nova deste PR, então ficou o da main.

O #416 mordeu na porta, como no #413: o `vram-check.mjs` nasceu com o mesmo
defeito - anunciava "portão cego" e saía por `falhas.length`, que ali é zero por
definição. Aplicado o padrão da casa: o caso entra na lista de falhas.

Nenhum arquivo de textura ou de código foi tocado.

Agent: Claude Opus 5 (Claude Code)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
rubenmarcus added a commit that referenced this pull request Aug 22, 2026
… definir

Dos 8 arquivos em conflito, 7 eram gerados. O único de verdade era o
package.json - e ele quase me pegou: resolvendo pela linha do `check:`, fiquei com
a lista de um lado e PERDI as DEFINIÇÕES do outro. `eval:wfsecret`,
`eval:deploygate` e `eval:autofix` viraram nome órfão de uma vez. Um nome órfão
mata o npm em "missing script" e TODOS os passos depois dele param de rodar - o
portão pararia no meio sem ninguém perceber.

Foi o segundo caso do dia: o #372 citava `eval:gelo` no `check:fast` sem nunca ter
definido o script, com a régua existindo em disco e desligada. Conflito de
`package.json` é o mais comum que existe aqui, porque todo PR que acrescenta régua
mexe na mesma linha - então isto vai se repetir.

Daí a PI: todo passo citado nos dois portões tem de estar definido (PI1) e toda
régua tem de apontar para arquivo que existe (PI2). 97 citações conferidas. Os
dois mutantes mordem, e ela reprova o #372 de verdade, não só o caso sintético.

As três réguas desta pilha também receberam o padrão do #416, que entrou na main
depois delas: prova que não morde é vermelho, não aviso.

Agent: Claude Opus 5 (Claude Code)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Commit-grande: merge da main na pilha de CI — 21 dos 24 arquivos são bloco gerado re-derivado
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
rubenmarcus added a commit that referenced this pull request Aug 22, 2026
… pode ter (#408)

* fix(ci): classify não reprova PR de fork por secret que o gatilho não pode ter

MEDIDO nos últimos 29 PRs: `classify` vermelho em 11 dos 14 vindos de FORK e em 0
dos 15 de casa. A causa não era o código de ninguém. Num PR de fork, os gatilhos
`pull_request_review` e `pull_request_review_comment` rodam SEM os secrets do
repositório - regra do GitHub - e o guard de identidade saía com erro.

A prova é o mesmo PR, o mesmo commit, dois runs: `pull_request_target` fecha em
22s com sucesso e aplica o rótulo; `pull_request_review` morre em 4s com
`GH_TOKEN` vazio. O rótulo estava certo o tempo todo; o vermelho que o
colaborador via era de um run que nunca teve chance.

Mesma regra que o #402 deu ao portão de autoria em clone raso: portão que não
pode medir não vota. O job ganha um `if:` que o restringe aos gatilhos que
enxergam secret. Para não perder o motivo pelo qual os gatilhos de review
existem - reclassificar DEPOIS que o CodeRabbit comenta, o defeito da #240 - entra
um sweep de meia em meia hora que roda no contexto base e reclassifica os PRs
abertos por `workflow_dispatch`, caminho que tem token. O classify já dedupe
rótulo e comentário, então repetir não polui o PR.

A régua nova (WSEC1) varre os 14 workflows e reprova a combinação que causou
isto: guard de secret junto de gatilho cego, sem `if:` que exclua o caso de fork.
Os dois mutantes mordem - tirar o `if:` do classify e pôr um gatilho cego no
preview-bot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Agent: Claude Code

* fix(ci): quem bloqueia o PR é o build do CI, não a Vercel (#409)

* fix(ci): quem bloqueia o PR é o build do CI, não a Vercel

MEDIDO nos últimos 29 PRs: a Vercel reprovou 13 dos 14 PRs vindos de fork, sempre
com `Authorization required to deploy.` - proteção de fork da própria Vercel, que
nenhum commit do colaborador resolve. Nos PRs de casa o vermelho era build de
verdade, uma vez porque o `fetch-decals.sh` não baixou o acervo (196 de 197
decalques faltando) num soluço de rede.

O `ci.yml` já constrói o site em `pull_request`: o portão que importa existe e é
esse. A régua nova guarda as três condições que deixam a Vercel sair do caminho
crítico sem perder cobertura:

  DG1 o CI constrói no PR - sem isso, tirar a Vercel do bloqueio deixaria o PR sem
      nenhuma prova de que o site compila;
  DG2 nenhum `curl` do caminho do build corre sem `--retry`. `set -e` mais curl sem
      retry transforma soluço de rede em PR vermelho, e o autor não tem o que
      consertar - mesmo dano do portão que não pode medir;
  DG3 a etiqueta que autoriza o preview de fork é criada por quem depende dela.

A DG3 achou código morto: o job `preview` do preview-bot já sabe publicar pela CLI
da Vercel depois de conferir permissão do ator e SHA aprovado, mas dispara em
`labeled` com `preview-autorizado` - e essa etiqueta NUNCA existiu no repositório.
O bot pedia um rótulo que ninguém tinha como aplicar. Agora o próprio workflow a
cria.

Os dois ajustes que sobram são de painel da Vercel e não cabem no repositório;
ficaram escritos no PROD-READINESS.md, com o que medir.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Agent: Claude Code

* feat(ci): autofix conserta o mecânico, com lista de permissão e sem mergear (#411)

* feat(ci): autofix conserta o mecânico, com lista de permissão e sem mergear

MEDIDO nos últimos 29 PRs: nenhum bot deste repositório jamais commitou um
conserto. Quem conserta é sempre uma pessoa. O #405 está vermelho por
`DOCS1: documentação DESATUALIZADA`, cujo conserto é `npm run docs` mais um
commit - trabalho sem julgamento nenhum que hoje devolve o PR para o autor.

O autofix roda em `pull_request_target`, o único gatilho que enxerga secret em PR
de fork (é a mesma regra que a WSEC1 passou a guardar), regenera os blocos
derivados e empurra o commit.

A TRAVA é o que torna isso aceitável: `autofix_allowlist.py` só libera arquivo
GERADO, e o commit sai da saída dela - nunca de um `git add -A`. Encostou em
qualquer outro caminho, o bot aborta e comenta. Sem a lista, o primeiro conserto
errado reescreve o mapa de um colaborador e ninguém repara; com ela, o pior caso
é regenerar uma doc que já era derivada.

`.github/` está entre os PROIBIDOS de propósito: um bot que edita o workflow que
o governa amplia a própria permissão num commit. E as ferramentas que rodam são
restauradas da BASE antes de executar - PR nenhum reescreve o gerador e faz o bot
executar o que ele mandar.

Duas saídas sem push, porque vermelho que o autor não entende é o dano que este
trabalho inteiro está atacando: fork com "allow edits by maintainers" desligado
recebe o comando por comentário, e sem `CSBRASIL_BOT_TOKEN` o job avisa e sai
verde em vez de reprovar.

A régua AF1/AF2/AF3 guarda as três condições - escrita só depois da trava, lista
sem caminho de código, e o bot NÃO mergeia (deixar pronto e fechar são coisas
diferentes). Os quatro mutantes mordem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Agent: Claude Code

* fix(ci): bot marca `pronto-pra-merge` em vez de mergear sozinho (#412)

A intenção declarada dos bots é autocorreção e autorrevisão para deixar o PR
PRONTO - não fechar o assunto. Só que o `csbrasil-bot-automerge` chamava
`gh pr merge --squash --delete-branch --auto`, e era a ÚNICA coisa que um bot
deste repositório fazia sozinho: justamente a que não devia.

O passo agora aplica a etiqueta `pronto-pra-merge` e comenta por que o PR está
pronto. Quando o PR deixa de ser elegível, a etiqueta sai - senão ela vira um
carimbo velho que ninguém confere. O botão de merge continua humano.

A AF4 estende a régua do autofix para o repositório inteiro: nenhum workflow
pode chamar `gh pr merge`. Ela ignora linha de comentário de propósito, para que
o comentário que explica por que a chamada saiu possa citá-la. O mutante
`automerge-volta` recoloca a chamada e reprova.

Fora do alcance deste repositório: o Esbirro, que repetiu o mesmo alerta de
`bundle-em-dia` a cada 30 minutos por 17 horas na issue #393 sem nunca agir, vive
em `game3/bots/vigia-prod/plantao.mjs`. Dar ação a ele é trabalho de lá.



Agent: Claude Code

Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

---------

Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

---------

Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* Merge da main (alpha.175) na pilha de CI, e liga o que ela citava sem definir

Dos 8 arquivos em conflito, 7 eram gerados. O único de verdade era o
package.json - e ele quase me pegou: resolvendo pela linha do `check:`, fiquei com
a lista de um lado e PERDI as DEFINIÇÕES do outro. `eval:wfsecret`,
`eval:deploygate` e `eval:autofix` viraram nome órfão de uma vez. Um nome órfão
mata o npm em "missing script" e TODOS os passos depois dele param de rodar - o
portão pararia no meio sem ninguém perceber.

Foi o segundo caso do dia: o #372 citava `eval:gelo` no `check:fast` sem nunca ter
definido o script, com a régua existindo em disco e desligada. Conflito de
`package.json` é o mais comum que existe aqui, porque todo PR que acrescenta régua
mexe na mesma linha - então isto vai se repetir.

Daí a PI: todo passo citado nos dois portões tem de estar definido (PI1) e toda
régua tem de apontar para arquivo que existe (PI2). 97 citações conferidas. Os
dois mutantes mordem, e ela reprova o #372 de verdade, não só o caso sintético.

As três réguas desta pilha também receberam o padrão do #416, que entrou na main
depois delas: prova que não morde é vermelho, não aviso.

Agent: Claude Opus 5 (Claude Code)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Commit-grande: merge da main na pilha de CI — 21 dos 24 arquivos são bloco gerado re-derivado
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>

---------

Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
rubenmarcus added a commit that referenced this pull request Aug 22, 2026
…pilha

DUAS COISAS, e a primeira é um resgate.

1. A fase 5 (#414, resolução automática de conflito de arquivo gerado) ficou
   ÓRFÃ. Ela mergeou em `fix/deixar-pronto-nao-e-mergear`, mas essa branch já
   tinha subido para a de cima antes — então o conteúdo mergeou para lugar
   nenhum. Conferido: a pilha do #408 não tinha `--caminhos` no autofix.yml nem
   a AF5 na régua. Trazida de volta por merge da branch original.

2. O autofix só acordava quando o PR se mexia. Mas quem desatualiza PR é a MAIN
   andando: 9 `chore(release)` em 20 horas, cada um reescrevendo
   README/STATUS/ARCH/docs e reabrindo conflito em todo PR aberto ao mesmo tempo.
   O bot consertava quem empurra commit e nunca quem está parado esperando
   revisão — que é exatamente quem precisa. Entra o gatilho `push: [main]` e um
   job de varredura que lista os PRs não-MERGEABLE e dispara o autofix de cada um
   pelo `workflow_dispatch`, o caminho que enxerga secret.

A AF6 guarda isso: sem o gatilho de push, o portão acende. Os SETE mutantes
mordem. As duas réguas re-mescladas também receberam o padrão do #416.

Agent: Claude Opus 5 (Claude Code)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Commit-grande: reúne a fase 5 órfã e acrescenta a varredura pós-release
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

target:main PR apontando para a branch main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants