<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel><title>Kvasir Blog</title><link>https://kvasir-ai.net/technology</link><atom:link href="https://kvasir-ai.net/feed.xml" rel="self" type="application/rss+xml" /><description>Engineering notes from the Kvasir decentralized AI inference network.</description><language>en</language><lastBuildDate>Wed, 15 Jul 2026 19:17:00 GMT</lastBuildDate><item><title>The Kvasir Economy: A Virtuous Cycle of Cost and Reward</title><link>https://kvasir-ai.net/technology/kvasir-economy-virtuous-cycle</link><guid isPermaLink="true">https://kvasir-ai.net/technology/kvasir-economy-virtuous-cycle</guid><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><description>A decentralized inference network only works if the price consumers pay and the reward nodes earn reinforce each other. Here is the flywheel we're building toward, the spirals that kill it, and the three invariants that keep it turning.</description><category>economics</category><category>tokenomics</category><category>KVR</category><category>design</category><content:encoded><![CDATA[<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted"><strong class="font-semibold text-ink">Thesis:</strong> Kvasir is a two-sided market settled in one token — consumers pay KVR to infer, nodes earn KVR to serve. The whole design succeeds or fails on one property: those two sides must form a <strong class="font-semibold text-ink">virtuous cycle</strong>, where each turn makes the next turn easier. Get that wrong and any price policy eventually collapses; get it right and the network grows *cheaper* as it grows *larger*.</p></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">It's tempting to treat cost and reward as a tug-of-war — every dollar a consumer saves is a dollar a node doesn't earn. That framing is a trap. In a healthy network they are the <strong class="font-semibold text-ink">same flywheel</strong> seen from two ends: payments become rewards, rewards become supply, supply becomes capacity and lower prices, lower prices become more usage, and more usage becomes more payments. The question isn't how to split a fixed pie; it's how to keep the wheel turning so the pie grows.</p>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/kvasir-economy-virtuous-cycle.jpg" alt="A flywheel where usage, token demand, rewards and supply each drive the next" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The flywheel</div><h2 class="mt-2 text-2xl font-semibold text-ink">Why usage and supply grow together</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The engine of the cycle is a single rule already true in Kvasir: <strong class="font-semibold text-ink">inference must be paid in KVR</strong>. That makes every unit of usage a unit of real demand for the token — utility, not speculation. Token demand supports the value of the KVR nodes earn; attractive rewards pull in supply; supply expands capacity and, through competition and finer expert-sharding, drives the marginal cost of serving down; cheaper, faster, more capable service pulls in more usage. Kvasir tightens the loop with a property no centralized API can copy: a participant can be <strong class="font-semibold text-ink">consumer and supplier at once</strong>. The demand side and the supply side often grow inside the *same people*, which damps the imbalances that wreck one-sided markets.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The failure modes</div><h2 class="mt-2 text-2xl font-semibold text-ink">Four spirals that run the wheel backward</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">A flywheel can spin down as easily as up. Naming the death spirals is how you design against them:</p>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Spiral</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">How it starts</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Where it ends</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Reward dilution</td><td class="px-4 py-3 text-ink-muted">More nodes chase flat demand</td><td class="px-4 py-3 text-ink-muted">Per-node reward falls, nodes leave, capacity drops</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Price-too-low</td><td class="px-4 py-3 text-ink-muted">Cheap price, rewards below node cost</td><td class="px-4 py-3 text-ink-muted">Serving stops paying, supply and quality collapse</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Price-too-high</td><td class="px-4 py-3 text-ink-muted">Good rewards, but above market</td><td class="px-4 py-3 text-ink-muted">Users pick a cheaper API, revenue dries up</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Emission dependence</td><td class="px-4 py-3 text-ink-muted">Rewards paid by minting, not revenue</td><td class="px-4 py-3 text-ink-muted">Inflation erodes KVR until both sides give up</td></tr></tbody></table></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The invariants</div><h2 class="mt-2 text-2xl font-semibold text-ink">Three rules that keep the cycle virtuous</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Rewards are funded by real revenue.</strong> At steady state, what nodes earn comes from what consumers pay — not from open-ended token emission. Emission is a bootstrap subsidy that must *taper* as fee revenue grows. Kvasir already helps here by rewarding <strong class="font-semibold text-ink">real work</strong> — KVR per tokens actually served × layer share, not mere presence — so subsidy can't leak to idle 'mercenary' nodes.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">KVR is the mandatory medium.</strong> Because you can't infer without paying KVR, usage is a permanent demand sink for the token. That anchors token value to real utility instead of speculation — the difference between a currency and a chip.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Price floats inside a band.</strong> A floor kept above node marginal cost keeps serving worthwhile; a ceiling kept below centralized alternatives keeps Kvasir competitive. Between them, price moves — which is where the network's growth finally shows up as lower cost.</span></li></ul>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The thermostat</div><h2 class="mt-2 text-2xl font-semibold text-ink">Making &quot;more nodes → cheaper&quot; true in code</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Today price is a governed constant — sensible for a devnet, but it means adding nodes raises *capacity*, not affordability. The design direction is a <strong class="font-semibold text-ink">utilization-driven price</strong>: idle supply nudges the price down toward the floor, congestion nudges it up toward the ceiling. That single signal turns the intuition *&quot;the more people share compute, the cheaper it gets&quot;* into a rule the protocol enforces — while the floor keeps operators solvent so the supply that made it cheap doesn't evaporate. Because price is a sensitive economic parameter, it changes only under <strong class="font-semibold text-ink">genesis-wallet authority with wallet-signature + 2FA</strong>, never a stray environment variable.</p>
<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted"><strong class="font-semibold text-ink">&quot;Free&quot; is the net, not the price.</strong> You pay for what you infer and earn for what you serve; contribute roughly as much as you consume and your bill nets to zero. No subscription API — Claude Max, a Codex seat — can offer that, because you can never be their supply side. With Kvasir you can run models your own machine can't hold *and* be paid for helping others run theirs.</p></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">None of this requires exotic mechanism design. It requires discipline about three things: reward from revenue, value from usage, balance from a bounded floating price. Kvasir already ships the hard, honest parts — non-custodial settlement, work-proportional rewards, a token you must actually spend to use the network. The rest is the economic roadmap: the taper, the fee split that funds an insurance pool for failed inferences, and the thermostat. Built in that order, cost and reward stop fighting and start compounding.</p>]]></content:encoded></item><item><title>NVIDIA Blackwell Joined the Swarm</title><link>https://kvasir-ai.net/technology/blackwell-joins-the-swarm</link><guid isPermaLink="true">https://kvasir-ai.net/technology/blackwell-joins-the-swarm</guid><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><description>A GB10 Grace Blackwell computed real 122B expert-FFN slices in CUDA and matched AMD ROCm bit-for-bit (cosine 1.0000000000) and Grace ARM CPU within tolerance. The cross-backend matrix is complete.</description><category>core tech</category><category>numerics</category><category>CUDA</category><category>Blackwell</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">A swarm's premise is *whatever hardware shows up*. Numerical equivalence — the proof that CUDA, ROCm, Adreno and CPU workers all emit the same token — was already measured on ROCm, phone ARM and numpy. NVIDIA is the <strong class="font-semibold text-ink">default and best-optimized</strong> path in stock ggml/inference engine, yet it was the one backend the matrix hadn't been closed on. Running real Blackwell hardware closes it.</p>
<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted"><strong class="font-semibold text-ink">GB10 Blackwell CUDA ↔ MI250 ROCm gfx90a: cosine 1.0000000000</strong> — max abs diff 3.5×10⁻¹⁰. On the same real Qwen3.5-122B layer-0 expert slice, the two GPU backends are effectively bit-identical.</p></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/blackwell-joins-the-swarm.jpg" alt="A new GPU docking into an almost-complete matrix of backend-comparison cells, its waveform snapping into overlap with a red GPU&#39;s" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Measured · real Qwen3.5-122B-A10B, layer-0 expert slice</div><h2 class="mt-2 text-2xl font-semibold text-ink">The cross-backend matrix</h2></div>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Comparison</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Hardware</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">cosine</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">max abs</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">CUDA ↔ ROCm</td><td class="px-4 py-3 text-ink-muted">GB10 Blackwell ↔ MI250 gfx90a</td><td class="px-4 py-3 text-ink-muted">1.0000000000</td><td class="px-4 py-3 text-ink-muted">3.5e-10</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">CUDA ↔ CPU</td><td class="px-4 py-3 text-ink-muted">GB10 Blackwell ↔ Grace ARM</td><td class="px-4 py-3 text-ink-muted">0.9997525825</td><td class="px-4 py-3 text-ink-muted">2.6e-05</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">CPU ↔ ROCm</td><td class="px-4 py-3 text-ink-muted">Grace ARM ↔ MI250 gfx90a</td><td class="px-4 py-3 text-ink-muted">0.9997525823</td><td class="px-4 py-3 text-ink-muted">2.6e-05</td></tr></tbody></table></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The two GPU backends (CUDA, ROCm) share kernel sources, so they land <strong class="font-semibold text-ink">effectively bit-identical</strong> (10⁻¹⁰). GPU↔CPU carries ~10⁻³ per-op perturbation from a different accumulation order, but stays equivalent at <strong class="font-semibold text-ink">cosine 0.99975</strong> — the same pattern as the earlier ROCm↔phone-ARM 0.99992. The router-authority principle holds again on NVIDIA: <strong class="font-semibold text-ink">the discrete decisions (argmax, expert selection) are invariant over this continuous perturbation.</strong></p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Setup</div><h2 class="mt-2 text-2xl font-semibold text-ink">What ran, on what</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Device</strong> — NVIDIA GB10 (Grace Blackwell), aarch64, compute 12.1 / sm_121a, 124.5 GB unified memory.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Toolkit</strong> — CUDA 13.0.88 · gcc 13.3 · ggml 0.15.3; the pure-ggml/gguf expert-worker built with Blackwell kernels.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Model</strong> — Qwen3.5-122B-A10B-Q4_K_M, layer-0 all experts (256 experts, n_embd 3072, n_ff 1024, Q4_K/Q6_K).</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Method</strong> — the 1.58 GB L0 slice streamed MI250 → GB10 (lossless compare); the same input (h/ids) run through CUDA, CPU and ROCm; float32 output vectors (36,864) compared by cosine, relative L2 and max-abs.</span></li></ul>
<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted"><strong class="font-semibold text-ink">One real-hardware gotcha:</strong> the GB10's integrated GPU classifies as ggml device type <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ACCEL</code>, not <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">GPU</code> — so <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">init_by_type(GPU)</code> found nothing. Fixed by selecting the first non-CPU device instead of hard-coding the GPU type.</p></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Why it matters</div><h2 class="mt-2 text-2xl font-semibold text-ink">The matrix is closed</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">For heterogeneous workers to serve one model, a CUDA box and a ROCm box must be <strong class="font-semibold text-ink">interchangeable</strong>, and a GPU and a CPU must be <strong class="font-semibold text-ink">numerically equivalent</strong>. With Blackwell measured, both hold across the full backend matrix: CUDA↔ROCm workers can stand in for each other, and GPU↔CPU workers agree within a bounded, well-conditioned tolerance. The most common accelerator on earth is now a verified swarm citizen.</p>]]></content:encoded></item><item><title>Hardening the Money Path: Transaction Security in KVR Settlement</title><link>https://kvasir-ai.net/technology/securing-the-kvr-money-path</link><guid isPermaLink="true">https://kvasir-ai.net/technology/securing-the-kvr-money-path</guid><pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate><description>Three real vulnerability classes — payment-signature replay, unauthenticated reward minting, and race double-spends — found, exploited in tests, and closed in the gateway's settlement service.</description><category>security</category><category>settlement</category><category>Solana</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">In a DePIN, the money path is exactly as adversarial as the compute path: every endpoint that credits KVR will eventually be probed by someone who wants KVR without doing the work. A security pass over the gateway's settlement service — the process that verifies on-chain payments and credits stakes, node rewards and inference charges — found and closed <strong class="font-semibold text-ink">three real vulnerability classes</strong>. Each one was demonstrated with an exploit-style test before the fix and re-verified after.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The trust model</div><h2 class="mt-2 text-2xl font-semibold text-ink">Verify on-chain facts, not client claims</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Kvasir's custody model keeps keys with users: wallets sign transactions, Solana records them, and the settlement service's only job is to <strong class="font-semibold text-ink">verify what actually happened on chain</strong> before touching a balance. Payments follow *quote → payment → inference*, with every consumed transaction signature recorded in a one-shot <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">usedSignatures</code> registry so it can never be presented twice. That makes the settlement service the chokepoint — and the rule it must never break is: credit only what the chain proves, never what the client asserts.</p>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/securing-the-kvr-money-path.jpg" alt="A settlement vault guarded by three locks: sender binding, trusted reporter, and a serialization gate" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Fix #1 · sender binding</div><h2 class="mt-2 text-2xl font-semibold text-ink">Bind the payment to the payer</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Solana signatures are <strong class="font-semibold text-ink">public</strong>. The stake-verification path checked that the vault *received* the expected KVR — but never *who sent it*. An attacker could watch devnet for a victim's KVR→vault transfer, then submit <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">{owner: attacker, signature: victim's}</code>: the vault-received check passed, the principal was credited to the attacker, and one unstake later the funds were theirs. Direct theft, using nothing but a block explorer.</p>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">The fix: the KVR must have been debited from token accounts owned by the credited owner.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">verifyStakeTransfer(signature, owner, amount):
  delta(vault)  &gt;= amount            # vault actually received it (old check)
  Σ debits from token accounts
    whose owner == credited owner    # NEW — sender binding
                &gt;= amount            # summed across that owner's accounts
  # inference path (no owner): bound by private requestId
  # + one-shot usedSignatures instead</pre></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Fix #2 · trusted reporter</div><h2 class="mt-2 text-2xl font-semibold text-ink">Rewards only from authenticated sources</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The node-reward endpoints minted claimable KVR from <strong class="font-semibold text-ink">self-reported input</strong>: <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">POST /api/node/contribution</code> credited whatever <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">units</code> the client claimed — <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">units: 1e9</code> and a claim call could drain the vault — and register/heartbeat honored self-declared hub/gateway roles (hourly infra rewards) and performance scores (reward multipliers). The fix gates every reward-affecting assertion behind a <strong class="font-semibold text-ink">trusted reporter</strong>: only the M2M service token used by the hub's contribution poll, or an authenticated admin, may assert units, infra roles or perf tiers — enforced even in open LAN mode, because these mint KVR. The token comparison is constant-time, and wallet↔node linking still works freely; it just can't assert its own rewards anymore.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Fix #3 · settlement serialization</div><h2 class="mt-2 text-2xl font-semibold text-ink">One writer on every balance</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Settlement state was a lock-free read-modify-write, and every money operation *awaits* an on-chain payout or verification in the middle — yielding the event loop with a stale balance in hand. Two concurrent claims could both read the same 100 KVR pending balance and both pay out. This wasn't theoretical: the exploit test showed <strong class="font-semibold text-ink">three concurrent claims paying 300 for a 100 balance</strong>.</p>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">Per-key async serialization: same-key money operations run strictly one after another.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">withLock(key, fn)         # per-key promise chain, self-cleaning map
  stake / unstake / claim  → keyed by owner
  inference settlement     → keyed by requestId
