<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: speed engineer</title>
    <description>The latest articles on DEV Community by speed engineer (@speed_engineer).</description>
    <link>https://dev.to/speed_engineer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3844864%2F78a68c07-7a26-44f8-a98d-84d4d29fa7ef.png</url>
      <title>DEV Community: speed engineer</title>
      <link>https://dev.to/speed_engineer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/speed_engineer"/>
    <language>en</language>
    <item>
      <title>Your Average Latency Is Lying to You: The Tail at Scale</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Mon, 06 Jul 2026 04:40:44 +0000</pubDate>
      <link>https://dev.to/speed_engineer/your-average-latency-is-lying-to-you-the-tail-at-scale-43l</link>
      <guid>https://dev.to/speed_engineer/your-average-latency-is-lying-to-you-the-tail-at-scale-43l</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Here's a service that looks healthy. Median response time is 10ms. The dashboard shows an average around 20ms. Nobody's paging you.&lt;/p&gt;

&lt;p&gt;Then you put it behind a request that fans out to 100 of these services in parallel — a search, a feed build, a page that queries 100 shards and needs every answer — and suddenly two-thirds of your users are waiting more than a second.&lt;/p&gt;

&lt;p&gt;Nothing got slower. You just discovered that at scale, your p99 is the number that matters, and your average was hiding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;p&gt;Give that "healthy" service a fat tail: 99% of requests return in 10ms, but 1% take 1000ms (a GC pause, a cold cache, a lock, a TCP retransmit — pick your poison). The average is &lt;code&gt;0.99 × 10 + 0.01 × 1000 ≈ 20ms&lt;/code&gt;. Genuinely fine on one call.&lt;/p&gt;

&lt;p&gt;Now fan out to N servers and wait for all of them, because you need every shard's answer before you can respond. The request is fast only if &lt;em&gt;every&lt;/em&gt; server dodged its slow path. The probability that at least one server hits its 1% tail is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;P(slow request) = 1 − (0.99)^N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch it move:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;N =   1  →   1.0%
N =  10  →   9.6%
N = 100  →  63.4%
N = 200  →  86.6%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At a fan-out of 100, the slow path that happens 1% of the time on a single server becomes the &lt;em&gt;common case&lt;/em&gt; for the user. The tail didn't add up — it compounded. This is what Jeff Dean and Luiz Barroso named "the tail at scale": in fan-out systems, the 99th-percentile latency of a component is effectively the &lt;em&gt;median&lt;/em&gt; latency of the whole request.&lt;/p&gt;

&lt;p&gt;The trap is that every instinct points the wrong way. You optimize the average — shave p50 from 10ms to 8ms — and the user-facing number barely moves, because the user-facing number is built out of tails, not medians.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Attack the tail, not the average.&lt;/strong&gt; Improve the &lt;em&gt;per-server&lt;/em&gt; slow rate and the compounded number collapses. Take that 1% down to 0.1%:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;N = 100, p = 1%    →  63.4%
N = 100, p = 0.1%  →   9.5%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 10× improvement in the tail buys a ~6.6× improvement for the user. The same 10× on the median buys you nothing. So put your SLOs on p99/p99.9, not the average, and hunt the specific causes of tails: GC pauses, cold caches, head-of-line blocking, one slow disk in the fleet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send a backup request (hedging).&lt;/strong&gt; You don't have to make every server fast — you have to stop waiting on the unlucky one. Fire the request to one replica; if it hasn't answered by, say, the 95th-percentile expected latency, fire a second copy to another replica and take whichever returns first. Because you only hedge the slow ~5%, you pay a few percent extra load and cut the high-percentile tail by roughly an order of magnitude. It's the highest-leverage trick in the tail-tolerance playbook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cancel the loser.&lt;/strong&gt; Hedging without cancellation just doubles work under load and can push you into a spiral. "Tied requests" fix this: send to two replicas, tell each about the other, and whichever one starts executing cancels its twin. You get the latency win without paying double.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduce the fan-out.&lt;/strong&gt; &lt;code&gt;1 − (1−p)^N&lt;/code&gt; is exponential in N. Fewer, fatter shards beat many thin ones for tail behavior. If you can answer from 10 servers instead of 100, you've moved from 63% to 10% for free — before any hedging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The average latency of a component is nearly useless once you fan out. In a request that waits on N servers, the user experiences the &lt;em&gt;tail&lt;/em&gt;, not the median.&lt;/li&gt;
&lt;li&gt;The math is &lt;code&gt;1 − (1−p)^N&lt;/code&gt;, and it compounds fast: a 1% per-server slow rate becomes 63% at a fan-out of 100.&lt;/li&gt;
&lt;li&gt;Optimizing p50 is mostly wasted effort for user-facing latency. Move your SLOs and your attention to p99/p99.9.&lt;/li&gt;
&lt;li&gt;Hedged requests (fire a backup after the 95th percentile, take the first answer) cut tail latency by ~10× for a few percent more load. Cancel the loser so you don't double the work.&lt;/li&gt;
&lt;li&gt;Fewer shards = smaller N = smaller tail. Reducing fan-out is the cheapest tail fix there is.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>distributedsystems</category>
      <category>architecture</category>
      <category>scalability</category>
    </item>
    <item>
      <title>Debugging Is a Search Problem: Bisect Everything</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Sun, 05 Jul 2026 05:08:50 +0000</pubDate>
      <link>https://dev.to/speed_engineer/debugging-is-a-search-problem-bisect-everything-22d3</link>
      <guid>https://dev.to/speed_engineer/debugging-is-a-search-problem-bisect-everything-22d3</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Two engineers get the same bug: a value that's correct when it enters the system and wrong when it leaves. One fixes it in fifteen minutes. The other burns the afternoon. Same tools, same access, same intelligence.&lt;/p&gt;

&lt;p&gt;The difference isn't knowledge of the codebase. It's that one of them is running a binary search and the other is poking around.&lt;/p&gt;

&lt;p&gt;Most engineers debug linearly: start where the error showed up, read the nearby code, change something, re-run, repeat. That's &lt;code&gt;O(n)&lt;/code&gt; in the size of the problem — and worse, because most of those changes produce no information, so it's often not even that good.&lt;/p&gt;

&lt;p&gt;The senior move is to treat every bug as a search over a space of possible causes, and to make each observation cut that space roughly in half. Ten halvings cover a thousand candidates. That's the whole trick, and it generalizes far past &lt;code&gt;git bisect&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;p&gt;A bug lives somewhere in a space you can't see all at once. That space has several axes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt; — which change introduced it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code&lt;/strong&gt; — which module, function, or line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layers&lt;/strong&gt; — at which stage of the pipeline the data went bad.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input&lt;/strong&gt; — which part of the payload triggers it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Linear debugging searches one axis by hand — usually the code axis, starting at the symptom. But the symptom is where the bug &lt;em&gt;surfaced&lt;/em&gt;, which is rarely where it &lt;em&gt;lives&lt;/em&gt;. So you read the wrong neighborhood and mutate code hoping to get lucky. Each speculative edit that "might fix it" gives you almost nothing when it doesn't.&lt;/p&gt;

