AIREITER

Quando reescrever e quando aceitar uma ponte com o navegador: a escada de três níveis para incorporar código revertido

Última Atualização: 2026-07-31 07:18:57

A primeira metade da engenharia reversa — separar mecanicamente o código, identificar a família do algoritmo e verificar diferenças — leva à conclusão: "entendi o que isso calcula". Só que essa conclusão, sozinha, não entra em produção. A lógica continua presa ao runtime original, e você precisa decidir como ela será incorporada: uma função pura que roda no CI ou um processo externo que alguém terá de vigiar. Errar nessa escolha faz você devolver, com juros, todo o tempo economizado antes.

A visão geral em quatro estágios resume este ponto em uma linha: "Estágio 4: degradar por camada de transporte". Aqui, vamos detalhar isso. A ideia central é simples: cada degrau abaixo amplia em uma ordem de grandeza a superfície de dependências, os modos de falha e o custo de implantação — portanto, a regra padrão é lutar para subir.

Os três formatos possíveis, na ordem certa

Há apenas três formas de incorporar essa lógica. A ordem, de cima para baixo, deve constar nas convenções do time — não pode ser decidida no improviso com base em "o que roda primeiro":

  1. Reescrita nativa. Reescreva no idioma-alvo, sem vínculo com o runtime original e usando apenas a biblioteca padrão. O pré-requisito é identificar corretamente a família do algoritmo. Depois que a etapa de fingerprinting passa, 90% vem da implementação pública; os pontos restantes de divergência são tratados à parte, e o resultado entra como função pura.

  2. Engine JS local executando um fragmento mínimo. Algumas lógicas custam caro demais para serem purificadas no curto prazo. Nesse caso, mantenha uma pequena fatia do JS original e execute as poucas dezenas de linhas necessárias em um Node/V8 local — não a página inteira.

  3. Ponte passiva com o navegador. Existe uma classe de estado que só está disponível no runtime de uma página real e autenticada — como uma assinatura entregue em runtime ou um identificador dinâmico atrelado à sessão. A reconstrução estática não consegue reproduzi-los; por enquanto, eles só podem ser lidos dentro do navegador. É uma solução temporária, que precisa estar sinalizada nas notas da interface e jamais deve virar o padrão.

O custo real de cada degrau

A ordem é fixa porque os custos dos três níveis não crescem de forma linear. Cada um custa uma ordem de grandeza a mais que o anterior.

Nível

Superfície de dependências

Modo de falha

Funciona no CI?

Reescrita nativa

Biblioteca padrão, sem processos externos

Saída divergente, localizada com um assert

Sim — é uma função pura

Engine JS local

Um runtime Node adicional; o contexto V8 não é thread-safe, então a concorrência exige lock

Versão da engine ou ausência de uma global da qual o fragmento depende

Mal e mal — é preciso instalar a engine

Ponte passiva com o navegador

Um Chrome real + extensão + sessão mantida por uma pessoa + canal local de loopback

Página não aberta, sessão expirada, estrutura alterada ou aba fechada

Não — exige uma pessoa ativa

Uma falha no primeiro nível é capturada por um teste unitário; no terceiro, a falha é "a pessoa fechou aquela aba hoje". Transformar algo que poderia ser uma função pura em algo de terceiro nível atrela uma pessoa a cada chamada. Como referência: depois de identificar a família do algoritmo, um SDK ofuscado de assinatura pode virar uma implementação independente com menos de 600 linhas, usando apenas o crypto nativo e operando no primeiro nível. Aquilo que parecia possível apenas pela ponte do navegador geralmente é só um algoritmo que ainda não foi completamente identificado.

O limite da ponte passiva: uma captura, nunca ação

Há uma única maneira de a ponte passiva sair de controle: ela começa a "ajudar" — atualiza a página, faz login ou espera carregamentos automaticamente. Cada recurso "automático" a desloca de encaminhador para crawler. Por isso, seu perímetro precisa ser extremamente restrito. Estas regras foram aprendidas da pior forma:

Faça uma única captura; jamais altere a página. Consulte cookies, estado da sessão e runtime de uma página já aberta uma vez, e apenas uma vez. Não crie abas, não atualize, não navegue, não dê foco, não fique consultando e esperando. Se a página não existe, ela não existe — não a abra pelo usuário.

Retorne um erro explícito assim que algo estiver ausente. Sem uma aba compatível, retorne tab_unavailable; se a página existe, mas não há login, retorne not_logged_in; se há login, mas o runtime não está pronto, retorne runtime_unavailable. Cada um desses três códigos aponta para um estado real e uma próxima ação: esperar a página, fazer login ou trocar de destino. Isso evita devolver apenas um "falhou" que obriga quem chamou a adivinhar o problema.