inside the lock:
  usedSignatures check + credit   # no same-signature double-credit
  pay out FIRST, then debit       # failed payout leaves balance intact</pre></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Defense in depth</div><h2 class="mt-2 text-2xl font-semibold text-ink">Where each layer now stands</h2></div>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Layer</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Mechanism</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Identity</td><td class="px-4 py-3 text-ink-muted">SIWS wallet-signature login over a server nonce + TOTP 2FA + single-use backup codes</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Transport</td><td class="px-4 py-3 text-ink-muted">Wallet-derived node tokens on shard downloads; build-fingerprint agreement on the relay</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Payment</td><td class="px-4 py-3 text-ink-muted">Sender binding on stake transfers; one-shot usedSignatures; private requestId on inference</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Settlement</td><td class="px-4 py-3 text-ink-muted">Per-key locks around every balance write; pay-first-then-debit; idempotent re-submit</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Reporting</td><td class="px-4 py-3 text-ink-muted">Reward-affecting facts only from the M2M service token or admin, constant-time compared</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Custody</td><td class="px-4 py-3 text-ink-muted">Non-custodial wallets — the service can move only what the vault holds, never user keys</td></tr></tbody></table></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Measured, not assumed</div><h2 class="mt-2 text-2xl font-semibold text-ink">Each fix carries its own exploit test</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Replaying a victim's transfer signature under an attacker's wallet is now rejected (&quot;not sent by owner&quot;); legitimate stakes, over-claims and inference payments behave unchanged.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Three concurrent claims against one balance pay <strong class="font-semibold text-ink">exactly once</strong>; re-submitting an already-paid inference idempotently returns the same result.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Self-asserted <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">units</code>, hub/gateway roles and perf tiers from unauthenticated clients no longer move a single lamport of rewards.</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The through-line of all three fixes is one principle applied three ways: <strong class="font-semibold text-ink">the chain is the source of truth, the service is a verifier, and every balance has exactly one writer</strong>. The settlement service still runs on Solana devnet — which is exactly where you want to find, exploit and fix these classes before mainnet raises the stakes.</p>]]></content:encoded></item><item><title>A Phone Joined 122B Inference</title><link>https://kvasir-ai.net/technology/phone-joins-122b-inference</link><guid isPermaLink="true">https://kvasir-ai.net/technology/phone-joins-122b-inference</guid><pubDate>Tue, 14 Jul 2026 00:00:00 GMT</pubDate><description>A Galaxy S25 autonomously downloaded its expert slice from the hub and computed one layer's experts every step of a live 122B decode. The output was correct.</description><category>demo</category><category>Galaxy S25</category><category>122B live</category><content:encoded><![CDATA[<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted">prompt: <strong class="font-semibold text-ink">&quot;The capital of France is&quot;</strong> → generated (with the phone in the loop): <strong class="font-semibold text-ink">&quot; Paris.&quot;</strong> — 8/8 tokens identical to the local run.</p></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Measured · real 122B, phone computing layer-0</div><h2 class="mt-2 text-2xl font-semibold text-ink">Correctness + TPS</h2></div>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">8/8</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">tokens identical to local</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">4.01</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">TPS local (baseline)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">3.13</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">TPS with phone</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">1.58 GB</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">autonomous download</div></div></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/phone-joins-122b-inference.jpg" alt="A phone docked to a towering 122B model, printing tokens that spell Paris" loading="lazy" class="block w-full"></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Even with the phone computing layer-0's experts for every token, the <strong class="font-semibold text-ink">generated tokens are exactly the local ones</strong> — the correct &quot;Paris.&quot;. TPS drops to 3.13 from 4.01 — the phone-dispatch round trip (MI250 → tunnel → phone, ~100 ms/token) costs 22%. Throughput comes back with batching and replicas (M4).</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The autonomous participation flow</div><h2 class="mt-2 text-2xl font-semibold text-ink">Discover → reward-driven download → join the compute</h2></div>
