Skip to content

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

Merged
rubenmarcus merged 2 commits into
fix/portoes-sem-secret-em-forkfrom
fix/vercel-fora-do-caminho-critico
Aug 21, 2026
Merged

fix(ci): quem bloqueia o PR é o build do CI, não a Vercel#409
rubenmarcus merged 2 commits into
fix/portoes-sem-secret-em-forkfrom
fix/vercel-fora-do-caminho-critico

Conversation

@rubenmarcus

Copy link
Copy Markdown
Member

Empilhado sobre o #408 (fase 1). A base deste PR é fix/portoes-sem-secret-em-fork; ao mergear o #408 o diff aqui fica só o desta fase.

Summary

  • régua nova DG1/DG2/DG3 guarda as condições que deixam a Vercel sair do caminho crítico do PR;
  • curl dos dois fetchers de asset ganha --retry;
  • a etiqueta preview-autorizado passa a ser criada pelo workflow que depende dela.

Evidência

A Vercel reprovou 13 dos 14 PRs vindos de fork, sempre com Authorization required to deploy. — é a proteção de fork da própria Vercel, e nenhum commit do colaborador a resolve.

Nos PRs de casa o vermelho era build de verdade. Um caso, do #397:

decalques: 196 de 197 do acervo faltando
`bash scripts/fetch-decals.sh` falhou ou não rodou.
Error: Command "... && npm run check:deploy && npm run build" exited with 1

O assert:assets está certo em reprovar — os mapas subiriam com a parede pelada. O defeito é o curl -fsSL sem --retry sob set -e: soluço de rede vira PR vermelho que o autor não tem como consertar.

Achado da DG3 — código morto. O job preview do preview-bot.yml já sabe publicar pela CLI da Vercel, depois de conferir permissão do ator e SHA aprovado. Ele dispara em labeled com preview-autorizado, e essa etiqueta nunca existiu no repositório (gh api .../labels não a devolve; o job nunca rodou uma vez). O bot pedia um rótulo que ninguém tinha como aplicar. Agora o próprio workflow a cria.

O ci.yml já roda npm run build em pull_request, então o portão que importa existe — a DG1 passa a guardar isso, para que tirar a Vercel do bloqueio não deixe o PR sem prova de que o site compila.

Os três mutantes mordem: ci-sem-build, download-sem-retry, preview-sem-etiqueta.

Fica fora do repositório

Dois ajustes são de painel da Vercel e precisam da conta dona (escritos no PROD-READINESS.md):

  1. Project → Git → Fork Protection: desligar deploy automático de PR vindo de fork;
  2. Settings → Git → Ignored Build Step: opcional, para não gastar build em branch de PR interna.

Risk

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

CI e dois scripts de download. Nenhum arquivo do jogo.

Validation

  • npm run check:fast - 59/59
  • npm run check:deploy - 32/32
  • eval:deploygate + os três mutantes

Limite declarado

Não desliga o preview da Vercel (é painel) e não cria o autofix — é a fase 3.

Bot notes

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

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 21, 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 21, 2026 11:30pm

Request Review

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

csbrasil-BOT commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

csbrasil-bot classification

Note

@rubenmarcus abriu 20 arquivo(s) · +548 −28, base fix/portoes-sem-secret-em-fork.

O que mudou

área arquivos + amostra
📚 docs 8 +37 −13 ARCH.generated.md, PROD-READINESS.md, README.md
🤖 CI 6 +327 −9 autofix.yml, ci.yml, csbrasil-bot-automerge.yml
📦 outros 3 +7 −5 package.json, fetch-audio.sh, fetch-decals.sh
🧪 arnês 3 +177 −1 autofix-check.mjs, deploy-gate-check.mjs, fixture-check.mjs

Labels

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

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

@estraga-codigo estraga-codigo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Palhaço Mal

Palhaço Mal · revisor da casa · 🤡

mapa da mudança

  • docs (8): ARCH.generated.md, PROD-READINESS.md, README.md, STATUS.md
  • CI (3): ci.yml, preview-bot.yml, ensure_labels.py
  • outros (3): package.json, fetch-audio.sh, fetch-decals.sh
  • arnês (2): deploy-gate-check.mjs, fixture-check.mjs

Tip

Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓

pente fino passado: nenhum achado que eu defenda em voz alta

Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.


maquiagem de verde por cima de vermelho eu desenmascaro no primeiro golpe de vista 🤡

…ergear (#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>

@estraga-codigo estraga-codigo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Palhaço Mal

Palhaço Mal · revisor da casa · 🤡

mapa da mudança

  • docs (8): ARCH.generated.md, PROD-READINESS.md, README.md, STATUS.md
  • CI (6): autofix.yml, ci.yml, csbrasil-bot-automerge.yml, preview-bot.yml
  • outros (3): package.json, fetch-audio.sh, fetch-decals.sh
  • arnês (3): autofix-check.mjs, deploy-gate-check.mjs, fixture-check.mjs

Tip

Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓

nada aqui que quebre amanhã. amanhã é outro diff

Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.


maquiagem de verde por cima de vermelho eu desenmascaro no primeiro golpe de vista 🤡

@rubenmarcus
rubenmarcus merged commit cdea780 into fix/portoes-sem-secret-em-fork Aug 21, 2026
15 checks passed
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>
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.

3 participants