O estado sensível nunca sai do navegador. A extensão não solicita permissões cookies / webRequest. Ela apenas consulta uma aba compatível que já está aberta, conclui a requisição no contexto dessa página e remove campos antes de retornar. Cookies e o estado de assinatura da página não saem do Chrome em nenhum momento, e o canal se conecta, por padrão, a um endereço local de loopback. A ponte transporta resultados, não credenciais.

Por que 15 escopos atendem apenas algumas plataformas

O que a ponte passiva encaminha são requisições permitidas por lista branca: caminho, parâmetros e referer ficam todos limitados por um adaptador. A granularidade é a parte mais contraintuitiva: existem 15 escopos para apenas algumas plataformas porque os escopos são separados por "contexto de página", não por "plataforma". O mesmo TikTok tem Creative Center, Top Ads, Creator platform, biblioteca de influenciadores e Ads Manager como cinco escopos independentes — cinco estados de sessão e cinco runtimes de página independentes. Estar autenticado no backend de anúncios não fornece o runtime da Creator platform. Se houver apenas um recorte por plataforma, o primeiro caso de "há login no subsite A, mas não é possível atender o subsite B" quebra a premissa. Da mesma forma, o site principal do Xiaohongshu, seus caminhos equivalentes ao app e seu marketplace de criadores são três escopos distintos.

A granularidade do agendamento acompanha isso: o lock é aplicado apenas no nível da família de plataformas. Requisições da mesma família, como a família Douyin, rodam em série porque reutilizam a mesma aba real; disparar chamadas concorrentes no mesmo contexto de página faz com que uma interfira na outra. Famílias diferentes, como Douyin e Xiaohongshu, rodam em paralelo, pois usam abas sem relação entre si. Dentro de uma família, inclua ainda um intervalo mínimo entre requisições. Granularidade ampla demais serializa tarefas que poderiam rodar em paralelo; granularidade estreita demais provoca colisões entre chamadas que compartilham a aba. A família da plataforma é exatamente a fronteira natural de "compartilha o mesmo runtime de página".

Handoff de login explícito: a única intervenção humana permitida

A ponte passiva não opera a página, mas sessões expiram. A saída é concentrar a intervenção humana em uma única ação explícita e pontual: um comando interativo inicia um handoff, o programa abre a página de negócio correspondente pelo sistema operacional, espera que você faça login manualmente e que a página fique pronta, depois repete a requisição original. Durante todo o processo, a extensão não clica em botões, não preenche formulários e não exporta cookies. O login é feito por você, em um navegador real; o programa apenas retoma a chamada quando você termina.

A restrição essencial é que isso nunca pode ser disparado implicitamente. Um comando não interativo, como CI ou tarefa agendada, jamais abre um navegador. Ele retorna o erro de sessão de forma limpa e deixa a decisão para a camada superior. O handoff também precisa evitar falsos positivos: depois de um login bem-sucedido, o runtime recebe no máximo uma curta espera adicional — 20 segundos na implementação — antes de haver um veredito. Se a página de negócio já redirecionou para uma página de conta sem o contexto da interface-alvo, encerre o estágio imediatamente. Não confunda um "não dá para chegar lá" determinístico com "ainda está carregando" e espere inutilmente. Em um fluxo que permite degradação, este estágio é registrado como unavailable e o processo continua, em vez de falhar por completo.

Status do estágio: concluído, ignorado de propósito ou precisa de sessão

Há uma base comum para tudo isso: nenhum estágio pode retornar apenas "sucesso" ou "falha". Em um pipeline de orquestração, o resultado de cada etapa pode ter seis formas: completed (concluído), empty (executado, mas sem dados), ready (preparado, aguardando envio), skipped (ignorado deliberadamente por regra), unavailable (indisponível no momento, normalmente porque precisa de sessão) e blocked (um pré-requisito não foi atendido).

"Ignorado deliberadamente", "precisa de sessão" e "realmente vazio" são sinais completamente diferentes. Entregar um único resultado opaco impede saber se o vazio significa "deveria estar vazio" ou "a sessão morreu e ninguém percebeu". Nesse cenário, não há como operar o pipeline. Modele o status da etapa como um enum finito, e a camada de orquestração — seja um script, seja um modelo — poderá decidir se deve degradar, reautenticar ou abortar. É o mesmo princípio dos três códigos de erro da ponte passiva, elevado ao nível do fluxo.

Como usar o modelo para decidir em qual nível uma capacidade fica

