<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matheus de Camargo Marques</title>
    <description>The latest articles on DEV Community by Matheus de Camargo Marques (@matheuscamarques).</description>
    <link>https://dev.to/matheuscamarques</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F882243%2Fde69153a-a393-4f28-9761-e5b60402c45b.jpeg</url>
      <title>DEV Community: Matheus de Camargo Marques</title>
      <link>https://dev.to/matheuscamarques</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matheuscamarques"/>
    <language>en</language>
    <item>
      <title>CEPA: A Consensus-Governed Plugin Architecture Explained in 8 Concepts</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Thu, 03 Sep 2026 16:19:17 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/cepa-a-consensus-governed-plugin-architecture-explained-in-8-concepts-13pe</link>
      <guid>https://dev.to/matheuscamarques/cepa-a-consensus-governed-plugin-architecture-explained-in-8-concepts-13pe</guid>
      <description>&lt;h1&gt;
  
  
  CEPA: A Consensus-Governed Plugin Architecture Explained in 8 Concepts
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;The problem of &lt;em&gt;fork spaghetti&lt;/em&gt;, elementary premises, facts, actions, instigations, and notifications — everything sustaining &lt;strong&gt;CEPA&lt;/strong&gt; (Consensus-Driven Evolutionary Plugin Architecture), reduced to a vocabulary of 8 words. And how this turned into real code on the BEAM, inside &lt;strong&gt;JusrisOS&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Problem We Are Solving
&lt;/h2&gt;

&lt;p&gt;Companies selling software to &lt;strong&gt;multiple clients in the same market niche&lt;/strong&gt; face a classic dilemma:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Over-standardize&lt;/strong&gt; -&amp;gt; the product fails to meet each client's specific variations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-customize&lt;/strong&gt; -&amp;gt; every client becomes a divergent &lt;em&gt;fork&lt;/em&gt;, leading to duplicated bugs, scattered logic, and expensive synchronization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is &lt;strong&gt;uniquely customized fork spaghetti&lt;/strong&gt;: fast point-in-time delivery at the cost of chronic codebase fragmentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CEPA&lt;/strong&gt; solves this via a third path: an architecture delivering &lt;strong&gt;the speed of an exclusive fork at the edge&lt;/strong&gt; alongside &lt;strong&gt;the stability of a single product at the center&lt;/strong&gt; — organizing functionalities into orders of plugins and governing system evolution through consensus.&lt;/p&gt;




&lt;h2&gt;
  
  
  Elementary Premises
&lt;/h2&gt;

&lt;p&gt;Before writing any code, we establish the core axioms of the model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An invariant nucleus (Kernel Core) and a disposable edge exist.&lt;/strong&gt; The center does not change on a whim; the edge changes at will.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation is not human discipline — it is a build property.&lt;/strong&gt; The compiler, not the team's good intentions, guarantees the edge never contaminates the center.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promotion is governed by consensus and data, not opinion.&lt;/strong&gt; An edge variation ascends to the center only when it proves stability and reusability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The local device is the primary source of truth.&lt;/strong&gt; The system operates offline; a master node reconciles conflicts later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These four premises form the baseline contract for everything that follows.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Model's Vocabulary (Minimal Ontology)
&lt;/h2&gt;

&lt;p&gt;We reduce the entire architecture to &lt;strong&gt;8 concepts&lt;/strong&gt;. Using them, we can describe everything from plugin activation to data conflict resolution.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Attribute
&lt;/h3&gt;

&lt;p&gt;Every observable state in the system. A plugin has order, maturity, and activation status; an aggregate has a version and timestamp; a node has online/offline status.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Attribute := (name, value, timestamp)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Example: (order, "2nd"), (maturity, 0.814), (sync_status, :offline)&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Condition
&lt;/h3&gt;

&lt;p&gt;A boolean predicate over attributes — free of side effects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Condition := attributes -&amp;gt; {true, false}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Examples: Stability S(P) &amp;gt;= lambda * r^2  (promotion gate)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;current_wip + reservations &amp;gt;= limit  (WIP limit)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;now &amp;gt;= sla_deadline_date  (SLA breach)&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Rule
&lt;/h3&gt;

&lt;p&gt;The stable association &lt;strong&gt;"condition(s) =&amp;gt; action(s)"&lt;/strong&gt;. This is where decision-making resides.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Rule := {conditions, actions}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Examples: {stable and reused by N clients} =&amp;gt; {promote to 1st order}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{cross-boundary call} =&amp;gt; {compilation error}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{conflict detected} =&amp;gt; {apply resolution strategy}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Action
&lt;/h3&gt;

&lt;p&gt;The triggered side effect: promote, activate/deactivate, dispatch event, synchronize, resolve.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Action in {promote, activate, dispatch, synchronize, resolve, notify}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Attribute Notification
&lt;/h3&gt;

&lt;p&gt;"Attribute X changed to value V". This is the heartbeat keeping the system reactive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Examples: Event "v1.crm:customer_registered"
          {:mnesia_change, :cards_cache, record}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Condition Notification
&lt;/h3&gt;

&lt;p&gt;"Condition C crossed the threshold" — representing the state transition rather than a static value evaluation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Examples: "wip_limit_reached" (false -&amp;gt; true)
          "node status" (offline -&amp;gt; online)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Rule Notification
&lt;/h3&gt;

&lt;p&gt;"Rule R triggered" — an audit trail of an executed decision.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Examples: "plugin promoted to 1st order"
          "conflict resolved via master_wins"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Notification Engine / Action Manager
&lt;/h3&gt;

&lt;p&gt;The component that &lt;strong&gt;subscribes&lt;/strong&gt; to notifications, &lt;strong&gt;evaluates&lt;/strong&gt; conditions, &lt;strong&gt;triggers&lt;/strong&gt; rules, and &lt;strong&gt;dispatches&lt;/strong&gt; actions. In CEPA, this encompasses the entire &lt;strong&gt;microkernel runtime&lt;/strong&gt;: &lt;code&gt;AppManager&lt;/code&gt;, &lt;code&gt;HookRegistry&lt;/code&gt;, &lt;code&gt;SyncEngine&lt;/code&gt;, &lt;code&gt;ConflictResolver&lt;/code&gt;, &lt;code&gt;RulesSupervisor&lt;/code&gt; — along with the &lt;strong&gt;phased compiler&lt;/strong&gt; acting as the build-time engine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Facts
&lt;/h2&gt;

&lt;p&gt;A fact represents current state: the complete set of attributes and their values.&lt;/p&gt;

&lt;p&gt;In CEPA, the primary facts are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order hierarchy&lt;/strong&gt; — where each plugin resides: Kernel Core (r = 0), 1st order, 2nd order (edge), or 3rd order (experimental).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maturity&lt;/strong&gt; — the index rho in [0, 1] for each plugin (test coverage, error rate, reuse metrics).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activation and consent state&lt;/strong&gt; — active and consented plugins per tenant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync queue&lt;/strong&gt; — the pending outbox state on each local node.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In JusrisOS, these facts live in &lt;strong&gt;ETS&lt;/strong&gt; (&lt;code&gt;AppManager&lt;/code&gt;), &lt;strong&gt;Mnesia&lt;/strong&gt; (&lt;code&gt;plugin_activation&lt;/code&gt;, &lt;code&gt;plugin_consents&lt;/code&gt;, &lt;code&gt;outbox&lt;/code&gt;), and &lt;strong&gt;local SQLite&lt;/strong&gt; — avoiding expensive query reconstruction on hot paths.&lt;/p&gt;




&lt;h2&gt;
  
  
  Actions
&lt;/h2&gt;