&lt;p&gt;Binary search wins because information compounds. If you can find one observation that's true on one half of the space and false on the other, a single measurement deletes half your candidates — no matter which half.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;Pick the axis with the cleanest before/after boundary and halve it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time — automate &lt;code&gt;git bisect&lt;/code&gt;.&lt;/strong&gt; If it worked last release and breaks now, you don't need to read the diff. Write a script that exits &lt;code&gt;0&lt;/code&gt; on good and &lt;code&gt;1&lt;/code&gt; on bad, and let git run the search:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect start
git bisect bad                 &lt;span class="c"&gt;# current commit is broken&lt;/span&gt;
git bisect good v2.3.0         &lt;span class="c"&gt;# this release was fine&lt;/span&gt;
git bisect run ./repro.sh      &lt;span class="c"&gt;# git binary-searches for you&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Across 1,000 commits that's ~10 runs, not 1,000. The output is the exact commit that introduced the bug — often the entire investigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layers — check the middle of the pipeline.&lt;/strong&gt; Data flows &lt;code&gt;A → B → C → D → E&lt;/code&gt; and comes out wrong at E. Don't start at A or E. Log the value at C. If it's already wrong at C, the bug is in A–C; if it's fine, it's in C–E. One print statement halved the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input — shrink the repro.&lt;/strong&gt; A 4,000-line request fails. Delete half. Still fails? Delete half of what's left. Passes now? Put it back and cut the other half. In a dozen steps a 4,000-line payload becomes the three fields that actually matter. This is delta debugging, and it works on config files, CSS, and feature flags — anything you can chop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code — disable half.&lt;/strong&gt; Comment out half the handlers, half the middleware, half the plugins. Bug gone? It was in the half you removed. This feels crude; it is faster than reading.&lt;/p&gt;

&lt;p&gt;The discipline underneath all four: &lt;strong&gt;each step's job is information, not a fix.&lt;/strong&gt; Before you touch anything, ask "what's the one observation that splits this in half?" If a change can't tell you &lt;em&gt;which half&lt;/em&gt; the bug is in, you're not searching — you're guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A bug is a point in a search space, not a line of code. Your job is to shrink the space, fast.&lt;/li&gt;
&lt;li&gt;Every good observation halves what's left. &lt;code&gt;log2(n)&lt;/code&gt;, not &lt;code&gt;n&lt;/code&gt; — ten steps cover a thousand suspects.&lt;/li&gt;
&lt;li&gt;Bisect on whichever axis has the cleanest boundary: time (&lt;code&gt;git bisect&lt;/code&gt;), layers (check the midpoint value), input (shrink the repro), or code (disable half).&lt;/li&gt;
&lt;li&gt;Optimize each step for information, not for a fix. "Might this fix it?" is the wrong question. "Which half does this rule out?" is the right one.&lt;/li&gt;
&lt;li&gt;The symptom is where the bug surfaced, not where it lives. Stop starting there.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>debugging</category>
      <category>productivity</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Your Struct Layout Is Part of Your Wire Protocol</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Sat, 04 Jul 2026 04:42:36 +0000</pubDate>
      <link>https://dev.to/speed_engineer/your-struct-layout-is-part-of-your-wire-protocol-27af</link>
      <guid>https://dev.to/speed_engineer/your-struct-layout-is-part-of-your-wire-protocol-27af</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;A message-processing system that comfortably handled 50,000 messages/second fell off a cliff one night: 8,000 msg/sec and collapsing. The confusing part was the dashboards. Network: green. Database: barely working. CPU utilization: 23%.&lt;/p&gt;

&lt;p&gt;Nothing looked busy, and yet nothing was moving. Three weeks of profiling later, the culprit turned out not to live in any code path. It lived in a struct definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PaymentMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MessageHeader&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// 28 bytes of mixed-size fields&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;     &lt;span class="n"&gt;sender_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;     &lt;span class="n"&gt;recipient_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;     &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;     &lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt;  &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;__attribute__&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;packed&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;         &lt;span class="c1"&gt;// 101 bytes. Practically always misaligned.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;101 packed bytes means nearly every message straddled two cache lines — sometimes three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;p&gt;CPUs don't read bytes. They read cache lines: 64-byte blocks. Ask for one byte and the CPU pulls in that byte's 63 neighbors whether you need them or not.&lt;/p&gt;

&lt;p&gt;Most of us design binary protocols as if the struct exists in isolation — fields ordered by meaning, packed to save bytes on the wire. But in memory, that struct lands wherever the allocator put it, and the fast path (validate → route → count) reads fields scattered across the whole layout: magic at the front, checksum at the back, timestamp in the middle.&lt;/p&gt;

&lt;p&gt;At tens of millions of field accesses per second, every extra cache line touched is an extra trip to memory. An L1 hit costs about a nanosecond; a main-memory fetch costs about a hundred. Multiply "2–3 lines per message instead of 1" by 50K messages/sec and the pipeline spends its life stalled on the memory bus while the cores look eerily idle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Split hot from cold.&lt;/strong&gt; Everything the fast path reads goes in the first 64 bytes, aligned to a line boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;CacheOptimizedMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Hot: validation + routing — first 32 bytes&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;message_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// widened for alignment&lt;/span&gt;
    &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;sequence_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Warm: next 32 bytes&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;     &lt;span class="n"&gt;sender_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;    &lt;span class="c1"&gt;// compacted&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;     &lt;span class="n"&gt;recipient_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;payload_offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// variable data lives elsewhere&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;__attribute__&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;aligned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;   &lt;span class="c1"&gt;// exactly one cache line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fast path now costs exactly one cache fetch: validate, route, and update without ever reaching past the first line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Move variable-length data behind an offset.&lt;/strong&gt; Flexible fields get their own 64-byte-aligned section with a small offset table. One extra indirection when you need them — zero cost when you don't (which is most of the time).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Batch and prefetch.&lt;/strong&gt; Once messages are line-aligned, batches become predictable, and the prefetcher becomes your friend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;__builtin_prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;process_message_fast_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rework took the system from 14,700 to 50,100 msg/sec — 3.4× — on the same hardware, same algorithms. P50 latency went from 89ms to 12ms; P99 from 456ms to 34ms. Cache misses dropped 78%.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to bother
&lt;/h2&gt;

