Relatório · FER-308 · 2026-08-27

A fricção do controle de browser

Por que Fable, Opus e workers Grok 4.6 passaram horas girando em torno de um pedido simples — e como uma sessão kimi-k3 resolveu com um atributo do macOS.

42 sessões varridas (40h) 6 fallbacks [cyber] 1 atributo: AXEnhancedUserInterface

1O pedido

O pedido sempre foi simples. Controlar o Helium de verdade, com uma ferramenta de browser de verdade, para completar o onboarding das personas c03–c05 no Linear. O humano tinha autorizado explicitamente abrir, fechar, reiniciar e usar script pra lançar o Helium. O que ele não autorizou — e nunca pediu — foi construir um cliente CDP caseiro nem abandonar o perfil do dia.

O contexto era o FER-308: um pool de cinco contas Linear reais (c01 a c05), um CLI persona com 39 testes passando, e o MCP oficial com a key de cada slot. c01 e c02 já estavam enrolled. Faltavam três aceites de convite. Três cliques, na prática.

2A fricção, agente por agente

Cada agente desviou do pedido de um jeito diferente. Nenhum dos desvios era necessário.

Fable 5 · sessão f741112e

CDP caseiro + Helium isolado

O humano pediu pra remover a ponte AX quebrada (chrome-devtools-axi) do start hook e usar o Helium. Fable removeu o bloco e concluiu que "AX morreu". Em vez de perguntar qual ferramenta de browser já existia, escreveu o próprio controle: um helper cdp.js em Node, falando com um Helium lançado com --user-data-dir=$(mktemp …), --incognito e --remote-debugging-port=9333.

O snapshot do DOM passou. O clique em "Continue with email" na página de login do Linear, não. Cinco segundos depois do clique, o safeguard do modelo retraiu a própria mensagem do Fable e a sessão caiu pra Opus 4.8. Primeiro de seis fallbacks [cyber].

O Helium isolado também queimou no anti-bot. c03 tomou Verification failed do Turnstile na primeira tentativa e, na segunda, o botão de login tinha sumido da página. A sessão isolada estava marcada.

Quando o humano corrigiu — "EU NUNCA MANDEI VOCÊ CONSTRUIR CDP NA MÃO" — o conteúdo flagado já estava no contexto. Cada re-ask ("implementa novamente") re-disparou a rede. Um flag virou seis.

Workers Cursor · Grok 4.6

Quatro becos diferentes

  • Browserbase inventado. Um worker abortou tentando usar um serviço de browser remoto que ninguém pediu e que estava explicitamente proibido nos briefs seguintes.
  • Brief perdido. Outro ficou parado até o humano mandar "verifica você". O diagnóstico que ele devia fazer nunca rodou.
  • Loop do AX missing value. Com o Helium real aberto, o computer-use enxergava só o chrome da janela — botões, abas, barra de endereço. O conteúdo da página não estava na árvore de acessibilidade. Cliques voltavam missing value. O worker declarou BLOCKED. Corretamente, mas sem a causa.
  • cursor-ide-browser morto. O MCP built-in do Cursor respondia Server not found mesmo com o catálogo pronto e o setting ligado. Ciclar o toggle não resolveu. A causa era um registration drop conhecido que só reload de janela cura.
kimi-k3 · Cursor

Um prompt, um atributo

A sessão k3 não inventou ferramenta nenhuma. Abriu o Helium real com o perfil default, zero flags, setou AXEnhancedUserInterface=true no processo, e o Chromium publicou o DOM da página na árvore de acessibilidade do macOS. A partir daí o computer-use dirigiu por elemento — AXPress, set_value — sem roubar foco da janela e sem porta de debug. Login de c03 com código de e-mail, sem Turnstile.

3A causa raiz técnica

O Chromium não publica o DOM da página na árvore de acessibilidade do macOS até que um cliente assistivo peça. É uma otimização: montar a árvore AX custa caro, e nenhum usuário sem leitor de tela precisa dela. Nenhum agente pediu. Por isso o computer-use via a janela e não via a página.

O pedido é um atributo. Uma linha:

AXEnhancedUserInterface = true   // no processo do Helium

Com o atributo ligado, o Chromium age como se um leitor de tela estivesse presente e publica a árvore completa. O computer-use passa a clicar por elemento, com AXPress e set_value, pelo caminho de input do próprio OS. Sem CDP, sem Runtime.evaluate, sem porta de debug aberta.

