Skip to content

fix(crash): ponte injetada pelo navegador não é bug do jogo — __gCrWeb para de abrir issue (#428) - #433

Open
nunreasonable wants to merge 1 commit into
corosolto:mainfrom
nunreasonable:fix/428-ponte-injetada
Open

fix(crash): ponte injetada pelo navegador não é bug do jogo — __gCrWeb para de abrir issue (#428)#433
nunreasonable wants to merge 1 commit into
corosolto:mainfrom
nunreasonable:fix/428-ponte-injetada

Conversation

@nunreasonable

Copy link
Copy Markdown
Contributor

__gCrWeb é a ponte JS que o Chrome para iOS injeta em toda página. A #428 chegou como
classe codigo e abriu issue como se fosse defeito nosso:

Origem: https://www.csbrasil.online/:1:9
Stack:  global code@https://www.csbrasil.online/:1:9

A prova de que não é nosso é tripla. O nome não existe em nenhum arquivo do repositório e
git log --all -S não devolve um único commit para ele; o fingerprint publicado d85ae7e1
reproduz exatamente crashFingerprint('error', <mensagem>, '…/:1:9'), ou seja o e.filename é
a própria página; e o único frame é global code@.

Não é incidente isolado — é uma família que já reincidiu quatro vezes

Mesma forma, e as três anteriores foram fechadas à mão sem que nada no código as impedisse
de voltar. A #428 é a volta.

issue mensagem origem fingerprint
#379 Can't find variable: __firefox__ /:1:12 470752a2
#380 window.__firefox__.reader /:1:19 7122f83c
#381 Can't find variable: DarkReader /:1:11 cd468274
#428 Can't find variable: __gCrWeb /:1:9 d85ae7e1

Causa

isExternalCrash inocenta por origem, e o WebKit reporta script injetado no mundo da
página com o filename da página. O atalho if (sourceOrigin === ownOrigin) return false;
decidia "é nosso" antes de qualquer outra prova, e o classifyCrash caía no return 'codigo'
final — que escala.

O corte é por NOME e não pela FORMA, e isso foi medido

A tentação óbvia era cortar "pilha de frame único global code@<própria-origem>/:1:N". Ela
reprova: a linha 1 do dist/client/index.html tem 268 caracteres e o compressHTML do
Astro cola o <!DOCTYPE>, o <head>, o comentário e o nosso primeiro <script is:inline>
(o define:vars do __SUPPORT) todos nela — o nosso código começa na coluna 167 da linha 1.
O que separa a #428 (coluna 9) do nosso código é o comprimento de um comentário HTML: resíduo de
build, não invariante. Além disso global code@ é redação só do WebKit, e o corte por forma não
tem invariante de honestidade possível. As duas primeiras fixtures negativas do EP16 travam essa
decisão em régua.

Correção, em duas camadas espelhadas

  • src/lib/error-provenance.mjsPONTE_INJETADA_RE e o ramo em isExternalCrash, na mesma
    posição e pelo mesmo motivo da VENDOR_RE
    : antes do atalho same-origin. A linha continua
    gravada no js_error; some o disparo automático, não o dado.
  • src/pages/index.astro — a mesma redação em origemDoJogo. Sem cota nova (cai no
    TETO_EXTERNO da BUG-51), e com interna === false a ponte deixa de virar erroDoBoot /
    lancamento.fail.

O corte é estreito em dois eixos: exige o nome do global de terceiro e a caixa dele.
webkit solto não foi comprado (o jogo usa window.webkitAudioContext), e __\w+__ genérico
está proibido — sete globais do jogo são dunder.

Custo declarado, medido na população real

Reclassificando as 96 issues crash-auto do repositório com o helper de antes e o de
depois, exatamente 4 mudam de classe:

ANTES : codigo 59 · externo 25 · recuperavel 12
DEPOIS: codigo 55 · externo 29 · recuperavel 12

As outras 92 ficam idênticas. Nenhuma outra issue deixa de abrir.

Régua

EP16 em tools/eval/error-provenance-check.mjs (npm run eval:error-origin, já no
check:fast e no check:deploy — nenhum passo novo no portão). Classifica os payloads reais
das quatro issues, confere os quatro fingerprints publicados contra a receita, exige que sete
vizinhas continuem codigo (duas com a mesma forma da família) e executa o origemDoJogo
recortado do fonte
. Carrega uma invariante de honestidade que fica vermelha no dia em que
o jogo falar com uma dessas pontes — e ela lê o fonte mutado, não o disco, para que um
mutante consiga acendê-la. Mutantes novos: sem-ponte, ponte-ampla, ponte-insensivel,
sem-ponte-cliente, jogo-com-ponte. Cláusulas 15 → 16, matriz de mutação 44/44.

Portão local

check:deploy 35/35, build completo, eval:error-origin verde com as 16 cláusulas.
check:fast 61/62: audio:check reprova por falta dos assets de áudio (gitignored,
ausentes nesta máquina) e reprova idêntico na árvore limpa de origin/main, antes de
qualquer mudança desta PR.

Sobreposição com a #406

A #406 (carteira cripto, #403/#404) está aberta e toca as mesmas linhas: o ramo vizinho em
isExternalCrash, a mesma função origemDoJogo, as mesmas regiões da régua — e também
reivindica EP16 e BUG-75. Conflito textual é esperado; quem mergear em segundo renumera.
São famílias diferentes (ponte de navegador × carteira web3) e nenhuma das duas subsume a outra.

NÃO VERIFICADO

Não há browser nesta máquina: a reprodução com um Chrome para iOS de verdade não foi feita — a
régua mede a classificação, não a injeção. A tabela js_error do Supabase não foi
consultada. Pontos cegos declarados: a invariante não varre public/vendor/ nem pega acesso por
string (window["__gCrWeb"]), e o corte vale em qualquer campo, inclusive na mensagem — o mesmo
furo estrutural que a EXTENSION_RE tem desde a BUG-51.

Closes #428

…b para de abrir issue (corosolto#428)

A corosolto#428 chegou como classe `codigo`, alpha.182, com origem e stack apontando para a PRÓPRIA
PÁGINA:

    ReferenceError: Can't find variable: __gCrWeb
    Origem: https://www.csbrasil.online/:1:9
    Stack:  global code@https://www.csbrasil.online/:1:9

`__gCrWeb` é a ponte JS que o Chrome para iOS injeta em toda página. Não é defeito do jogo, e
a prova é tripla. O nome NÃO existe em nenhum arquivo do repositório e `git log --all -S` não
devolve um único commit para ele. O fingerprint publicado reproduz EXATAMENTE
`crashFingerprint('error', <mensagem>, 'https://www.csbrasil.online/:1:9')` — `d85ae7e1` —, ou
seja o `e.filename` é a própria página, `lineno=1`, `colno=9`. E o único frame é `global code@`:
nenhum arquivo do jogo aparece na pilha.

Não é incidente isolado: é uma FAMÍLIA que já reincidiu quatro vezes, mesma forma, e as três
anteriores foram fechadas À MÃO sem que nada no código as impedisse de voltar — a corosolto#428 é a
volta. corosolto#379 `__firefox__` (fp 470752a2), corosolto#380 `window.__firefox__.reader` (fp 7122f83c) e
corosolto#381 `DarkReader` (fp cd468274), todas com origem `/:1:N` e frame único `global code@`.

Causa: o `isExternalCrash` inocenta por ORIGEM, e o WebKit reporta script injetado no mundo da
página com o filename da página. O atalho `if (sourceOrigin === ownOrigin) return false;`
decidia "é nosso" antes de qualquer outra prova, nenhuma das regex seguintes mordia (OPAQUE_RE,
AMBIENTE_RE, CACHE_SPLIT_RE, RECOVERABLE_RE, MEDIA_ABORT_RE) e o `classifyCrash` caía no
`return 'codigo'` final, que escala.

O corte é por NOME e NÃO pela forma, e isso foi medido, não escolhido. A tentação óbvia era
cortar "pilha de frame único `global code@<própria-origem>/:1:N`". Ela REPROVA: a linha 1 do
`dist/client/index.html` tem 268 caracteres e o `compressHTML` do Astro cola o `<!DOCTYPE>`, o
`<head>`, o comentário e o NOSSO primeiro `<script is:inline>` (o `define:vars` do `__SUPPORT`)
todos nela — o nosso código começa na COLUNA 167 DA LINHA 1. O que separa a corosolto#428 (coluna 9) do
nosso código é o comprimento de um comentário HTML, que é resíduo de build e não invariante.
Além disso `global code@` é redação só do WebKit, e o corte por forma não tem invariante de
honestidade possível: depende de uma propriedade do artefato buildado, que o `check:fast` não
constrói. As duas primeiras fixtures negativas do EP16 travam essa decisão em régua.

Correção em duas camadas espelhadas, o mesmo remédio das BUG-51/72/73:

- src/lib/error-provenance.mjs — PONTE_INJETADA_RE e o ramo em `isExternalCrash`, na MESMA
  posição e pelo mesmo motivo da VENDOR_RE: antes do atalho same-origin, porque a ponte roda no
  próprio domínio mas o código é de terceiro. A linha continua gravada no `js_error`; some o
  disparo automático, não o dado.
- src/pages/index.astro — a MESMA redação em `origemDoJogo`. Nenhuma cota nova: ponte cai no
  balde do TETO_EXTERNO que a BUG-51 já abriu. Com `interna === false` o erro também deixa de
  virar `erroDoBoot` e `lancamento.fail` — uma ponte que estoura durante o boot podia ser
  acusada de ter derrubado o carregamento do jogo.

O corte é ESTREITO em dois eixos: exige o NOME do global de terceiro e exige a CAIXA dele.
Identificador JS é sensível a caixa e a mensagem o cita verbatim, então `darkreader.glb` num
texto nosso continua `codigo` — divergência deliberada em relação às outras regex do arquivo,
que usam `/i`, e é o mutante `ponte-insensivel`. `webkit` solto NÃO foi comprado (só
`webkit.messageHandlers`), porque o jogo usa `window.webkitAudioContext` de verdade. E
`__\w+__` genérico está proibido: sete globais do JOGO são dunder (`__GEO_LANG__`, `__SUPPORT`,
`__CS_MAIN_FAILED`, `__CS_MAIN_READY__`, `__CS_BOOT_SRC`, `__gameLaunch`, `__semWebgl`) e o
corte genérico calaria crash nosso — é o mutante `ponte-ampla`. O roster cobre a FAMÍLIA (ponte
de WebView, extensão, hook de devtools) e não uma regex por incidente, que é a crítica que a
BUG-72 fez ao padrão antigo: `webkit.messageHandlers` e os dois hooks de devtools entram SEM
incidente, pelo mesmo mecanismo.

Medido (helper e `origemDoJogo` reais, extraídos do fonte, sem browser):

  corosolto#428/corosolto#379/corosolto#380/corosolto#381 classificadas externo .... 0/4 -> 4/4
  corosolto#428/corosolto#379/corosolto#380/corosolto#381 abrem issue .............. 4/4 -> 0/4
  cliente inocenta a ponte ..................... 0/6 -> 6/6
  vizinhas que continuam `codigo` .............. 7/7 -> 7/7 (inalterado, de propósito)

Custo declarado, na população real e não estimado: reclassificando as 96 issues `crash-auto` do
repositório (mensagem, origem e stack lidos do corpo publicado) com o helper de antes e o de
depois, exatamente 4 mudam de classe — a corosolto#428, a corosolto#379, a corosolto#380 e a corosolto#381. As outras 92 ficam
idênticas (59 `codigo` -> 55, 25 `externo` -> 29, 12 `recuperavel` -> 12). NENHUMA outra issue
deixa de abrir.

Régua: EP16 em tools/eval/error-provenance-check.mjs (npm run eval:error-origin, já no
check:fast e no check:deploy — nenhum passo novo no portão). Classifica os payloads REAIS das
quatro issues, confere os quatro fingerprints publicados contra a receita (fixture "arrumada"
deixa de bater e acusa; as sintéticas não têm `fp` e não podem se passar por publicadas), exige
que SETE vizinhas continuem `codigo` — duas delas com a MESMA forma da família — e EXECUTA o
`origemDoJogo` recortado do fonte, porque regex de fiação sozinha aprovaria
`function origemDoJogo(){ return true; }`. Carrega ainda uma INVARIANTE DE HONESTIDADE: varre
`src/` e `public/js/` pela forma de USO e fica VERMELHA no dia em que o jogo falar com uma
dessas pontes de verdade, para o corte não virar mordaça silenciosa. Ela lê o fonte MUTADO e
não o disco — sem isso nenhum mutante conseguiria acendê-la, e régua que ninguém pode quebrar
não mede nada. Mutantes novos: sem-ponte, ponte-ampla, ponte-insensivel, sem-ponte-cliente e
jogo-com-ponte, todos acendendo EP16 e só ele. Cláusulas 15->16, matriz de mutação 44/44.

BUG-75 no KNOWN-BUGS.md. O bloco gerado de autoria do colaborar.md (pt e en) foi regenerado
com `npm run docs` porque este commit muda o `git shortlog` da branch (11 -> 12 identidades
humanas) - mesmo passo que o corosolto#382 e o corosolto#389 deram, e sem ele o eval:docsautoria não tem como
medir.

NÃO VERIFICADO: não há browser nesta máquina, então a reprodução com um Chrome para iOS de
verdade não foi feita — a régua mede a CLASSIFICAÇÃO, não a injeção. A tabela `js_error` do
Supabase não foi consultada. Pontos cegos declarados: a invariante não varre `public/vendor/`
nem pega acesso por string (`window["__gCrWeb"]`), e o corte vale em qualquer campo, inclusive
na mensagem — o mesmo furo estrutural que a EXTENSION_RE tem desde a BUG-51. No portão local,
`audio:check` reprova por falta dos assets de áudio (gitignored, ausentes nesta máquina):
reprova IDÊNTICO na árvore limpa de origin/main, antes de qualquer mudança deste commit. Os
outros 61 passos do check:fast passam, o check:deploy fecha 35/35 e o build completa.

Closes corosolto#428

Signed-off-by: nunreasonable <rafaelpasquarella@gmail.com>
Agent: Claude Code (Opus 5)
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

@nunreasonable is attempting to deploy a commit to the rubenmarcus' projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 cs-brasil-ai-bot: candidato a preview; um mantenedor deve revisar o SHA e aplicar o label preview-autorizado.

@csbrasil-BOT csbrasil-BOT added needs-staging Mudança precisa validação integrada em staging target:main PR apontando para a branch main labels Aug 24, 2026
@csbrasil-BOT

csbrasil-BOT commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

csbrasil-bot classification

Note

@nunreasonable abriu 6 arquivo(s) · +237 −2, base main.

O que mudou

área arquivos + amostra
📚 docs 3 +112 −2 KNOWN-BUGS.md, colaborar.md, colaborar.md
⚙️ backend 1 +6 −0 error-provenance.mjs
🌐 site 1 +4 −0 index.astro
🧪 arnês 1 +115 −0 error-provenance-check.mjs

Labels

label por quê
needs-staging mudança de runtime/UI — valida integrado no staging antes do merge
target:main vai direto pra main, sem fila de integração

@csbrasil-BOT

Copy link
Copy Markdown
Collaborator

🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 preview no ar → https://csbrasil-9n528vop9-rubenmarcus-projects.vercel.app

@estraga-codigo

Copy link
Copy Markdown
Collaborator

Esbirro

Esbirro · plantão da produção · 🕵️

check vermelho parado neste PR

Caution

Não sei classificar este vermelho. Segue o que o CI cuspiu — palpite de bot sobre bug alheio só atrapalha.

o quê valor
head ca80c0bd5b06
checks vermelhos 1
classe outra
hora do plantão 2026-08-24T19:44:50.774Z

Vermelho:

Vercel (https://vercel.com/git/authorize?team=rubenmarcus'%20projects&slug=rubenmarcus-projects&teamId=team_4nZdRW8viHMCXpdixaCtzZ7z&type=github&job=%7B%22headInfo%22%3A%7B%22sha%22%3A%22ca80c0bd5b06a347bb95db1752e38e3c12674284%22%7D%2C%22id%22%3A%22Qman7BAS7cNdmgdsC4Bow2iKmPysik6mF5GfaY2Z2PcqC9%22%2C%22org%22%3A%22corosolto%22%2C%22prId%22%3A433%2C%22repo%22%3A%22client%22%7D)

Log do run já expirou — abrir pelo link do check.


nada fora do normal no meu turno 🕵️

@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 (3): KNOWN-BUGS.md, colaborar.md, colaborar.md
  • backend (1): error-provenance.mjs
  • site (1): index.astro
  • arnês (1): error-provenance-check.mjs

Tip

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

limpo pelos critérios das minhas ações desta rodada

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 🤡

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-staging Mudança precisa validação integrada em staging target:main PR apontando para a branch main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

crash em produção: ReferenceError: Can't find variable: __gCrWeb

3 participants