<div class="mt-6"><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">1. Phone knows the hub (hub.kvasir-ai.net) — already holds its wallet node-token
2. GET /api/proxy/models/…/expert-shard?layers=0:1&amp;experts=0:256
   # partially downloads its own expert slice (1.58 GB, WiFi)
3. linkcpp-expert-worker --serve
   # loads the slice (Adreno device, CPU backend) + waits for dispatch
4. MI250 backbone decodes the 122B → every token, layer-0 experts
   dispatch to the phone → experts return → combine → &quot;Paris.&quot;
   (8/8 identical to local)</pre></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Verified vs remaining</div><h2 class="mt-2 text-2xl font-semibold text-ink">The mechanism is complete; the in-app loop is productionization</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Partial download (the expert-shard endpoint), worker serving, backbone dispatch, live 122B generation and TPS — all verified on the real device.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Correctness: with the phone participating, 8/8 tokens equal the local run, with the correct answer.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Remaining: the in-app autonomous loop (poll expert-demand → volunteer → download → serve → register) is Kotlin wiring — this demo drove the mechanism directly.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Transport: this demo used an SSH tunnel; production uses the 443 relay (already verified in the ring work).</span></li></ul>]]></content:encoded></item><item><title>Phase 7 — Batched Dispatch Throughput (M4)</title><link>https://kvasir-ai.net/technology/m4-batched-dispatch-throughput</link><guid isPermaLink="true">https://kvasir-ai.net/technology/m4-batched-dispatch-throughput</guid><pubDate>Sat, 11 Jul 2026 00:00:00 GMT</pubDate><description>The swarm is a throughput fabric, not a latency play: batching dispatch calls amortizes per-request overhead 77× per token.</description><category>M4</category><category>throughput</category><category>batching</category><content:encoded><![CDATA[<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Measured · ROCm, expert FFN, n_used = 8</div><h2 class="mt-2 text-2xl font-semibold text-ink">Bigger batches, more tok/s per worker</h2></div>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">batch</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">tok/s per worker</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">1</td><td class="px-4 py-3 text-ink-muted">688</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">16</td><td class="px-4 py-3 text-ink-muted">4,255</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">64</td><td class="px-4 py-3 text-ink-muted">8,130</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">256</td><td class="px-4 py-3 text-ink-muted">30,666</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">512</td><td class="px-4 py-3 text-ink-muted">53,067</td></tr></tbody></table></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/m4-batched-dispatch-throughput.jpg" alt="A conveyor packing tokens into growing batch crates feeding one GPU, output meter rocketing" loading="lazy" class="block w-full"></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">From <strong class="font-semibold text-ink">1.45 ms/tok</strong> at batch 1 to <strong class="font-semibold text-ink">0.019 ms/tok</strong> at batch 512 — a 77× per-token improvement. The per-call time barely moves (1.45 → 9.6 ms) while the batch grows 512× — the GPU processes the batch nearly for free behind a fixed overhead. This is the <strong class="font-semibold text-ink">throughput-fabric property</strong> that makes expert-parallel practical: batched dispatch amortizes per-request RTT and overhead.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Done</div><h2 class="mt-2 text-2xl font-semibold text-ink">Batched dispatch throughput</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Worker <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--bench</code>: compute_dispatch timings for batch 1…512 → tok/s.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">53k tok/s per worker</strong> at batch 512 (ROCm) — batching amortizes the overhead.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Hot-expert caching and multi-worker aggregate scaling (replica routing) stack on top of this.</span></li></ul>
