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.
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.
Cada agente desviou do pedido de um jeito diferente. Nenhum dos desvios era necessário.
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.
missing value. O worker declarou BLOCKED. Corretamente, mas sem a causa.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.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.
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.
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.
O Turnstile existe pra barrar exatamente o que a receita do Helium isolado empilhava. Cada flag era um sinal de bot:
mktemp + --incognito. Zero cookies, zero histórico, zero idade de sessão. O Linear via um Chromium que nasceu naquele segundo e foi direto pra /login.--remote-debugging-port com --remote-allow-origins='*' é fingerprint clássico de automação.Runtime.evaluate + element.click() não é o caminho de input do usuário.linear.app/login?email=… em vez do accept do convite. O Turnstile mora na página de login.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.
mktempelement.click()linear.app/login[cyber]AXPress / set_valueDepois 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.
As 41 limpas incluem três quase-misses que delimitam a rede com precisão:
| Sessão | O que fez | Resultado |
|---|---|---|
| 181a6cc2 | Implementou uma feature de login, em código | Limpa |
| 3a8e24c3 | Trabalhou tokens OIDC de npm e 2FA pra CI/CD | Limpa |
| 7d69a167 | Construiu o mesmo projeto de personas, inteiro pelo MCP do Linear e GraphQL | Limpa |
| 3116daa1 | Abriu com hipérbole de auto-agressão na primeira mensagem | Limpa |
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.
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.
Regras práticas que saíram da varredura de 40h.
[cyber]. Se uma sessão sugerir isso, matar a sugestão em vez de re-pedir — o re-ask mantém o conteúdo flagado no contexto e garante o próximo fallback.AXEnhancedUserInterface, computer-use com AXPress/set_value. Sem --remote-debugging-port, sem --user-data-dir=$(mktemp …), sem --incognito em fluxos de conta. Isso evita o classificador e o Turnstile ao mesmo tempo./clear ou sessão nova antes de tentar de novo. Tentar de novo dentro do contexto flagado foi o que transformou um flag em seis na f741112e.