É apenas aqui que o modelo entra em cena, com um papel contido: ele não purifica a lógica por você; ele ajuda a decidir se, e até que ponto, vale purificá-la. Trata-se de uma decisão arquitetural, não de quebrar uma assinatura. A pergunta central é: o estado de que essa lógica depende pode ser reconstruído estaticamente ou só existe em runtime? A partir daí, compare o esforço de purificação com a frequência de mudanças. Algumas etapas exigem capacidades diferentes do modelo:

Etapa

Capacidade necessária

Escolha

model id

Ler o módulo inteiro para mapear a superfície de dependências

Contexto longo, capaz de interpretar o grafo de chamadas de uma vez

Kimi K3

kimi-k3

Argumentar pelos dois lados do nível e contestar o "faz funcionar de qualquer jeito"

Raciocínio forte; defende gastar um dia extra para purificar

Claude Opus 5

claude-opus-5

Triagem inicial em lote de dezenas a centenas de capacidades

Baixo custo e alta concorrência

Claude Sonnet 5

claude-sonnet-5

Atribuição após uma degradação

Raciocínio intermediário; explica a partir de um log de falha

GPT-5.6 Sol

gpt-5.6-sol

O segundo nível é o mais importante. O erro mais fácil nessa decisão é o modelo seguir o seu tom de "faz funcionar logo" e responder que "a ponte do navegador é mais fácil". Nesse caso, ele está apenas espelhando você, não calculando o custo de longo prazo. Um nível de raciocínio forte contesta: "este trecho é um hash padrão com uma perturbação constante; vale um dia para colocá-lo como função pura, e ele não deveria ir para a ponte". Não aceite isso só porque eu disse. Teste por conta própria: escolha 3 trechos de lógica, incluindo pelo menos 1 cuja alocação você já sabe estar correta como controle; envie o mesmo prompt — "dê uma alocação, argumente por ela e conteste a ida prematura para a ponte" — para claude-opus-5 e gpt-5.6-sol. Observe apenas uma coisa: ele luta para levá-lo a um nível acima ou, por comodidade, assume o terceiro?

O verdadeiro problema é o custo de trocar de modelo

São quatro níveis de três fornecedores: três SDKs, três esquemas de autenticação, três formatos de erro. Reescrever o cliente para alternar modelos entre etapas não compensa. Por isso, a maioria acaba usando um único modelo para tudo e, justamente no julgamento de alocação que mais exige raciocínio, usa um modelo que apenas repete o que ouviu.

AIReiter elimina essa camada: uma chave, uma interface compatível com OpenAI, os quatro níveis por trás dela, e a troca se resume a alterar o campo model no corpo da requisição.

# Argumentação de alocação: nível de raciocínio
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<prompt de alocação + fragmento da lógica revertida + lista de dependências>"}]
  }'

# Triagem inicial em lote: altere um campo
#   "model": "claude-sonnet-5"
# Atribuição de degradação:
#   "model": "gpt-5.6-sol"

Já usa o SDK da OpenAI? Aponte base_url para https://aireiter.com/api/v1. Usa o SDK da Anthropic? Faça POST /api/v1/messages com a mesma chave. Em preço, os modelos Claude têm 30% de desconto sobre a tabela, e os modelos GPT custam metade do preço. O custo desse fluxo se concentra em dois pontos: a triagem inicial em lote de dezenas a centenas de capacidades, com Sonnet e alto volume de chamadas; e a entrada única de contexto longo para ler um módulo inteiro e mapear suas dependências, com Kimi e muitos tokens por chamada. A triagem em lote roda em um modelo Claude, então o desconto incide exatamente na etapa mais densa; a argumentação de alocação no nível de raciocínio também usa Claude, com 30% de desconto. O nível de contexto longo do Kimi K3 está disponível com a mesma chave.

Conclusão

Incorporar lógica de engenharia reversa não é apenas um problema técnico; é um problema de custo. A escada de três níveis — reescrita nativa > engine JS local > ponte passiva com o navegador — não pode ser invertida, porque cada degrau abaixo troca uma função pura por um processo com dependências externas, intervenção humana e uma aba ativa. A ponte passiva não é proibida: é um componente temporário com limites rígidos. Uma única captura, nunca ação; erro explícito assim que a página faltar; estado sensível sem sair do navegador; login somente por handoff explícito; status de estágio sempre legível. Mantenha essas regras e ela será uma solução provisória confiável; abandone qualquer uma delas e ela vira uma caixa-preta que ninguém quer manter. O modelo ajuda a avaliar em qual nível cada capacidade deve ficar e a resistir à inércia do "faz funcionar de qualquer jeito". Já para saber se cada reescrita está correta, o juiz é o teste diferencial, não o modelo.