&lt;p&gt;Above ~10K messages/sec with CPU-bound processing: this is one of the highest-leverage changes available to you. Between 1K and 10K: measure first. Below 1K, or if you're IO-bound, or your messages vary wildly in size: skip it — you're trading real development velocity for latency you won't notice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CPUs fetch 64-byte cache lines, not fields. A struct that straddles lines multiplies memory traffic on every access.&lt;/li&gt;
&lt;li&gt;Put every field your fast path reads into the first cache line; push cold metadata to the next.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aligned(64)&lt;/code&gt; guarantees your hot line starts at a line boundary — packed-and-misaligned undoes everything.&lt;/li&gt;
&lt;li&gt;Variable-length data goes behind an offset, fetched only when needed.&lt;/li&gt;
&lt;li&gt;Verify with &lt;code&gt;perf stat&lt;/code&gt; (cache-misses, instructions-per-cycle) before and after. The numbers don't lie; intuition does.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This is a condensed version of a longer war story I published on Medium — the full piece walks through the L1/L2 layering, platform portability, and the batch buffer design: &lt;a href="https://medium.com/@speed_enginner/binary-protocols-designing-messages-for-cache-lines-ac4bea82410c" rel="noopener noreferrer"&gt;Binary Protocols: Designing Messages For Cache Lines&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>performance</category>
      <category>networking</category>
      <category>c</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your Manager Can't Remember What You Did in March — and That's a Systems Problem</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Fri, 03 Jul 2026 03:42:05 +0000</pubDate>
      <link>https://dev.to/speed_engineer/your-manager-cant-remember-what-you-did-in-march-and-thats-a-systems-problem-5fh0</link>
      <guid>https://dev.to/speed_engineer/your-manager-cant-remember-what-you-did-in-march-and-thats-a-systems-problem-5fh0</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Every consequential decision about your career — promotion, calibration rating, who lands on a layoff list — gets made in a room you're not in, usually in a few minutes per name.&lt;/p&gt;

&lt;p&gt;Here's the uncomfortable part: the input to that decision is not your work. Your commits, your incident responses, your design docs — none of that is in the room. What's in the room is a lossy, human-memory summary of your work, reconstructed months after the fact by people juggling ten other names.&lt;/p&gt;

&lt;p&gt;Most engineers treat this as politics. It's not. It's a data problem, and you can engineer around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;p&gt;Think of it as a caching problem.&lt;/p&gt;

&lt;p&gt;Your actual output lives on disk: the repo history, the closed incidents, the migration that shipped without drama. Nobody reads disk during calibration. There's no time. They read cache — the handful of impressions that survived in your manager's memory.&lt;/p&gt;

&lt;p&gt;And that cache has a brutal eviction policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recency wins.&lt;/strong&gt; Q1 work is mostly gone by review season. The last six weeks are over-weighted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loud events survive; quiet competence doesn't.&lt;/strong&gt; The engineer who heroically fixed a burning outage generates a story. The engineer whose systems never caught fire generates... nothing. Prevention produces no events, so it's evicted first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manager change = cache flush.&lt;/strong&gt; New manager, and your last two years of context drop to whatever made it into writing. In most orgs, that's a few one-line review summaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why the most load-bearing engineers so often score as "solid, meets expectations" while the firefighter — sometimes fighting fires of their own making — scores as "high impact." Nobody is being malicious. The work was simply never logged anywhere a decision-maker could read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;Maintain an evidence log. Five minutes a week, three fields per entry:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What changed&lt;/strong&gt; — the outcome, not the activity. "Migrated checkout to the new payment service" beats "worked on payments."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The number&lt;/strong&gt; — before/after, with a link to the dashboard or PR. "p95 checkout latency 480ms → 210ms; conversion +1.9%." A claim with a number survives a calibration room. "Worked on performance" does not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who can vouch&lt;/strong&gt; — the staff engineer who reviewed it, the PM who saw the metric move. Names make claims checkable, and checkable claims get repeated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then do three things with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Log prevention explicitly.&lt;/strong&gt; "Added connection-pool alerting after incident #2141 — zero repeat incidents in 6 months" turns invisible work into a record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send your manager a short monthly summary.&lt;/strong&gt; Five bullets, no prose. This isn't bragging — you're warming their cache with accurate data before eviction does its work. Most managers are quietly grateful: you're writing their calibration notes for them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write one-page decision docs&lt;/strong&gt; for anything contested. Six months later, "why is the queue architecture like this?" has an answer with your name on it, instead of an archaeology project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before review season, distill the log into five promo-ready claims. What took your peers a panicked weekend of git-log archaeology takes you twenty minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Career decisions read from memory, not from history. Memory is a cache with recency and drama bias.&lt;/li&gt;
&lt;li&gt;Prevention work is evicted first. If you don't log it with numbers, it functionally didn't happen.&lt;/li&gt;
&lt;li&gt;Five minutes a week of evidence logging beats five hours of reconstruction the night before your review.&lt;/li&gt;
&lt;li&gt;Legibility isn't politics. It's writing for the room you won't be in.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>engineering</category>
      <category>productivity</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Prompt Rot: Why Your Best AI Prompt Quietly Stops Working</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Thu, 02 Jul 2026 03:45:45 +0000</pubDate>
      <link>https://dev.to/speed_engineer/prompt-rot-why-your-best-ai-prompt-quietly-stops-working-1ba4</link>
      <guid>https://dev.to/speed_engineer/prompt-rot-why-your-best-ai-prompt-quietly-stops-working-1ba4</guid>
      <description>&lt;p&gt;You saved a prompt two months ago that wrote the perfect customer reply. Today you run it and the output is... fine. Not great. You can't point to what changed.&lt;/p&gt;

&lt;p&gt;Welcome to prompt rot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What prompt rot actually is
&lt;/h2&gt;

&lt;p&gt;A saved prompt isn't a fixed tool. It's a set of instructions balanced on top of three things that all quietly move: the AI model, your own facts, and the people using it. When any of them drift, the prompt keeps running — but the results slowly slide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three reasons a good prompt goes bad
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The model changed under you.&lt;/strong&gt; Providers update ChatGPT, Claude, and Gemini all the time. A prompt that fit last quarter's behavior can land differently today. Same words, different result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Your facts moved, the prompt didn't.&lt;/strong&gt; It still says "our starter plan is $9," uses the old product name, or leans on the pre-rebrand tone. The AI faithfully repeats yesterday.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The prompt got tweaked in private.&lt;/strong&gt; Whoever wrote it keeps refining it in their own tab and never updates the shared copy. Everyone else is running a stale version and doesn't know it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it's so sneaky
&lt;/h2&gt;

&lt;p&gt;Prompt rot doesn't throw an error. The output is still plausible — just worse. A slightly off tone, a fact that's six months stale, a structure that used to be tighter. So nobody flags it. People just quietly stop using the prompt and go back to writing from scratch, which is the exact waste a shared prompt was supposed to kill.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to keep prompts fresh (no technical skills required)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date and label.&lt;/strong&gt; Put a "last checked" date and a one-line "works for: [task]" note on every saved prompt. A prompt with no date is a prompt nobody trusts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-test your top 5 monthly.&lt;/strong&gt; Run your five most-used prompts on a real task and read the output like a first-time reader. If it slipped, fix the prompt — don't lower your bar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the old versions.&lt;/strong&gt; When you "improve" a prompt, keep the previous one. Half the time the improvement is worse and you'll want to roll back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch what quietly drops.&lt;/strong&gt; A prompt whose usage falls off a cliff is often rotted, not unneeded. That drop is your signal to go re-test it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where PromptShip fits in
&lt;/h2&gt;

