fix(crash): ponte injetada pelo navegador não é bug do jogo — __gCrWeb para de abrir issue (#428) - #433
Conversation
…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)
|
@nunreasonable is attempting to deploy a commit to the rubenmarcus' projects Team on Vercel. A member of the Team first needs to authorize it. |
|
🤖 cs-brasil-ai-bot: candidato a preview; um mantenedor deve revisar o SHA e aplicar o label |
csbrasil-bot classificationNote @nunreasonable abriu 6 arquivo(s) · +237 −2, base main. O que mudou
Labels
|
|
🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso. |
|
🤖 preview no ar → https://csbrasil-9n528vop9-rubenmarcus-projects.vercel.app |
|
Esbirro · plantão da produção · 🕵️ check vermelho parado neste PRCaution Não sei classificar este vermelho. Segue o que o CI cuspiu — palpite de bot sobre bug alheio só atrapalha.
Vermelho: Log do run já expirou — abrir pelo link do check. — nada fora do normal no meu turno 🕵️ |
estraga-codigo
left a comment
There was a problem hiding this comment.
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 🤡
__gCrWebé a ponte JS que o Chrome para iOS injeta em toda página. A #428 chegou comoclasse
codigoe abriu issue como se fosse defeito nosso:A prova de que não é nosso é tripla. O nome não existe em nenhum arquivo do repositório e
git log --all -Snão devolve um único commit para ele; o fingerprint publicadod85ae7e1reproduz exatamente
crashFingerprint('error', <mensagem>, '…/:1:9'), ou seja oe.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.
Can't find variable: __firefox__/:1:12470752a2window.__firefox__.reader/:1:197122f83cCan't find variable: DarkReader/:1:11cd468274Can't find variable: __gCrWeb/:1:9d85ae7e1Causa
isExternalCrashinocenta por origem, e o WebKit reporta script injetado no mundo dapágina com o filename da página. O atalho
if (sourceOrigin === ownOrigin) return false;decidia "é nosso" antes de qualquer outra prova, e o
classifyCrashcaía noreturn '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". Elareprova: a linha 1 do
dist/client/index.htmltem 268 caracteres e ocompressHTMLdoAstro cola o
<!DOCTYPE>, o<head>, o comentário e o nosso primeiro<script is:inline>(o
define:varsdo__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ãotem 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.mjs—PONTE_INJETADA_REe o ramo emisExternalCrash, na mesmaposição e pelo mesmo motivo da
VENDOR_RE: antes do atalho same-origin. A linha continuagravada no
js_error; some o disparo automático, não o dado.src/pages/index.astro— a mesma redação emorigemDoJogo. Sem cota nova (cai noTETO_EXTERNOda BUG-51), e cominterna === falsea ponte deixa de virarerroDoBoot/lancamento.fail.O corte é estreito em dois eixos: exige o nome do global de terceiro e a caixa dele.
webkitsolto não foi comprado (o jogo usawindow.webkitAudioContext), e__\w+__genéricoestá proibido — sete globais do jogo são dunder.
Custo declarado, medido na população real
Reclassificando as 96 issues
crash-autodo repositório com o helper de antes e o dedepois, exatamente 4 mudam de classe:
As outras 92 ficam idênticas. Nenhuma outra issue deixa de abrir.
Régua
EP16emtools/eval/error-provenance-check.mjs(npm run eval:error-origin, já nocheck:faste nocheck:deploy— nenhum passo novo no portão). Classifica os payloads reaisdas 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 oorigemDoJogorecortado 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:deploy35/35,buildcompleto,eval:error-originverde com as 16 cláusulas.check:fast61/62:audio:checkreprova por falta dos assets de áudio (gitignored,ausentes nesta máquina) e reprova idêntico na árvore limpa de
origin/main, antes dequalquer 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çãoorigemDoJogo, as mesmas regiões da régua — e tambémreivindica
EP16eBUG-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_errordo Supabase não foiconsultada. Pontos cegos declarados: a invariante não varre
public/vendor/nem pega acesso porstring (
window["__gCrWeb"]), e o corte vale em qualquer campo, inclusive na mensagem — o mesmofuro estrutural que a
EXTENSION_REtem desde a BUG-51.Closes #428