<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted">With M4, the whole <strong class="font-semibold text-ink">M0 → M4 pipeline is demonstrated on a real 122B</strong>: backbone offload · expert slices · verified workers · live decode dispatch (argmax MATCH) · distributed processes · coverage market · batched throughput.</p></div>]]></content:encoded></item><item><title>Phase 6 — The Expert Coverage Market (M3)</title><link>https://kvasir-ai.net/technology/m3-expert-coverage-market</link><guid isPermaLink="true">https://kvasir-ai.net/technology/m3-expert-coverage-market</guid><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><description>Weak nodes see which (layer, expert-range) is scarcest and highest-reward, and fill it themselves — the proven layer market, regrained.</description><category>M3</category><category>market</category><category>self-healing</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Kvasir's layer-shard market — demand map, max-reward self-enrollment, partial download, per-node rewards — was already device-verified. M3 re-parameterizes the same mechanism at the <strong class="font-semibold text-ink">(layer, expert-range)</strong> grain, so coverage self-heals toward the most under-replicated, highest-reward expert ranges.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Verified · API</div><h2 class="mt-2 text-2xl font-semibold text-ink">Scarcity aggregation → max-reward range assignment</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Three workers register on layer 0: A = [0,128), B = [128,256), C = [0,128) as a second replica, with <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">target_replicas = 2</code>:</p>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">layer</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">experts</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">replicas</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">scarcity</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">0</td><td class="px-4 py-3 text-ink-muted">[0, 128)</td><td class="px-4 py-3 text-ink-muted">2</td><td class="px-4 py-3 text-ink-muted">0.0 (target met)</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">0</td><td class="px-4 py-3 text-ink-muted">[128, 256)</td><td class="px-4 py-3 text-ink-muted">1</td><td class="px-4 py-3 text-ink-muted">0.5 (under target)</td></tr></tbody></table></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/m3-expert-coverage-market.jpg" alt="A market board of expert-range tiles with scarcity heat and volunteering devices" loading="lazy" class="block w-full"></div>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">volunteer(max_experts=64) → clips the scarcest range to the node's budget.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">POST /api/expert-volunteer {&quot;max_experts&quot;: 64}
  → {layer: 0, experts: [128, 192], scarcity: 0.5, replicas: 1, target: 2}</pre></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Done · pure Python (hub)</div><h2 class="mt-2 text-2xl font-semibold text-ink">A supply/demand market at expert grain</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">POST /api/expert-coverage</code> — workers heartbeat their (layer, expert-range) holdings.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">GET /api/expert-demand</code> — per-expert replica aggregation → contiguous expert-range segments with scarcity scores.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">POST /api/expert-volunteer</code> — assigns the scarcest range clipped to the node's budget.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>The existing layer market (self-enroll · partial download · rewards) re-parameterized to (layer, expert-range).</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">What follows in M4: batched dispatch for concurrent requests plus a hot-expert cache — tokens/s proportional to worker count — and replica routing (nearest/fastest worker) with churn fallback.</p>]]></content:encoded></item><item><title>Phase 5 — Distributed Expert Dispatch (M2)</title><link>https://kvasir-ai.net/technology/m2-distributed-expert-dispatch</link><guid isPermaLink="true">https://kvasir-ai.net/technology/m2-distributed-expert-dispatch</guid><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><description>A live 122B decode hands one layer's expert compute to a separate worker process over TCP — and predicts exactly the same token.</description><category>M2</category><category>argmax MATCH</category><category>TCP dispatch</category><content:encoded><![CDATA[<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Verified · real 122B, two processes</div><h2 class="mt-2 text-2xl font-semibold text-ink">Backbone decode → TCP → worker → experts → same token</h2></div>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">MATCH</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">argmax OFF == ON (11751)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">0.99869</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">logit cosine</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">0</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">transport loss (byte-identical)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">2</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">processes (backbone + worker)</div></div></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The expert worker serves the layer-0 slice as a <strong class="font-semibold text-ink">separate process</strong> (ROCm), and the 122B backbone's <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">build_moe_ffn</code> dispatch callback ships <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">(cur, sel)</code> over TCP and receives the expert outputs. The logit cosine is <strong class="font-semibold text-ink">exactly the in-process value</strong> (0.99868775) — the transport is lossless. Expert-parallel swarm compute works across a process boundary.</p>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/m2-distributed-expert-dispatch.jpg" alt="Backbone and worker rooms joined by one TCP pipe, sealed with an argmax MATCH stamp" loading="lazy" class="block w-full"></div>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">One long-lived TCP connection — the same stream the ring/443 relay can tunnel.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted"># worker: serving as a separate process
linkcpp-expert-worker --serve 52700 --model L0_all.gguf --layer 0 --n-embd 3072
# backbone: build_moe_ffn callback dispatches to the worker
linkcpp-moe-verify 122B.gguf ... --dispatch-port 52700
  → protocol: [n_used, n_tokens] + cur + sel  →  experts</pre></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Done</div><h2 class="mt-2 text-2xl font-semibold text-ink">The distributed dispatch pipeline</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--serve</code> mode: load the slice, listen on TCP, answer <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">(n_used, n_tokens, cur, sel) → experts</code>.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--dispatch-port</code>: the backbone callback sends/receives over TCP to a separate worker, replacing in-process compute.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Measured on a live 122B decode with layer-0 dispatched out-of-process → <strong class="font-semibold text-ink">argmax MATCH</strong>, cosine 0.99869 (= in-process, lossless).</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>M2 core (earlier): the phone's ARM computed real 122B experts at cosine 0.99992 (Android cross-build).</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Next from here: tunneling the same TCP stream through the <strong class="font-semibold text-ink">443 relay</strong> to workers on other machines and phones (the transport was already proven in the ring work), then the M3 coverage market and M4 batched throughput.</p>]]></content:encoded></item><item><title>From Blueprint to Hardware: What's Verified, and the Keystone</title><link>https://kvasir-ai.net/technology/swarm-verified-and-keystone</link><guid isPermaLink="true">https://kvasir-ai.net/technology/swarm-verified-and-keystone</guid><pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate><description>A recap of the verification campaign — design through M2-core proved on a real 122B — and the one integration piece that unlocks the rest.</description><category>progress</category><category>milestones</category><category>122B</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Over the past weeks, the hard, novel pieces of the expert-sharded swarm were proven one by one on a real <strong class="font-semibold text-ink">Qwen3.5-122B</strong> — not simulated, not toy-sized. Here is the verification trail so far, and the single keystone that remained.</p>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/swarm-verified-and-keystone.jpg" alt="A verification trail of stamped checkpoints ending at a keystone being placed" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The trail · all verified on the real 122B</div><h2 class="mt-2 text-2xl font-semibold text-ink">What has landed so far</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Design (5 revisions since the blueprint)</strong> — EP architecture, partial-weight autonomous participation, the relay, worker kernel spec, and cross-backend numerical equivalence codified as core technology. Router authority written down as the coherence invariant.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M0 — backbone expert RAM offload (planner verified):</strong> 122B is *feasible* on a single 64 GB coordinator — 10 expert layers offloaded to RAM, VRAM 62.6 GiB / RAM 14.2 GiB, wired via <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--override-tensor</code>.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M1 — expert-slice data path:</strong> per-expert mini-GGUF slicing (ne[2] slabs, byte copy without dequant) + the <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">/expert-shard</code> download endpoint.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M1 — numerical oracle:</strong> dispatch + combine == monolithic with <strong class="font-semibold text-ink">max|Δ| = 3.6e-12</strong> on real layer-0 experts — sharding is an exact regrouping of the same weighted sum.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M1 — C++ worker on hardware:</strong> <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">linkcpp-expert-worker</code> (pure ggml/gguf) built and run on ROCm, <strong class="font-semibold text-ink">cosine 0.99995</strong> vs the oracle; router → two C++ workers → combine matches monolithic at cosine 0.9997–0.9999.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M2 core — a phone computes real 122B experts:</strong> Android cross-build, run on an SM-S938N, <strong class="font-semibold text-ink">cosine 0.99992</strong> vs the oracle.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Numerics — 3-backend equivalence matrix:</strong> the same 122B computation on ROCm × phone ARM CPU × numpy — ROCm↔phone cosine 0.99990, ROCm↔numpy 0.99996, phone↔numpy 0.99992. All equivalent, none bit-identical.</span></li></ul>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The keystone</div><h2 class="mt-2 text-2xl font-semibold text-ink">Backbone dispatch, integrated into live decode</h2></div>