&lt;p&gt;This is a big part of why we built &lt;a href="https://promptship.co" rel="noopener noreferrer"&gt;PromptShip&lt;/a&gt;: a shared prompt library for non-technical teams. It keeps version history so you can roll back a change that made output worse, and shows usage so you can spot the prompt that quietly stopped getting used — usually the first sign of rot. Organize prompts by team (Marketing, Sales, Support), copy any of them into ChatGPT, Claude, or Gemini in one click, and everyone runs the current version instead of a private fork.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prompts decay silently — no error, just slowly worse output.&lt;/li&gt;
&lt;li&gt;The usual culprits: the model updated, your facts changed, or the shared copy went stale.&lt;/li&gt;
&lt;li&gt;Date them, re-test the top few monthly, keep version history, and watch for usage drop-offs.&lt;/li&gt;
&lt;li&gt;A prompt library only pays off if the prompts inside it are still true.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When did you last re-check the prompts your team runs every day?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>teams</category>
      <category>saas</category>
    </item>
    <item>
      <title>Why Your Project Quotes Are Always Wrong (And the Log That Fixes It)</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Wed, 01 Jul 2026 04:47:57 +0000</pubDate>
      <link>https://dev.to/speed_engineer/why-your-project-quotes-are-always-wrong-and-the-log-that-fixes-it-28ba</link>
      <guid>https://dev.to/speed_engineer/why-your-project-quotes-are-always-wrong-and-the-log-that-fixes-it-28ba</guid>
      <description>&lt;p&gt;Every freelancer I know has a number in their head for how long things take. "A landing page? Two days." "A logo revision round? An afternoon." We quote from that number. And that number is almost always wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: you quote from memory, not measurement
&lt;/h2&gt;

&lt;p&gt;Here's the trap. You finish a project, feel good, and move on. Six weeks later a similar project comes in and you pull a quote out of the same fuzzy memory that has quietly forgotten the two evenings you spent untangling the client's brand assets, the three rounds of "small" revisions, and the hour you lost every morning just reloading context.&lt;/p&gt;

&lt;p&gt;So you quote for the &lt;em&gt;happy path&lt;/em&gt; — the version of the project where nothing goes sideways. Then reality shows up, the hours balloon, and you eat the difference. Not because you're slow. Because you estimated against a memory that was edited to make you feel competent.&lt;/p&gt;

&lt;p&gt;Underquoting doesn't feel like a crisis. It feels like a slightly disappointing month, over and over.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: keep an actuals log
&lt;/h2&gt;

&lt;p&gt;You don't need a methodology. You need one habit: &lt;strong&gt;after every project, write down what you estimated and what it actually took.&lt;/strong&gt; Two numbers and a one-line note.&lt;/p&gt;

&lt;p&gt;A minimal version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Project type      | Quoted (hrs) | Actual (hrs) | Note                          |
|-------------------|--------------|--------------|-------------------------------|
| Landing page      | 16           | 27           | Client assets were a mess     |
| Logo, 3 concepts  | 8            | 14           | Revision rounds ran long      |
| Blog, 1500 words  | 4            | 5.5          | Research heavier than assumed |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do this five times and something uncomfortable but useful happens: you get a personal multiplier. Mine hovered around 1.6x for design work — meaning my gut estimate needed to be multiplied by 1.6 to land near reality. That single number changed my quoting more than any pricing course.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the actuals are the hard part
&lt;/h2&gt;

&lt;p&gt;The estimate is easy — you write it when you send the quote. The &lt;em&gt;actual&lt;/em&gt; is where everyone falls off, because reconstructing real hours at the end of a project means fighting the same faulty memory that caused the problem in the first place.&lt;/p&gt;

&lt;p&gt;The only reliable way to know your actual hours is to have captured them as they happened, in small pieces, without ceremony. That's the whole reason time tracking exists — not for surveillance, but so future-you can quote honestly.&lt;/p&gt;

&lt;p&gt;This is where a low-friction tracker earns its place. I use &lt;a href="https://fillthetimesheet.com" rel="noopener noreferrer"&gt;FillTheTimesheet&lt;/a&gt; so the "actual hours" column fills itself from what I logged during the work, instead of me guessing on a Friday. The point isn't the tool — it's that your actuals need to be a byproduct of working, not a separate chore you'll skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your mental estimate is edited to make you look good; it's not data.&lt;/li&gt;
&lt;li&gt;Underquoting rarely feels dramatic — it just quietly caps your income.&lt;/li&gt;
&lt;li&gt;Log estimated vs. actual hours after every project. Two numbers, one note.&lt;/li&gt;
&lt;li&gt;After ~5 projects you'll have a personal multiplier worth more than any template.&lt;/li&gt;
&lt;li&gt;The actuals only exist if you captured time as you worked — that's the part to automate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quote from a spreadsheet of what actually happened, not from the story you tell yourself about how it went.&lt;/p&gt;

</description>
      <category>freelance</category>
      <category>productivity</category>
      <category>business</category>
      <category>timetracking</category>
    </item>
    <item>
      <title>How to Build a Shared Prompt Library Your Team Will Actually Use</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Tue, 30 Jun 2026 03:38:29 +0000</pubDate>
      <link>https://dev.to/speed_engineer/how-to-build-a-shared-prompt-library-your-team-will-actually-use-5gng</link>
      <guid>https://dev.to/speed_engineer/how-to-build-a-shared-prompt-library-your-team-will-actually-use-5gng</guid>
      <description>&lt;p&gt;If your team uses ChatGPT, Claude, or Gemini every day, you already have a prompt library. It's just scattered across Slack DMs, sticky notes, a forgotten Notion page, and three people's heads.&lt;/p&gt;

&lt;p&gt;The result is predictable: your best-performing prompt — the one that writes the perfect support reply or the cleanest sales follow-up — gets rewritten from scratch every week by someone who didn't know it already existed.&lt;/p&gt;

&lt;p&gt;Here's a simple, repeatable system to fix that. No prompt-engineering background required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Capture before you organize
&lt;/h2&gt;

&lt;p&gt;Don't start by designing the perfect taxonomy. Start by collecting. For one week, ask everyone to drop any prompt they reuse into a single place. You'll be surprised how many duplicates surface — and the duplicates are gold, because a prompt three people independently saved is a prompt that works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Name prompts by the job, not the tool
&lt;/h2&gt;

&lt;p&gt;A prompt called "GPT thing" helps no one. Name it after the outcome: "Draft a refund-approval email," "Summarize a discovery call into 5 bullets," "Rewrite copy for a skeptical CFO." When the name describes the job to be done, the right person finds it in seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Group by team function, not by model
&lt;/h2&gt;

&lt;p&gt;Marketing, Sales, HR, Support, Writing. People think in terms of their work, not in terms of which AI model they're pasting into. Organize around how your team is actually structured and adoption takes care of itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Make reuse a one-click action
&lt;/h2&gt;