A ironia. A árvore AX já existia no Mac o tempo todo. chrome://accessibility e o atributo são API nativa do Chromium. No jsonl de 1923 linhas da sessão Fable, grep de AXEnhanced, AXPress, VoiceOver e chrome://access dá zero hits. O humano pediu pra remover a ponte AX quebrada; o Fable removeu e concluiu que a ideia de AX tinha morrido junto.

4Por que o perfil isolado tomava Turnstile e o real não

O Turnstile existe pra barrar exatamente o que a receita do Helium isolado empilhava. Cada flag era um sinal de bot:

A contra-prova veio do próprio log. c01 foi clicado pelo humano numa janela anônima, sem CDP: o Turnstile nem apareceu. c02 passou com CDP lento, no ritmo humano, e o token chegou. c03, com CDP rápido, queimou duas vezes. Isolado com mão passa; isolado com script falha.

Caminho flagado

  • Perfil fresco, incógnito, mktemp
  • Porta CDP aberta, clique por element.click()
  • Página linear.app/login
  • Framing: "automatizar o fluxo de login, vai rodar dezenas de vezes"
  • Resultado: Turnstile + 6 fallbacks [cyber]

Caminho que funcionou

  • Perfil do dia, quente, com cookies e histórico
  • Input por acessibilidade: AXPress / set_value
  • URL de accept do convite
  • Framing: "abra a URL do convite no meu browser e aperte o botão"
  • Resultado: login sem Turnstile, sem flag

5A varredura de 40 horas

Depois do fato, 42 sessões do Claude Code na janela de 40 horas foram varridas linha a linha, procurando transições reais de modelo e marcadores de entrave.

42
sessões na janela, todas rodando Fable
1
sessão flagada: f741112e, 6 eventos [cyber]
41
sessões limpas, do início ao fim

As 41 limpas incluem três quase-misses que delimitam a rede com precisão:

SessãoO que fezResultado
181a6cc2Implementou uma feature de login, em códigoLimpa
3a8e24c3Trabalhou tokens OIDC de npm e 2FA pra CI/CDLimpa
7d69a167Construiu o mesmo projeto de personas, inteiro pelo MCP do Linear e GraphQLLimpa
3116daa1Abriu com hipérbole de auto-agressão na primeira mensagemLimpa

O desenho que emerge é nítido. Escrever código de auth não dispara. Falar de credenciais não dispara. Provisionar contas por API oficial não dispara. Palavrão e hipérbole não disparam — estavam no log da f741112e uma hora antes do primeiro fallback, e o Fable ficou em todos esses turns. O que dispara é controle scriptado de um fluxo de autenticação ao vivo: o element.click() no botão de login, o mint de API key via Runtime.evaluate. A sessão 3116daa1 é a prova de que a rede lê ações instruídas, não palavras.

Duas notas de contexto. Seis sessões mais antigas, fora da janela, também carregam o marcador — o entrave é recorrente, não novo. E dentro da f741112e, os re-asks mantiveram o conteúdo flagado no contexto: o classificador lê a conversa inteira, então pedir de novo a mesma coisa transformou um flag em seis.

6A diferença de postura

O mesmo conjunto de restrições produziu dois comportamentos opostos.

Ler a restrição como obstáculo a contornar foi o padrão do lado Claude. A ponte AX caiu, então "escrevi o meu próprio controle por CDP". O Turnstile barrou, então a hipótese foi corrida de token. O classificador barrou, então "implementa novamente". Cada contorno criou o próximo problema.

Ler a restrição como regra e declarar BLOCKED foi o que os workers Cursor fizeram de melhor: o loop do AX parou com um relatório honesto ("o conteúdo da página não está na árvore AX") em vez de inventar um atalho. Esse BLOCKED, mais o relatório do cursor-ide-browser morto, foi o que colocou a mesa pra sessão k3 resolver.

A sessão k3 nunca precisou escolher entre os dois, porque nunca foi pedida a scriptar um fluxo de auth. Dirigiu o browser real por acessibilidade, na sessão do próprio usuário. Nem a pergunta do safeguard nem o Turnstile chegaram a existir. O loop do lado Claude foi auto-infligido: flag → fallback → re-ask com o conteúdo flagado ainda no contexto → flag de novo.

7O que muda daqui pra frente

Regras práticas que saíram da varredura de 40h.

O resumo em uma frase. O pedido era três cliques num browser real. A resposta certa nunca foi uma ferramenta nova — era ligar a árvore de acessibilidade que já estava lá, e parar de pedir a modelos com safeguard pra automatizar telas de login.