<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted">Every <strong class="font-semibold text-ink">component</strong> — slices, workers, dispatch/combine logic, numerical equivalence, phone compute — was device-verified. What remained was wiring them <strong class="font-semibold text-ink">inside a real inference engine decode</strong>: a <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">build_moe_ffn</code> hook that dispatches experts to their owner nodes mid-graph. It required modifying the pinned inference engine submodule and several build-verify cycles. Once this keystone stands, <strong class="font-semibold text-ink">M2 relay integration, the M3 expert coverage market, and M4 batched throughput</strong> open in sequence — all of them depend on this dispatch.</p></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The keystone has since landed: the follow-up posts on M2, M3, M4 and the live phone demo are the results of exactly this integration.</p>]]></content:encoded></item><item><title>Numerical Equivalence Across Heterogeneous Backends</title><link>https://kvasir-ai.net/technology/cross-backend-numerical-equivalence</link><guid isPermaLink="true">https://kvasir-ai.net/technology/cross-backend-numerical-equivalence</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><description>CUDA, ROCm, Adreno and CPUs will never agree bit-for-bit. That the swarm still produces one coherent model is a designed property, not luck.</description><category>core tech</category><category>numerics</category><category>router authority</category><content:encoded><![CDATA[<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The key distinction</div><h2 class="mt-2 text-2xl font-semibold text-ink">Exact vs equivalent — two different properties</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Within one backend — exact (3.6e-12):</strong> splitting experts across nodes and combining is the same weighted sum regrouped; the only difference is floating-point accumulation order. Oracle-verified.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Across backends — equivalent (1e-3…1e-6):</strong> the same op on different hardware carries a per-op relative error around 1e-3–1e-6, and is never zero. <strong class="font-semibold text-ink">The swarm lives in this regime.</strong></span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">&quot;Exact&quot; is what decomposition guarantees inside one device. &quot;Equivalent&quot; is what heterogeneous hardware gives you. The swarm's job is to keep equivalence from compounding into divergence.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Measured · real 122B, three backends</div><h2 class="mt-2 text-2xl font-semibold text-ink">Not a theory — measured on hardware</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The same Qwen3.5-122B layer-0 expert FFN, computed by <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">linkcpp-expert-worker</code> on an MI250 (<strong class="font-semibold text-ink">ROCm</strong>), a phone's <strong class="font-semibold text-ink">ARM CPU</strong> (SM-S938N), and an x86 <strong class="font-semibold text-ink">numpy</strong> reference — same inputs, same weights, different instruction sets and reduction orders:</p>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/cross-backend-numerical-equivalence.jpg" alt="Three backends feeding one comparator where their waveforms overlap within tolerance" loading="lazy" class="block w-full"></div>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Backend pair</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">max|Δ|</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">cosine</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">ROCm (GPU) vs numpy (x86)</td><td class="px-4 py-3 text-ink-muted">7.9e-7</td><td class="px-4 py-3 text-ink-muted">0.99996</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Phone ARM CPU vs numpy (x86)</td><td class="px-4 py-3 text-ink-muted">1.4e-6</td><td class="px-4 py-3 text-ink-muted">0.99992</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">ROCm GPU vs phone ARM CPU</td><td class="px-4 py-3 text-ink-muted">1.5e-6</td><td class="px-4 py-3 text-ink-muted">0.99990</td></tr></tbody></table></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Three instruction sets, one computation — every pair equivalent (cosine ≈ 0.9999), no pair bit-identical (Δ ≈ 1e-6). The residuals are small <strong class="font-semibold text-ink">because router authority pinned the inputs and the expert selection</strong>.</p>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">A later run on real <strong class="font-semibold text-ink">NVIDIA GB10 Grace Blackwell</strong> hardware closed the matrix on the last backend: CUDA ↔ ROCm landed at <strong class="font-semibold text-ink">cosine 1.0000000000</strong> (max abs 3.5e-10, effectively bit-identical, since both GPU backends share kernel sources), and CUDA ↔ Grace ARM CPU at cosine 0.99975 — the same GPU↔CPU pattern seen above.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Why backends differ</div><h2 class="mt-2 text-2xl font-semibold text-ink">Floating-point addition is not associative</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Matmul reduction order</strong> — tensor cores, MFMA tiles, OpenCL workgroups and SIMD lanes each accumulate in different orders and tilings.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">FMA fusion</strong> — <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">a*b+c</code> rounded once (FMA) or twice, fused differently per backend.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Accumulation precision</strong> — F16/BF16 storage with F32 vs F16 accumulators (the biggest lever on divergence).</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Transcendental approximations</strong> — polynomial/table variants of exp (softmax), silu/sigmoid (swiglu), rsqrt (norms).</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Dequant + matmul path</strong> — dequantize-then-matmul vs fused quantized kernels round intermediates differently.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Nondeterministic kernels</strong> — atomic/split-K reductions can differ run to run on the same device.</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">None of this is a bug. It is the price each accelerator's fast path pays.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Why it still works</div><h2 class="mt-2 text-2xl font-semibold text-ink">One authority for decisions, enough precision for accumulation</h2></div>
<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted"><strong class="font-semibold text-ink">ROUTER AUTHORITY — the core invariant.</strong> The only discrete decision inside the network is MoE routing (top-8 of 256). If every backend re-ran the router, borderline tokens would pick <strong class="font-semibold text-ink">different experts</strong> and genuinely diverge. Kvasir runs the router <strong class="font-semibold text-ink">once, on the backbone</strong>, and sends workers only the selected expert ids. A heterogeneous swarm may differ in the *magnitude* of each expert's output — it never differs in *which experts run*. This converts catastrophic discrete divergence into bounded continuous error, and is the coherence rule of heterogeneous expert sharding.</p></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Discrete argmax:</strong> decoding is an argmax over logits. A 1e-3 wobble flips a token only when two candidates are within 1e-3 — at most positions the margin is far larger, so <strong class="font-semibold text-ink">tokens come out identical</strong>; the rare flips are positions as ambiguous as a different seed.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Combine is addition:</strong> partial results merge as a probability-weighted <strong class="font-semibold text-ink">sum</strong>. Independent ~1e-4 errors add incoherently — they grow like √k, not k — and there is no cancellation of large values, so the residual stays well-conditioned.</span></li></ul>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Where it can break · and the rules that stop it</div><h2 class="mt-2 text-2xl font-semibold text-ink">Divergence modes and defenses</h2></div>
<div class="mt-6 overflow-x-auto rounded-2xl ring-1 ring-line"><table class="w-full min-w-[28rem] text-left text-sm"><thead><tr class="bg-surface-2/70"><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Divergence mode</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Mechanism</th><th class="px-4 py-3 font-mono text-[0.68rem] font-semibold uppercase tracking-wider text-ink-faint">Rule</th></tr></thead><tbody><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Routing mismatch</td><td class="px-4 py-3 text-ink-muted">Backends pick different top-8 for borderline tokens</td><td class="px-4 py-3 text-ink-muted">Router authority — decided once on the backbone, ids dispatched</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Trajectory fork</td><td class="px-4 py-3 text-ink-muted">Per-token logit wobble eventually flips a token; the sequence forks like a new seed</td><td class="px-4 py-3 text-ink-muted">Decode/sampling pinned to one node</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Depth accumulation</td><td class="px-4 py-3 text-ink-muted">49 layers × ~1e-4 each → up to 1e-2 at the final logits</td><td class="px-4 py-3 text-ink-muted">F32 accumulation at boundaries and combine</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Self-nondeterminism</td><td class="px-4 py-3 text-ink-muted">Atomic/split-K kernels vary run-to-run</td><td class="px-4 py-3 text-ink-muted">Deterministic combine kernels; verification uses tolerances</td></tr><tr class="border-t border-line"><td class="px-4 py-3 font-mono text-ink">Precision mismatch</td><td class="px-4 py-3 text-ink-muted">One node accumulates F16, another F32</td><td class="px-4 py-3 text-ink-muted">Accumulation precision advertised as a capability; F32 nodes preferred for output ranks</td></tr></tbody></table></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Equivalence is a number</div><h2 class="mt-2 text-2xl font-semibold text-ink">The measurement protocol</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Per-op delta</strong> — same inputs, A vs B relative error on matmul, swiglu, softmax, norm.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Layer-boundary drift</strong> — residual delta after one layer, stacked to see whether depth accumulates as √L or L.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">End-to-end logit divergence</strong> — L∞, L2 and <strong class="font-semibold text-ink">KL divergence</strong> over the full forward.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Decision agreement</strong> — top-1 token agreement plus top-8 routing agreement (validating why router authority is necessary).</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Generation stability</strong> — greedy N tokens; the first index where A and B diverge.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Task level</strong> — perplexity and eval-score deltas: the only metric a user actually feels.</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">A pass is a <strong class="font-semibold text-ink">tolerance</strong> — &quot;top-1 agreement ≥ 99.x%, KL ≤ ε&quot;. A node outside tolerance is marked unfit for sensitive ranks, not rejected outright.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Why this is core swarm technology</div><h2 class="mt-2 text-2xl font-semibold text-ink">Bit-agreement is impossible — and unnecessary</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">A homogeneous cluster can assume bit-exactness; a swarm cannot — its premise is *whatever hardware shows up*. So Kvasir treats numerical equivalence exactly like protocol compatibility: a <strong class="font-semibold text-ink">first-class, measured contract</strong>. Backends and accumulation precision are advertised as node capabilities, router authority is enforced as an invariant, and every verification uses tolerances instead of bit-equality. <strong class="font-semibold text-ink">Measured numerical equivalence + single-authority discrete decisions</strong> — that is what lets one model run on every GPU on earth at once. That is the swarm.</p>]]></content:encoded></item><item><title>Phase 4 — The Expert-Slice Data Path (M1)</title><link>https://kvasir-ai.net/technology/m1-expert-slice-data-path</link><guid isPermaLink="true">https://kvasir-ai.net/technology/m1-expert-slice-data-path</guid><pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate><description>A weak device downloads a few 6 MB experts, not a 1.4 GB layer — and sharded compute matches monolithic to 3.6e-12.</description><category>M1</category><category>oracle 3.6e-12</category><category>ROCm</category><content:encoded><![CDATA[<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Verified · real Qwen3.5-122B-A10B</div><h2 class="mt-2 text-2xl font-semibold text-ink">An expert slice is a byte copy — no dequant</h2></div>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">256→8</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">expert-dim slice</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">~6.1</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">MB / expert (Q4+Q6)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">206 MB</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">2 layers × 16 experts download</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">200</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">HTTP, valid GGUF</div></div></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">MoE expert tensors stack all experts along the outermost ggml dimension, so the reader exposes <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">(n_expert, rows, row_bytes)</code> of raw quantized bytes. Expert *e* is a quant-block-aligned contiguous slab — the slice is literally <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">data[a:b]</code>, with no dequantization and no re-packing.</p>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">write_expert_shard_gguf — the verified round trip.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">sliced = tensor.data[a:b]              # outermost axis = expert
writer.add_tensor(name, sliced, raw_dtype=tensor.tensor_type)
# router (ffn_gate_inp) &amp; shared expert stay on the backbone → excluded
GET /api/proxy/models/{m}/expert-shard?layers=0:2&amp;experts=0:16  # node-token authed</pre></div></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/m1-expert-slice-data-path.jpg" alt="A laser slicing one expert slab into a mini-GGUF beside a perfectly level balance scale" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The numerical oracle</div><h2 class="mt-2 text-2xl font-semibold text-ink">dispatch + combine == monolithic, exactly</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">With real 122B layer-0 experts (dequantized reference), splitting the experts into 4 shards, computing each separately and combining <strong class="font-semibold text-ink">matches the monolithic MoE FFN</strong>: sharding is an exact regrouping of the same weighted sum, not an approximation.</p>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">3.6e-12</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">max|mono − sharded|</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">1.2e-07</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">relative error</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">True</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">allclose(1e-5)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">28/256</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">experts touched</div></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">C++ worker, hardware-verified</div><h2 class="mt-2 text-2xl font-semibold text-ink">linkcpp-expert-worker reproduces the oracle on ROCm</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Pure ggml/gguf</strong> (no libllama): loads the slice into a GPU backend and runs <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">mul_mat_id(up/gate) → swiglu → mul_mat_id(down)</code>.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">ROCm build + run</strong> on an MI250: 122B layer-0, experts [0,8), 4 tokens.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Cosine 0.99995 vs the oracle</strong>, allclose(1e-3) = True, max|Δ| = 7.9e-7 — this residual is itself the first measured instance of cross-backend equivalence (ROCm vs numpy).</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>The same code path covers CUDA/Metal/Vulkan/CPU (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">mul_mat_id</code>/<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">swiglu</code> are stock ggml; CUDA has a dedicated MoE kernel).</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The hardest, riskiest piece — the on-device worker kernel — was verified here. What remained was backbone↔worker orchestration; the worker is a proven pure function consuming these slices.</p>]]></content:encoded></item><item><title>Phase 3 — Backbone Expert RAM Offload (M0)</title><link>https://kvasir-ai.net/technology/m0-backbone-expert-ram-offload</link><guid isPermaLink="true">https://kvasir-ai.net/technology/m0-backbone-expert-ram-offload</guid><pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate><description>Stream MoE expert FFNs from CPU RAM instead of VRAM, and a single 64 GB coordinator holds a 122B — with no graph surgery.</description><category>M0</category><category>planner</category><category>RAM offload</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Expert FFNs don't have to live in VRAM. Streaming them from CPU RAM lets one coordinator hold a model whose experts exceed its VRAM — the foundation that lets weak nodes join a large MoE at all.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Planner verified · real 122B GGUF</div><h2 class="mt-2 text-2xl font-semibold text-ink">A 122B fits a single 64 GB coordinator</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Previously the ring placed weights VRAM-only, so the 122B (77.6 GB) was <strong class="font-semibold text-ink">infeasible</strong> on a 64 GB GCD. With expert-offload rules the dry-run comes back <strong class="font-semibold text-ink">feasible</strong>:</p>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">feasible</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">122B ring plan</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">62.6</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">VRAM GiB (≤ 64)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">14.2</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">RAM GiB (experts)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">10</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">offloaded layers</div></div></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/m0-backbone-expert-ram-offload.jpg" alt="A coordinator siphoning expert tiles from VRAM into a RAM reservoir, stamped feasible" loading="lazy" class="block w-full"></div>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">Planner output — inference engine -ot rule format.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">node 0  layers [0,48]  vram=62.6  ram=14.2  ot_rules=10
sample: blk\.38\.ffn_(up|down|gate)_(ch|)exps=CPU   # inference engine -ot format</pre></div></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">What was wired · pure Python, no C++ rebuild</div><h2 class="mt-2 text-2xl font-semibold text-ink">Carrying the planner's offload rules into a real load</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">planner</strong> — already emits <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ot</code> (comma-joined <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">-ot</code> rules) in each placement.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">protocol.py</strong> — added the <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">StageStartRequest.ot</code> field.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">runtime.py</strong> — forwards the placement's <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ot</code> into the stage request.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">stage_service.py</strong> — the coordinator launches with <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--override-tensor</code>.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">linkcpp-server</code> forwards unknown args to stock llama-server, so <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">-ot</code> applies untouched.</span></li></ul>
<div class="mt-6"><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted"># stage_service.py — coordinator branch
if request.ot:
    command += [&quot;--override-tensor&quot;, request.ot]</pre></div></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Verified with an <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ot</code> protocol round-trip test plus confirmation that the coordinator command emits <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--override-tensor</code>; the hub redeployed cleanly with no regressions. Remaining at the time: the full 2-node 77 GB load (coordinator with offload + a phone holding a ~1.5 GB one-layer window), gated on server availability. The core of M0 — the backbone offload that lets weak nodes participate in a big MoE — was complete at the code and planner level.</p>]]></content:encoded></item><item><title>Expert-Sharded Swarm Inference: The Design</title><link>https://kvasir-ai.net/technology/expert-sharded-swarm-design</link><guid isPermaLink="true">https://kvasir-ai.net/technology/expert-sharded-swarm-design</guid><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><description>86% of a 122B MoE is 12,544 independent 5.3 MB experts. Slice the model at that grain and a phone can carry a real share of frontier inference.</description><category>design</category><category>MoE</category><category>kvasir-net</category><content:encoded><![CDATA[<div class="mt-6 rounded-2xl bg-brand-500/8 p-6 ring-1 ring-brand-500/25"><p class="leading-relaxed text-ink-muted"><strong class="font-semibold text-ink">The thesis:</strong> 86% of Qwen3.5-122B's weight is 12,544 mutually independent 5.3 MB experts. Shard at the expert grain and a weak device carries &quot;8–64 experts (42–340 MB)&quot; instead of &quot;a 1.4 GB layer&quot; — exactly the unit a phone can actually hold. MoE is the natural substrate of a swarm.</p></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/expert-sharded-swarm-design.jpg" alt="Blueprint of a MoE model carved into expert bundles flowing to a swarm of devices" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Substrate · Qwen3.5-122B-A10B (Q4_K_M)</div><h2 class="mt-2 text-2xl font-semibold text-ink">The weights are already packaged in swarm-sized units</h2></div>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">49</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">layers</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">256</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">experts / layer</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">8</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">active / token</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">5.3 MB</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">one expert (Q4)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">12,544</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">experts total</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">86%</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">of weight in experts</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">3072</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">n_embd</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">ne[2]</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">expert dim = outermost</div></div></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The expert index is the <strong class="font-semibold text-ink">outermost dimension</strong> of every MoE tensor, so each expert is a contiguous, quant-block-aligned slab. An expert-sliced mini-GGUF is a clean byte-range copy — no dequantization, no re-packing.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Two roles</div><h2 class="mt-2 text-2xl font-semibold text-ink">Backbone stage × expert worker</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Backbone stage (strong node):</strong> attention + KV cache, all norms, the <strong class="font-semibold text-ink">router</strong>, the shared expert, and the residual combine — the entire dense path. It also keeps all experts resident as a fallback replica (RAM offload), which gives the swarm churn tolerance.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Expert worker (a phone):</strong> not a transformer. No attention, no KV, no sampler — a pure function <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">(hidden, local_ids) → out</code> made of three mat-muls, holding only its own expert slice. It fits any budget down to a 4 GB phone.</span></li></ul>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">The cut point: router runs once on the backbone, with authority.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">cur   = ffn_norm(x)                       # backbone