&lt;p&gt;This is where most libraries die. If using a saved prompt means scrolling a doc, copying carefully around the formatting, and pasting into another tab, people stop bothering and go back to winging it. The library only works if grabbing a prompt is faster than rewriting one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Keep the best, retire the rest
&lt;/h2&gt;

&lt;p&gt;Once a month, look at what's actually being used. Promote the winners, archive the dead weight. A library of 30 great prompts beats a graveyard of 300.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where PromptShip fits in
&lt;/h2&gt;

&lt;p&gt;We built &lt;a href="https://promptship.co" rel="noopener noreferrer"&gt;PromptShip&lt;/a&gt; because we kept watching non-technical teams lose their best prompts. It's a shared prompt library — organize prompts by team function, copy any of them straight into ChatGPT, Claude, or Gemini with one click, and see usage analytics so you know what's actually working. There's a library of 50k+ community prompts to start from, and the free tier covers 200 prompts for a single user.&lt;/p&gt;

&lt;p&gt;Think of it as Notion-for-prompts, built for Marketing, Sales, HR, and Support rather than engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your team already has a prompt library — it's just disorganized&lt;/li&gt;
&lt;li&gt;Capture first, organize second; duplicates reveal your best prompts&lt;/li&gt;
&lt;li&gt;Name by outcome, group by team function&lt;/li&gt;
&lt;li&gt;Reuse has to be effortless or the library dies&lt;/li&gt;
&lt;li&gt;Prune monthly so quality stays high&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does your team's prompt workflow look like today — shared system, or scattered chaos?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>teams</category>
      <category>saas</category>
    </item>
    <item>
      <title>How Japan Just Beat Claude Mythos</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Fri, 26 Jun 2026 04:56:39 +0000</pubDate>
      <link>https://dev.to/speed_engineer/how-japan-just-beat-claude-mythos-2odd</link>
      <guid>https://dev.to/speed_engineer/how-japan-just-beat-claude-mythos-2odd</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4bc3ry54tmygicfmb5c2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4bc3ry54tmygicfmb5c2.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;A founder I know forwarded me the Sakana launch tweet with one line on top: "should we switch?"&lt;br&gt;
Look, the tweet worked on him. Fugu Ultra stands shoulder-to-shoulder with Fable 5 and Mythos preview, no export controls attached, and that was all it took. My honest first reaction was a small stomach drop, because if it were true it'd reset half my stack.&lt;br&gt;
Then I read the actual post. Fugu isn't a model. It's an orchestration layer wearing a model's coat.&lt;br&gt;
And the part that should bother you isn't the marketing. It's that a lot of senior people saw one benchmark beat Fable and stopped reading right there.&lt;br&gt;
I've had three of these models in production this year, so I read launch posts like this one with a particular kind of suspicion. This one earned it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters before you forward it to your&amp;nbsp;CTO
&lt;/h2&gt;

&lt;p&gt;The export-controls line isn't a benchmark claim. It's a procurement claim. Fable and Mythos access got suspended under a directive, so a vendor shows up saying you can have that frontier output anyway, through them, no paperwork.&lt;br&gt;
And honestly, if legal just killed your Mythos access mid-project, that hurts. A wrapper that routes around it sounds like oxygen.&lt;br&gt;
But you're not buying a model. You're buying a middleman who rents the same models you could rent yourself, then charges you to pick between them. Somebody should say that out loud before the contract gets signed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number everyone&amp;nbsp;misread
&lt;/h2&gt;

&lt;p&gt;The standard instinct is that a higher LiveCodeBench score means a smarter system, and usually that instinct is fair. Most of us live and die by SWE-bench and terminal-bench numbers when we pick a coding model.&lt;br&gt;
That breaks the moment the thing on the leaderboard isn't a model.&lt;br&gt;
Fugu Ultra scored 93.2 on LiveCodeBench. Fable scored 89.3. But Fable is inside Fugu Ultra. So is GPT. We don't actually know the full roster underneath, and that right there is part of the problem.&lt;br&gt;
You didn't watch Japan beat Anthropic. You watched Anthropic's model, plus a few other models, plus a router, beat Anthropic's model running alone.&lt;br&gt;
A collection of models beating one of its own members isn't a discovery. We've known that since boosting. Four of you post a faster total than Usain Bolt, and somehow that's "we beat Bolt."&lt;/p&gt;

&lt;h2&gt;
  
  
  What they actually built is a router, not a&amp;nbsp;model
&lt;/h2&gt;

&lt;p&gt;The framing is junk. The engineering underneath is actually interesting.&lt;br&gt;
OpenRouter already shipped this shape with their Fusion idea, where one prompt fans out to several models at once and a judge model reads all the answers and stitches them into a single reply. Same path on every request, nothing learned about when to do what.&lt;br&gt;
Sakana's twist is that the orchestrator is itself a small trained LLM. It doesn't fire every model on every request. It's trained to decide which models to call, when to delegate, and how to stitch the result. They ship two tiers. Fugu handles low-latency work; Fugu Ultra pulls in a deeper pool of agents for the hard multi-step stuff.&lt;br&gt;
So the thing you call is a learned dispatcher, right? The raw intelligence still comes from the frontier models underneath: Opus, GPT, Fable, take your pick. Sakana owns the routing and the synthesis, and that's the whole product.&lt;br&gt;
There's a name for this. It's the mixture-of-agents pattern, productized behind one endpoint. Useful, but nowhere near frontier.&lt;br&gt;
Sakana FuguThat's why the leaderboard comparison doesn't survive a second look. The number proves the bundle is good. It says nothing about whether Sakana built the good part, and for a buying decision that's the whole game.&lt;br&gt;
It's closer to an AI harness than a model, honestly. Claude Code is a harness too, and nobody puts Claude Code on a model leaderboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same call, four&amp;nbsp;invoices
&lt;/h2&gt;

&lt;p&gt;The API is the seductive part. You hit one endpoint, you get one answer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Looks like any other model call. That's the whole pitch.&lt;br&gt;
resp = client.messages.create(&lt;br&gt;
    model="fugu-ultra",          # not a model, a dispatcher&lt;br&gt;
    messages=[{"role": "user", "content": prompt}],&lt;br&gt;
)&lt;br&gt;
Under the hood this may have called Opus + GPT + Fable,&lt;br&gt;
run a judge pass, and billed you for every token of all of them.&lt;br&gt;
You can't see which. The selection logic is closed source.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That last comment is the real problem. You don't get to see the routing. You can't inspect which models ran, why, or how the final answer got assembled. It's a black box sitting on top of other black boxes.&lt;br&gt;
Now the bill, in dollars. Somebody on Hacker News put it better than any analyst:&lt;br&gt;
You already pay $200 each to Anthropic, OpenAI, Cursor, Google. It doesn't round up nicely, so you end up paying another $200 a month to Sakana just to coordinate it.&lt;br&gt;
Call it another $200. The exact figure doesn't matter, the shape does. You're already paying every provider underneath, and now you're paying a margin on top to have something choose between them.&lt;br&gt;
Do the math on a single hard request and it's worse than one tax.&lt;/p&gt;