&lt;p&gt;Actions represent the operational verbs of the architecture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;JusrisOS Mechanism&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Promote&lt;/strong&gt; (2nd -&amp;gt; 1st order)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git cherry-pick&lt;/code&gt;/PR from fork to core, after passing &lt;code&gt;mix precommit&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Activate/deactivate&lt;/strong&gt; plugin&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AppManager.install_with_dependencies/1&lt;/code&gt; + &lt;code&gt;deactivate_plugin/1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Dispatch&lt;/strong&gt; event&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Event.new/3&lt;/code&gt; -&amp;gt; &lt;code&gt;HookRegistry.dispatch/1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Synchronize&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SyncEngine&lt;/code&gt; -&amp;gt; &lt;code&gt;:rpc.call(master, :process_sync_event)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Resolve&lt;/strong&gt; conflict&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ConflictResolver&lt;/code&gt; (&lt;code&gt;master_wins&lt;/code&gt; / &lt;code&gt;LWW&lt;/code&gt; / &lt;code&gt;branch_merge&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Enforce&lt;/strong&gt; boundary&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mix compile --warnings-as-errors&lt;/code&gt; (compilation error)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The golden rule: &lt;strong&gt;an action is always a side effect separated from state&lt;/strong&gt;. A compiler blocking a boundary violation does not "fix" the code; a &lt;code&gt;SyncEngine&lt;/code&gt; performing synchronization does not rewrite the local transaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Instigations
&lt;/h2&gt;

&lt;p&gt;An instigation is an operational trigger that wakes up the engine. CEPA defines four primary classes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Attribute change&lt;/strong&gt; — a versioned domain event (&lt;code&gt;v1.crm:customer_registered&lt;/code&gt;) or cache write (&lt;code&gt;{:mnesia_change, ...}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition transition&lt;/strong&gt; — a promotion gate crossing threshold S(P) &amp;gt;= lambda * r^2, or WIP hitting capacity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exact temporal trigger&lt;/strong&gt; — &lt;code&gt;SlaTimerNode&lt;/code&gt; scheduling &lt;code&gt;Process.send_after/3&lt;/code&gt; down to the millisecond; &lt;code&gt;SyncEngine&lt;/code&gt; utilizing exponential backoff on reconnect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consensus decision&lt;/strong&gt; — the &lt;em&gt;Law of Consensus&lt;/em&gt; deliberating and instigating an upstream promotion.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key principle: &lt;strong&gt;no engine polls the environment&lt;/strong&gt;. All processes remain suspended until instigation occurs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Notifications
&lt;/h2&gt;

&lt;p&gt;CEPA differentiates &lt;strong&gt;three notification tiers&lt;/strong&gt;, establishing structural auditability:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Target Question&lt;/th&gt;
&lt;th&gt;CEPA Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Attribute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"What changed?"&lt;/td&gt;
&lt;td&gt;Versioned event, cache update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Condition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Which threshold was crossed?"&lt;/td&gt;
&lt;td&gt;Promotion gate reached, SLA breach, WIP capacity hit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rule&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Which decision was taken?"&lt;/td&gt;
&lt;td&gt;Promotion approved, conflict resolved, plugin activated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Delivery channels are split by operational context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Personal notification&lt;/strong&gt; (&lt;code&gt;JusrisOs.Notifications&lt;/code&gt;) — targeted directly to &lt;code&gt;users:{id}:notifications&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational alert&lt;/strong&gt; (&lt;code&gt;JusrisOs.Alerts&lt;/code&gt;) — system-wide visibility routed to &lt;code&gt;/dashboard/alerts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Distinguishing between "what changed", "which threshold was crossed", and "which decision was made" provides &lt;strong&gt;algorithmic due process&lt;/strong&gt;: every automated decision preserves provenance and an execution trail.&lt;/p&gt;




&lt;h2&gt;
  
  
  Modeling the Architecture in Elixir/BEAM
&lt;/h2&gt;

&lt;p&gt;These 8 concepts are not an external framework — they are &lt;strong&gt;native OTP primitives&lt;/strong&gt; combined deterministically.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;JusrisOS Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fact&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ETS (&lt;code&gt;AppManager&lt;/code&gt;) + Mnesia + &lt;code&gt;GenServer&lt;/code&gt; state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rule&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rule nodes (&lt;code&gt;WipRuleNode&lt;/code&gt;, &lt;code&gt;SlaTimerNode&lt;/code&gt;) + &lt;code&gt;ConflictResolver&lt;/code&gt; strategies + &lt;code&gt;@callback&lt;/code&gt; behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Engine / Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AppManager&lt;/code&gt; + &lt;code&gt;RulesSupervisor&lt;/code&gt; (&lt;code&gt;DynamicSupervisor&lt;/code&gt;) + &lt;code&gt;SyncEngine&lt;/code&gt; + &lt;code&gt;HookRegistry&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Attribute Notification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Event&lt;/code&gt;/&lt;code&gt;EventContract&lt;/code&gt; + &lt;code&gt;MnesiaCache&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rule Notification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;HookRegistry.dispatch/1&lt;/code&gt; + &lt;code&gt;Phoenix.PubSub&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AppManager.activate/deactivate&lt;/code&gt;, &lt;code&gt;SyncEngine.flush&lt;/code&gt;, &lt;code&gt;ConflictResolver&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Mix.Tasks.Compile.Phased&lt;/code&gt; + &lt;code&gt;:boundary&lt;/code&gt; (enforced at &lt;strong&gt;build time&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The end-to-end architecture lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Edge (2nd order) — client customization without touching the core
        │  Attribute Notification: versioned event / cache write
        ▼
   Engine (AppManager + HookRegistry + SyncEngine + RulesSupervisor)
        │  evaluates Conditions (stability, WIP, SLA, conflict)
        ▼
   Rule triggers
        │  Actions
        ├──► promote (upstream)       — consensus governance
        ├──► dispatch event           — decoupled communication
        ├──► synchronize / resolve    — local-first → master reconciler node
        └──► notify (personal / dashboard)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;phased compiler&lt;/strong&gt; (&lt;code&gt;Mix.Tasks.Compile.Phased&lt;/code&gt;) operates as the build-time engine: &lt;strong&gt;Phase 1&lt;/strong&gt; compiles the isolated Core (the edge does not yet exist), &lt;strong&gt;Phase 2&lt;/strong&gt; compiles plugins in parallel, and &lt;strong&gt;Phase 3&lt;/strong&gt; re-checks the Core with loaded plugins. Consequently, a 2nd-order plugin &lt;strong&gt;cannot leak function signatures&lt;/strong&gt; into the Kernel — isolation is a &lt;strong&gt;mathematical build property&lt;/strong&gt;, not an informal developer guideline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current System State
&lt;/h2&gt;

&lt;p&gt;The model is &lt;strong&gt;implemented and running&lt;/strong&gt; in JusrisOS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared-nothing microkernel&lt;/strong&gt; — &lt;code&gt;Support&lt;/code&gt; -&amp;gt; &lt;code&gt;Kernel&lt;/code&gt; -&amp;gt; &lt;code&gt;Plugins&lt;/code&gt; with compile-time &lt;code&gt;:boundary&lt;/code&gt; enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phased compiler&lt;/strong&gt; — &lt;code&gt;Mix.Tasks.Compile.Phased&lt;/code&gt; (isolated Core + parallel plugins + re-checking pass).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioned event-driven core&lt;/strong&gt; — &lt;code&gt;Event&lt;/code&gt; + &lt;code&gt;EventContract&lt;/code&gt; + &lt;code&gt;HookRegistry&lt;/code&gt; + &lt;code&gt;Snapshot&lt;/code&gt;/&lt;code&gt;Projection&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local-first&lt;/strong&gt; — SQLite (&lt;code&gt;LocalRepo&lt;/code&gt;) + Mnesia + transactional outbox pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Master reconciler node&lt;/strong&gt; — &lt;code&gt;SyncEngine&lt;/code&gt; + domain-specific &lt;code&gt;ConflictResolver&lt;/code&gt; (&lt;code&gt;master_wins&lt;/code&gt;, &lt;code&gt;LWW&lt;/code&gt;, &lt;code&gt;branch_merge&lt;/code&gt;, 3-way AST merge).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule Engine (NOP)&lt;/strong&gt; — WIP and SLA tracked as stateful runtime processes on demand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 8-concept ontology provides a clean framework for formal evaluation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Formalization&lt;/strong&gt; — promotion decisions are expressed mathematically (S(P) &amp;gt;= lambda * r^2); runtime invariants can be modeled in &lt;strong&gt;LTL/CTL&lt;/strong&gt; (&lt;code&gt;G(offline -&amp;gt; F flushed)&lt;/code&gt;, &lt;code&gt;AG(not corrupted_core)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance as non-monotonic logic&lt;/strong&gt; — the &lt;em&gt;Law of Consensus&lt;/em&gt; functions as a revisionable default theory: plugins can be retracted from promotion queues as new operational facts emerge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mechanized verification&lt;/strong&gt; — the "phase isolation theorem" (the Core exhibits no compile-time dependencies on the edge) can be formally proved using assistant environments like Lean, Coq, or Isabelle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geometric mapping&lt;/strong&gt; — the Platform Hypersphere maps maturity (r), domain (theta), and tenant (phi) into spherical coordinates, expressing "distance to core" as a measurable metric.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why It Matters
&lt;/h2&gt;

&lt;p&gt;This 8-word vocabulary is a &lt;strong&gt;formal structural blueprint&lt;/strong&gt; for extensible, long-lived software systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attribute / Condition / Rule / Action&lt;/strong&gt; = the &lt;em&gt;syntactic&lt;/em&gt; dimension (state representations and executable transitions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribute / Condition / Rule Notifications&lt;/strong&gt; = the &lt;em&gt;temporal&lt;/em&gt; dimension (event timing and state propagation).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification Engine / Action Manager&lt;/strong&gt; = the &lt;em&gt;operational&lt;/em&gt; dimension (observation, orchestration, and execution).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CEPA functions as &lt;strong&gt;a notification engine at architectural scale&lt;/strong&gt;: the edge emits attribute notifications, the engine evaluates conditions, rules execute actions, and consensus mechanisms govern which edge extensions ascend to the core.&lt;/p&gt;

&lt;p&gt;When building multi-tenant systems without resorting to codebase forks, the design principle remains straightforward: &lt;strong&gt;define your 8 core concepts before implementing the first plugin.&lt;/strong&gt; The rest follows from there.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>architecture</category>
      <category>events</category>
      <category>plugins</category>
    </item>
    <item>
      <title>Building a Phased Microkernel Compiler in Elixir: How We Tamed Dependency Graphs in JusrisOS</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:09:49 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/building-a-phased-microkernel-compiler-in-elixir-how-we-tamed-dependency-graphs-in-jusrisos-37ob</link>
      <guid>https://dev.to/matheuscamarques/building-a-phased-microkernel-compiler-in-elixir-how-we-tamed-dependency-graphs-in-jusrisos-37ob</guid>
      <description>&lt;p&gt;When building large-scale, modular systems in Elixir, you eventually hit a architectural crossroads: do you split your domain into multiple Umbrella apps/Engines, or do you maintain a single cohesive monolith with strict boundaries?&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;JusrisOS&lt;/strong&gt;, we chose a &lt;em&gt;local-first microkernel architecture&lt;/em&gt;. The system relies on an immutable Core (kernel, ports, adapters, sync layer) and a set of &lt;em&gt;shared-nothing&lt;/em&gt; plugins located under &lt;code&gt;lib/jusris_os_core/plugins/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, as the system grew, standard compilation (&lt;code&gt;mix compile.elixir&lt;/code&gt;) presented two distinct structural problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compilation Cascades &amp;amp; False Warnings:&lt;/strong&gt; The Core module often references plugin schemas dynamically or at runtime (e.g., central state modules tracking registered extensions). During standard compilation, if the Core compiles before or alongside plugins, Elixir raises &lt;code&gt;module is not available&lt;/code&gt; warnings or triggers full recompilation loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict Boundary Enforcement:&lt;/strong&gt; Plugins must remain completely decoupled (&lt;em&gt;shared-nothing&lt;/em&gt;). They can depend on &lt;code&gt;Kernel&lt;/code&gt; or &lt;code&gt;Support&lt;/code&gt;, but &lt;strong&gt;never&lt;/strong&gt; on each other. Standard compilation treats all &lt;code&gt;.ex&lt;/code&gt; files in &lt;code&gt;lib/&lt;/code&gt; as a flat dependency graph, making it easy for transitive dependencies to leak across domain boundaries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To solve this, we wrote a custom compiler: &lt;code&gt;Mix.Tasks.Compile.Phased&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: A Phased Compiler Task
&lt;/h2&gt;

&lt;p&gt;Instead of hacking custom scripts, we extended &lt;code&gt;Mix.Task.Compiler&lt;/code&gt; to introduce a &lt;strong&gt;3-phase compilation pipeline&lt;/strong&gt; directly into Mix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Compile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Phased&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Compiler&lt;/span&gt;

  &lt;span class="nv"&gt;@manifest&lt;/span&gt; &lt;span class="s2"&gt;"compile.elixir"&lt;/span&gt;
  &lt;span class="nv"&gt;@core_manifest&lt;/span&gt; &lt;span class="s2"&gt;"compile.elixir.core"&lt;/span&gt;
  &lt;span class="nv"&gt;@plugins_manifest&lt;/span&gt; &lt;span class="s2"&gt;"compile.elixir.plugins"&lt;/span&gt;
  &lt;span class="nv"&gt;@plugins_root&lt;/span&gt; &lt;span class="s2"&gt;"lib/jusris_os_core/plugins"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By replacing &lt;code&gt;:elixir&lt;/code&gt; with &lt;code&gt;:phased&lt;/code&gt; in &lt;code&gt;mix.exs&lt;/code&gt;, our custom task takes full control over how files are partitioned, compiled, and validated, while maintaining $100\%$ compatibility with standard Mix tooling (&lt;code&gt;mix xref&lt;/code&gt;, &lt;code&gt;mix clean&lt;/code&gt;, protocol consolidation, and LiveView asset compilation).&lt;/p&gt;




&lt;h2&gt;
  
  
  How the 3-Phase Pipeline Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: Core Compilation (The Invariant Base)
&lt;/h3&gt;

&lt;p&gt;The compiler first isolates all core sources from plugin sources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;partition_sources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;all_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extract_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:ex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;slugs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plugin_slugs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;plugin_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;plugin_file?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slugs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;all_files&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;plugin_files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plugin_files&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It compiles the Core using its own manifest (&lt;code&gt;compile.elixir.core&lt;/code&gt;). Because Core modules might reference plugin structs at runtime before plugins exist in the BEAM code path, Phase 1 applies three key compiler overrides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;core_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:consolidate_protocols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:infer_signatures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:no_warn_undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;no_warn_undefined: :all&lt;/code&gt;&lt;/strong&gt;: Suppresses temporary "undefined module" warnings during the initial bootstrap pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;infer_signatures: false&lt;/code&gt;&lt;/strong&gt;: Disables type inference temporarily to force a re-check pass later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;consolidate_protocols: false&lt;/code&gt;&lt;/strong&gt;: Postpones protocol consolidation until plugins (and their &lt;code&gt;defimpl&lt;/code&gt; implementations) are loaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Phase 1 fails due to a syntax or logical error in the Core, compilation halts immediately without touching the plugins.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 2: Parallel Plugin Compilation (Shared-Nothing)
&lt;/h3&gt;

&lt;p&gt;Once the Core is compiled and guaranteed to be consistent, Phase 2 kicks in. Plugins are compiled via &lt;code&gt;Kernel.ParallelCompiler&lt;/code&gt;, distributing files across all available Erlang schedulers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Compilers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Elixir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;plugins_manifest&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;plugin_srcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;erlang_manifests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;erlang_modules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because our microkernel architecture mandates that plugins are strictly &lt;em&gt;shared-nothing&lt;/em&gt;—they only depend on the Core and never on sibling plugins—compiling all plugin sources in parallel is fast, safe, and completely isolated.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 3: Core Re-checking &amp;amp; Validation
&lt;/h3&gt;

&lt;p&gt;After plugins are compiled, their modules inhabit the code path. Now, Phase 3 performs a verification pass over the Core:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;recheck_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:consolidate_protocols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:force&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Compilers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Elixir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;core_manifest&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;core_srcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;erlang_manifests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;erlang_modules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;recheck_opts&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By toggling &lt;code&gt;infer_signatures&lt;/code&gt; back on and removing &lt;code&gt;no_warn_undefined: :all&lt;/code&gt;, Mix triggers a &lt;code&gt;reinfer?&lt;/code&gt; check. It &lt;strong&gt;does not recompiling the Core binaries&lt;/strong&gt;, but it re-evaluates module references. If the Core contains a reference to a non-existent plugin or broken module, it is caught here with accurate compiler diagnostics.&lt;/p&gt;




&lt;h2&gt;
  
  
  Merging Manifests for Tooling Compatibility
&lt;/h2&gt;

&lt;p&gt;To keep the rest of the Elixir ecosystem happy (&lt;code&gt;mix clean&lt;/code&gt;, &lt;code&gt;mix xref&lt;/code&gt;, &lt;code&gt;phoenix_live_view&lt;/code&gt; colocated hooks), the phased compiler merges the isolated manifests (&lt;code&gt;compile.elixir.core&lt;/code&gt; and &lt;code&gt;compile.elixir.plugins&lt;/code&gt;) back into the canonical &lt;code&gt;compile.elixir&lt;/code&gt; manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;merge_manifests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core_manifest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plugins_manifest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest_manifest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;read_raw_manifest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core_manifest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;read_raw_manifest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugins_manifest&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="n"&gt;vsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ccwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cdc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ccm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cproto&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;vsn2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pproto&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vsn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;vsn&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;vsn2&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;vsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;cck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ccwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;cdc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;cpm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ccm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;merge_protocols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cproto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pproto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir_p!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_manifest&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_manifest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;term_to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:compressed&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
      &lt;span class="ss"&gt;:ok&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="ss"&gt;:ok&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, it triggers downstream compiler hooks (such as &lt;code&gt;:boundary&lt;/code&gt; tracer unloading or LiveView asset compilation):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;ProjectStack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_after_compiler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:elixir&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enforce Boundaries at Build Time:&lt;/strong&gt; Custom Mix compilers allow you to move architectural rules (like microkernel core vs. plugin isolation) into the compilation pipeline itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Compilation Intact:&lt;/strong&gt; By maintaining dedicated manifests per phase (&lt;code&gt;.core&lt;/code&gt; and &lt;code&gt;.plugins&lt;/code&gt;), Mix can incrementally recompile modified plugin files without invalidating the Core cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Ecosystem Tradeoffs:&lt;/strong&gt; Merging binary term manifests back into &lt;code&gt;compile.elixir&lt;/code&gt; ensures native Mix tasks remain functional.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>elixir</category>
      <category>erlang</category>
      <category>kernel</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Quando o telefone não encontra o dispositivo: uma caçada ao bug de pareamento WhatsApp em Elixir</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Wed, 02 Sep 2026 23:31:37 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/quando-o-telefone-nao-encontra-o-dispositivo-uma-cacada-ao-bug-de-pareamento-whatsapp-em-elixir-56ln</link>
      <guid>https://dev.to/matheuscamarques/quando-o-telefone-nao-encontra-o-dispositivo-uma-cacada-ao-bug-de-pareamento-whatsapp-em-elixir-56ln</guid>
      <description>&lt;p&gt;Depois de semanas de trabalho, o QR era gerado corretamente, o telefone escaneava... e nada. O WhatsApp dizia que não conseguia &lt;strong&gt;encontrar o dispositivo&lt;/strong&gt;. Sem &lt;code&gt;pair-success&lt;/code&gt;. Sem erro óbvio.&lt;/p&gt;

&lt;p&gt;Aqui está a história completa de como chegamos à causa raiz. Não foi no handshake criptográfico, não foi no registro, não foi no QR. Foi em uma função de 4 linhas que retornava a tupla errada.&lt;/p&gt;




&lt;h2&gt;
  
  
  O contexto
&lt;/h2&gt;

&lt;p&gt;Estamos portando o &lt;a href="https://github.com/WhiskeySockets/Baileys" rel="noopener noreferrer"&gt;Baileys&lt;/a&gt; (cliente WhatsApp Web em TypeScript) para um &lt;strong&gt;plugin Elixir&lt;/strong&gt; chamado &lt;code&gt;JusrisOsCore.Plugins.Baileys&lt;/code&gt;, dentro de um monólito modular (um projeto &lt;strong&gt;JusrisOS Core&lt;/strong&gt;). O princípio-guia que adotamos desde o início:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Baileys é o spec."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nada de inventar comportamento de protocolo: se o Baileys faz X, a gente faz X. A regra é clara porque o WhatsApp Web é um protocolo proprietário, fechado e que &lt;strong&gt;não perdoa desvios&lt;/strong&gt; — um byte errado no handshake e o servidor te descarta, às vezes silenciosamente.&lt;/p&gt;

&lt;p&gt;A arquitetura segue camadas &lt;code&gt;Support → Kernel → Plugins&lt;/code&gt;, com dependências puras no runtime (sem Rust/NIF no plugin). A criptografia é toda Elixir/&lt;code&gt;:crypto&lt;/code&gt; nativo (X25519, AES-256-GCM, Ed25519) — não usamos os NIFs &lt;code&gt;snow&lt;/code&gt;/&lt;code&gt;curve25519-dalek&lt;/code&gt; que o baileys_ex usa.&lt;/p&gt;

&lt;p&gt;Tínhamos três implementações de referência que &lt;strong&gt;funcionam&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Papel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/WhiskeySockets/Baileys" rel="noopener noreferrer"&gt;Baileys&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Fonte da verdade&lt;/strong&gt; (o spec)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;baileys_ex&lt;/td&gt;
&lt;td&gt;Elixir + Rust NIFs&lt;/td&gt;
&lt;td&gt;Port funcional, funciona&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wa-go / whatsapp-rust&lt;/td&gt;
&lt;td&gt;Go / Rust&lt;/td&gt;
&lt;td&gt;Outras reimplementações, funcionam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O objetivo era que o nosso port fosse &lt;strong&gt;byte-idêntico&lt;/strong&gt; ao baileys_ex no que importa.&lt;/p&gt;




&lt;h2&gt;
  
  
  O sintoma
&lt;/h2&gt;

&lt;p&gt;O pareamento QR do WhatsApp Web funciona assim (simplificado):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cliente conecta em &lt;code&gt;wss://web.whatsapp.com/ws/chat&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Executa o &lt;strong&gt;handshake Noise XX&lt;/strong&gt; (clientHello → serverHello → clientFinish).&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;clientFinish&lt;/code&gt;, envia o &lt;strong&gt;ClientPayload&lt;/strong&gt; (registro) cifrado.&lt;/li&gt;
&lt;li&gt;O servidor responde com um desafio &lt;code&gt;iq[xmlns=md] pair-device&lt;/code&gt; contendo 6 &lt;code&gt;&amp;lt;ref&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;O cliente responde &lt;code&gt;iq{to, type:result, id}&lt;/code&gt; (ack).&lt;/li&gt;
&lt;li&gt;O cliente gera o &lt;strong&gt;QR&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   https://wa.me/settings/linked_devices#&amp;lt;ref&amp;gt;,&amp;lt;noiseB64&amp;gt;,&amp;lt;identityB64&amp;gt;,&amp;lt;advB64&amp;gt;,&amp;lt;platformId=1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;O telefone escaneia → servidor verifica → envia &lt;code&gt;pair-success&lt;/code&gt; ao cliente.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nosso cliente chegava &lt;strong&gt;até o passo 6&lt;/strong&gt;. QR gerado, PNG bonito na tela. O telefone escaneava, girava o ícone... e o WhatsApp mostrava que &lt;strong&gt;não conseguia encontrar o dispositivo&lt;/strong&gt;. Nunca recebíamos o &lt;code&gt;pair-success&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O dado mais frustrante: nada no log parecia errado. O handshake "funcionava" (o &lt;code&gt;pair-device&lt;/code&gt; chegava), o ack "era enviado", o QR "era gerado". Mas o telefone não achava.&lt;/p&gt;




&lt;h2&gt;
  
  
  A estratégia: oráculo comparativo
&lt;/h2&gt;

&lt;p&gt;Como estávamos seguindo o Baileys à risca, a tática foi &lt;strong&gt;importar o baileys_ex para o nosso &lt;code&gt;mix.exs&lt;/code&gt; e comparar função a função&lt;/strong&gt;. O baileys_ex funciona, então ele é o padrão-ouro de comportamento.&lt;/p&gt;

&lt;p&gt;Primeiro passo: &lt;strong&gt;gerar um QR com o baileys_ex e escanear&lt;/strong&gt;. Se o baileys_ex pareasse, o problema era nosso. Se não pareasse, o problema era a conta/rede/ambiente.&lt;/p&gt;

&lt;p&gt;Rodamos o baileys_ex com um estado de auth fresco:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ensure_all_started&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:baileys_ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;BaileysEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;NativeFilePersistence&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;persisted_auth&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NativeFilePersistence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_native_file_auth_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;BaileysEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persisted_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;on_qr:&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;qr&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;O baileys_ex PAREOU.&lt;/strong&gt; O log mostrou:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[Wire] RECV tag=iq id=375824115 children=[pair-device] state=authenticating
[Wire] SEND tag=iq id=375824115 ... type=result to=s.whatsapp.net
... QR gerado ...
[Wire] RECV tag=iq id=311336498 children=[pair-success] state=authenticating
[Wire] SEND tag=iq id=311336498 ... type=result to=s.whatsapp.net
[PushNameDiag] creds_update changed push name previous=nil next="Matheus de Camargo Marques"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pair-success&lt;/code&gt; recebido, e o push name veio com o nome real da conta. &lt;strong&gt;O telefone achou o dispositivo do baileys_ex.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Isso foi o divisor de águas: &lt;strong&gt;telefone, conta e rede estavam OK.&lt;/strong&gt; O bug era 100% no nosso cliente. Como o registro é byte-idêntico e as chaves são as mesmas, a diferença tinha que estar no handshake ou na conexão.&lt;/p&gt;




&lt;h2&gt;
  
  
  As pistas falsas (e o que aprendemos com cada uma)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. O &lt;code&gt;registration_id&lt;/code&gt; fora do intervalo
&lt;/h3&gt;

&lt;p&gt;Nosso &lt;code&gt;Auth&lt;/code&gt; gerava o ID de registro com 24 bits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strong_rand_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# [0, 16.7M] — FORA DO RANGE!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas o Baileys TS faz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registrationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16384&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// 14 bits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o wa-go também: &lt;code&gt;k[0] &amp;amp;= 248; ...&lt;/code&gt; e &lt;code&gt;NewRegistrationID = &amp;amp; 16383&lt;/code&gt;. A referência usa &lt;strong&gt;14 bits&lt;/strong&gt;, &lt;code&gt;[0, 16383]&lt;/code&gt;. Corrigimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strong_rand_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Bitwise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16_383&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso o registro ficou &lt;strong&gt;byte-idêntico&lt;/strong&gt; ao baileys_ex (286 bytes). Mas o pareamento &lt;strong&gt;continuava falhando&lt;/strong&gt;. *pista falsa*&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A geração de chave X25519 bruta
&lt;/h3&gt;

&lt;p&gt;Usávamos &lt;code&gt;Curve25519.generate_key_pair()&lt;/code&gt; que retorna uma chave &lt;strong&gt;sem clamp&lt;/strong&gt;. Passamos a usar o &lt;code&gt;:crypto&lt;/code&gt; nativo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priv&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ecdh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:x25519&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# clamped (RFC 7748)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O efeito é o mesmo (ambas clamptam na derivação), então foi mais cosmético que a causa. *pista falsa* — e foi bom ter descartado.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. O hash inicial do handshake
&lt;/h3&gt;

&lt;p&gt;Nos debruçamos no &lt;code&gt;noise-handler.ts&lt;/code&gt; do Baileys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NOISE_HEADER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;// &amp;lt;&amp;lt;87, 65, 6, 3&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;// ← chave efêmera do CLIENTE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ficamos convencidos de que o nosso &lt;code&gt;new/2&lt;/code&gt; não autenticava a chave efêmera do cliente no hash inicial. Mas, ao reler, &lt;strong&gt;já estava lá&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@noise_wa_header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;public_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*pista falsa*. O hash estava correto.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A ordem do &lt;code&gt;authenticate&lt;/code&gt; no &lt;code&gt;encrypt&lt;/code&gt;/&lt;code&gt;decrypt&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;O noise &lt;code&gt;decrypt&lt;/code&gt; do nosso código fazia &lt;code&gt;authenticate(ciphertext)&lt;/code&gt;. O resumo anterior dizia que o Baileys TS autentica o &lt;em&gt;plaintext&lt;/em&gt;. Ao olhar no fonte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// encrypt → cifra&lt;/span&gt;
&lt;span class="mi"&gt;115&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// decrypt → cifra&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na verdade o Baileys autentica a &lt;strong&gt;cifra&lt;/strong&gt; nos dois. A nossa implementação &lt;strong&gt;batia&lt;/strong&gt;. *pista falsa*.&lt;/p&gt;




&lt;h2&gt;
  
  
  O caminho que faltava: o transporte
&lt;/h2&gt;

&lt;p&gt;Depois de descartar handshake, registro e QR (todos idênticos ao baileys_ex), a única diferença restante era o &lt;strong&gt;cliente WebSocket&lt;/strong&gt;. O baileys_ex usa &lt;code&gt;Mint.WebSocket&lt;/code&gt;; nós usávamos &lt;code&gt;WebSockex&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A pergunta do usuário foi a chave: &lt;strong&gt;"usa o mint na nossa implementação também."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Migrei o &lt;code&gt;transport.ex&lt;/code&gt; de um GenServer WebSockex para um GenServer usando &lt;code&gt;Mint.HTTP&lt;/code&gt; + &lt;code&gt;Mint.WebSocket&lt;/code&gt;, mantendo toda a lógica do handshake Noise intacta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Mint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;timeout:&lt;/span&gt; &lt;span class="mi"&gt;20_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mode:&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;protocols:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:http1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;transport_opts:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;cacerts:&lt;/span&gt; &lt;span class="ss"&gt;:public_key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cacerts_get&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;

&lt;span class="no"&gt;Mint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;WebSocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ws_scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="ss"&gt;mode:&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O socket do Mint é &lt;code&gt;active: :once&lt;/code&gt; por padrão, então o &lt;code&gt;GenServer&lt;/code&gt; recebe &lt;code&gt;{:tcp, socket, data}&lt;/code&gt; / &lt;code&gt;{:ssl, socket, data}&lt;/code&gt; e alimenta &lt;code&gt;Mint.WebSocket.stream(conn, msg)&lt;/code&gt; — o mesmo modelo do baileys_ex.&lt;/p&gt;

&lt;p&gt;Rodamos contra o servidor real: &lt;code&gt;clientHello → serverHello → clientFinish → pair-device → ack → QR&lt;/code&gt;. Tudo "funcionou"... &lt;strong&gt;menos um detalhe.&lt;/strong&gt; No log apareceu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt; &lt;span class="n"&gt;terminating&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ss"&gt;:websocket&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;JusrisOsCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Baileys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Protocol&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Noise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;State&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um crash assim que o ack era processado. E o ack tinha "enviado" — só que &lt;strong&gt;não tinha sido realmente enviado&lt;/strong&gt;, porque o &lt;code&gt;GenServer&lt;/code&gt; morreu antes.&lt;/p&gt;




&lt;h2&gt;
  
  
  A causa raiz: &lt;code&gt;encode_node&lt;/code&gt; retornava a tupla errada
&lt;/h2&gt;

&lt;p&gt;O ack passa por &lt;code&gt;encode_node&lt;/code&gt;, que fazia:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;encode_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;buff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WABinary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode_binary_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;Noise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode_frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;noise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# ← retorna {frame, noise_state}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare. &lt;code&gt;Noise.encode_frame&lt;/code&gt; retorna &lt;strong&gt;dois elementos&lt;/strong&gt;: o frame e o &lt;strong&gt;estado Noise&lt;/strong&gt; atualizado. O &lt;code&gt;encode_node&lt;/code&gt; repassava isso sem transformar. Mas os chamadores faziam:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encode_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# ctx vira o Noise.State!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aí estava o bug. Em Elixir, o &lt;code&gt;{:ok, ctx}&lt;/code&gt; de um map é reatribuível — mas aqui o segundo elemento não é o nosso &lt;code&gt;ctx&lt;/code&gt; (que carrega &lt;code&gt;conn&lt;/code&gt;, &lt;code&gt;websocket&lt;/code&gt;, &lt;code&gt;on_frame&lt;/code&gt;, etc.), é o &lt;strong&gt;estado interno do Noise&lt;/strong&gt;. Ao fazer &lt;code&gt;{frame, ctx} = encode_node(...)&lt;/code&gt;, a variável &lt;code&gt;ctx&lt;/code&gt; passa a apontar para o &lt;code&gt;%Noise.State{}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Quando o &lt;code&gt;handle_info({:send_wa_node, node}, ctx)&lt;/code&gt; chamava &lt;code&gt;send_frame(ctx, frame)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;send_frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Mint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;WebSocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# ctx.websocket → CRASH&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ctx.websocket&lt;/code&gt; sobre &lt;code&gt;%Noise.State{}&lt;/code&gt; → &lt;code&gt;KeyError&lt;/code&gt;. O transporte morria. E, como ele morria &lt;strong&gt;antes de realmente gravar o ack no socket&lt;/strong&gt;, o servidor &lt;strong&gt;nunca recebia o ack&lt;/strong&gt; do &lt;code&gt;pair-device&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;E foi isso o tempo todo. Sem o ack do &lt;code&gt;pair-device&lt;/code&gt;, o WhatsApp não marca o dispositivo como "pronto pra pareamento". O telefone escaneia, olha o ref, não acha o dispositivo ativo → &lt;strong&gt;"não consigo encontrar o dispositivo"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O mais cruel: o log mostrava &lt;code&gt;ENVIADO (iq) 35b&lt;/code&gt; porque a linha de log rodava &lt;strong&gt;antes&lt;/strong&gt; do &lt;code&gt;send_frame&lt;/code&gt; que crashava. Parecia que tinha enviado. Não tinha.&lt;/p&gt;

&lt;p&gt;A correção é uma linha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;encode_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;buff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WABinary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode_binary_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noise&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Noise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode_frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;noise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;noise:&lt;/span&gt; &lt;span class="n"&gt;noise&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;    &lt;span class="c1"&gt;# ← preserva o ctx (com conn/websocket/on_frame)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse bug &lt;strong&gt;também existia na versão WebSockex original&lt;/strong&gt; — o mesmo &lt;code&gt;{frame, ctx} = encode_node(...)&lt;/code&gt; reatribuía &lt;code&gt;ctx&lt;/code&gt; para o estado do Noise. Ou seja, a migração para Mint não "inventou" o problema; ela o tornou &lt;strong&gt;visível&lt;/strong&gt; (o crash do &lt;code&gt;Mint.WebSocket.encode&lt;/code&gt; era mais claro que o comportamento estranho do WebSockex após o estado corrompido).&lt;/p&gt;




&lt;h2&gt;
  
  
  A verificação
&lt;/h2&gt;

&lt;p&gt;Depois do fix, o fluxo real ficou assim, sem crash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clientHello enviado (36 bytes)
serverHello recebido (ephemeral: 32b, static: 48b, payload: 257b)
process_handshake OK (keyEnc: 48b)
ENVIADO (clientFinish) 361b
clientFinish enviado → modo transporte ativo
pair-device: 6 refs
node decodificado: tag="iq" attrs=%{"type" =&amp;gt; "set", "xmlns" =&amp;gt; "md"}
ack pair-device enviado (id=...)          ← AGORA enviado de verdade
ENVIADO (iq) 35b
✅ QR GERADO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O servidor também mandou um ping &lt;code&gt;urn:xmpp:ping&lt;/code&gt; antes de fechar a conexão ~30s depois — exatamente o comportamento do baileys_ex.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lições que eu levaria em conta
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"O X é a causa" é uma hipótese, não um fato.&lt;/strong&gt; Cada vez que achamos a "causa", validamos contra o oráculo (baileys_ex). Se o oráculo pareia e nós não, com registro byte-idêntico, então &lt;strong&gt;o bug está fora do que a gente acha que está errado&lt;/strong&gt;. A validação com o baileys_ex (gerar QR e escanear) foi o que separou "problema de ambiente/conta" de "bug no cliente".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quando tudo "funciona" mas falha, procure o que está silenciosamente errado na fronteira.&lt;/strong&gt; Aqui tudo funcionava porque o log era impresso &lt;strong&gt;antes&lt;/strong&gt; do crash. O frame era calculado, o log rodava, e só então o send quebrava. Mentira por omissão de logging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tuplas de retorno e reatribuição de variável é um buraco em Elixir.&lt;/strong&gt; &lt;code&gt;{a, ctx} = foo(ctx)&lt;/code&gt; onde &lt;code&gt;foo&lt;/code&gt; retorna &lt;code&gt;{a, outro_estado}&lt;/code&gt; reatribui &lt;code&gt;ctx&lt;/code&gt; silenciosamente. Vale um nome mais explícito (&lt;code&gt;{:ok, frame, %{ctx | noise: noise}}&lt;/code&gt;) para não deixar a reatribuição implícita.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Uma implementação de referência que funciona é o melhor debugger.&lt;/strong&gt; Ter o baileys_ex funcionando, importável no mesmo projeto, tornou cada comparação objetiva: primeiro baileys_ex para ver o comportamento esperado, depois o nosso para achar o desvio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O protocolo não perdoa.&lt;/strong&gt; O handshake pode estar "funcionando" (o servidor responde) e ainda assim a associação do dispositivo estar quebrada. O &lt;code&gt;pair-device&lt;/code&gt; é enviado de boa vontade; o que faz o telefone achar o dispositivo é o &lt;strong&gt;ack&lt;/strong&gt; e o estado da conexão — se o ack não chega, o servidor jamais "publica" o dispositivo.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  O que ficou
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lib/jusris_os_core/plugins/baileys/protocol/transport.ex&lt;/code&gt; — reescrito para &lt;strong&gt;Mint&lt;/strong&gt; (&lt;code&gt;Mint.HTTP&lt;/code&gt; + &lt;code&gt;Mint.WebSocket&lt;/code&gt;) e com o fix do &lt;code&gt;encode_node&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mix.exs&lt;/code&gt; — &lt;code&gt;{:websockex, ...}&lt;/code&gt; → &lt;code&gt;{:mint, "~&amp;gt; 1.6"}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auth_test.exs&lt;/code&gt; — assert do &lt;code&gt;push_name&lt;/code&gt; atualizado (o registro não mais fixa &lt;code&gt;"JusrisOS"&lt;/code&gt;, para casar com o baileys_ex).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todos os 443 testes do plugin passam; &lt;code&gt;mix compile --warnings-as-errors&lt;/code&gt; compila limpo após &lt;code&gt;mix clean&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O pareamento agora deve completar. A lição maior: quando você portar um protocolo fechado, &lt;strong&gt;tenha uma referência que funcione e compare tudo — inclusive as funções que você acha que não podem estar erradas.&lt;/strong&gt; O bug estava numa função de 4 linhas que o time todo tinha lido várias vezes.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>whatsapp</category>
      <category>baileys</category>
      <category>debugging</category>
    </item>
    <item>
      <title>How WhatsApp &amp; Signal Sign Messages Using X25519 Keys (Demystifying XEdDSA)</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Wed, 02 Sep 2026 15:08:05 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/how-whatsapp-signal-sign-messages-using-x25519-keys-demystifying-xeddsa-963</link>
      <guid>https://dev.to/matheuscamarques/how-whatsapp-signal-sign-messages-using-x25519-keys-demystifying-xeddsa-963</guid>
      <description>&lt;p&gt;If you have ever tried to implement the Signal Protocol or parse WhatsApp Multi-Device primitives in languages like Elixir, Go, or Rust, you likely hit a conceptual wall: &lt;strong&gt;"How are they using the exact same X25519 public key for Diffie-Hellman AND for verifying digital signatures?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The short answer is &lt;strong&gt;XEdDSA&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we will look at why XEdDSA exists, how it solves key reuse for Curve25519, and how to translate the math behind &lt;code&gt;axlsign&lt;/code&gt; / &lt;code&gt;TweetNaCl&lt;/code&gt; into clean code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: X25519 vs. Ed25519
&lt;/h2&gt;

&lt;p&gt;Curve25519 is one of the most widely used elliptic curves. However, it is commonly represented in two different mathematical forms:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Montgomery (X25519):&lt;/strong&gt; Optimized for &lt;strong&gt;Key Exchange (ECDH)&lt;/strong&gt;. It only stores the &lt;strong&gt;u&lt;/strong&gt; (or &lt;strong&gt;x&lt;/strong&gt;) coordinate of curve points.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twisted Edwards (Ed25519):&lt;/strong&gt; Optimized for &lt;strong&gt;Signatures (EdDSA)&lt;/strong&gt;. It stores complete &lt;strong&gt;(x, y)&lt;/strong&gt; coordinates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In traditional cryptographic designs, you need two separate key pairs per device: a key exchange key (X25519) and an identity/signing key (Ed25519). &lt;/p&gt;

&lt;p&gt;Managing, storing, and exchanging two sets of public keys per user increases protocol overhead. &lt;strong&gt;XEdDSA&lt;/strong&gt; (designed by Trevor Perrin for the Signal Foundation) solves this by enabling &lt;strong&gt;a single X25519 key pair to be used for both operations&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How XEdDSA Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;Instead of modifying the private key derivation, XEdDSA converts the Montgomery public key into the Edwards format &lt;strong&gt;before&lt;/strong&gt; signing or verifying.&lt;/p&gt;

&lt;p&gt;This conversion relies on a mathematical mapping called &lt;strong&gt;Birational Equivalence&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Point Mapping (u -&amp;gt; y)
&lt;/h3&gt;

&lt;p&gt;Given a point with coordinate &lt;strong&gt;u&lt;/strong&gt; on the Montgomery curve (X25519) over the finite field modulo &lt;strong&gt;p = 2^255 - 19&lt;/strong&gt;, the corresponding &lt;strong&gt;y&lt;/strong&gt; coordinate on the Edwards curve (Ed25519) is calculated as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;y = (u - 1) / (u + 1) mod p&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the &lt;strong&gt;u&lt;/strong&gt; coordinate on a Montgomery curve discards the sign of the &lt;strong&gt;v&lt;/strong&gt; coordinate, converting an X25519 public key to Edwards introduces a sign ambiguity. XEdDSA handles this deterministically by forcing the sign bit of the converted public key &lt;strong&gt;A&lt;/strong&gt; to &lt;strong&gt;0&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Verification Flow (XEd25519)
&lt;/h2&gt;

&lt;p&gt;When you receive a message signed with XEd25519, validation follows these steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[X25519 Key (u)] ----&amp;gt; Point Conversion (u -&amp;gt; y) ----&amp;gt; [Ed25519 Key (A)]
                                                              |
[Signature (R, s)] -------------------------------------------+---&amp;gt; Validate: s*B = R + h*A
[Message M]        ----&amp;gt; Hash: h = SHA512(R || A || M) -------+

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Recover Public Key A:&lt;/strong&gt; Take the 32-byte X25519 public key (representing &lt;strong&gt;u&lt;/strong&gt;) and compute the &lt;strong&gt;y&lt;/strong&gt; coordinate. Ensure the most significant bit (sign bit) is cleared.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpack Signature:&lt;/strong&gt; The 64-byte signature consists of &lt;strong&gt;R&lt;/strong&gt; (32 bytes, ephemeral Edwards point) and &lt;strong&gt;s&lt;/strong&gt; (32 bytes, scalar).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute Challenge Hash (h):&lt;/strong&gt; Compute &lt;strong&gt;h = SHA-512(R || A || M) mod L&lt;/strong&gt; (where &lt;strong&gt;L&lt;/strong&gt; is the curve order).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify Equation:&lt;/strong&gt; Check if the group equation &lt;strong&gt;s * B = R + h * A&lt;/strong&gt; holds true.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Implementing in Elixir: From Math to Code
&lt;/h2&gt;

&lt;p&gt;If you need to perform this verification in Elixir without relying on external native C dependencies, you can implement the field arithmetic using Erlang's &lt;code&gt;:crypto&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;Here is the core logic that converts an X25519 public key into the Edwards format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;XEd25519&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Prime p = 2^255 - 19&lt;/span&gt;
  &lt;span class="nv"&gt;@p&lt;/span&gt; &lt;span class="mi"&gt;57896044618658097711785492504343953926634992332820282019728792003956564819949&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Converts a Montgomery u public key (X25519) to an Edwards Y point (Ed25519).
  """&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;x25519_pk_to_ed25519&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;byte_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Decode Little-Endian bytes to Integer&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode_unsigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:little&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# y = (u - 1) * inv(u + 1) mod p&lt;/span&gt;
    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;den&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;den&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@p&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;@p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Encode back to 32-byte Little-Endian binary&lt;/span&gt;
    &lt;span class="n"&gt;y_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode_unsigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:little&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pad_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# In XEd25519, the sign bit of A (bit 255) is forced to 0&lt;/span&gt;
    &lt;span class="n"&gt;y_bytes&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Modular Inverse via Fermat's Little Theorem: a^(p-2) mod p&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="ss"&gt;:crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mod_pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode_unsigned&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;pad_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;byte_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;byte_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;pad_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Practical Shortcut with &lt;code&gt;libsodium&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If performance is critical in production, &lt;code&gt;libsodium&lt;/code&gt; provides native functions that perform point conversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In C / libsodium&lt;/span&gt;
&lt;span class="n"&gt;crypto_sign_ed25519_pk_to_curve25519&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;curve25519_pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ed25519_pk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Elixir, packages such as &lt;code&gt;:enacl&lt;/code&gt; expose C NIF bindings to handle these transformations efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;XEdDSA&lt;/strong&gt; is an elegant solution in modern cryptography: a mathematical bridge that eliminates key management complexity without sacrificing security. Protocols like Signal and WhatsApp rely on it to maintain a single identity key per device for billions of users.&lt;/p&gt;

&lt;p&gt;If you are writing protocol parsers or porting Signal clients to functional languages: &lt;strong&gt;convert the u coordinate to y, and you have an Ed25519 public key ready for signature verification.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>elixir</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The 80/20 Rule of AI Engineering: Why Rejection Pipelines Make Agentic Systems Work</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Wed, 02 Sep 2026 14:32:02 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/the-8020-rule-of-ai-engineering-why-rejection-pipelines-make-agentic-systems-work-4obn</link>
      <guid>https://dev.to/matheuscamarques/the-8020-rule-of-ai-engineering-why-rejection-pipelines-make-agentic-systems-work-4obn</guid>
      <description>&lt;h2&gt;
  
  
  The Paradigm Shift: From Code Generators to Systems Auditors
&lt;/h2&gt;

&lt;p&gt;With the rapid adoption of LLMs and autonomous coding agents, the core challenge of software engineering has shifted. The bottleneck is no longer &lt;strong&gt;generating syntax&lt;/strong&gt;, but &lt;strong&gt;enforcing deterministic boundaries around probabilistic engines&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you apply the Pareto Principle (80/20 Rule) to modern agentic workflows, a clear insight emerges: &lt;strong&gt;20% of your engineering effort spent on governance, strict contract design, and compliance pipelines solves 80% of the non-determinism, hallucinations, and regression issues in production.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lately, shifting focus exclusively toward test suites, compliance design, software architecture, and pre-commit validation cycles reveals a stark metric: &lt;strong&gt;only ~20% of the code generated by agents actually reaches production.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The remaining 80% is filtered out and rejected by automated quality gates. And that is by design.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Discardable Code vs. Expensive Human Labor
&lt;/h2&gt;

&lt;p&gt;When working with human software engineers, discarding 80% of written code is economically catastrophic. With LLMs, compute time is cheap, but production downtime caused by unverified code is extremely expensive.&lt;/p&gt;

&lt;p&gt;Treating agent-generated code as &lt;strong&gt;disposable artifacts&lt;/strong&gt; changes the developer feedback loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Do not fix an agent's code manually&lt;/strong&gt; if it violates architecture or fails integration tests.&lt;/li&gt;
&lt;li&gt;Adjust the &lt;strong&gt;contract (OpenAPI, Protobuf, Types)&lt;/strong&gt; or the system prompt.&lt;/li&gt;
&lt;li&gt;Force a clean regeneration cycle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the generated output fails a regression test or a linter, the pipeline rejects it instantly without human intervention. The engineer's efficiency is measured not by how much code is merged, but by the &lt;strong&gt;rigor of the filtration system&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Architectural Isolation in Multi-Agent Systems
&lt;/h2&gt;

&lt;p&gt;When orchestrating multiple agents working in parallel, avoiding race conditions, context pollution, and destructive side-effects requires strict system boundary enforcement:&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Isolation Mechanics
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Architectural Pattern&lt;/th&gt;
&lt;th&gt;System Benefit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Local short-term memory with strictly bounded read-only interfaces to global contracts.&lt;/td&gt;
&lt;td&gt;Prevents one agent's reasoning hallucinations from corrupting shared context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Communication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Asynchronous Event-Driven Architecture (Actor Model / Messaging Queues).&lt;/td&gt;
&lt;td&gt;Eliminates direct coupled side-effects between agent instances.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gatekeeping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static analysis, strict type enforcement, pre-eval loops.&lt;/td&gt;
&lt;td&gt;Instantly drops invalid ASTs before they touch the main branch.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Regression&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automated integration tests in isolated, ephemeral containers.&lt;/td&gt;
&lt;td&gt;Ensures zero regression without blocking parallel execution streams.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3. Contract-First &amp;amp; Spec-Driven Development
&lt;/h2&gt;

&lt;p&gt;To allow agents to operate independently, they must work against immutable constraints. &lt;strong&gt;Spec-Driven Development&lt;/strong&gt; serves as the anchor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schemas as Ground Truth:&lt;/strong&gt; Define input/output specifications, types, and invariant properties &lt;em&gt;before&lt;/em&gt; triggering the agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Oracle:&lt;/strong&gt; The test suite acts as the deterministic source of truth. An agent cannot negotiate with a failing unit test or a broken type-checker.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Academic References &amp;amp; Literature
&lt;/h2&gt;

&lt;p&gt;This practical shift towards rigorous validation pipelines and multi-agent coordination is backed by recent empirical research in software engineering and cognitive architectures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AgentBench: Evaluating LLMs as Agents&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Liu et al. (2023).&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Demonstrates the variance in LLM reliability when executing complex multi-step tasks, highlighting the necessity of rigid external validation and execution environments to mitigate agent failure modes in real-world operating systems and codebases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Communicative Agents for Software Development (ChatDev)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Qian et al. (2023).&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Analyzes multi-agent collaboration across the software development lifecycle (waterfall/agile stages). The research highlights how explicit role separation (reviewer, programmer, tester) and formal inspection phases drastically decrease bug density in agentic code generation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self-Correction and Self-Reflection in Large Language Models: A Survey&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Pan et al. (2024).&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Examines the limitations of internal LLM self-correction without external feedback. Confirms that agents require deterministic external feedback signals (unit test failures, compilers, static analyzers) to achieve reliable iterative improvement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Software Engineering in the Era of AI: A Roadmap for Automated Verification and Synthesis&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Godefroid et al. (2024).&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Explores the integration of formal methods, contract-first design, and property-based testing into AI-driven code generation, arguing that automated verification must serve as the primary gatekeeper in autonomous development workflows.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The key to unlocking scaling efficiency with AI agents isn't prompting better—it's &lt;strong&gt;building better software containment systems&lt;/strong&gt;. By shifting focus to high-impact foundations like contract design, compliance pipelines, and cognitive agent isolation, software engineers build a sustainable pipeline where 20% of high-quality code flows into production safely, backed by automated proof.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>testing</category>
      <category>devops</category>
    </item>
    <item>
      <title>Metacognição Multi-Agente e Consenso Causal via PON</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:27:11 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/metacognicao-multi-agente-e-consenso-causal-via-pon-1km5</link>
      <guid>https://dev.to/matheuscamarques/metacognicao-multi-agente-e-consenso-causal-via-pon-1km5</guid>
      <description>&lt;p&gt;À medida que os sistemas de IA evoluem de um único agente isolado para ecossistemas &lt;strong&gt;Multi-Agente&lt;/strong&gt;, a arquitetura tradicional enfrenta um gargalo crítico: a dependência de &lt;strong&gt;orquestradores centralizados&lt;/strong&gt; (como Grafos de Estado rígidos, pipelines sequenciais ou nós mestres de roteamento).&lt;/p&gt;

&lt;p&gt;Em um orquestrador centralizado, cada agente precisa se reportar a um coordenador que avalia o estado global, faz &lt;em&gt;polling&lt;/em&gt; nos subprocessos e decide a próxima chamada de API. O resultado é o inevitável:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cascata de Latência:&lt;/strong&gt; O tempo de resposta final é a soma linear da execução de todos os agentes mais o &lt;em&gt;overhead&lt;/em&gt; de serialização do orquestrador.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contenção de Estado:&lt;/strong&gt; O nó central vira um gargalo de memória e CPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rigidez Operacional:&lt;/strong&gt; Falhar um nó mestre interrompe toda a cadeia de raciocínio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Na natureza, sistemas complexos — desde enxames de insetos até redes neurais corticais — não possuem um "nó central controlador". O consenso emerge da interação reativa entre partes autônomas que notificam mudanças de estado para seus vizinhos imediatos.&lt;/p&gt;

&lt;p&gt;Para construir ecossistemas multi-agente escaláveis, precisamos migrar da orquestração procedural para o &lt;strong&gt;Consenso Causal baseado no Paradigma Orientado a Notificação (PON)&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Teoria da Mente em Agentes Distribuídos
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Teoria da Mente&lt;/strong&gt; é a capacidade cognitiva de inferir e representar os estados mentais, intenções e conhecimentos de outros indivíduos. Em um sistema distribuído de IA, isso significa que um agente deve compreender o contexto e a capacidade dos seus pares sem precisar disparar mensagens de consulta (&lt;em&gt;"Você está livre?", "O que você sabe sobre X?"&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;No Kernel PON, o estado de cada agente é mapeado diretamente em &lt;strong&gt;Atributos de Estado Globais/Replicados&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│               PON State Registry (Atributos em Memória)               │
│                                                                        │
│  [Agente_Pesquisa] ──► Status: Ocupado  │ Carga: 85% │ Especialidade: RAG │
│  [Agente_Validador] ──► Status: Livre    │ Carga: 10% │ Especialidade: Bacen│
│  [Agente_Síntese]   ──► Status: Repouso  │ Carga: 0%  │ Especialidade: LLM  │
└───────────────────────────────────┬────────────────────────────────────┘
                                    │
                         (Propagação por Notificação)
                                    │
                                    ▼
┌────────────────────────────────────────────────────────────────────────┐
│                        Notificação Causal Direct                       │
│  O Agente_Pesquisa atualiza seu estado ──► Notifica APENAS quem depende  │
│  de 'Status' e 'Especialidade' sem requisição de busca (Zero Polling).  │
└────────────────────────────────────────────────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em vez de enviar um prompt consultando a disponibilidade do Agente B, o Agente A lê o atributo notificado em memória em tempo de execução de complexidade &lt;code&gt;O(1)&lt;/code&gt;. A &lt;strong&gt;Teoria da Mente&lt;/strong&gt; deixa de ser uma troca de mensagens pesada entre LLMs e passa a ser uma &lt;strong&gt;matriz de estados notificados reativamente&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Consenso Causal e Negociação de Latência sem Locks
&lt;/h3&gt;

&lt;p&gt;Quando múltiplos agentes autônomos trabalham em um mesmo problema (ex: um agente de RAG vetorial, um agente de Busca em Grafo e um agente de Validação Regulatória), eles frequentemente entram em divergência ou competem por tempo de execução.&lt;/p&gt;

&lt;p&gt;No modelo tradicional, usam-se travas de sincronização (&lt;em&gt;locks&lt;/em&gt;) ou algoritmos de consenso síncronos (como Paxos/Raft adaptados), o que paralisa as threads até que todos respondam.&lt;/p&gt;

&lt;p&gt;Via &lt;strong&gt;PON&lt;/strong&gt;, o consenso é estritamente &lt;strong&gt;Causal e Reativo&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  A. Redes de Regras de Consenso (Rule-Nets)
&lt;/h4&gt;

&lt;p&gt;As regras de convergência habitam o próprio Kernel. Quando o Agente_RAG altera o atributo &lt;code&gt;Resposta_Parcial_V1&lt;/code&gt;, o nó da regra de consenso é notificado. Se a regra exige $N$ confirmações ou um limiar de confiança $\ge 0.85$, o nó avalia a condição instantaneamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Regra_Consenso: IF (RAG_Score &amp;gt;= 0.85 AND Regulatória_Status == :aprovado) 
                THEN Disparar(Agente_Síntese)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  B. Negociação Dinâmica de Latência (Window Shrinking)
&lt;/h4&gt;

&lt;p&gt;Se o Agente de Busca em Grafo percebe que vai demorar 800ms para concluir o percurso, ele atualiza seu atributo &lt;code&gt;Latência_Estimada&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Essa mudança &lt;strong&gt;notifica instantaneamente&lt;/strong&gt; o nó de regra do consenso, que reduz adaptativamente a janela de espera e força o sistema a tomar a decisão com as evidências disponíveis até o momento, eliminando estouros de &lt;em&gt;timeout&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Resolução Reativa de Conflitos sem Laços de Bloqueio
&lt;/h3&gt;

&lt;p&gt;Em cenários onde dois agentes geram hipóteses contraditórias (ex: Agente A sugere "Aprovar Crédito" e Agente B sugere "Recusar Crédito"), a resolução ocorre por &lt;strong&gt;Propagação Causal de Notificações&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────┐            ┌──────────────────────────────┐
│  Agente A: Hipótese (Aprovar) │            │   Agente B: Hipótese (Recusar)│
└──────────────┬───────────────┘            └──────────────┬───────────────┘
               │                                           │
         (Atualiza Estado)                           (Atualiza Estado)
               │                                           │
               └─────────────────────┬─────────────────────┘
                                     │
                                     ▼
                      ┌──────────────────────────────┐
                      │  Nó de Conflito (Rule-Net)   │
                      │  - Avalia DIVERGÊNCIA        │
                      └──────────────┬───────────────┘
                                     │
                     (Notifica Sub-Sistema Metacognitivo)
                                     │
                                     ▼
                      ┌──────────────────────────────┐
                      │    Arbitragem por Raciocínio │
                      │      Sistema 2 (Slow Path)   │
                      └──────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;A presença de valores contraditórios nos atributos aciona a &lt;strong&gt;Rule-Net de Conflito&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Essa regra não trava os agentes em laços &lt;code&gt;while(true)&lt;/code&gt;; ela gera uma &lt;strong&gt;notificação de arbitragem&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A notificação escala a decisão assincronamente para o &lt;strong&gt;Sistema 2 (Slow Path)&lt;/strong&gt;, enquanto os agentes de borda continuam livres para processar outros eventos da fila.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Tabela Comparativa: Multi-Agente Centralizado vs. Consenso Causal PON
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimensão&lt;/th&gt;
&lt;th&gt;Orquestração Centralizada (Grafos/Master)&lt;/th&gt;
&lt;th&gt;Consenso Causal via PON&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Arquitetura&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hierárquica / Nó Mestre de Roteamento&lt;/td&gt;
&lt;td&gt;Distribuída / Baseada em Notificação&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Teoria da Mente&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Troca de prompts/mensagens entre nós&lt;/td&gt;
&lt;td&gt;Atributos de estado compartilhados em &lt;code&gt;O(1)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resolução de Conflitos&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bloqueia o pipeline até resolver&lt;/td&gt;
&lt;td&gt;Reativa: Dispara nó de arbitragem assíncrono&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adição de Agentes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requer atualizar a lógica do orquestrador&lt;/td&gt;
&lt;td&gt;Agente apenas assina notificações de seu interesse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gargalo de CPU/Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alto no nó coordenador&lt;/td&gt;
&lt;td&gt;Distribuído por complexidade atômica &lt;code&gt;O(k)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Conclusão: Emergência sobre Controle
&lt;/h3&gt;

&lt;p&gt;Tentar controlar redes complexas de IA através de orquestradores centralizados rígidos é repetições dos erros da computação distribuída dos anos 90.&lt;/p&gt;

&lt;p&gt;A verdadeira metacognição multi-agente exige uma infraestrutura onde a &lt;strong&gt;comunicação seja tão barata quanto a própria mudança de estado&lt;/strong&gt;. Ao integrar o Paradigma Orientado a Notificação (PON) como a espinha dorsal de comunicação entre agentes autônomos, eliminamos o &lt;em&gt;overhead&lt;/em&gt; de orquestração e permitimos que o consenso emergente aconteça na velocidade da memória.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ia</category>
      <category>arquitetura</category>
      <category>backend</category>
    </item>
    <item>
      <title>Epigenética em IA: Modulação de Contexto sem Alteração do Código Base</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:26:16 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/epigenetica-em-ia-modulacao-de-contexto-sem-alteracao-do-codigo-base-154m</link>
      <guid>https://dev.to/matheuscamarques/epigenetica-em-ia-modulacao-de-contexto-sem-alteracao-do-codigo-base-154m</guid>
      <description>&lt;p&gt;Na biologia, o código genético (DNA) de um organismo é essencialmente estático. Uma célula da pele e um neurônio possuem exatamente a mesma sequência de nucleotídeos, mas desempenham papéis radicalmente opostos. O que determina quem expressa o quê é a &lt;strong&gt;Epigenética&lt;/strong&gt;: um conjunto de marcadores químicos que ligam, desligam ou atenuam genes com base no ambiente sem alterar uma única letra da fita primária de DNA.&lt;/p&gt;

&lt;p&gt;No desenvolvimento de arquiteturas de IA para cenários &lt;strong&gt;Multi-Tenant enterprise&lt;/strong&gt;, enfrentamos um desafio análogo:&lt;/p&gt;

&lt;p&gt;Como fazer com que o mesmo Kernel e os mesmos modelos de IA se comportem de forma totalmente personalizada para centenas de clientes, departamentos ou regulações distintas, &lt;strong&gt;sem precisar recalibrar pesos (fine-tuning)&lt;/strong&gt; e &lt;strong&gt;sem espalhar blocos condicionais (&lt;code&gt;if/else&lt;/code&gt;) pelo código-fonte&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;A solução é tratar o Kernel da aplicação e os pesos do LLM como o DNA imutável, introduzindo uma camada de &lt;strong&gt;Epigenética Computacional&lt;/strong&gt; em tempo de execução.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. O Dilema do Multi-Tenancy em LLMs
&lt;/h3&gt;

&lt;p&gt;As abordagens tradicionais para isolamento de comportamento em multi-tenancy falham em termos de sustentabilidade e custo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning por Tenant:&lt;/strong&gt; Criar modelos finetunados para cada cliente é inviável financeiramente e impraticável para manutenção de CI/CD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Engineering Procedural (&lt;code&gt;if/else&lt;/code&gt; no código):&lt;/strong&gt; Injetar regras específicas do cliente no código da aplicação gera débito técnico massivo e invalida estratégias de cache global.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bancos Vetoriais Duplicados:&lt;/strong&gt; Manter índices vetoriais separados por tenant aumenta exponencialmente o custo de infraestrutura e a latência de atualização.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A abordagem epigenética resolve isso separando o &lt;strong&gt;Genoma&lt;/strong&gt; (DNA estático da infraestrutura) do &lt;strong&gt;Epigenoma&lt;/strong&gt; (Camada de Modulação Contextual).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│                        GENOMA (DNA Imutável)                           │
│  - Modelo de Linguagem Base (Weights)                                 │
│  - Banco Vetorial Global e Índice Hierárquico                          │
│  - Kernel PON de Orquestração Reativa                                 │
└───────────────────────────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────┐
│                      EPIGENOMA (Marcadores de Tenant)                   │
│  - Prompts Epigenéticos (Ativação/Silenciamento de Regras)             │
│  - Máscaras e Pesos de Atenuação de Vetores                            │
│  - Restrições Regulatórias e Contexto Ambiental                        │
└───────────────────────────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────┐
│                 Fenótipo Resultante (Resposta Adaptada)                │
└────────────────────────────────────────────────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Prompts Epigenéticos: Ativação e Silenciamento de Expressão
&lt;/h3&gt;

&lt;p&gt;Assim como a metilação do DNA impede que determinados genes sejam transcritos, os &lt;strong&gt;Prompts Epigenéticos&lt;/strong&gt; atuam como modulações de contexto carregadas dinamicamente na borda (&lt;em&gt;Edge&lt;/em&gt;), sem tocar na lógica do Kernel.&lt;/p&gt;

&lt;p&gt;O tenant injeta um &lt;strong&gt;Metadado de Expressão&lt;/strong&gt; durante a requisição. Esse metadado não sobrescreve as instruções primárias de segurança do sistema, mas altera os pesos de atenção do modelo:&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo de Estrutura Epigenética:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DNA Base (Kernel):&lt;/strong&gt; &lt;code&gt;"Responda à dúvida do usuário com base no contexto fornecido mantendo rigor técnico."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marcador Epigenético (Tenant Financeiro):&lt;/strong&gt; &lt;code&gt;{ "metilação": ["girias", "especulação"], "expressão": ["conformidade_bacen", "tom_formal"] }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marcador Epigenético (Tenant Startup):&lt;/strong&gt; &lt;code&gt;{ "metilação": ["juridiquês"], "expressão": ["linguagem_direta", "exemplos_em_code"] }&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Kernel compõe a instrução final via &lt;strong&gt;Fusão Reativa de Atributos&lt;/strong&gt; no PON, garantindo que o modelo assuma a personalidade e as restrições corretas no milissegundo em que a requisição é avaliada.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Camadas de Atenuação e Máscaras Vetoriais
&lt;/h3&gt;

&lt;p&gt;No RAG bio-inspirado, os documentos e embeddings habitam uma base de dados unificada. Em vez de duplicar vetores para cada cliente, aplicamos &lt;strong&gt;Camadas de Atenuação de Embedding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quando uma busca vetorial é executada, o vetor de resposta passa por uma função de transformação linear de baixa latência em complexidade &lt;code&gt;O(N)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;V_efetivo = V_base ⊙ M_tenant

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Onde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;V_base&lt;/code&gt; é o embedding original do documento.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M_tenant&lt;/code&gt; é a &lt;strong&gt;máscara de modulação do cliente&lt;/strong&gt; (um vetor de pesos de atenuação que anula dimensões semânticas não permitidas para aquele perfil).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;⊙&lt;/code&gt; representa o &lt;strong&gt;produto de Hadamard&lt;/strong&gt; (multiplicação elemento a elemento).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso garante que um documento global de políticas internas traga apenas os aspectos jurídicos para o Tenant A, enquanto para o Tenant B os aspectos operacionais ganham maior relevância — &lt;strong&gt;usando exatamente a mesma representação vetorial no banco&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Tabela de Comparação: Arquitetura Tradicional vs. Epigenética
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimensão&lt;/th&gt;
&lt;th&gt;Multi-Tenancy Tradicional&lt;/th&gt;
&lt;th&gt;Modulação Epigenética&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Código do Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Repleto de lógicas &lt;code&gt;switch(tenant_id)&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;100% agnóstico e imutável&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Índice Vetorial&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fragmentado ou duplicado por cliente&lt;/td&gt;
&lt;td&gt;Compartilhado com Máscaras de Atenuação&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Peso dos LLMs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Necessita de Fine-Tuning ou LoRA adapters&lt;/td&gt;
&lt;td&gt;Modelo base compartilhado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inclusão de Clientes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requer alteração de código ou novos deploys&lt;/td&gt;
&lt;td&gt;Instantânea (apenas registro de novos marcadores)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tempo de Resposta&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Overhead por checagens condicionais&lt;/td&gt;
&lt;td&gt;Sub-milissegundo via atributos PON&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Conclusão: Evolução sem Mutação
&lt;/h3&gt;

&lt;p&gt;Construir software escalável exige evitar a mutação desnecessária do código principal. Ao adotar a Epigenética em IA, permitimos que uma única arquitetura cognitiva se adapte a infinitos domínios de negócio com elegância, mantendo a performance do Kernel intacta e eliminando o débito técnico de lógicas personalizadas hardcodadas.&lt;/p&gt;

&lt;p&gt;O futuro das arquiteturas multi-tenant não é multiplicar infraestruturas, mas sim &lt;strong&gt;aprender a modular o mesmo cérebro para diferentes contextos&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ia</category>
      <category>arquitetura</category>
      <category>multitenancy</category>
    </item>
    <item>
      <title>Memória Imunológica em IA: Guardrails Anti-Adversariais e Segurança Bio-Inspirada</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:14:06 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/memoria-imunologica-em-ia-guardrails-anti-adversariais-e-seguranca-bio-inspirada-3de9</link>
      <guid>https://dev.to/matheuscamarques/memoria-imunologica-em-ia-guardrails-anti-adversariais-e-seguranca-bio-inspirada-3de9</guid>
      <description>&lt;p&gt;Os métodos tradicionais de segurança em aplicações de IA sofrem de uma dicotomia ineficiente: ou utilizam &lt;strong&gt;filtros de texto estáticos rígidos&lt;/strong&gt; (regex e listas de palavras bloqueadas) que são facilmente contornados por variações sintáticas, ou dependem de &lt;strong&gt;LLMs avaliadores pesados&lt;/strong&gt; (Guardrail LLMs) rodando de forma síncrona na frente de cada requisição, disparando a latência e os custos operacionais.&lt;/p&gt;

&lt;p&gt;Enquanto isso, vetores de ataque como &lt;em&gt;Prompt Injections&lt;/em&gt;, &lt;em&gt;Jailbreaks&lt;/em&gt; indetectáveis e &lt;em&gt;Data Poisoning&lt;/em&gt; (envenenamento do banco vetorial por documentos maliciosos) continuam burlando as defesas corporativas.&lt;/p&gt;

&lt;p&gt;Na biologia, o corpo humano não envia cada molécula que entra na corrente sanguínea para análise deliberada no cérebro. O organismo conta com um &lt;strong&gt;Sistema Imunológico&lt;/strong&gt; dividido em duas camadas causais:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Imunidade Inata:&lt;/strong&gt; Reação imediata e genérica contra estruturas estranhas conhecidas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Imunidade Adaptativa:&lt;/strong&gt; Reconhecimento de novos patógenos, isolamento da ameaça, produção de anticorpos específicos e &lt;strong&gt;geração de memória imunológica&lt;/strong&gt; para neutralizações futuras instantâneas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para proteger uma Arquitetura Cognitiva em produção, precisamos traduzir estes princípios biológicos em um modelo de &lt;strong&gt;Segurança Bio-Inspirada e Reativa&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Linfócitos de Verificação Assíncrona
&lt;/h3&gt;

&lt;p&gt;No pipeline de execução de baixa latência, paralisar a requisição no &lt;em&gt;Fast Path&lt;/em&gt; para checar se o input é malicioso destrói a experiência do usuário. A abordagem bio-inspirada utiliza &lt;strong&gt;Linfócitos de Verificação Assíncrona&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Enquanto a Camada de Reflexo entrega a resposta inicial baseada nas regras de segurança do Sistema 1, &lt;em&gt;workers&lt;/em&gt; dedicados em background (operando como Linfócitos T e B) analisam as trajetórias semânticas e o comportamento dos payloads em tempo real.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;                      ┌──────────────────────────────┐
                      │      Entrada do Usuário      │
                      └──────────────┬───────────────┘
                                     │
               ┌─────────────────────┴─────────────────────┐
               │ (Fluxo Síncrono)                          │ (Fluxo Assíncrono)
               ▼                                           ▼
┌──────────────────────────────┐            ┌──────────────────────────────┐
│  Camada de Reflexo (S1)      │            │  Linfócitos de Verificação   │
│  - Checagem Inata Fast-Path  │            │  - Análise Semântica Fina    │
│  - Libera Resposta (&amp;lt;20ms)   │            │  - Detecção de Anomalias     │
└──────────────────────────────┘            └──────────────┬───────────────┘
                                                           │
                                             (Se detectar ameaça)
                                                           │
                                                           ▼
                                            ┌──────────────────────────────┐
                                            │  Disparo de Resposta Imune   │
                                            │  - Geração de Anticorpos     │
                                            │  - Quarentena do Vetor       │
                                            └──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o linfócito assíncrono detecta que uma requisição continha uma técnica sutil de &lt;em&gt;Prompt Injection&lt;/em&gt; (ex: marcações invisíveis em Unicode ou instruções ocultas em base64), ele não apenas bloqueia a sessão do usuário, mas dispara um evento causal no Kernel PON para vacinar o sistema.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Quarentena de Vetores e Antídotos Semânticos
&lt;/h3&gt;

&lt;p&gt;O risco de segurança mais crítico em sistemas de RAG enterprise não vem apenas da pergunta do usuário, mas do &lt;strong&gt;envenenamento de dados (Data Poisoning)&lt;/strong&gt;. Um documento malicioso inserido no SharePoint ou na base de conhecimento pode conter instruções ocultas (&lt;em&gt;Indirect Prompt Injection&lt;/em&gt;) para vazamento de dados confidenciais quando lido pelo LLM.&lt;/p&gt;

&lt;h4&gt;
  
  
  A. Particionamento em Quarentena (Vector Quarantine)
&lt;/h4&gt;

&lt;p&gt;Quando novos documentos são ingeridos no banco vetorial, eles não entram imediatamente no índice de produção principal. Eles habitam uma &lt;strong&gt;Partição de Quarentena&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scoring de Proveniência e Confiança:&lt;/strong&gt; Os vetores recebem uma nota de imunidade baseada na reputação da fonte e na análise de anomalias semânticas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provas de Estresse (Sandbox Prompts):&lt;/strong&gt; Documentos suspeitos passam por execuções de teste em ambiente isolado antes de serem liberados para o índice global.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolamento de Custo:&lt;/strong&gt; Chunks mantidos em quarentena não podem ser acessados pela Camada de Reflexo imediata.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  B. Antídotos Semânticos
&lt;/h4&gt;

&lt;p&gt;Se um vetor envenenado for inevitavelmente resgatado durante a busca, o sistema não precisa falhar completamente. A camada de Visão injeta um &lt;strong&gt;Antídoto Semântico&lt;/strong&gt; direto no prompt: uma instrução de sobreposição gerada dinamicamente que neutraliza o vetor de ataque sem perder a informação contextual legítima contida no documento.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Memória de Anticorpos (Cache Determinístico de Ataques)
&lt;/h3&gt;

&lt;p&gt;A verdadeira força do sistema imunológico reside na sua capacidade de &lt;strong&gt;lembrar&lt;/strong&gt;. Uma vez que um organismo é exposto a um vírus e o neutraliza, ele produz anticorpos para que a segunda exposição seja eliminada antes de causar qualquer sintoma.&lt;/p&gt;

&lt;p&gt;Na IA, traduzimos isso na criação de um &lt;strong&gt;Cache Determinístico de Anticorpos Semânticos&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Geração de Assinatura:&lt;/strong&gt; Quando o Linfócito de Verificação neutraliza um ataque inédito, ele extrai a "proteína de superfície" da ameaça (o padrão semântico essencial do ataque, abstraindo variações de palavras).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Armazenamento no Reflexo (Layer 1):&lt;/strong&gt; Essa assinatura é vetorizada e registrada diretamente no cache semântico de baixíssima latência (Redis / GenServer Memory).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bloqueio em $O(1)$:&lt;/strong&gt; Nas requisições subsequentes, tentativas parecidas com o ataque original não chegam nem perto de tocar em um LLM ou consumir recursos de inferência. A resposta imune bloqueia o payload na borda (&lt;em&gt;Edge&lt;/em&gt;) em sub-milissegundos.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Regra da Memória Imunológica:&lt;/strong&gt; Um ataque de prompt injection só deve custar tokens de processamento &lt;strong&gt;uma única vez&lt;/strong&gt; na história do seu sistema. Da segunda vez em diante, ele é destruído pelo anticorpo no reflexo.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Tabela Comparativa: Guardrails Tradicionais vs. Imunologia em IA
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Recurso&lt;/th&gt;
&lt;th&gt;Guardrails Tradicionais&lt;/th&gt;
&lt;th&gt;Sistema Imunológico Artificial&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inspecção&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Síncrona e bloqueante no pipeline&lt;/td&gt;
&lt;td&gt;Mista (Inata no reflexo + Linfócitos assíncronos)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Detecção de Injections&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Regex rígido ou LLM avaliador caro&lt;/td&gt;
&lt;td&gt;Anticorpos semânticos + Análise de anomalia causal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tratamento de Ingestão&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Indexação cega direta no Vector DB&lt;/td&gt;
&lt;td&gt;Particionamento em Quarentena com Sandbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custo de Re-Ataque&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Constante (Paga tokens em toda requisição)&lt;/td&gt;
&lt;td&gt;Próximo de zero ($O(1)$ via Memória de Anticorpos)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Conclusão: De Sistemas Vulneráveis a Organismos Imunes
&lt;/h3&gt;

&lt;p&gt;Tentar proteger aplicações modernas de Inteligência Artificial construindo muros rígidos de código procedural é uma batalha perdida. A variabilidade das linguagens naturais garante que atacantes sempre encontrarão uma brecha na sintaxe.&lt;/p&gt;

&lt;p&gt;Ao adotar uma arquitetura de &lt;strong&gt;Segurança Imunológica&lt;/strong&gt;, seu RAG deixa de ser um alvo passivo. Ele passa a monitorar ameaças assincronamente, isolar dados não confiáveis em quarentena e transformar cada tentativa de invasão em um novo &lt;strong&gt;anticorpo permanente&lt;/strong&gt; — garantindo que o sistema se torne exponencialmente mais forte e mais barato de defender a cada ataque sofrido.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ia</category>
      <category>arquitetura</category>
      <category>seguranca</category>
    </item>
    <item>
      <title>Homeostase Cognitiva e FinOps: Regulação Metabólica de Tokens e Compute</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:10:22 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/homeostase-cognitiva-e-finops-regulacao-metabolica-de-tokens-e-compute-46ki</link>
      <guid>https://dev.to/matheuscamarques/homeostase-cognitiva-e-finops-regulacao-metabolica-de-tokens-e-compute-46ki</guid>
      <description>&lt;p&gt;O cérebro humano representa apenas 2% da massa corporal, mas consome cerca de &lt;strong&gt;20% de toda a energia metabólica&lt;/strong&gt; do organismo. Em situações de estresse, escassez ou hipoxia, ele não entra em colapso desordenado; ele ativa mecanismos rigorosos de &lt;strong&gt;homeostase e alostase&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;O cérebro desliga funções secundárias, restringe o raciocínio profundo (Sistema 2), prioriza o reflexo (Sistema 1) e ajusta a taxa de queima de glicose token por token, garantindo a sobrevivência do organismo.&lt;/p&gt;

&lt;p&gt;No entanto, a maioria das arquiteturas de IA em produção opera no extremo oposto: &lt;strong&gt;são metabolicamente cegas&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Sob uma rajada súbita de requisições ou durante um pico de concorrência, a infraestrutura padrão continua tentando processar &lt;em&gt;prompts&lt;/em&gt; gigantescos de 32k tokens em modelos de última geração. O resultado é previsível: saturação de nós de processamento, estouro de limites de taxa (&lt;em&gt;Rate Limits&lt;/em&gt;) nas APIs de provedores e uma &lt;strong&gt;fatura de nuvem devastadora ao final do mês&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para construir sistemas de IA resilientes em escala enterprise, a gestão de custos (FinOps) e o controle de capacidade não podem ser métricas tratadas em dashboards a posteriori. Elas precisam atuar como um &lt;strong&gt;mecanismo homeostático metabólico em tempo real&lt;/strong&gt; rodando direto no Kernel da aplicação.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Feedback Loops Hormonais: O Endócrino da Infraestrutura
&lt;/h3&gt;

&lt;p&gt;Na biologia, o cortisol e a adrenalina modulam a prontidão e o consumo energético das células com base no estresse ambiental. Na engenharia de software, traduzimos isso substituindo o &lt;em&gt;Rate Limiting&lt;/em&gt; estático por &lt;strong&gt;Feedback Loops Hormonais&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;Rate Limiting&lt;/em&gt; tradicional (como o algoritmo de &lt;em&gt;Token Bucket&lt;/em&gt; rígido) é estúpido: ele bloqueia o usuário com um erro &lt;code&gt;429 Too Many Requests&lt;/code&gt; de forma binária. &lt;/p&gt;

&lt;p&gt;A regulação metabólica, por outro lado, introduz um &lt;strong&gt;Índice de Estresse Sistêmico (Hormônio de Cortisol)&lt;/strong&gt;, calculado continuamente pela infraestrutura com base em três fatores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Saturação de RAM/CPU&lt;/strong&gt; dos nós do Kernel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumo de Orçamento Financeiro em Tempo Real&lt;/strong&gt; (taxa de queima de tokens/minuto).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latência Média de Resposta&lt;/strong&gt; das chamadas de upstream.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;                  ┌──────────────────────────────┐
                  │    Sensores de Estresse      │
                  │  (CPU, Latência, Burn Rate)  │
                  └──────────────┬───────────────┘
                                 │
                                 ▼
                  ┌──────────────────────────────┐
                  │  Cálculo do Nível de Cortisol│
                  │       (Estado Hormonal)      │
                  └──────────────┬───────────────┘
                                 │
     ┌───────────────────────────┼───────────────────────────┐
     │ (Cortisol Baixo)          │ (Cortisol Médio)          │ (Cortisol Alto)
     ▼                           ▼                           ▼
┌───────────────────┐       ┌───────────────────┐       ┌───────────────────┐
│ Modo Abundância   │       │ Modo Conservação  │       │ Modo Sobrevivência│
│ - Modelo Superior │       │ - Modelo Médio    │       │ - Apenas Cache S1 │
│ - Contexto Total  │       │ - Context Throttling │   │ - Zero LLM Heavy  │
└───────────────────┘       └───────────────────┘       └───────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conforme o nível do "hormônio" sobe na aplicação, o sistema não rejeita requisições imediatamente; ele &lt;strong&gt;reconfigura metabolicamente o pipeline de execução&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Estrangulamento Adaptativo de Contexto (Context Throttling)
&lt;/h3&gt;

&lt;p&gt;A forma mais rápida de queimar dinheiro e estourar a memória dos nós de processamento é enviar vetores e documentos desnecessários no prompt. Quando o sistema entra em estado de estresse elevado, ele aciona o &lt;strong&gt;Context Throttling Adaptativo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em vez de truncar o texto arbitrariamente, a camada metabólica comprime a janela de atenção do sistema em tempo real:&lt;/p&gt;

&lt;h4&gt;
  
  
  A. Redução do Top-K Dinâmico
&lt;/h4&gt;

&lt;p&gt;Em condições normais (&lt;em&gt;homeostase de repouso&lt;/em&gt;), a busca no banco vetorial retorna $top_k = 20$ chunks para a Camada de Visão. Sob alto estresse, o limiar é estrangulado dinamicamente para $top_k = 5$, priorizando estritamente os vetores com score de similaridade mais alto.&lt;/p&gt;

&lt;h4&gt;
  
  
  B. Degradamento Elegante de Resolução (Downsampling)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status Normal:&lt;/strong&gt; Envia o documento pai completo (&lt;em&gt;Parent Chunk&lt;/em&gt;) com suporte a GraphRAG e cross-encoders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status de Estresse:&lt;/strong&gt; Suprime a busca em grafo, remove embeddings secundários e passa apenas os &lt;em&gt;Small Chunks&lt;/em&gt; limpos de texto plano.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status de Crise:&lt;/strong&gt; Desativa a chamada ao LLM deliberativo e responde exclusivamente via respostas em cache na &lt;strong&gt;Camada de Reflexo&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ganho Metabólico:&lt;/strong&gt; Redução imediata de até 75% no volume de tokens de entrada (&lt;em&gt;input tokens&lt;/em&gt;) sem interrupção total do serviço.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. Otimização Dinâmica de Custo por Resposta (Routing Genético)
&lt;/h3&gt;

&lt;p&gt;Um cérebro em modo de economia de energia não usa o córtex pré-frontal para espantar uma mosca. Da mesma forma, uma arquitetura de IA não deve utilizar um modelo de raciocínio de ponta (&lt;em&gt;Frontier Model&lt;/em&gt;) para responder a uma pergunta simples de FAQ ou validação de formulário.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Otimização Dinâmica de Custo&lt;/strong&gt; aplica o conceito de &lt;em&gt;Roteamento Metabólico de Modelos&lt;/em&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Nível de Estresse&lt;/th&gt;
&lt;th&gt;Custo Estimado / 1k req&lt;/th&gt;
&lt;th&gt;Modelo Utilizado&lt;/th&gt;
&lt;th&gt;Estratégia de Processamento&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Baixo (Normal)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R$ 15,00&lt;/td&gt;
&lt;td&gt;LLM Frontier (ex: GPT-4o / Gemini Pro)&lt;/td&gt;
&lt;td&gt;Contexto completo + GraphRAG + Reescrita&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Médio (Alerta)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R$ 2,50&lt;/td&gt;
&lt;td&gt;LLM Mid-tier (ex: Mini / Flash)&lt;/td&gt;
&lt;td&gt;Context Throttling ($top_k = 5$) + RAG Simples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Alto (Crise)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R$ 0,10&lt;/td&gt;
&lt;td&gt;Small Language Model Local / Cache&lt;/td&gt;
&lt;td&gt;Respostas pré-computadas + Regras de CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O chaveamento entre esses estados ocorre de forma &lt;strong&gt;reativa e sem restart&lt;/strong&gt;, orquestrado diretamente pelas notificações do Kernel (PON). Se a taxa de erro de um provedor dispara ou o limite financeiro do dia se aproxima, as instâncias de aplicação adaptam seus roteadores instantaneamente.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Integração com o Kernel PON
&lt;/h3&gt;

&lt;p&gt;A regulação metabólica depende de baixíssima latência para ser efetiva. Se a checagem de custo ou o cálculo do nível de estresse demorar 100ms, o próprio mecanismo de defesa vira o gargalo.&lt;/p&gt;

&lt;p&gt;Aqui, o &lt;strong&gt;Paradigma Orientado a Notificação (PON)&lt;/strong&gt; atua como a rede nervosa:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A métrica de estresse atualiza o Atributo &lt;code&gt;SystemStressLevel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A alteração de estado dispara uma &lt;strong&gt;Notificação de Regra&lt;/strong&gt; no Kernel.&lt;/li&gt;
&lt;li&gt;Os nós de execução do RAG alteram seus ponteiros de rotas em tempo de memória ($O(1)$) antes mesmo de processar a próxima requisição na fila.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusão: Sistemas Sustentáveis não Queimam Recursos à Toa
&lt;/h3&gt;

&lt;p&gt;FinOps em Inteligência Artificial não consiste em cortar custos às cegas ou limitar a capacidade dos modelos. Trata-se de dar ao software a &lt;strong&gt;inteligência biológica da sobrevivência&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Arquiteturas que operam com regulação metabólica em tempo real respondem com a precisão máxima quando os recursos são abundantes, mas sabem encolher sua pegada computacional, economizar tokens e proteger a infraestrutura nos momentos de estresse.&lt;/p&gt;

&lt;p&gt;Um RAG maduro para produção não é apenas aquele que acerta a resposta — é aquele que sabe exatamente a quantidade de energia necessária para entregá-la.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ia</category>
      <category>arquitetura</category>
      <category>finops</category>
    </item>
    <item>
      <title>Como integrar APIs de IA (Deep Seek V4 ou GPT-4 Flash) gratuitamente em seus agentes e automações</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:03:42 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/como-integrar-apis-de-ia-deep-seek-v4-ou-gpt-4-flash-gratuitamente-em-seus-agentes-e-automacoes-4md3</link>
      <guid>https://dev.to/matheuscamarques/como-integrar-apis-de-ia-deep-seek-v4-ou-gpt-4-flash-gratuitamente-em-seus-agentes-e-automacoes-4md3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Como integrar APIs de IA (GPT-4 Flash) gratuitamente em seus agentes e automações&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Manter rotinas de automação no n8n, Typebot ou agentes de IA com chamadas em dólar e cobrança por token impacta rapidamente o custo de qualquer projeto. Para prototipar ou escalar fluxos sem estourar o orçamento, é possível utilizar provedores com cotas zeradas de entrada e saída (&lt;code&gt;Input: $0&lt;/code&gt; / &lt;code&gt;Output: $0&lt;/code&gt;), como a plataforma B.ai, para acessar modelos como o GPT-4 Flash e Vision de forma gratuita.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Passo 1: Criar a conta e acessar o painel&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Acesse o painel pelo &lt;a href="https://chat.b.ai/chat?invite_code=JZLCVY" rel="noopener noreferrer"&gt;link de cadastro na B.ai&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Faça o login utilizando sua conta Google.&lt;/li&gt;
&lt;li&gt;No menu principal, clique na aba &lt;strong&gt;API&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Passo 2: Gerar a API Key e copiar a Base URL&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verifique na lista os modelos disponíveis que apresentam consumo zerado para entrada e saída de dados (ex: &lt;code&gt;GPT-4 Flash&lt;/code&gt; ou &lt;code&gt;GPT-4 Flash Vision&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Criar API&lt;/strong&gt;, defina um nome para a chave (ex: &lt;code&gt;automations-prod&lt;/code&gt;) e confirme.&lt;/li&gt;
&lt;li&gt;Copie e armazene a chave gerada.&lt;/li&gt;
&lt;li&gt;Copie a &lt;strong&gt;Base URL&lt;/strong&gt; da API exibida na página, garantindo que o endereço termine em &lt;code&gt;/v1&lt;/code&gt; (exemplo: &lt;code&gt;https://.../v1&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Passo 3: Configuração em Agentes (Exemplo via Hermes CLI / Custom Endpoint)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Por utilizar a especificação padrão da OpenAI, o endpoint pode ser plugado em qualquer ferramenta compatível com chamadas HTTP/REST personalizadas.&lt;/p&gt;

&lt;p&gt;Em um ambiente de linha de comando ou agente via VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Acessar o ambiente do agente&lt;/span&gt;
su - hermes
hermes setup model

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Selecione a opção &lt;strong&gt;Custom Endpoint&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Insira a &lt;strong&gt;Base URL&lt;/strong&gt; copiada do painel (finalizando em &lt;code&gt;/v1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Insira a sua &lt;strong&gt;API Key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Escolha o tipo de requisição (&lt;code&gt;Chat&lt;/code&gt;) e selecione o modelo desejado (&lt;code&gt;GPT-4 Flash&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Aplicações recomendadas&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Typebot / Chatbots de Vendas:&lt;/strong&gt; Respostas de mensagens e contorno de objeções no WhatsApp sem custo operacional por token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipelines no n8n:&lt;/strong&gt; Automação de extração e estruturação de texto em workflows de backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototipagem de Agentes:&lt;/strong&gt; Validação de arquiteturas multi-agente e chamadas de ferramentas antes de migrar para infraestruturas pagas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Nota: As gratuidades de chamadas dependem de campanhas de infraestrutura dos provedores e podem sofrer alterações sem aviso prévio. O recomendado é criar as credenciais e aproveitar a cota zerada para testes e desenvolvimento.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>help</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>PON como Kernel Cognitivo: Paradigma Orientado a Notificação para RAGs Bio-Inspirados</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:46:55 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/pon-como-kernel-cognitivo-paradigma-orientado-a-notificacao-para-rags-bio-inspirados-23b1</link>
      <guid>https://dev.to/matheuscamarques/pon-como-kernel-cognitivo-paradigma-orientado-a-notificacao-para-rags-bio-inspirados-23b1</guid>
      <description>&lt;p&gt;Ao longo de toda a nossa jornada, desconstruímos o RAG tradicional e desenhamos uma verdadeira &lt;strong&gt;Arquitetura Cognitiva Bio-Inspirada&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Substituímos o repositório estático por &lt;strong&gt;Ciclos de Sonho&lt;/strong&gt; e consolidação noturna.&lt;/li&gt;
&lt;li&gt;Dividimos o fluxo de decisão em &lt;strong&gt;Sistema 1 (Reflexo / Fast Path)&lt;/strong&gt; e &lt;strong&gt;Sistema 2 (Razão / Slow Path)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Mapeamos a infraestrutura em camadas de &lt;strong&gt;Reflexo, Visão e Esquecimento&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Damos tridimensionalidade ao contexto com &lt;strong&gt;Percepção Espaço-Temporal em 4D&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Garantimos a sobrevivência do sistema através de &lt;strong&gt;Algoritmos Adaptativos e Evolutivos&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Porém, quando colocamos todas essas peças para rodar juntas em produção, esbarramos em um &lt;strong&gt;gargalo estrutural de infraestrutura&lt;/strong&gt;: a forma como os processos se comunicam.&lt;/p&gt;

&lt;p&gt;Se a sua arquitetura tenta unir essas camadas usando o modelo tradicional de requisição-resposta (polling, loops de checagem ou pipeline linear de funções), ela colapsa sob o próprio peso. A latência acumula, o &lt;em&gt;overhead&lt;/em&gt; de CPU dispara e o determinismo do tempo de resposta é destruído.&lt;/p&gt;

&lt;p&gt;Na biologia, o cérebro &lt;strong&gt;não faz polling&lt;/strong&gt;. Um neurônio não fica perguntando aos vizinhos a cada milissegundo se eles mudaram de estado. Ele repousa em silêncio absoluto até que um potencial de ação atinja o limiar — momento em que dispara uma &lt;strong&gt;notificação pontual e reativa&lt;/strong&gt; apenas para as conexões sinápticas afetadas.&lt;/p&gt;

&lt;p&gt;Para construir o kernel definitivo dessa arquitetura cognitiva, precisamos adotar o &lt;strong&gt;Paradigma Orientado a Notificação (PON)&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  O Que é o PON (Paradigma Orientado a Notificação)?
&lt;/h3&gt;

&lt;p&gt;O &lt;strong&gt;Paradigma Orientado a Notificação (PON)&lt;/strong&gt; é um paradigma de programação e arquitetura que rompe com os modelos estruturado e orientado a objetos tradicionais. &lt;/p&gt;

&lt;p&gt;Em vez de avaliar condições repetidamente via laços de controle (&lt;code&gt;if/else&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;polling&lt;/code&gt;) ou encadear chamadas de métodos onde o chamador precisa esperar a resposta, o PON divide a lógica em entidades causais discretas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rule-Nets (Redes de Regras):&lt;/strong&gt; A regra de negócio é decomposta em nós atômicos de condição e ação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes &amp;amp; States:&lt;/strong&gt; Os dados habitam instâncias que notificam diretamente os nós condicionais interessados apenas quando o seu valor se altera.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Causalidade Pura:&lt;/strong&gt; Um nó de avaliação só executa cálculo se for explicitamente notificado de que uma de suas dependências diretas mudou.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Inversão do Fluxo:&lt;/strong&gt; No modelo tradicional, o código &lt;em&gt;busca&lt;/em&gt; o dado para testar o estado. No PON, a &lt;em&gt;mudança de estado&lt;/em&gt; notifica pontualmente apenas quem precisa agir.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Por que o PON é o Kernel Perfeito para a Arquitetura Cognitiva?
&lt;/h3&gt;

&lt;p&gt;Unir Sistema 1/2, busca em Grafos, janelas temporais, decay de vetores e &lt;em&gt;Contextual Bandits&lt;/em&gt; em uma única requisição de usuário cria uma teia complexa de dependências.&lt;/p&gt;

&lt;p&gt;Usar o PON como o &lt;strong&gt;Kernel Reativo&lt;/strong&gt; desta arquitetura traz três vantagens críticas:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Sub-Latência e Custo Computacional Mínimo
&lt;/h4&gt;

&lt;p&gt;Sem laços de varredura ou reavaliação de estado desnecessária, o consumo de CPU da camada de orquestração despenca para próximo de zero enquanto o sistema aguarda eventos. A execução de regras e rotas ocorre com &lt;strong&gt;complexidade temporal $O(1)$ a $O(k)$&lt;/strong&gt; (onde $k$ é o número de atributos alterados), em vez de $O(N)$ sobre todas as regras do sistema.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Ativação Sináptica Dinâmica (Reflexo vs. Razão)
&lt;/h4&gt;

&lt;p&gt;O &lt;em&gt;Gating Mechanism&lt;/em&gt; (Sistema 1 / Sistema 2) deixa de ser uma decisão procedural rígida. Ele torna-se uma &lt;strong&gt;Rede de Notificação&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A entrada do usuário atualiza o atributo de estado &lt;code&gt;QueryContext&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se o score de similaridade com o Cache Semântico bater o limiar de alta confiança, o nó do &lt;strong&gt;Sistema 1 (Reflexo)&lt;/strong&gt; aciona a notificação de resposta &lt;strong&gt;imediatamente&lt;/strong&gt;, interrompendo a propagação para os nós mais pesados.&lt;/li&gt;
&lt;li&gt;Se o atributo indicar ambiguidade ou alta complexidade, a notificação se propaga para a &lt;strong&gt;Camada de Visão Espaço-Temporal&lt;/strong&gt; e aciona o &lt;strong&gt;Sistema 2 (Razão)&lt;/strong&gt; de forma assíncrona.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Orquestração com Concorrência Massiva (Erlang/BEAM)
&lt;/h4&gt;

&lt;p&gt;O casamento do PON com ecossistemas de alta concorrência baseados no Actor Model (como Erlang/OTP e Elixir na BEAM) cria um kernel indestrutível. Cada nó de regra ou entidade de conhecimento opera como um processo leve e isolado, trocando mensagens determinísticas acionadas estritamente por notificações.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Topologia do Kernel Cognitivo Orientado a Notificação
&lt;/h3&gt;

&lt;p&gt;O diagrama abaixo ilustra como as notificações fluem pelo kernel sem chamadas bloqueantes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;                  ┌──────────────────────────────┐
                  │    Input: Evento de Query    │
                  └──────────────┬───────────────┘
                                 │
                    (Notifica Mudança de Estado)
                                 │
                                 ▼
                  ┌──────────────────────────────┐
                  │  Atributos do QueryContext   │
                  └──────────────┬───────────────┘
                                 │
           ┌─────────────────────┴─────────────────────┐
           │                                           │&lt;span class="sb"&gt;


&lt;/span&gt;(Notificação / Condição S1)                 (Notificação / Condição S2)
│                                           │
▼                                           ▼
┌──────────────────────────────┐            ┌──────────────────────────────┐
│  Nó de Regra: Fast Path      │            │  Nó de Regra: Slow Path      │
│  - Match no Cache (&amp;gt;0.95)    │            │  - Baixa Confiança           │
│  - Resposta do Reflexo       │            │  - Enriquecimento em Grafo   │
└──────────────┬───────────────┘            └──────────────┬───────────────┘
│                                           │
(Dispara Ação)                              (Dispara Ação)
│                                           │
▼                                           ▼
┌──────────────────────────────┐            ┌──────────────────────────────┐
│   Retorno em Sub-Latência    │            │  Raciocínio Espaço-Temporal  │
│          (&amp;lt; 10ms)            │            │         (4D Pipeline)        │
└──────────────────────────────┘            └──────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  O Ciclo Completo: Do Kernel ao Ecossistema Vivo
&lt;/h3&gt;

&lt;p&gt;Com a introdução do PON como Kernel, fechamos o ciclo da nossa arquitetura cognitiva integrada:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Kernel Reativo (PON):&lt;/strong&gt; Garante a orquestração reativa, paralela e de ultra-baixa latência baseada em notificações pontuais.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sistema 1 &amp;amp; Sistema 2:&lt;/strong&gt; Chaveiam o fluxo de execução com base no estado notificado pelo contexto da requisição.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflexo, Visão e Esquecimento:&lt;/strong&gt; O Reflexo responde via acionamento rápido de notificação; a Visão conecta dados no espaço-tempo; o Esquecimento (poda) atualiza os estados no background para desativar regras obsoletas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algoritmos Evolutivos &amp;amp; Adaptativos:&lt;/strong&gt; Ajustam os pesos e limiares das Notificações de Regra (Rule-Nets), garantindo que a topologia do sistema evolua com o tempo.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusão: O Fim do Polling na Inteligência Artificial
&lt;/h3&gt;

&lt;p&gt;A inteligência de alto desempenho não combina com estruturas procedurais rígidas. Para que modelos de linguagem, bancos de dados vetoriais, grafos e agentes operem em sintonia, o &lt;em&gt;middleware&lt;/em&gt; que os une precisa ser tão eficiente quanto a biologia que o inspirou.&lt;/p&gt;

&lt;p&gt;O Paradigma Orientado a Notificação fornece os &lt;strong&gt;trilhos causais&lt;/strong&gt; que faltavam: ele elimina o desperdício computacional, transforma a orquestração em uma teia de reações em cadeia determinísticas e entrega o kernel de ultra-baixa latência necessário para sustentarmos sistemas cognitivos vivos em produção.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ia</category>
      <category>arquitetura</category>
      <category>backend</category>
    </item>
    <item>
      <title>IA Bio-Inspirada: Algoritmos Evolutivos e Adaptativos na Prática do RAG</title>
      <dc:creator>Matheus de Camargo Marques</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:42:54 +0000</pubDate>
      <link>https://dev.to/matheuscamarques/ia-bio-inspirada-algoritmos-evolutivos-e-adaptativos-na-pratica-do-rag-33a9</link>
      <guid>https://dev.to/matheuscamarques/ia-bio-inspirada-algoritmos-evolutivos-e-adaptativos-na-pratica-do-rag-33a9</guid>
      <description>&lt;p&gt;Ao longo desta série, reconstruímos a arquitetura de RAG do zero. Deixamos para trás o modelo estático de "banco de dados burro" e projetamos um sistema dotado de &lt;strong&gt;Ciclos de Sonho&lt;/strong&gt;, alinhamento entre &lt;strong&gt;Sistema 1 e Sistema 2&lt;/strong&gt;, camadas de &lt;strong&gt;Reflexo, Visão e Esquecimento&lt;/strong&gt;, e percepção &lt;strong&gt;Espaço-Temporal em 4D&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Mas ainda resta um problema crítico de engenharia: &lt;strong&gt;quem ajusta os hiperparâmetros da sua arquitetura em produção?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Na maioria das empresas, decisões como o tamanho do &lt;em&gt;chunk&lt;/em&gt;, os pesos da busca híbrida (BM25 vs. Vetor), os limiares de &lt;em&gt;gating&lt;/em&gt; do Sistema 1/2 e os &lt;em&gt;prompts&lt;/em&gt; de reescrita são &lt;strong&gt;estáticos e codificados na mão&lt;/strong&gt; (&lt;em&gt;hardcoded&lt;/em&gt;). O engenheiro escolhe um valor arbitrário, faz o &lt;em&gt;deploy&lt;/em&gt; e torce para que funcione bem para todos os tipos de consulta.&lt;/p&gt;

&lt;p&gt;A biologia não opera com parâmetros estáticos. Organismos vivos sobrevivem há bilhões de anos porque possuem dois mecanismos complementares de sobrevivência:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Adaptação (Plasticidade Sináptica em Tempo Real):&lt;/strong&gt; Ajustes rápidos no comportamento do indivíduo em resposta ao ambiente dinâmico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evolução (Algoritmos Genéticos e Seleção Natural):&lt;/strong&gt; Mudanças estruturais na população ao longo de gerações, eliminando o que é ineficiente e multiplicando o que funciona.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para que a sua Arquitetura Cognitiva seja verdadeiramente resiliente, ela precisa parar de ser um código rígido e passar a operar como um &lt;strong&gt;ecossistema evolutivo&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Algoritmos Adaptativos: Plasticidade Sináptica no Runtime
&lt;/h3&gt;

&lt;p&gt;A camada adaptativa lida com o imediato. Ela ajusta o comportamento do pipeline em tempo real com base no perfil da requisição e no &lt;em&gt;feedback&lt;/em&gt; imediato do usuário ou do sistema.&lt;/p&gt;

&lt;p&gt;Em um RAG tradicional, o peso da busca vetorial contra a busca léxica é fixo (ex: 70% Vetor / 30% BM25). Porém, perguntas sobre um código de erro numérico exigem 100% de busca léxica, enquanto perguntas conceituais exigem 100% de busca semântica.&lt;/p&gt;

&lt;p&gt;Para resolver isso sem criar rotinas manuais de &lt;code&gt;if/else&lt;/code&gt; infinitas, utilizamos &lt;strong&gt;Algoritmos Adaptativos&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  A. Contextual Bandits (Multi-Armed Bandits)
&lt;/h4&gt;

&lt;p&gt;Em vez de um roteador estático para o &lt;em&gt;Confidence Gate&lt;/em&gt; (Sistema 1 vs. Sistema 2), o roteador utiliza um modelo de &lt;strong&gt;Contextual Bandits&lt;/strong&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Funcionamento:&lt;/strong&gt; O algoritmo testa diferentes estratégias de recuperação para diferentes categorias de perguntas. Se a estratégia X (ex: busca em grafo simples) resolver a dúvida com baixa latência e alta nota de &lt;em&gt;eval&lt;/em&gt;, o bandit aumenta a probabilidade de escolher essa rota para perguntas similares no futuro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resultado:&lt;/strong&gt; O sistema aprende sozinho qual o caminho de menor custo e menor latência para cada tipo de input sem intervenção humana.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  B. Dynamic Chunking e Ajuste de Temperatura
&lt;/h4&gt;

&lt;p&gt;A plasticidade sináptica também ajusta o nível de esforço do LLM. Se a entrada é classificada como ambígua, o sistema ajusta dinamicamente a temperatura, expande o tamanho do contexto recuperado (&lt;em&gt;top-k&lt;/em&gt;) e eleva a sensibilidade dos filtros de segurança no reflexo.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Algoritmos Evolutivos: A Seleção Natural de Prompts e Topologias
&lt;/h3&gt;

&lt;p&gt;Enquanto os algoritmos adaptativos fazem ajustes finos em milissegundos, os &lt;strong&gt;Algoritmos Evolutivos&lt;/strong&gt; operam em &lt;em&gt;background&lt;/em&gt; (durante os &lt;strong&gt;Ciclos de Sonho&lt;/strong&gt;) para promover mutações estruturais na base de conhecimento e nos componentes do sistema.&lt;/p&gt;

&lt;p&gt;Inspirados na seleção natural darwiniana, aplicamos quatro operadores biológicos na arquitetura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;              ┌───────────────────────────────┐
              │ População Inicial de Prompts  │
              │   e Parâmetros de Chunking    │
              └───────────────┬───────────────┘
                              │
                              ▼
              ┌───────────────────────────────┐
              │       Avaliação de Fitness   │
              │   (Evals: Latência + Cost +   │
              │      Context Precision)       │
              └───────────────┬───────────────┘
                              │
                              ▼
              ┌───────────────────────────────┐
              │     Seleção e Expurgo         │
              │   (Sobrevivem os Melhores)    │
              └───────────────┬───────────────┘
                              │
                              ▼
              ┌───────────────────────────────┐
              │    Crossover e Mutação        │
              │  (Geração de Novas Variantes) │
              └───────────────┬───────────────┘
                              │
                              └────────► (Repete no Ciclo Noturno)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1. A Função de Aptidão (Fitness Function)
&lt;/h4&gt;

&lt;p&gt;Para haver evolução, é preciso haver pressão seletiva. A &lt;em&gt;Fitness Function&lt;/em&gt; do seu RAG é um cálculo composto por métricas FinOps e de qualidade:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fitness = (Precisão do Contexto × Relevância da Resposta) / (Custo em Tokens × Latência em Segundos)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  2. Mutação de Prompts de Reescrita e Raciocínio
&lt;/h4&gt;

&lt;p&gt;Em vez de manter um único &lt;em&gt;prompt&lt;/em&gt; estático para reescrever as perguntas do usuário, o sistema mantém uma &lt;strong&gt;população de prompts&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Durante o ciclo noturno, &lt;em&gt;workers&lt;/em&gt; usam técnicas de mutação genômica (geradas por LLMs) para alterar ligeiramente as instruções, criar variações de poucas palavras ou mudar a ordem das regras. As mutações que obtiverem a maior pontuação de &lt;em&gt;Fitness&lt;/em&gt; na suíte de testes (&lt;em&gt;Golden Dataset&lt;/em&gt;) tornam-se os novos "genes dominantes" da aplicação.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Crossover de Estratégias de Recuperação
&lt;/h4&gt;

&lt;p&gt;Mutações genéticas não se aplicam apenas ao texto, mas às rotas de busca. O sistema combina características de dois pipelines bem-sucedidos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pai A:&lt;/strong&gt; Estratégia excelente em extrair entidades via GraphRAG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pai B:&lt;/strong&gt; Estratégia ultra-rápida de busca por janela temporal em PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filho (Crossover):&lt;/strong&gt; Uma nova rota híbrida que aplica o filtro de janela temporal diretamente nos nós do Grafo antes do re-ranking.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4. Seleção e Expurgo (Pruning)
&lt;/h4&gt;

&lt;p&gt;Variantes de &lt;em&gt;prompts&lt;/em&gt;, estratégias de busca ou &lt;em&gt;chunks&lt;/em&gt; sintéticos que apresentam nota de &lt;em&gt;Fitness&lt;/em&gt; cadente ao longo do tempo sofrem &lt;strong&gt;extinção&lt;/strong&gt;. O sistema deleta automaticamente essas rotas do registro de execução, impedindo o acúmulo de complexidade desnecessária.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. A Tabela da Evolução Arquitetural
&lt;/h3&gt;

&lt;p&gt;A diferença entre a engenharia de software tradicional e o design de arquiteturas cognitivas adaptativas:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Componente&lt;/th&gt;
&lt;th&gt;RAG Tradicional (Estático)&lt;/th&gt;
&lt;th&gt;RAG Adaptativo e Evolutivo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pesos de Busca&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Definidos manualmente em código&lt;/td&gt;
&lt;td&gt;Ajustados em tempo real via Contextual Bandits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompts de Sistema&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Estáticos, dependem de PRs manuais&lt;/td&gt;
&lt;td&gt;Sofrem mutação e seleção natural contínua&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Limiar de Gating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fixo (ex: corte de similaridade em 0.8)&lt;/td&gt;
&lt;td&gt;Dinâmico baseado na entropia da busca&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Otimização&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reativa (feita quando um usuário reclama)&lt;/td&gt;
&lt;td&gt;Proativa e contínua durante os Ciclos de Sonho&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Conclusão: De Sistemas Projetados para Sistemas Cultivados
&lt;/h3&gt;

&lt;p&gt;A verdadeira fronteira da arquitetura de software para Inteligência Artificial não consiste em escrever pipelines cada vez mais longos e rígidos. Consiste em projetar as &lt;strong&gt;regras do jogo&lt;/strong&gt; e as &lt;strong&gt;funções de fitness&lt;/strong&gt;, permitindo que o próprio sistema aprenda a se otimizar.&lt;/p&gt;

&lt;p&gt;Ao unir a &lt;strong&gt;plasticidade sináptica&lt;/strong&gt; dos algoritmos adaptativos com a &lt;strong&gt;pressão seletiva&lt;/strong&gt; dos algoritmos evolutivos, o seu RAG deixa de ser um pedaço de código passivo e torna-se uma infraestrutura viva: que aprende com os erros do dia, evolui durante a noite e se adapta continuamente à complexidade do mundo real.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ia</category>
      <category>arquitetura</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