ids,p = top_k(softmax(cur @ router), 8)   # backbone — authoritative
── dispatch selected experts to owner nodes ──
send  (cur rows, local_ids)  →  worker    # ~6 KB per decode step
recv  expert_out             ←  worker
x = x + combine(p, partials) + shared(cur)  # backbone — numerically exact</pre></div></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Because the router runs <strong class="font-semibold text-ink">exactly once</strong> on the backbone, each selected expert is computed exactly once by whichever node owns it. There is <strong class="font-semibold text-ink">no approximation</strong> — the sharding only moves where the mat-muls happen.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Not a new subsystem</div><h2 class="mt-2 text-2xl font-semibold text-ink">The swarm is the proven reward market, at a finer grain</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Kvasir already runs an autonomous scarcity market for <strong class="font-semibold text-ink">layer</strong> shards, verified on real devices: a NAT-bound phone polls the demand map, self-enrolls into the <strong class="font-semibold text-ink">highest-reward</strong> segment, partially downloads only that window, loads it on its Adreno GPU, and completes ring inference — earning contribution rewards. Expert sharding reuses all of it — coverage map, max-reward self-enroll, partial download, per-node rewards — changing only the coverage unit from *layer ranges* to *(layer, expert-range)*.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Two innovations, already device-verified</div><h2 class="mt-2 text-2xl font-semibold text-ink">Partial-weight participation + the 443 relay</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Reward-driven partial-weight download:</strong> conventional RPC/TP/PP setups ship the full checkpoint to every rank and a scheduler dictates placement. In Kvasir a node downloads <strong class="font-semibold text-ink">only the slice it will compute</strong>, and picks that slice <strong class="font-semibold text-ink">itself, by reward</strong> — a 254 MB stage mini-GGUF versus the 77.6 GB full model. This is how a 4 GB phone joins a model far bigger than itself.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">443 relay data plane:</strong> Cloudflare's 80/443-only edge plus carrier NAT means no direct dial in either direction. A per-edge WebSocket bridge with a 1-byte role preamble lets <strong class="font-semibold text-ink">both sides dial outbound</strong> (the phone opens zero inbound ports). Landing it meant fixing three real bugs — build-fingerprint agreement, node-token download auth, and a Kotlin <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">Int.ushr</code> frame-length bug that silently corrupted every frame ≥ 64 KiB (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ushr</code> uses only the low 5 bits of its shift; <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">len ushr 56</code> became <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">len ushr 24</code>) — fixed by moving to <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">Long</code> shifts.</span></li></ul>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The honest crux</div><h2 class="mt-2 text-2xl font-semibold text-ink">A throughput fabric, not a low-latency decoder</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Decode is 49 serial layers, and a cross-internet round trip per layer costs 2.5–10 s per token. So the swarm's contest is <strong class="font-semibold text-ink">serving models nobody can host alone</strong>, measured in aggregate throughput: batch dispatch amortizes RTT, the backbone keeps a hot-expert cache, and requests route to near replicas. The low-latency path stays with the pipeline ring.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Roadmap</div><h2 class="mt-2 text-2xl font-semibold text-ink">M0 → M4</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M0</strong> — backbone expert RAM offload: run 122B on one coordinator, no graph surgery.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M1</strong> — single-host expert-parallel proof: expert-sliced mini-GGUF + worker runtime + dispatch, logits exactly matching monolithic.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M2</strong> — LAN + NAT phone workers computing real 122B experts through the 443 relay.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M3</strong> — expert-grain coverage market with replicas and churn fallback.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">M4</strong> — throughput: batched dispatch + hot-expert cache, tokens/s scaling with worker count.</span></li></ul>]]></content:encoded></item><item><title>Phase 2 — Inside a 122B MoE: Why the Weights Want to Be Sharded</title><link>https://kvasir-ai.net/technology/inside-a-122b-moe</link><guid isPermaLink="true">https://kvasir-ai.net/technology/inside-a-122b-moe</guid><pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate><description>A tensor-level analysis of Qwen3.5-122B: 86% of the bytes are 12,544 independent expert slabs, each one a clean byte-range copy away from standing alone.</description><category>MoE</category><category>GGUF</category><category>analysis</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Before designing anything, we took the 122B apart on disk. The question: if a swarm of weak devices is to carry this model, what is the natural unit of carrying? The answer fell out of the GGUF tensor layout itself.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Anatomy · Qwen3.5-122B-A10B (Q4_K_M)</div><h2 class="mt-2 text-2xl font-semibold text-ink">What a MoE layer is actually made of</h2></div>
<div class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4"><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">49</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">layers</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">256</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">experts / layer</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">8</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">active / token</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">12,544</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">experts total</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">5.3 MB</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">one expert (Q4)</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">86%</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">of weight in experts</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">3072</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">n_embd</div></div><div class="rounded-2xl bg-surface-2 p-4 ring-1 ring-line"><div class="font-mono text-xl font-bold tracking-tight text-brand-gradient">77.6 GB</div><div class="mt-1 font-mono text-[0.7rem] text-ink-faint">full checkpoint</div></div></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/inside-a-122b-moe.jpg" alt="Anatomical cutaway of a MoE model: slim dense spine beside a huge honeycomb of experts" loading="lazy" class="block w-full"></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Each layer splits into a <strong class="font-semibold text-ink">dense path</strong> — attention + KV, the norms, the router (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ffn_gate_inp</code>), a shared expert — and an <strong class="font-semibold text-ink">expert bank</strong>: 256 independent FFNs stored as three stacked tensors (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ffn_up_exps</code>, <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ffn_gate_exps</code>, <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ffn_down_exps</code>). The dense path is the minority of the bytes; the expert bank is 86% of the model.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The layout gift</div><h2 class="mt-2 text-2xl font-semibold text-ink">Experts are contiguous, block-aligned slabs</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>The expert index is the <strong class="font-semibold text-ink">outermost ggml dimension</strong> (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ne[2]</code>) of every expert tensor — expert *e* occupies one contiguous, quant-block-aligned slab of raw quantized bytes.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>That makes per-expert extraction a <strong class="font-semibold text-ink">byte-range copy</strong>: <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">data[a:b]</code>, no dequantization, no re-packing — an expert-sliced mini-GGUF is cheap to produce and bit-faithful.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Per token only <strong class="font-semibold text-ink">8 of 256</strong> experts fire per layer, chosen by the router — so at decode time a layer's expert traffic is a handful of small matrix multiplies over one hidden vector.</span></li></ul>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The implication</div><h2 class="mt-2 text-2xl font-semibold text-ink">The carrying unit drops from 1.4 GB to 5.3 MB</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">At layer grain, the least a node can hold is ~<strong class="font-semibold text-ink">1.4 GB</strong> — out of reach for most phones once the app, KV and OS take their share. At expert grain, the unit is <strong class="font-semibold text-ink">5.3 MB</strong>, and a realistic contribution is 8–64 experts (<strong class="font-semibold text-ink">42–340 MB</strong>) — comfortably inside any modern device. The experts are mutually independent, so ownership can be scattered arbitrarily and re-balanced freely. This analysis is what made expert-level sharding the design bet: the weights were already packaged in swarm-sized units — the network just had to honor the packaging.</p>]]></content:encoded></item><item><title>Phase 1 — The Ring: Pipeline Inference Without a Master</title><link>https://kvasir-ai.net/technology/ring-topology-pipeline-inference</link><guid isPermaLink="true">https://kvasir-ai.net/technology/ring-topology-pipeline-inference</guid><pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate><description>Every device loads only its layer window and passes a small hidden-state boundary to its neighbor. No node holds the model; no central master exists.</description><category>ring runtime</category><category>topology</category><category>NAT</category><content:encoded><![CDATA[<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Why not a star</div><h2 class="mt-2 text-2xl font-semibold text-ink">The RPC master is a bottleneck and a gatekeeper</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">In the classic RPC topology one master opens the <strong class="font-semibold text-ink">entire GGUF</strong> and dials out to every worker. That shape breaks in an open network three ways: the master must hold and serve the whole checkpoint; every worker must be dialable — phones behind carrier NAT are not; and the master is a single owner in a network that should have none.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The ring</div><h2 class="mt-2 text-2xl font-semibold text-ink">Layer windows + boundary passing</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Every device stores the same model but <strong class="font-semibold text-ink">loads only its contiguous layer window</strong>, then opens exactly two links: one to its predecessor, one to its successor.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>A request enters the ring; each node runs its layers and passes only the <strong class="font-semibold text-ink">hidden-state boundary</strong> to its neighbor. The last rank samples the token and sends it back around — no central master, and no node holds the whole model.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span>Placement comes from the planner's <strong class="font-semibold text-ink">rank manifest</strong> — for Qwen3.5-122B, 49 layers split across whatever mix of GPU, CPU, NPU and phone shows up.</span></li></ul>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/ring-topology-pipeline-inference.jpg" alt="A transit-map style loop of device stations passing packet trains" loading="lazy" class="block w-full"></div>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Making weak devices real members</div><h2 class="mt-2 text-2xl font-semibold text-ink">Partial shards, mobile GPUs, and the 443 relay</h2></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Partial-shard download:</strong> a ring stage doesn't need the checkpoint — it needs its window. A stage mini-GGUF carries just those tensors (<strong class="font-semibold text-ink">254 MB of 26 tensors</strong> versus the 77.6 GB full model), so a phone pulls ~1.5 GB for a one-layer window instead of everything.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Mobile GPU path:</strong> the RPC route to a phone GPU proved infeasible (Adreno's OpenCL buffer layout doesn't survive RPC serialization), but a <strong class="font-semibold text-ink">ring stage runs on the Adreno GPU directly</strong> — the stage owns its backend locally, so nothing crosses the wire but boundaries.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">NAT traversal:</strong> phones can't accept inbound connections, so the data plane runs through a <strong class="font-semibold text-ink">443 relay</strong> — a per-edge WebSocket bridge with a 1-byte role preamble that lets both ends dial outbound. The phone opens zero inbound ports.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Self-enrollment market:</strong> stages are claimed, not assigned. A node polls the coverage/demand map, picks the <strong class="font-semibold text-ink">highest-reward</strong> uncovered window, downloads that window, and joins — verified end-to-end with a NAT-bound phone completing ring inference and earning its contribution.</span></li></ul>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Where the ring fits</div><h2 class="mt-2 text-2xl font-semibold text-ink">The low-latency path</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">The ring is Kvasir's <strong class="font-semibold text-ink">latency</strong> path: boundaries are small, hops are few, and decode flows around the loop without gathering anything centrally. Its limitation is granularity — the smallest unit a node can carry is a layer (~1.4 GB on the 122B). Removing that floor is what the expert-sharded swarm does; the ring remains the serving backbone it plugs into.</p>]]></content:encoded></item><item><title>Phase 0 — The Engine: linkcpp, a Control Plane for inference engine</title><link>https://kvasir-ai.net/technology/linkcpp-control-plane</link><guid isPermaLink="true">https://kvasir-ai.net/technology/linkcpp-control-plane</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><description>inference engine ships a capable RPC data plane but no control plane. linkcpp adds the missing half — discovery, planning, launch and gateways — around stock binaries.</description><category>linkcpp</category><category>control plane</category><category>BSL</category><content:encoded><![CDATA[<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">Everything Kvasir runs on starts here. <strong class="font-semibold text-ink">linkcpp</strong> is a source-available control plane (Business Source License) around inference engine's RPC data plane: it runs large AI models across multiple GPUs and machines using *stock* <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">ggml-rpc-server</code> / <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">llama-server</code> binaries. The data plane stays unforked — everything linkcpp adds is orchestration.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">The gap</div><h2 class="mt-2 text-2xl font-semibold text-ink">A data plane without a control plane</h2></div>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">inference engine can already split a model across machines over RPC — but someone has to discover the GPUs, decide which layers go where, launch the right workers with the right budgets, check that every node speaks the same protocol, and expose an API developers can actually call. Doing that by hand for one cluster is a chore; doing it for an open network of strangers' devices is impossible. That coordination layer is linkcpp.</p>
<div class="mt-12"><div class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-400">Architecture</div><h2 class="mt-2 text-2xl font-semibold text-ink">One hub, stock workers, standard gateways</h2></div>
<div class="mt-6"><p class="mb-2 text-xs text-ink-faint">Request flow — the hub orchestrates, stock binaries compute.</p><div class="overflow-x-auto rounded-2xl bg-surface p-5 ring-1 ring-line"><pre class="font-mono text-[0.8rem] leading-relaxed text-ink-muted">browser / SDK
  → hub :19000                      # FastAPI control plane (single Docker image)
  → GPU-less llama-server master    # per-controller, :8080+
  → ggml-rpc-server workers         # local slots, remote units, managed agents</pre></div></div>