&lt;p&gt;`One hard request, Fugu Ultra fans out to ~3 models + a synthesis pass.&lt;/p&gt;

&lt;p&gt;Solo call (what you do today):&lt;br&gt;
   ~20K input + ~4K output, billed once, to one provider.&lt;/p&gt;

&lt;p&gt;Fugu Ultra, same request:&lt;br&gt;
   ~20K input x 3 models       -&amp;gt; ~60K input across 3 providers&lt;br&gt;
   ~4K output x 3 models       -&amp;gt; ~12K output&lt;br&gt;
   synthesis pass reads it all -&amp;gt; ~32K input + ~4K output&lt;/p&gt;




&lt;p&gt;~3x to 4x the tokens, in and out, for ONE answer,&lt;br&gt;
   then Sakana's margin on top.&lt;/p&gt;

&lt;p&gt;At frontier prices, that's not a rounding error.&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;For a one-off hard problem where being right beats the bill, sure, maybe it's worth it. For your day-to-day coding loop, you're lighting money on fire to get an answer your existing frontier model would've handed you anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  The aftermath
&lt;/h2&gt;

&lt;p&gt;To be fair, the team isn't a bunch of clowns. David Ha, co-founder and CEO, made managing director at Goldman running rates trading in Japan before he left for Google Brain, where he co-authored the World Models paper that a lot of us actually read. The beta ran with close to 500 early users building real things, and the demos aren't faked: small UIs, chess, 3D-cube solving, some ML work.&lt;br&gt;
But the reaction split for a reason. The same crowd that respects the founder is also side-eyeing a lab that calls itself frontier while mostly selling B2B AI apps to Japanese businesses, with recruiting people describe as abrasive. He's clearly driven. But this thing just doesn't feel thought through.&lt;/p&gt;

&lt;h2&gt;
  
  
  There's no moat&amp;nbsp;here
&lt;/h2&gt;

&lt;p&gt;Plenty could still go wrong here, and I don't do happy endings.&lt;br&gt;
First, defensibility. If the routing is a genuinely novel trick that reliably squeezes more out of the same models, then every frontier lab ships their own version inside a week. Anthropic and OpenAI already hold all the pieces. Why would they hand the coordination margin to a third party sitting on top of their own models? They wouldn't. They'd absorb it.&lt;br&gt;
Then there's variance. A chunk of that "feels smarter" could be retry behavior and lucky sampling, not real lift. Run it across many benchmarks instead of one cherry-picked bench and the gap might shrink to noise. They showed one bench, which is the tell.&lt;br&gt;
And the black box. When Fugu hands you a wrong answer, you can't tell which underlying model failed or why the router picked it. Good luck debugging that during an incident. You've outsourced the exact layer you need to see into, and that opacity bites you in production every single time.&lt;br&gt;
So no, Japan didn't beat Mythos. A clever dispatcher rented Mythos by the token and stacked a few friends on top. If you're already on a frontier model, don't jump ship. If you're coming from something three or four months old, you'll feel a lift, but that lift is the frontier models underneath, and you can rent those directly without the extra invoice.&lt;br&gt;
They're selling it as the last API key you'll ever need. What it actually is: four bills to coordinate them all.&lt;/p&gt;




&lt;p&gt;Enjoyed the read? Let's stay connected!&lt;br&gt;
🚀 Follow The Speed Engineer for more Rust, Go and high-performance engineering stories.&lt;br&gt;
💡 Like this article? Follow for daily speed-engineering benchmarks and tactics.&lt;br&gt;
⚡ Stay ahead in Rust and Go - follow for a fresh article every morning &amp;amp; night.&lt;/p&gt;

&lt;p&gt;Your support means the world and helps me create more content you'll love. ❤️&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>Your users already built your product — look at their ugly workarounds</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Fri, 26 Jun 2026 03:48:15 +0000</pubDate>
      <link>https://dev.to/speed_engineer/your-users-already-built-your-product-look-at-their-ugly-workarounds-3mmg</link>
      <guid>https://dev.to/speed_engineer/your-users-already-built-your-product-look-at-their-ugly-workarounds-3mmg</guid>
      <description>&lt;p&gt;When you build software, users will happily tell you what they want. "Make it faster." "Add a dashboard." "Make it more like [competitor]." Most of it is noise. People are great at describing pain and terrible at prescribing solutions — and the solution they ask for is rarely the one that fixes the pain.&lt;/p&gt;

&lt;p&gt;The real signal isn't in what users request. It's in what they've already cobbled together to survive without you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two products, one habit
&lt;/h2&gt;

&lt;p&gt;I've built two SaaS products, and both came from staring at a workaround instead of a feature request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FillTheTimesheet.&lt;/strong&gt; Freelancers and agencies don't say "I need time-tracking software." They say tracking is annoying and they'll deal with it later. So I watched what "later" actually looked like: the last day of the month, a blank spreadsheet, and someone reconstructing three weeks of work from calendar invites, Slack scrollback, and memory. That monthly guessing ritual &lt;em&gt;was&lt;/em&gt; the spec. It said: capture has to happen in the moment, with near-zero friction, or it won't happen at all. Nobody requested that. The workaround screamed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PromptShip.&lt;/strong&gt; Teams using ChatGPT, Claude, or Gemini don't ask for a "prompt library." But watch them work and the same artifact shows up everywhere: a chaotic Google Doc, a pinned chat message, a personal notes file full of prompts that worked once. Someone writes a genuinely good prompt, shares it, and a month later everyone has lost it and rebuilt it from scratch. That messy doc is a feature request written in frustration. It said: these prompts are reusable assets the team keeps re-earning, so they need one shared home and one-click reuse — not better documentation discipline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why workarounds beat feedback
&lt;/h2&gt;

&lt;p&gt;A workaround is a revealed preference. It already passed the only test that matters: someone was annoyed enough to do extra work to get around the gap. That's a person voting with effort, not opinion.&lt;/p&gt;

&lt;p&gt;Feature requests are the opposite. They're cheap to say and easy to abandon. "I'd use that" predicts nothing. "I built a fragile spreadsheet to do that every Friday" predicts a real need.&lt;/p&gt;

&lt;p&gt;So when I sit with a user now, I've stopped asking "what do you want?" I ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What do you do right before and after using the tool? (the manual glue)&lt;/li&gt;
&lt;li&gt;Where's the spreadsheet, doc, or notes file you've built on the side?&lt;/li&gt;
&lt;li&gt;What do you redo every week that you wish you didn't?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The answers map almost directly onto a roadmap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap
&lt;/h2&gt;

&lt;p&gt;The catch is that workarounds are a little embarrassing, so people hide them. Nobody volunteers "I reconstruct my hours from memory" or "our prompts live in a doc called final_FINAL_v3." You have to make it safe to admit the hacky thing. Once you do, they'll hand you the spec for free.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Treat feature requests as symptoms, not specs.&lt;/li&gt;
&lt;li&gt;Hunt for the workaround: the spreadsheet, the doc, the pinned message, the manual ritual.&lt;/li&gt;
&lt;li&gt;A workaround is effort someone already spent — the strongest signal you'll get.&lt;/li&gt;
&lt;li&gt;Build the thing that makes the workaround unnecessary, then get out of the way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The two products I'm proudest of weren't ideas. They were someone's ugly workaround, made a little less ugly.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://fillthetimesheet.com" rel="noopener noreferrer"&gt;FillTheTimesheet&lt;/a&gt; and &lt;a href="https://promptship.co" rel="noopener noreferrer"&gt;PromptShip&lt;/a&gt; both started as someone's workaround. If you're running an ugly one right now, I'd genuinely love to hear it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>saas</category>
      <category>productivity</category>
      <category>lessons</category>
    </item>
    <item>
      <title>Your team's best AI prompts are dying in chat threads</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Thu, 25 Jun 2026 03:45:37 +0000</pubDate>
      <link>https://dev.to/speed_engineer/your-teams-best-ai-prompts-are-dying-in-chat-threads-21n0</link>
      <guid>https://dev.to/speed_engineer/your-teams-best-ai-prompts-are-dying-in-chat-threads-21n0</guid>
      <description>&lt;h2&gt;
  
  
  The $0 asset your team keeps throwing away
&lt;/h2&gt;

&lt;p&gt;Someone on your team just wrote a ChatGPT prompt that turns a messy bug report into a clean changelog entry. It works perfectly. They paste it in Slack. Three people react with a fire emoji.&lt;/p&gt;

&lt;p&gt;Two weeks later, nobody can find it.&lt;/p&gt;

&lt;p&gt;This happens on every team using AI right now. The prompts that actually work — the ones refined through ten frustrating iterations — live in DMs, sticky notes, and someone's chat history. They're treated as throwaway text instead of what they really are: reusable operational knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why prompts are worth saving
&lt;/h2&gt;

&lt;p&gt;A good prompt is basically a small program written in plain English. It encodes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exact context the model needs&lt;/li&gt;
&lt;li&gt;The output format you actually want&lt;/li&gt;
&lt;li&gt;The edge cases someone discovered the hard way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you lose it, you don't just lose text. You lose the twenty minutes of iteration that produced it — multiplied by every teammate who later reinvents the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lightweight system that works
&lt;/h2&gt;

&lt;p&gt;You don't need anything fancy to start. Here's the minimum viable prompt library:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One shared location.&lt;/strong&gt; Not five. One.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A title that describes the job, not the tool.&lt;/strong&gt; "Turn meeting notes into action items" beats "ChatGPT prompt 3".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A category.&lt;/strong&gt; Marketing, support, code, hiring — whatever maps to your team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The prompt itself, copy-paste ready.&lt;/strong&gt; No screenshots.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One line on when to use it.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. The discipline is harder than the structure: every time a prompt earns a reaction in chat, it goes in the library &lt;em&gt;before&lt;/em&gt; the thread scrolls away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this breaks down
&lt;/h2&gt;

&lt;p&gt;A shared doc or sheet gets you surprisingly far. It breaks when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People stop copying prompts out because it's two clicks too many&lt;/li&gt;
&lt;li&gt;There's no sense of which prompts are actually being used&lt;/li&gt;
&lt;li&gt;Prompts drift, and nobody knows which version is current&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point the bottleneck isn't structure — it's friction and visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  How PromptShip fits in
&lt;/h2&gt;

&lt;p&gt;This is the itch we built &lt;a href="https://promptship.co" rel="noopener noreferrer"&gt;PromptShip&lt;/a&gt; to scratch. It's a shared prompt library for teams: one-click copy straight into ChatGPT, Claude, or Gemini, categories, version history, and usage analytics so you can see which prompts your team actually relies on. Think &lt;em&gt;Notion-for-prompts&lt;/em&gt; rather than a developer toolkit — it's aimed at marketing, sales, support, and HR folks as much as engineers. There's a free tier if you want to try the idea without committing.&lt;/p&gt;

&lt;p&gt;But the tool is secondary. The mindset is the point: &lt;strong&gt;treat your best prompts as shared infrastructure, not disposable chat messages.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The prompts that work are operational knowledge — capture them deliberately&lt;/li&gt;
&lt;li&gt;Start with one shared location, job-based titles, and copy-paste-ready text&lt;/li&gt;
&lt;li&gt;Watch for friction and version drift as your library grows&lt;/li&gt;
&lt;li&gt;Whatever tool you use, the win is making good prompts findable and reusable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's your team's system for this right now? Curious whether anyone's actually cracked it with plain docs.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>teams</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>Sunday Notes: Find Where Before You Theorize Why</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Sun, 14 Jun 2026 03:47:56 +0000</pubDate>
      <link>https://dev.to/speed_engineer/sunday-notes-find-where-before-you-theorize-why-57o2</link>
      <guid>https://dev.to/speed_engineer/sunday-notes-find-where-before-you-theorize-why-57o2</guid>
      <description>&lt;p&gt;This week I wrote about two things that have nothing to do with each other.&lt;/p&gt;

&lt;p&gt;On Saturday it was a debugging story: a service was losing 30% of its UDP packets, I spent the better part of a day convinced a switch was dying, and the network turned out to be completely innocent — my own host was accepting the datagrams and then dropping them because a socket buffer kept filling during bursts. One kernel counter (&lt;code&gt;netstat -su&lt;/code&gt;, "receive buffer errors") would have told me that in about ten seconds.&lt;/p&gt;

&lt;p&gt;Earlier in the week it was product stuff: why teams keep losing their best work, why a freelancer's Friday disappears into "what was I even doing on Tuesday," why a marketing team rewrites the same prompt every quarter.&lt;/p&gt;

&lt;p&gt;It wasn't until I sat down to write this recap that I noticed they're the same lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shared mistake
&lt;/h2&gt;

&lt;p&gt;In the packet story, the expensive move was theorizing about &lt;em&gt;why&lt;/em&gt; before establishing &lt;em&gt;where&lt;/em&gt;. "The network is dropping packets" is a theory about cause. It sent me to the wrong team, the wrong dashboards, the wrong week. The cheap move — the one I skipped — was localizing first: are the packets dying on the wire, or after they reach my box? Two completely different buildings, identical symptom.&lt;/p&gt;

&lt;p&gt;Product decisions have the exact same failure mode. "Users churn because we're missing feature X" is a theory about why. It's also, usually, the most expensive possible thing to act on first, because building X takes a quarter and the theory might be wrong. The cheap move is to localize: &lt;em&gt;where&lt;/em&gt; in the week, the workflow, or the funnel does the value actually leak out?&lt;/p&gt;

&lt;p&gt;When you force yourself to find &lt;em&gt;where&lt;/em&gt; first, the answer is often boring and small — and boring and small is good news, because boring and small is cheap to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I keep coming back to this
&lt;/h2&gt;

&lt;p&gt;Both of the things I work on are, underneath the marketing, just instruments for making "where" visible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fillthetimesheet.com" rel="noopener noreferrer"&gt;FillTheTimesheet&lt;/a&gt; exists because "I undercharged this month" is a why-theory; the useful version is &lt;em&gt;where&lt;/em&gt; the billable hours actually went, captured while they happened instead of reconstructed on Friday.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://promptship.co" rel="noopener noreferrer"&gt;PromptShip&lt;/a&gt; is the same shape pointed at a different problem: "our team is bad at AI" is a why-theory; "the prompt that worked is sitting in one person's chat history and nobody else can find it" is a &lt;em&gt;where&lt;/em&gt;. One is an identity crisis, the other is a Tuesday-afternoon fix.&lt;/p&gt;

&lt;p&gt;Neither is glamorous. Both are counters you check before you theorize.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Sunday takeaway
&lt;/h2&gt;

&lt;p&gt;Find where before you theorize why. It works on packets, it works on churn, and it works on most arguments that have gone in circles for more than ten minutes. Locate the problem in space before you start explaining it — the explanation is usually cheaper, and more often correct, once you know where you're standing.&lt;/p&gt;

&lt;p&gt;The full UDP debugging story, counters and buffer math included, is on Medium if that's your kind of weekend reading: &lt;a href="https://medium.com/@speed_enginner/networking-for-developers-i-lost-30-of-udp-packets-the-debugging-story-f755f5680b35" rel="noopener noreferrer"&gt;I Lost 30% of My UDP Packets — The Debugging Story&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the last thing you assumed the cause of — before you actually measured where it was happening?&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>saas</category>
      <category>startup</category>
      <category>debugging</category>
    </item>
    <item>
      <title>I Lost 30% of My UDP Packets — and the Network Was Innocent</title>
      <dc:creator>speed engineer</dc:creator>
      <pubDate>Sat, 13 Jun 2026 03:54:53 +0000</pubDate>
      <link>https://dev.to/speed_engineer/i-lost-30-of-my-udp-packets-and-the-network-was-innocent-5die</link>
      <guid>https://dev.to/speed_engineer/i-lost-30-of-my-udp-packets-and-the-network-was-innocent-5die</guid>
      <description>&lt;p&gt;A receiver pulling a UDP feed was missing roughly 30% of its messages. No errors, no exceptions, no stack traces — just gaps in the sequence numbers. The first suspect is always the network: a flaky switch, a saturated link, a tired NIC.&lt;/p&gt;

&lt;p&gt;The network was innocent. The packets were being dropped &lt;em&gt;on the receiving host&lt;/em&gt;, after they'd already arrived. Here's how to tell the difference, and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why UDP makes this sneaky
&lt;/h2&gt;

&lt;p&gt;UDP has no retransmission and no backpressure. When a datagram is lost, nobody is notified — not the sender, not the receiver. The packet simply isn't there.&lt;/p&gt;

&lt;p&gt;That means two completely different failures look identical from the application's point of view:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The network dropped the packet &lt;em&gt;before&lt;/em&gt; it reached your machine.&lt;/li&gt;
&lt;li&gt;Your own host accepted the packet and then threw it away &lt;em&gt;after&lt;/em&gt; it arrived.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application sees the same thing in both cases: a missing sequence number. But the fix is in a different building depending on which one it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the packets actually go
&lt;/h2&gt;

&lt;p&gt;The receive path is: NIC → kernel socket receive buffer → your &lt;code&gt;recv()&lt;/code&gt; call. The kernel parks incoming datagrams in a per-socket buffer until your code reads them. If your code doesn't drain that buffer fast enough, it fills, and the kernel drops the overflow. Crucially, &lt;strong&gt;the kernel counts those drops.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Per-protocol summary — look for "receive buffer errors"&lt;/span&gt;
netstat &lt;span class="nt"&gt;-su&lt;/span&gt;

&lt;span class="c"&gt;# Or straight from the kernel counters&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/net/snmp | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A1&lt;/span&gt; Udp
&lt;span class="c"&gt;#   InDatagrams  ... InErrors  RcvbufErrors ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;RcvbufErrors&lt;/code&gt; is climbing, the network did its job and &lt;em&gt;your host&lt;/em&gt; discarded the datagrams. That single counter collapses a week of "is it the switch?" into about ten seconds of certainty.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;In this case the socket receive buffer was sitting at the default (~208 KB). The sender burst faster than a single receive thread could call &lt;code&gt;recv()&lt;/code&gt;. Average throughput looked fine on every dashboard — but the bursts filled the buffer in milliseconds, and everything past the brim was dropped. The metric that mattered wasn't mean throughput; it was peak burst versus drain rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, in order of leverage
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Drain faster.&lt;/strong&gt; The receive loop was parsing &lt;em&gt;and&lt;/em&gt; doing a database write inline. Anything that isn't "copy bytes out of the socket" belongs off the hot path: &lt;code&gt;recv()&lt;/code&gt; → hand the buffer to a queue → immediately loop back to &lt;code&gt;recv()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raise the buffer.&lt;/strong&gt; Bump &lt;code&gt;SO_RCVBUF&lt;/code&gt;, and raise &lt;code&gt;net.core.rmem_max&lt;/code&gt; so the kernel actually honors the request. A bigger buffer doesn't fix a slow consumer — it absorbs bursts so a fast-enough consumer never falls behind. You usually need both this and #1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch your syscalls.&lt;/strong&gt; &lt;code&gt;recvmmsg()&lt;/code&gt; pulls many datagrams per system call, which cuts per-packet overhead when volume is high.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spread the load.&lt;/strong&gt; If one core genuinely can't keep up, &lt;code&gt;SO_REUSEPORT&lt;/code&gt; lets multiple threads share the same port with separate buffers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"Packet loss" is a &lt;em&gt;location&lt;/em&gt;, not a cause. Find out &lt;strong&gt;where&lt;/strong&gt; before you theorize about &lt;strong&gt;why&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;With UDP, silent drops are the default — the protocol won't tell you, so the kernel counters have to.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RcvbufErrors&lt;/code&gt; is the first thing to check. It almost always points at a receive buffer that's too small or a consumer that's too slow.&lt;/li&gt;
&lt;li&gt;A bigger buffer absorbs bursts; a faster drain prevents them. You usually want both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full debugging story — the live-feed before/after, the buffer math, and the exact counters I watched while tuning it — is on Medium:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://medium.com/@speed_enginner/networking-for-developers-i-lost-30-of-udp-packets-the-debugging-story-f755f5680b35" rel="noopener noreferrer"&gt;Networking for Developers: I Lost 30% of UDP Packets — The Debugging Story&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I write more like this on Medium as **The Speed Engineer&lt;/em&gt;* — performance engineering, debugging stories, and the lower-level systems work that doesn't fit in a tweet.*&lt;/p&gt;

</description>
      <category>networking</category>
      <category>debugging</category>
      <category>programming</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