<div class="mt-6 overflow-hidden rounded-2xl ring-1 ring-line"><img src="/blog/linkcpp-control-plane.jpg" alt="A control deck orchestrating rows of stock inference engine engines below" loading="lazy" class="block w-full"></div>
<ul class="mt-5 max-w-3xl space-y-3"><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Three ways a machine joins:</strong> fixed <strong class="font-semibold text-ink">local node slots</strong> with editable VRAM/RAM/CPU budgets; <strong class="font-semibold text-ink">remote units</strong> — register another hub and import its nodes; and <strong class="font-semibold text-ink">managed node agents</strong> — worker-only services that join over plain request/response HTTP, deliberately not a persistent stream, so they survive simple LAN/VPN routing.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Compatibility gating is first-class:</strong> every unit, node and agent reports a protocol / runtime-pack identity plus backend details. Unit, runtime-pack, inference engine-revision and RPC-ABI mismatches are <strong class="font-semibold text-ink">hard-blocked before bind, plan, load or infer</strong> — backend differences (CUDA/Metal/Vulkan/CPU) are tracked as capabilities, not rejections.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">The planner</strong> reads GGUF metadata and produces contiguous per-node layer placement, <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">--tensor-split</code>, KV-cache/layer/expert VRAM estimates, and optional expert-FFN offload to RAM.</span></li><li class="flex items-start gap-3 text-sm leading-relaxed text-ink-muted"><span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-sm bg-brand-400"></span><span><strong class="font-semibold text-ink">Gateways:</strong> every controller exposes OpenAI-compatible (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">/v1/chat/completions</code>, <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">/v1/responses</code>, <code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">/v1/models</code>) and Anthropic-compatible (<code class="rounded bg-surface-3 px-1.5 py-0.5 font-mono text-[0.85em] text-brand-300">/anthropic/v1/messages|models</code>) endpoints, backed by the same loaded model — existing clients work unchanged.</span></li></ul>
<p class="mt-5 max-w-3xl leading-relaxed text-ink-muted">This deliberate split — an unmodified data plane under an open control plane — is what everything later builds on: the ring runtime, the layer market, and eventually the expert-sharded swarm are all control-plane evolutions over the same stock compute.</p>]]></content:encoded></item></channel></rss>
