<?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: vigneshwar</title>
    <description>The latest articles on DEV Community by vigneshwar (@vignesh_one).</description>
    <link>https://dev.to/vignesh_one</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%2F3935700%2F6e993d38-e7ea-457a-a1f2-58f418c63695.png</url>
      <title>DEV Community: vigneshwar</title>
      <link>https://dev.to/vignesh_one</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vignesh_one"/>
    <language>en</language>
    <item>
      <title>The 90-day window every medical shop misses: I built ShelfMitra to catch it, in Tamil, Hindi and English</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 15:59:17 +0000</pubDate>
      <link>https://dev.to/vignesh_one/the-90-day-window-every-medical-shop-misses-i-built-shelfmitra-to-catch-it-in-tamil-hindi-and-26dd</link>
      <guid>https://dev.to/vignesh_one/the-90-day-window-every-medical-shop-misses-i-built-shelfmitra-to-catch-it-in-tamil-hindi-and-26dd</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Walk into any medical shop in Chennai and look behind the counter. There are a couple of thousand strips, bottles and inhalers, bought from two or three distributors, each with a batch number and an expiry date printed somewhere tiny.&lt;/p&gt;

&lt;p&gt;Here is the part most people outside the trade don't know. Distributors will usually take expiring stock back, but only until a cutoff. On the invoice it says something like &lt;em&gt;"Expiry returns accepted up to 90 days before expiry against original invoice."&lt;/em&gt; Miss that window by a week and the strip is yours to throw away.&lt;/p&gt;

&lt;p&gt;Nobody misses it on purpose. The owner is billing customers from 8 AM to 10 PM. Checking 2,000 expiry dates against how fast each medicine actually sells is nobody's job, so the cutoff passes quietly and the money goes in the bin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ShelfMitra&lt;/strong&gt; does that check for every batch, every day:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You photograph the distributor invoice.&lt;/strong&gt; An open-weight vision model reads the table. Plain code then checks every line before anything is saved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It predicts which batches will still be sitting on the shelf when the return window closes&lt;/strong&gt;, using TabPFN-3.5 on the shop's own sales, and sorts the shelf by rupees at risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A durable Temporal workflow watches each batch&lt;/strong&gt; and reminds the owner at 60, 30, 14, 7 and 2 days before the cutoff, but only if that batch is at risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One tap writes the return request&lt;/strong&gt; to the distributor as a WhatsApp message, in Tamil, Hindi or English.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The owner can just ask.&lt;/strong&gt; "இந்த வாரம் எதை திருப்பி அனுப்பணும்?" (what should I send back this week?) or "Brufen 100 aur mangwaun?" goes to an agent that checks the numbers before it answers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Who pays: the owner of a single medical shop, the kind with one billing PC and no IT person. I'd charge ₹299 a month. The pitch is one sentence: if it saves one box of inhalers from the bin, it has paid for itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live app&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://shelfmitra.onrender.com" rel="noopener noreferrer"&gt;shelfmitra.onrender.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Website&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://shelfmitra.vercel.app" rel="noopener noreferrer"&gt;shelfmitra.vercel.app&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/vignesh2027/shelfmitra" rel="noopener noreferrer"&gt;github.com/vignesh2027/shelfmitra&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;60 s video&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://shelfmitra.vercel.app/media/shelfmitra-demo.mp4" rel="noopener noreferrer"&gt;shelfmitra-demo.mp4&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Eval&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/vignesh2027/shelfmitra/blob/master/eval/results.md" rel="noopener noreferrer"&gt;eval/results.md&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No signup needed. You land in a demo shop, &lt;em&gt;Lakshmi Medicals, Mylapore&lt;/em&gt;, and everything in it is live: the open models, the invoice reader and a Temporal watch on every batch. Create a free shop to get a private, empty one. It runs on Render's free instance, so if nobody has visited for a while the first load takes about a minute while it wakes up.&lt;/p&gt;

&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%2Feyxj7qcrf7w9dzgneiy4.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%2Feyxj7qcrf7w9dzgneiy4.png" alt="ShelfMitra live on Render" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One honest note about that live demo: TabPFN-3.5 peaks at about 2.3 GB of RAM while scoring on CPU, and the free instance has 512 MB. So the public demo scores with the straight-line rule, and the header says &lt;strong&gt;Rule only&lt;/strong&gt; instead of pretending. Every TabPFN screenshot below comes from the full app on my machine, and the benchmark further down shows exactly what TabPFN adds over that rule.&lt;/p&gt;

&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%2Fxtrepy9uqr3atz53q5le.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%2Fxtrepy9uqr3atz53q5le.png" alt="Dashboard" width="799" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the full app with TabPFN running. The shelf is sorted by money at risk rather than by date. The Asthalin inhaler is only 12 units, but it has 19 days left to return and an 86% chance of still being there, so it sits at the top:&lt;/p&gt;

&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%2F35hwv8int1mbc2pg4d5o.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%2F35hwv8int1mbc2pg4d5o.png" alt="Shelf sorted by rupees at risk" width="800" height="839"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reading an invoice photo. All 8 lines pass the checks, and brand names are matched to their ingredient (Montair LC becomes montelukast + levocetirizine):&lt;/p&gt;

&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%2Fe5hz10o4ip6zy4g60x0g.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%2Fe5hz10o4ip6zy4g60x0g.png" alt="Invoice read and checked" width="738" height="1218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole app switches to Tamil or Hindi, including the agent and the message to the distributor:&lt;/p&gt;

&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%2Fqb32ga63cloi2d9wh9tw.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%2Fqb32ga63cloi2d9wh9tw.png" alt="Tamil UI" width="799" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&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%2Fp53lgj2go3oggukvdpbi.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%2Fp53lgj2go3oggukvdpbi.png" alt="Return request in Tamil" width="800" height="1258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnislh6c2h8jfi8hvbmmk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnislh6c2h8jfi8hvbmmk.gif" alt="60 second demo" width="560" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vignesh2027" rel="noopener noreferrer"&gt;
        vignesh2027
      &lt;/a&gt; / &lt;a href="https://github.com/vignesh2027/shelfmitra" rel="noopener noreferrer"&gt;
        shelfmitra
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Catch medicines that will expire unsold while the distributor still takes them back. Tamil, Hindi, English. Open-weight models, TabPFN-3.5, Temporal.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vignesh2027/shelfmitra/web/logo.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvignesh2027%2Fshelfmitra%2FHEAD%2Fweb%2Flogo.svg" width="72" alt="ShelfMitra logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ShelfMitra&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Sell it before it expires.&lt;/b&gt;&lt;br&gt;
Expiry rescue for Indian medical shops, in Tamil, Hindi and English.&lt;/p&gt;
&lt;p&gt;
&lt;a href="https://shelfmitra.onrender.com" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Live app&lt;/b&gt;&lt;/a&gt; ·
&lt;a href="https://shelfmitra.vercel.app" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Website&lt;/b&gt;&lt;/a&gt; ·
&lt;a href="https://shelfmitra.vercel.app/media/shelfmitra-demo.mp4" rel="nofollow noopener noreferrer"&gt;60 s demo video&lt;/a&gt; ·
&lt;a href="https://github.com/vignesh2027/shelfmitra#run-it" rel="noopener noreferrer"&gt;Run it&lt;/a&gt; ·
&lt;a href="https://github.com/vignesh2027/shelfmitra#how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; ·
&lt;a href="https://github.com/vignesh2027/shelfmitra#does-tabpfn-actually-help" rel="noopener noreferrer"&gt;Eval&lt;/a&gt; ·
&lt;a href="https://github.com/vignesh2027/shelfmitra#temporal-kill-the-worker-lose-nothing" rel="noopener noreferrer"&gt;Crash demo&lt;/a&gt; ·
&lt;a href="https://github.com/vignesh2027/shelfmitra#limits" rel="noopener noreferrer"&gt;Limits&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vignesh2027/shelfmitra/docs/media/shelfmitra-demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvignesh2027%2Fshelfmitra%2FHEAD%2Fdocs%2Fmedia%2Fshelfmitra-demo.gif" alt="ShelfMitra demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The problem&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;A neighbourhood medical shop buys from two or three distributors. Most distributors take expired or near-expiry
stock back, but only until a cutoff, usually 60 to 90 days before the printed expiry. After that the strip is
the shop's loss. Nobody has time to check the expiry of 2,000 batches against how fast each one sells, so the
cutoff passes quietly and the medicine goes in the bin.&lt;/p&gt;
&lt;p&gt;ShelfMitra does that check for every batch, every day, and tells the owner which ones to send back while the
distributor will still take them.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reads the distributor invoice from a photo.&lt;/strong&gt; An open-weight vision model (Qwen)…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vignesh2027/shelfmitra" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT. Python, FastAPI, vanilla JS. Three commands to run it locally, 9 tests (Temporal time-skipping tests for the batch watch, plus account isolation tests).&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The one rule: the model reads, code decides
&lt;/h3&gt;

&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%2Fpfmcn0lqkkbvwr402p4p.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%2Fpfmcn0lqkkbvwr402p4p.png" alt="How ShelfMitra works" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every number the owner sees is a number they might act on with real money, so I split the work strictly:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Who does it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Copy the invoice table from a photo&lt;/td&gt;
&lt;td&gt;Qwen (open-weight vision model)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is &lt;code&gt;D2241&lt;/code&gt; a plausible batch? Is &lt;code&gt;03/27&lt;/code&gt; a real expiry? Does qty x rate = amount?&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Will this batch still be on the shelf at the cutoff?&lt;/td&gt;
&lt;td&gt;TabPFN-3.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return now, stop reordering, watch, or fine?&lt;/td&gt;
&lt;td&gt;Python, from TabPFN's risk and the days left&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write a polite return request in Tamil&lt;/td&gt;
&lt;td&gt;gpt-oss-120b writes a template once; Python fills every number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Understand "Brufen 100 aur mangwaun?" and pick a tool&lt;/td&gt;
&lt;td&gt;gpt-oss-120b&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Any invoice line that fails a check is flagged for the pharmacist instead of guessed. An expiry of &lt;code&gt;03/27&lt;/code&gt; becomes 31 March 2027, because medicines expire at the end of the printed month, and that is code, not a model's opinion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does TabPFN actually beat a simple rule?
&lt;/h3&gt;

&lt;p&gt;Before I trusted it, I built a benchmark. There is no public Indian pharmacy sales data that I could use, so I took a public dataset of six years of real daily sales from one pharmacy across eight drug classes (&lt;a href="https://www.kaggle.com/datasets/milanzdravkovic/pharma-sales-data" rel="noopener noreferrer"&gt;Pharma sales data on Kaggle&lt;/a&gt;, CC BY-NC 4.0). I dropped simulated batches into that history, each with a random quantity and a random number of days to its cutoff, and asked one question: &lt;strong&gt;will more than 10% of this batch still be unsold at the cutoff?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I trained on 2014 to 2017 and tested on 2018 to 2019, with five seeds per size.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Training batches&lt;/th&gt;
&lt;th&gt;ROC-AUC&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Straight-line rule (sales rate x days left)&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;0.903&lt;/td&gt;
&lt;td&gt;0.849&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logistic regression&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;0.908&lt;/td&gt;
&lt;td&gt;0.863&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gradient boosting&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;0.922&lt;/td&gt;
&lt;td&gt;0.858&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TabPFN-3.5&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;0.895&lt;/td&gt;
&lt;td&gt;0.833&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TabPFN-3.5&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;0.909&lt;/td&gt;
&lt;td&gt;0.849&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TabPFN-3.5&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;0.920&lt;/td&gt;
&lt;td&gt;0.858&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TabPFN-3.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;500&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.949&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.882&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&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%2Fbmzbi50ayzbvoksjwwh3.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%2Fbmzbi50ayzbvoksjwwh3.png" alt="ROC-AUC by training size" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This surprised me. The dumb rule is really good, 0.903, and with 500 examples logistic regression barely beats it. TabPFN passes the rule at about 100 examples and is clearly ahead at 500. So ShelfMitra uses TabPFN when it can and falls back to the rule when it can't, and the header tells you which one is running. I'd rather show that than pretend the rule doesn't exist.&lt;/p&gt;

&lt;p&gt;TabPFN also does a second job. When the owner asks about an order, the agent builds a hypothetical batch and scores it. That turned up a bug I'll come to in a minute.&lt;/p&gt;

&lt;h3&gt;
  
  
  Temporal: I killed the worker, and nothing was lost
&lt;/h3&gt;

&lt;p&gt;A batch can sit on the shelf for a year. The shop PC will restart many times in that year. A cron job or a &lt;code&gt;setTimeout&lt;/code&gt; would quietly forget, and the whole point of the product is to not forget.&lt;/p&gt;

&lt;p&gt;So each batch gets its own Temporal workflow. It sleeps on durable timers, wakes at fixed checkpoints, re-scores the batch with fresh sales, and reminds the owner only if the batch is at risk. It ends early as soon as the owner taps &lt;em&gt;Returned&lt;/em&gt; or &lt;em&gt;Sold&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To prove it, I wrote a &lt;a href="https://github.com/vignesh2027/shelfmitra/blob/master/scripts/crash_demo.py" rel="noopener noreferrer"&gt;crash demo&lt;/a&gt;. A shop "day" lasts one second, so a 70-day window plays out in about a minute. It kills the worker with &lt;code&gt;SIGKILL&lt;/code&gt; right after the first checkpoint and stays down while the next checkpoint falls due:&lt;/p&gt;

&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%2Ff50avsw99lgm36c6tyku.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%2Ff50avsw99lgm36c6tyku.png" alt="Crash demo output" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&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%2Fqbo01hwod60sygcd36kr.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%2Fqbo01hwod60sygcd36kr.png" alt="Temporal UI after the crash" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Temporal UI shows two workers on that one workflow, the one I killed and its replacement. The overdue checkpoint ran as soon as a worker came back. Activities retry with backoff and no attempt limit, so a flaky model call or a dropped connection delays a reminder instead of losing it.&lt;/p&gt;

&lt;p&gt;In the running app it looks like this. The demo shop's Dolo 650 batch has 413 days to its cutoff, so its watch is a single durable timer that will sleep for 11 months and 19 days before the first check:&lt;/p&gt;

&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%2F0cxardy6osma9qoj5yro.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%2F0cxardy6osma9qoj5yro.png" alt="A BatchWatch sleeping 11 months" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accounts, so it's a product and not a demo
&lt;/h3&gt;

&lt;p&gt;Visitors share the demo shop. Signing up creates a private shop with its own SQLite database. Passwords use PBKDF2, sessions are signed cookies, every query is scoped to the shop in the session, and the endpoints that spend model credits are rate-limited. A test checks that shop B can't see shop A's stock. If you already use billing software, you can export sales as CSV and import them. The importer matches columns loosely, because every billing package names them differently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Things I got wrong
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Tamil message came back cut off mid-sentence.&lt;/strong&gt; gpt-oss reasons before it answers, and on Tamil it spent most of my token budget thinking. The API said &lt;code&gt;finish_reason: "length"&lt;/code&gt; and my code didn't check. Now a truncated reply counts as a failure and is retried with more room, and the finished template is cached so it happens once per language, not per message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every model call took 76 seconds.&lt;/strong&gt; I blamed Groq. It was my network: the HTTP client tried IPv6 first, waited for it to time out, then fell back to IPv4. Forcing IPv4 took calls to 1 to 3 seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The agent answered a Tamil question in English.&lt;/strong&gt; My tool returned English labels like &lt;code&gt;return it now&lt;/code&gt;, and the model copied them. Now the tool returns the action already in the owner's language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The agent showed a shop owner &lt;code&gt;stop_reorder&lt;/code&gt; and &lt;code&gt;0.862&lt;/code&gt;&lt;/strong&gt; inside a markdown table, on a phone. Tool results now arrive as percents, rupees and DD/MM/YYYY dates, so there is nothing to convert and nothing to format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order advice ignored the stock already on the shelf.&lt;/strong&gt; "Should I order 100 more Brufen 400?" came back as 22% risk, while 45 strips were already sitting there unsold. Old stock sells first, so the new batch has to be judged on old plus new. Fixed, it's now 44% for 100, and the agent checks 50 instead (20%) before answering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hinglish questions got Tamil answers.&lt;/strong&gt; I had left the reply language to the model. Now plain code decides it from the script and a small list of Hinglish and Tanglish words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The small local model copied my prompt into its answer.&lt;/strong&gt; My invoice prompt described each field, like &lt;code&gt;"expiry": "MM/YY as printed"&lt;/code&gt;. The 3B vision model returned exactly that: every expiry came back as &lt;code&gt;03/27 as printed&lt;/code&gt;, and the return policy came back as my own description of it. The code checks rejected all 8 lines, so nothing wrong reached the shelf. That is the whole reason the checks exist. I rewrote the prompt so it describes the fields in a list instead of showing them as values, and the same model now gets every expiry right.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The data is the business.&lt;/strong&gt; A shop's purchase invoices show what it pays each distributor, its margins and what sells in that neighbourhood. Its sales history is close to a record of what its customers take. Owners won't upload that to whatever API is cheapest this quarter, and they are right not to. With open weights, the same models can run on the shop's own PC: set &lt;code&gt;SHELFMITRA_LLM=local&lt;/code&gt; and ShelfMitra uses Qwen through Ollama instead of a hosted endpoint. TabPFN-3.5 already runs locally on CPU.&lt;/p&gt;

&lt;p&gt;I tested that on my own laptop, an 8 GB M1 Mac, with nothing hosted:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Same sample invoice&lt;/th&gt;
&lt;th&gt;Hosted (Qwen 3.8 27B on Groq)&lt;/th&gt;
&lt;th&gt;Local (qwen2.5vl:3b on Ollama)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;3.5 s&lt;/td&gt;
&lt;td&gt;104 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expiry dates right&lt;/td&gt;
&lt;td&gt;8 of 8&lt;/td&gt;
&lt;td&gt;8 of 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch numbers right&lt;/td&gt;
&lt;td&gt;8 of 8&lt;/td&gt;
&lt;td&gt;7 of 8 (&lt;code&gt;CTZ7712&lt;/code&gt; read as &lt;code&gt;CTZ77712&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return policy read&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So local works, but it is slower, and a 3B model makes the kind of mistake that no format check can catch: &lt;code&gt;CTZ77712&lt;/code&gt; is a perfectly valid-looking batch number. That's why every invoice is shown to the pharmacist as a table before it goes onto the shelf. The local agent on qwen3:4b was too slow on 8 GB to be pleasant, more than ten minutes for three questions, so for now the realistic setup is local invoice reading overnight and hosted open models for chat. A shop PC with 16 GB would change that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The unit economics work.&lt;/strong&gt; I measured real token counts on the hosted open models:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Tokens in / out&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read one invoice photo&lt;/td&gt;
&lt;td&gt;Qwen 3.8 27B (vision)&lt;/td&gt;
&lt;td&gt;1,951 / 984&lt;/td&gt;
&lt;td&gt;about $0.0055&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answer one question&lt;/td&gt;
&lt;td&gt;gpt-oss-120b&lt;/td&gt;
&lt;td&gt;about 2,300 / 200 over 2 to 3 calls&lt;/td&gt;
&lt;td&gt;about $0.0005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Score a batch&lt;/td&gt;
&lt;td&gt;TabPFN-3.5 on CPU&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A busy shop that photographs an invoice every day and asks 100 questions a month costs about &lt;strong&gt;$0.22 a month in model calls, around ₹20&lt;/strong&gt;. At ₹299 a month that leaves room for hosting and support. On a closed frontier API, the per-shop cost could easily be several times higher, and I'd be one price change away from the business not working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tamil and Hindi are first-class, not an afterthought.&lt;/strong&gt; The owner should be able to ask the way they talk, including Tanglish and Hinglish typed in English letters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where a closed model would win, honestly:&lt;/strong&gt; blurry, handwritten or crumpled invoices. A big closed vision model would probably read those better than a 3B model on a shop PC. That's why every line goes through code checks and anything doubtful goes to the pharmacist rather than straight onto the shelf.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built ShelfMitra with an AI coding agent. I picked the problem, the name and the rules: the model reads and code decides, no discount advice on prescription medicines, and honest numbers in the post. The agent wrote most of the code and the eval harness, and I reviewed and steered it. The bugs above came from actually running it, mostly from screenshots that looked wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of TabPFN.&lt;/strong&gt; TabPFN-3.5 is the risk engine. It scores every batch on the shelf, and it scores hypothetical orders for the agent's &lt;code&gt;what_if_order&lt;/code&gt; tool. It is benchmarked against a straight-line rule, logistic regression and gradient boosting on real pharmacy sales with a time-based split (table above), and the app falls back to the rule, visibly, when TabPFN isn't available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Temporal.&lt;/strong&gt; One durable &lt;code&gt;BatchWatch&lt;/code&gt; workflow per batch, with checkpoint timers that span months, signals for the owner's decisions, queries for live status in the dashboard, and retry policies that never give up. It survived a &lt;code&gt;SIGKILL&lt;/code&gt; mid-watch with every checkpoint intact (crash demo above). It also has time-skipping tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Render.&lt;/strong&gt; The live app at &lt;a href="https://shelfmitra.onrender.com" rel="noopener noreferrer"&gt;shelfmitra.onrender.com&lt;/a&gt; is one Docker service on Render running three things together: the FastAPI app, a Temporal dev server and the Temporal worker. Every visitor's batches get real durable workflows on Render, which you can see in the dashboard's &lt;em&gt;Watching every batch&lt;/em&gt; panel:&lt;/p&gt;

&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%2Fdy4rg2ibn00yxrmuk71v.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%2Fdy4rg2ibn00yxrmuk71v.png" alt="Temporal watches running on Render" width="799" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The public demo is on the free instance, so it uses the rule engine and keeps its state on the instance's temporary disk, which resets when it restarts. The repo also has a &lt;a href="https://github.com/vignesh2027/shelfmitra/blob/master/render.yaml" rel="noopener noreferrer"&gt;render.yaml blueprint&lt;/a&gt; for the paid setup a real shop would use: a standard instance with enough RAM for TabPFN-3.5, and a persistent disk for each shop's database and Temporal's state, so reminders survive deploys.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>12 of 13 AI models knew the new name and still wrote the old one</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 15:38:25 +0000</pubDate>
      <link>https://dev.to/vignesh_one/12-of-13-ai-models-knew-the-new-name-and-still-wrote-the-old-one-2jla</link>
      <guid>https://dev.to/vignesh_one/12-of-13-ai-models-knew-the-new-name-and-still-wrote-the-old-one-2jla</guid>
      <description>

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kaggle-2026-09-23"&gt;Kaggle Benchmarking Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Benchmarked
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; I tested 17 AI models on writing, recalling and fixing OpenTelemetry instrumentation, graded in code against 26 releases of the spec.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;16 of 17&lt;/strong&gt; models wrote retired names, and &lt;strong&gt;83%&lt;/strong&gt; of those names had been retired for more than a year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;12 of 13&lt;/strong&gt; models wrote names they had correctly replaced when asked directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;7 of 17&lt;/strong&gt; "fixed" a metric by changing its unit and keeping its retired name, which breaks it both ways.&lt;/li&gt;
&lt;li&gt;One sentence naming the spec version cut retired names by &lt;strong&gt;36%&lt;/strong&gt;, and made models invent more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benchmark: &lt;a href="https://www.kaggle.com/benchmarks/applesone/semconv-drift" rel="noopener noreferrer"&gt;Semconv Drift on Kaggle&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&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%2F7xc1kt4zj9hj5geaxgw6.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%2F7xc1kt4zj9hj5geaxgw6.png" alt=" " width="800" height="714"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I asked Claude Sonnet 5 what replaced the OpenTelemetry attribute &lt;code&gt;db.system&lt;/code&gt;. It answered correctly: &lt;code&gt;db.system.name&lt;/code&gt;, the name the spec has used since January 2025.&lt;/p&gt;

&lt;p&gt;In the same benchmark, I asked it to add tracing to a go-redis call. It wrote this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db.system"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db.operation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmdName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db.statement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All three names are retired. The code compiles, the span exports, the backend stores it. Nothing fails. Weeks later, a dashboard that filters on &lt;code&gt;db.system.name&lt;/code&gt; shows no Redis traffic, and nobody connects the empty panel to a line of generated code.&lt;/p&gt;

&lt;p&gt;This year I have had 14 pull requests merged into OpenTelemetry's Go compile-time instrumentation project, and this is exactly the kind of bug I would wave through in review. The code looks right. It is only wrong against a spec version, and nobody reviews against a spec version. So I built a benchmark to measure how often it happens.&lt;/p&gt;
&lt;h3&gt;
  
  
  The task
&lt;/h3&gt;

&lt;p&gt;OpenTelemetry's semantic conventions are the shared vocabulary of telemetry: which key holds the HTTP method, what a database span calls its query, which unit a duration metric uses. They are versioned, and many of the names people learned first have been renamed. &lt;code&gt;http.method&lt;/code&gt; became &lt;code&gt;http.request.method&lt;/code&gt; in 2023. &lt;code&gt;db.statement&lt;/code&gt; became &lt;code&gt;db.query.text&lt;/code&gt; in 2024. &lt;code&gt;rpc.client.duration&lt;/code&gt;, in milliseconds, became &lt;code&gt;rpc.client.call.duration&lt;/code&gt;, in seconds, in January 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semconv Drift&lt;/strong&gt; has four tasks on Kaggle Benchmarks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Cases&lt;/th&gt;
&lt;th&gt;What the model does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Instrument everyday code: Flask and Express servers, an HTTP client, psycopg, go-redis, kafkajs, gRPC, metrics and resources, in Python, Go and TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Know&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;Name what replaced a retired name. Includes span-kind traps and two controls whose right answer is "unchanged"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fix&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Modernize old snippets, including real code from redis/go-redis, converting values where a unit changed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write with version hint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;The Write requests plus one sentence naming the current spec version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every Write prompt already says &lt;em&gt;"Follow the current OpenTelemetry semantic conventions."&lt;/em&gt; The models were told. The question is what "current" means to them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grading is code, not a judge.&lt;/strong&gt; The grader extracts every semantic convention name from an answer (string keys, metric names, SDK constants in four languages, enum values) and looks each one up in 1,563 names from 26 releases of the spec, v1.21.0 to v1.44.0, plus every name from v1.0.0 to v1.20.0 for the oldest ones. Every retired name carries the release and date that retired it. Reasoning text is stripped first, so a model is judged on the code it wrote. The answer key is tested too: the build fails if any gold answer is not a current name in the ground truth.&lt;/p&gt;

&lt;p&gt;The ground truth comes from &lt;a href="https://github.com/vignesh2027/attrition" rel="noopener noreferrer"&gt;Attrition&lt;/a&gt;, a dataset of every tagged release of &lt;a href="https://github.com/open-telemetry/semantic-conventions" rel="noopener noreferrer"&gt;open-telemetry/semantic-conventions&lt;/a&gt; that I built for DEV's &lt;a href="https://dev.to/apples_one_cd174284bffb/i-contribute-to-opentelemetry-and-still-shipped-two-retired-attribute-names-so-i-built-attrition-129i"&gt;Sanity challenge&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Models Tested
&lt;/h2&gt;

&lt;p&gt;17 models through Kaggle's model proxy, picked to answer three questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Does a newer generation fix it?&lt;/strong&gt; Three same-family pairs: Claude Sonnet 4.5 and 5, GPT-5.4 and 5.5, Gemini 2.5 Pro and 3.1 Pro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does spending more fix it?&lt;/strong&gt; Frontier models (GPT-6 Astra, Claude Opus 5, GPT-5.5, Gemini 3.1 Pro) next to small, cheap ones (GPT-5.4 mini, Claude Haiku 4.5, Gemini 3.7 and 3.8 Flash).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do open-weight models differ?&lt;/strong&gt; Qwen 3 235B, DeepSeek-R1, GLM-5, Gemma 4 31B and gpt-oss-120b.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is 830 graded answers, plus 84 more from repeat runs. Four reasoning models (DeepSeek-R1, GLM-5, Gemma 4 and gpt-oss-120b) have no Know score: on some short factual questions they spent the whole answer budget thinking and never answered. Grok 4.5 and 4.6 returned 404 for my account, so they are not in the lineup.&lt;/p&gt;
&lt;h2&gt;
  
  
  Findings
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. The drift is old, not new
&lt;/h3&gt;

&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%2Fj0is77i74zuxv6pjmbki.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%2Fj0is77i74zuxv6pjmbki.png" alt="Age of each retired name at the time of the run" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;16 of 17 models wrote at least one retired name in Write, 357 uses in all. If this were about training cutoffs, the retired names would be recent ones the models never saw. They are not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;297 of 357 (83%)&lt;/strong&gt; had been retired for more than a year when I ran the benchmark.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;238 (67%)&lt;/strong&gt; had been retired for more than two years, which means before October 2024. Every model in the lineup was released after that.&lt;/li&gt;
&lt;li&gt;The median retired name was retired &lt;strong&gt;2.4 years&lt;/strong&gt; earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These models were not missing the news. They had read the changelog, and years of tutorials before it, and the tutorials won. &lt;code&gt;db.system&lt;/code&gt; is the clearest case: 24 uses across 12 models, nearly two years after the rename.&lt;/p&gt;

&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%2F8ppf2cvwzq4056q97vu3.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%2F8ppf2cvwzq4056q97vu3.png" alt="Most frequent retired names in generated code" width="799" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only names a training cutoff could excuse are the January 2026 &lt;code&gt;rpc.*&lt;/code&gt; renames. 16 models wrote them. GPT-6 Astra was the only exception, and it also avoided every older retired name, so a late cutoff alone does not explain its perfect Write score.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. It told me the new name, then wrote the old one
&lt;/h3&gt;

&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%2Fq7hfba2yh3lbsr6on0im.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%2Fq7hfba2yh3lbsr6on0im.png" alt="Retired names a model wrote although it named the replacement in Know" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because Know and Write ask about the same names, I can check each model against itself. For every retired name a model wrote in Write, did the same model give the correct replacement in Know?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12 of 13 models wrote at least one retired name they had correctly replaced when asked directly&lt;/strong&gt;, 58 times in all. Claude Haiku 4.5 said &lt;code&gt;http.method&lt;/code&gt; became &lt;code&gt;http.request.method&lt;/code&gt;, then wrote &lt;code&gt;http.method&lt;/code&gt; five times. Sonnet 5 did it with &lt;code&gt;db.system&lt;/code&gt;, as in the opening. Only GPT-6 Astra never did it.&lt;/p&gt;

&lt;p&gt;This is not a knowledge gap. Asked a question, a model retrieves the changelog. Asked for code, it retrieves the most common code, and the most common code is old.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. The half fix
&lt;/h3&gt;

&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%2Fs0ej4p77xkj1tej1af0l.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%2Fs0ej4p77xkj1tej1af0l.png" alt="Outcomes of the rpc.client.duration fix" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One Fix case hands the model this Go snippet and asks it to move to v1.44.0, converting values if a unit changed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;dur&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;meter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Float64Histogram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rpc.client.duration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ms"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;invoker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dur&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Milliseconds&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The answer is &lt;code&gt;rpc.client.call.duration&lt;/code&gt;, unit &lt;code&gt;s&lt;/code&gt;, values in seconds. Only GPT-6 Astra got all of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7 of 17 models changed the unit to seconds, converted the values, and kept the retired name.&lt;/strong&gt; That is worse than leaving the code alone. Unchanged code is at least consistent with the old spec. The half-fixed metric emits the old name with the new unit, so it breaks in both directions: queries on the old name read values 1,000 times smaller than expected, and queries on the new name find nothing. The diff looks like a fix, so it passes review.&lt;/p&gt;

&lt;p&gt;Two more models, from two different vendors, did something stranger. GPT-5.5 and Gemini 3.7 Flash both renamed the metric to &lt;code&gt;rpc.client.request.duration&lt;/code&gt;. No release of the spec has ever defined that name. It is a plausible guess built from the real &lt;code&gt;http.client.request.duration&lt;/code&gt;, and both models made the same guess.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Why this domain drifts when others do not
&lt;/h3&gt;

&lt;p&gt;Another entry in this challenge tested removed pandas and Express APIs and found that models used the current ones. I think the difference is how each change fails.&lt;/p&gt;

&lt;p&gt;A removed function fails loudly. Call &lt;code&gt;DataFrame.append&lt;/code&gt; on pandas 2 and you get an error, a Stack Overflow question and an answer, and the answer ends up in training data. A retired attribute name fails silently. Nothing throws, nobody asks, and the old tutorials are never corrected. The OpenTelemetry project knows this: its instrumentation libraries offer &lt;code&gt;OTEL_SEMCONV_STABILITY_OPT_IN=http/dup&lt;/code&gt;, which emits both the old and the new HTTP names during a migration, because a rename does not propagate on its own.&lt;/p&gt;

&lt;p&gt;That is a hypothesis, not a measurement. But it predicts where to look for drift: anywhere the old form still works.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. One sentence of context helps, and it is not enough
&lt;/h3&gt;

&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%2Frgb5uagk47ljbsk6b21i.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%2Frgb5uagk47ljbsk6b21i.png" alt="Retired names written with and without a one-sentence version hint" width="800" height="827"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hint task repeats the 12 Write requests with one added sentence: &lt;em&gt;"Target OpenTelemetry semantic conventions v1.44.0 (released August 2026). Many attribute and metric names were renamed or removed between 2023 and 2026, so do not rely on older names."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before trusting any difference, I needed a noise floor. Kaggle's benchmark library accepts a temperature but drops it unless a model is flagged as supporting it, so the same prompt can give a different answer twice. I ran the plain Write task a second time on seven models. Their retired-name total moved from 156 to 166, about 6%, with nothing changed. The hint moved the same seven models from 166 to 94, a 43% drop.&lt;/p&gt;

&lt;p&gt;Across all 17 models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retired names fell by 36%&lt;/strong&gt;, from 357 to 230. The mean Write score rose from 39% to 48%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only one model reached zero&lt;/strong&gt;, and it was the one that was already there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invented names rose from 21 to 31.&lt;/strong&gt; Told that names had changed, some models stopped reaching for old names and started guessing new ones. Claude Haiku 4.5 went from 1 invented name to 7.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another entry in this challenge found that a one-sentence rule took clean answers from 64% to 96%. Here one sentence removed about a third of the drift and replaced part of it with guesses. A version number tells a model that names changed. It does not tell it what they changed to.&lt;/p&gt;
&lt;h3&gt;
  
  
  6. The leaderboard
&lt;/h3&gt;

&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%2Fd1hlh00e6yw9slslvayx.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%2Fd1hlh00e6yw9slslvayx.png" alt="Leaderboard: overall score per model" width="800" height="714"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overall is the average of a model's task scores, the same rule the Kaggle leaderboard uses.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Write&lt;/th&gt;
&lt;th&gt;Know&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;th&gt;Write + hint&lt;/th&gt;
&lt;th&gt;Overall&lt;/th&gt;
&lt;th&gt;Retired names written&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-6 Astra&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;92%&lt;/td&gt;
&lt;td&gt;98%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 5&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;81%&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;83%&lt;/td&gt;
&lt;td&gt;77%&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;77%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;83%&lt;/td&gt;
&lt;td&gt;76%&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.7 Flash&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;71%&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.8 Flash&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;71%&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.5&lt;/td&gt;
&lt;td&gt;42%&lt;/td&gt;
&lt;td&gt;68%&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;52%&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.1 Pro&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;td&gt;63%&lt;/td&gt;
&lt;td&gt;33%&lt;/td&gt;
&lt;td&gt;51%&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 mini&lt;/td&gt;
&lt;td&gt;33%&lt;/td&gt;
&lt;td&gt;64%&lt;/td&gt;
&lt;td&gt;38%&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;48%&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GLM-5&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;42%&lt;/td&gt;
&lt;td&gt;44%&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Pro&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 31B&lt;/td&gt;
&lt;td&gt;33%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;21%&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3 235B&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;23%&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek-R1&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;td&gt;46&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-120b&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two patterns are weaker than the findings above. Two of the three family pairs improved clearly (Sonnet 4.5 to 5: 52% to 77%; Gemini 2.5 Pro to 3.1 Pro: 26% to 51%), and the GPT pair tied (GPT-5.4 76%, GPT-5.5 75%). Price was a poor guide: GPT-5.4 matched GPT-5.5 for under a tenth of the cost ($0.10 against $1.36).&lt;/p&gt;
&lt;h3&gt;
  
  
  What surprised me
&lt;/h3&gt;

&lt;p&gt;I expected a cutoff story: new renames missed, old ones known. I got the opposite. The models know the renames, and they still write the names from the tutorials they read most. The half fix surprised me more. I wrote that case to catch models that forget the unit. Almost none forgot the unit. They forgot the name.&lt;/p&gt;
&lt;h3&gt;
  
  
  What this changed about how I review AI code
&lt;/h3&gt;

&lt;p&gt;I used to treat "the model knows the current API" as the thing to check. It is the wrong check. Asking a model what changed tells you nothing about what it will write. For telemetry code, I now check the names against the spec, not against my memory, and I treat a diff that changes a unit but not a name as a bug.&lt;/p&gt;
&lt;h3&gt;
  
  
  What this means for you
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lint telemetry names in CI.&lt;/strong&gt; The spec's registry marks every deprecated name and its replacement. A check of string literals against that list would flag every retired name counted in this post, &lt;code&gt;db.system&lt;/code&gt; included.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put the spec version in the prompt, then still lint.&lt;/strong&gt; It cut drift by a third here, and it also made models invent names. If you can, paste the current names you need instead of the version number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer generated constants pinned to a version.&lt;/strong&gt; In Go the semconv version is in the import path. Bump it on purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review units and names together.&lt;/strong&gt; A histogram whose unit changed and whose name did not is the hardest drift to spot, because the diff looks like a fix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;
  Try it on the model you use at work
  &lt;p&gt;Paste this prompt:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Language: Python.
Wrap this psycopg query in an OpenTelemetry client span. Record which database system it is, the database name, the operation, the table and the query text.

def list_orders(conn, customer_id):
    with conn.cursor() as cur:
        cur.execute('SELECT * FROM orders WHERE customer_id = %s', (customer_id,))
        return cur.fetchall()

Follow the current OpenTelemetry semantic conventions. Write attribute keys and metric names as string literals rather than SDK constants. Return one complete code block and nothing else.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Save the answer as &lt;code&gt;answer.py&lt;/code&gt; and run:&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-nE&lt;/span&gt; &lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;'](db&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;system|db&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;name|db&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;operation|db&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;statement|db&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;sql&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;table|net&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;peer&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;name)[&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;']"&lt;/span&gt; answer.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Any hit is a retired name. The current ones are &lt;code&gt;db.system.name&lt;/code&gt;, &lt;code&gt;db.namespace&lt;/code&gt;, &lt;code&gt;db.operation.name&lt;/code&gt;, &lt;code&gt;db.query.text&lt;/code&gt;, &lt;code&gt;db.collection.name&lt;/code&gt; and &lt;code&gt;server.address&lt;/code&gt;. Tell me in the comments which model you used and what it wrote.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  What I would measure next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More repeats.&lt;/strong&gt; Seven models ran Write twice. Every model should run every task several times, with a reported spread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Names instead of a version.&lt;/strong&gt; Does pasting the current names into the prompt remove the drift and the guessing, or only the drift?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Units beyond time.&lt;/strong&gt; The grader checks &lt;code&gt;ms&lt;/code&gt; against &lt;code&gt;s&lt;/code&gt; only. Byte and count units can drift too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The GenAI conventions.&lt;/strong&gt; They moved to their own repository and are changing fast, which makes them the next place to look.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small case counts.&lt;/strong&gt; Write has 12 cases, Know 22 and Fix 8. Claude Sonnet 5's 67% on Write has a 95% Wilson interval of 39% to 86%. The repeat runs flipped up to 3 of 12 Write cases for one model, so I would not claim any order in the middle of the table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know is missing for four reasoning models&lt;/strong&gt;, which ran out of answer budget while thinking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok is missing.&lt;/strong&gt; Grok 4.5 and 4.6 returned 404 through Kaggle's model proxy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One strict call.&lt;/strong&gt; Claude Opus 5 lost one Write case only for naming a custom key &lt;code&gt;app.ledger.entry_count&lt;/code&gt;. The spec has owned the &lt;code&gt;app.*&lt;/code&gt; namespace since its mobile conventions, so the grader counts it as invented, and the rule applies to every model the same way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A moving target.&lt;/strong&gt; Each semconv release retires more names. Re-running after the next release needs only a new ground-truth export, which is also what keeps this benchmark from going stale itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  My Benchmark
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Kaggle benchmark:&lt;/strong&gt; &lt;a href="https://www.kaggle.com/benchmarks/applesone/semconv-drift" rel="noopener noreferrer"&gt;https://www.kaggle.com/benchmarks/applesone/semconv-drift&lt;/a&gt;&lt;/p&gt;

&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%2Fijtlf3jnwdu0gf6l34lw.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%2Fijtlf3jnwdu0gf6l34lw.png" alt="The public Semconv Drift benchmark on Kaggle: 4 tasks, 17 models, GPT-6 Astra on top" width="800" height="761"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The four tasks, each with its own leaderboard and the full task code:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-write" rel="noopener noreferrer"&gt;semconv-drift-write&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Know&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-know" rel="noopener noreferrer"&gt;semconv-drift-know&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-fix" rel="noopener noreferrer"&gt;semconv-drift-fix&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write with version hint&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-write-with-version-hint" rel="noopener noreferrer"&gt;semconv-drift-write-with-version-hint&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Interactive results:&lt;/strong&gt; a sortable leaderboard with confidence intervals and every chart, at &lt;a href="https://vignesh2027.github.io/semconv-drift/" rel="noopener noreferrer"&gt;https://vignesh2027.github.io/semconv-drift/&lt;/a&gt;&lt;/p&gt;

&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%2Fk4d1fxhvofqgpdfpxkye.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%2Fk4d1fxhvofqgpdfpxkye.png" alt="The interactive results site" width="800" height="878"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code, grader and ground truth:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vignesh2027" rel="noopener noreferrer"&gt;
        vignesh2027
      &lt;/a&gt; / &lt;a href="https://github.com/vignesh2027/semconv-drift" rel="noopener noreferrer"&gt;
        semconv-drift
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Do AI models write OpenTelemetry code with names the spec already retired? A Kaggle benchmark graded in code against 1,563 names from 26 spec releases.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Semconv Drift&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Do AI models write OpenTelemetry code with names the spec already retired?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenTelemetry's semantic conventions name everything telemetry records: &lt;code&gt;http.request.method&lt;/code&gt;, &lt;code&gt;db.system.name&lt;/code&gt;, &lt;code&gt;http.server.request.duration&lt;/code&gt;. Those names change between releases. A model trained on older tutorials keeps writing the old ones, and nothing fails loudly: the data still flows, while dashboards and alerts quietly stop matching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://vignesh2027.github.io/semconv-drift/" rel="nofollow noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://www.kaggle.com/benchmarks/applesone/semconv-drift" rel="nofollow noopener noreferrer"&gt;Kaggle benchmark&lt;/a&gt;&lt;/strong&gt; · Tasks: &lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-write" rel="nofollow noopener noreferrer"&gt;Write&lt;/a&gt; · &lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-know" rel="nofollow noopener noreferrer"&gt;Know&lt;/a&gt; · &lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-fix" rel="nofollow noopener noreferrer"&gt;Fix&lt;/a&gt; · &lt;a href="https://www.kaggle.com/benchmarks/tasks/applesone/semconv-drift-write-with-version-hint" rel="nofollow noopener noreferrer"&gt;Write with version hint&lt;/a&gt; · &lt;a href="https://github.com/vignesh2027/semconv-drift/results/report.md" rel="noopener noreferrer"&gt;Results&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Semconv Drift measures that on Kaggle Benchmarks, with four tasks and no AI judge. Every answer is graded in code against 1,563 attribute, metric and event names from 26 releases of the specification (v1.21.0 to v1.44.0).&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Task&lt;/th&gt;

&lt;th&gt;Cases&lt;/th&gt;

&lt;th&gt;What it asks&lt;/th&gt;

&lt;th&gt;What counts as correct&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Write&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;12&lt;/td&gt;

&lt;td&gt;Instrument everyday code (HTTP server and client, Postgres, Redis, Kafka, gRPC, metrics, resources) in Python, Go and TypeScript&lt;/td&gt;

&lt;td&gt;Only current names, no invented names under a spec&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;…&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vignesh2027/semconv-drift" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;code&gt;analyze.py&lt;/code&gt; and &lt;code&gt;charts.py&lt;/code&gt; regenerate every number and chart in this post from the Kaggle runs. If you maintain OpenTelemetry instrumentation and want a case added, open an issue on the repo.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kagglechallenge</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>I contribute to OpenTelemetry and still shipped two retired attribute names, so I built Attrition</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sat, 03 Oct 2026 17:04:46 +0000</pubDate>
      <link>https://dev.to/vignesh_one/i-contribute-to-opentelemetry-and-still-shipped-two-retired-attribute-names-so-i-built-attrition-129i</link>
      <guid>https://dev.to/vignesh_one/i-contribute-to-opentelemetry-and-still-shipped-two-retired-attribute-names-so-i-built-attrition-129i</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path One: Ship an Agent That Queries Real Content&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Last month my entry won the DEV Summer Bug Smash. It was a Go demo that traced Redis commands into Sentry. This week I ran a new tool against that same file, and it flagged two names that OpenTelemetry had already retired:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db.system"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;       &lt;span class="c"&gt;// renamed to db.system.name in v1.30.0&lt;/span&gt;
&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db.operation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="c"&gt;// renamed to db.operation.name in v1.26.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I contribute to OpenTelemetry, and I still shipped them. That is the problem &lt;strong&gt;Attrition&lt;/strong&gt; solves.&lt;/p&gt;
&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;OpenTelemetry's semantic conventions define the names that telemetry uses: &lt;code&gt;http.request.method&lt;/code&gt;, &lt;code&gt;db.system.name&lt;/code&gt;, &lt;code&gt;http.server.request.duration&lt;/code&gt;. These names change between releases. Old tutorials, SDK constants and copied snippets keep the retired ones alive, and nothing breaks loudly when you use them. Instead, dashboards and alerts quietly stop matching, and teams find out weeks later.&lt;/p&gt;

&lt;p&gt;Finding these names sounds like a search problem. It is not. The correct answer often depends on context that a keyword search cannot see:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name in your code&lt;/th&gt;
&lt;th&gt;Why a search gets it wrong&lt;/th&gt;
&lt;th&gt;What Attrition answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;net.peer.name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;There are two correct replacements&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;server.address&lt;/code&gt; on a client span, &lt;code&gt;client.address&lt;/code&gt; on a server span, decided from your code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http.server.duration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;It vanished from the registry with no deprecation entry&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http.server.request.duration&lt;/code&gt;, with the unit changing from ms to s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;db.client.connections.wait_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;It looks like a simple rename&lt;/td&gt;
&lt;td&gt;The unit also changed from ms to s, so a rename alone records wrong values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cloud.platform = "azure_vm"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The key itself is current&lt;/td&gt;
&lt;td&gt;The value is retired; use &lt;code&gt;"azure.vm"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;db.name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The registry and the migration guide disagree&lt;/td&gt;
&lt;td&gt;Both views are shown, and the change is left for a person to decide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  What Attrition does
&lt;/h3&gt;

&lt;p&gt;Attrition reads instrumentation code and checks every attribute key, metric name, event name and enum value against &lt;strong&gt;1,563 names from 26 releases&lt;/strong&gt; of the specification. For each retired name it reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a verdict read from structured data, never guessed by a model&lt;/li&gt;
&lt;li&gt;the replacement that fits the span kind your code uses&lt;/li&gt;
&lt;li&gt;the release that retired it, and whether your pinned version already had it retired&lt;/li&gt;
&lt;li&gt;any unit change, when a renamed metric also changed its unit&lt;/li&gt;
&lt;li&gt;what the official migration guide adds, read from a Sanity Knowledge Base&lt;/li&gt;
&lt;li&gt;a link to the exact line of the specification that says so&lt;/li&gt;
&lt;li&gt;a patch, limited to the renames that are safe to automate&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live app, no login required:&lt;/strong&gt; &lt;a href="https://attrition-otel.vercel.app" rel="noopener noreferrer"&gt;https://attrition-otel.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmep7eksxe7zu4s4waffi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmep7eksxe7zu4s4waffi.gif" alt="Attrition demo" width="760" height="475"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Try it in two minutes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the app and click &lt;strong&gt;Checkout service&lt;/strong&gt;. One TypeScript file acts as both an HTTP server and an HTTP client. Notice that &lt;code&gt;net.peer.name&lt;/code&gt; receives a different answer on each span, and that two HTTP metrics are flagged even though the registry no longer mentions them.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Orders and an LLM call&lt;/strong&gt;. This Python sample shows a metric whose unit changed, a retired enum value, a chat event that became a span attribute, and a case where the registry and the migration guide disagree.&lt;/li&gt;
&lt;li&gt;Scroll to &lt;strong&gt;How this answer was built&lt;/strong&gt; under any result. It lists every Sanity Context call, the query it sent, the time it took and the number of documents returned.&lt;/li&gt;
&lt;li&gt;Ask the chat agent: &lt;em&gt;"We still record http.server.duration in milliseconds. What should we use now?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Open the &lt;a href="https://attrition-otel.vercel.app/decisions" rel="noopener noreferrer"&gt;Decisions page&lt;/a&gt; to see the conflicts the Knowledge Base raised and how each one was resolved.&lt;/li&gt;
&lt;/ol&gt;

&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%2Fxlkgwny5296qxm3ch34h.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%2Fxlkgwny5296qxm3ch34h.png" alt="Scanning a TypeScript checkout service" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The chat agent answers from the same two sources and shows its evidence under every reply:&lt;/p&gt;

&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%2Fguz0ktpbur8n6yaiyk93.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%2Fguz0ktpbur8n6yaiyk93.png" alt="Chat answer with the Sanity Context calls behind it" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Project page: &lt;a href="https://vignesh2027.github.io/attrition" rel="noopener noreferrer"&gt;https://vignesh2027.github.io/attrition&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vignesh2027" rel="noopener noreferrer"&gt;
        vignesh2027
      &lt;/a&gt; / &lt;a href="https://github.com/vignesh2027/attrition" rel="noopener noreferrer"&gt;
        attrition
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Find the OpenTelemetry attribute, metric and event names the semantic conventions already retired. Web app, Go CLI, GitHub Action, Rust offline scanner and Python agent on Sanity Context.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Attrition&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Find the OpenTelemetry names the spec already retired.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Paste instrumentation code. Attrition finds every attribute key, metric name, event name, enum value and SDK constant in it, checks each one against 1,563 names from 26 releases of the OpenTelemetry semantic conventions, and tells you what to use instead: for your span kind, with the release that retired it, the exact spec line that says so, and what the official migration guide adds. It writes a patch only for the renames that are safe to automate and leaves the rest for a person.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Live app&lt;/td&gt;

&lt;td&gt;
&lt;br&gt;
&lt;a href="https://attrition-otel.vercel.app" rel="nofollow noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://attrition-otel.vercel.app" rel="noopener noreferrer"&gt;https://attrition-otel.vercel.app&lt;/a&gt; (no login)&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Knowledge Base decisions&lt;/td&gt;

&lt;td&gt;
&lt;a href="https://attrition-otel.vercel.app/decisions" rel="nofollow noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://attrition-otel.vercel.app/decisions" rel="noopener noreferrer"&gt;https://attrition-otel.vercel.app/decisions&lt;/a&gt;
&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Project page&lt;/td&gt;

&lt;td&gt;
&lt;a href="https://vignesh2027.github.io/attrition" rel="nofollow noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://vignesh2027.github.io/attrition" rel="noopener noreferrer"&gt;https://vignesh2027.github.io/attrition&lt;/a&gt;
&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Sanity project ID&lt;/td&gt;

&lt;td&gt;
&lt;br&gt;
&lt;code&gt;y9raau23&lt;/code&gt;, dataset &lt;code&gt;production&lt;/code&gt; (public)&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Public dataset query&lt;/td&gt;

&lt;td&gt;&lt;a href="https://y9raau23.apicdn.sanity.io/v2025-02-19/data/query/production?query=*%5B_type%20in%20%5B%22attribute%22%2C%22metric%22%2C%22event%22%5D%20%26%26%20status%20!%3D%20%22current%22%5D%7B_type%2Ckey%2Cstatus%2Cdeprecation%7D" rel="nofollow noopener noreferrer"&gt;every retired name as JSON&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Sanity Studio&lt;/td&gt;

&lt;td&gt;
&lt;a href="https://attrition.sanity.studio" rel="nofollow noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://attrition.sanity.studio" rel="noopener noreferrer"&gt;https://attrition.sanity.studio&lt;/a&gt;
&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Context MCP, dataset&lt;/td&gt;

&lt;td&gt;&lt;code&gt;&lt;a href="https://api.sanity.io/v1/context/organizations/oc2g3x7ee/mcp/attrition" rel="noopener noreferrer"&gt;https://api.sanity.io/v1/context/organizations/oc2g3x7ee/mcp/attrition&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Context MCP, Knowledge Base&lt;/td&gt;

&lt;td&gt;&lt;code&gt;&lt;a href="https://api.sanity.io/v1/context/organizations/oc2g3x7ee/mcp/attrition-kb" rel="noopener noreferrer"&gt;https://api.sanity.io/v1/context/organizations/oc2g3x7ee/mcp/attrition-kb&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vignesh2027/attrition/docs/img/hero.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvignesh2027%2Fattrition%2FHEAD%2Fdocs%2Fimg%2Fhero.png" alt="Attrition scanning a TypeScript checkout service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vignesh2027/attrition/docs/img/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvignesh2027%2Fattrition%2FHEAD%2Fdocs%2Fimg%2Fdemo.gif" alt="Demo: two samples and the Knowledge Base decisions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why this needs structured content&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;The semantic conventions rename things between releases, and old blog posts, SDK…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vignesh2027/attrition" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;One dataset serves four clients, each built for a different job:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://attrition-otel.vercel.app" rel="noopener noreferrer"&gt;Web app&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;TypeScript, Next.js&lt;/td&gt;
&lt;td&gt;Pasting a file, reading the evidence, asking questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/vignesh2027/attrition/tree/main/cli" rel="noopener noreferrer"&gt;&lt;code&gt;cli/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;Scanning whole repositories and gating CI; &lt;code&gt;-fix&lt;/code&gt; applies only safe renames&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/vignesh2027/attrition/tree/main/rust" rel="noopener noreferrer"&gt;&lt;code&gt;rust/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;Offline scanning for pre-commit hooks and air-gapped CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/vignesh2027/attrition/tree/main/python" rel="noopener noreferrer"&gt;&lt;code&gt;python/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;A terminal agent built on the official Python MCP SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/vignesh2027/attrition/blob/main/action.yml" rel="noopener noreferrer"&gt;&lt;code&gt;action.yml&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;GitHub Action&lt;/td&gt;
&lt;td&gt;Failing a pull request that introduces a retired name&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Rust scanner is a port of the web extractor, and a parity script confirms that both produce identical counts on five real repositories. CI builds and tests all three languages and runs the Action against the repository's own samples.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Sanity
&lt;/h2&gt;

&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%2Fgigylhjgdmgz70jllkxp.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%2Fgigylhjgdmgz70jllkxp.png" alt="How Attrition works" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The design rests on one rule: &lt;strong&gt;structured data decides the verdict, the Knowledge Base explains the change, and the model never decides what replaced what.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Modelling the specification as structured content
&lt;/h3&gt;

&lt;p&gt;The specification is published as YAML spread across many files and releases. A deterministic importer reads every tagged release from v1.21.0 to v1.44.0 and writes &lt;strong&gt;1,654 documents&lt;/strong&gt; to Sanity: 940 &lt;code&gt;attribute&lt;/code&gt;, 571 &lt;code&gt;metric&lt;/code&gt; and 36 &lt;code&gt;event&lt;/code&gt; documents, plus namespaces and release statistics.&lt;/p&gt;

&lt;p&gt;The newest release defines each name. The older releases add history that no single release contains: &lt;code&gt;introducedIn&lt;/code&gt;, &lt;code&gt;deprecatedIn&lt;/code&gt;, and &lt;strong&gt;50 names that disappeared from the registry without any deprecation entry&lt;/strong&gt;. Those are recorded with the verdict &lt;code&gt;DROPPED&lt;/code&gt; and the last release that defined them.&lt;/p&gt;

&lt;p&gt;Every retired name receives a verdict computed in code from the specification's own &lt;code&gt;reason&lt;/code&gt;, &lt;code&gt;renamed_to&lt;/code&gt; and &lt;code&gt;note&lt;/code&gt; fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Attributes&lt;/th&gt;
&lt;th&gt;Metrics&lt;/th&gt;
&lt;th&gt;Events&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RENAMED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;td&gt;71&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http.method&lt;/code&gt; becomes &lt;code&gt;http.request.method&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REPLACED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;rpc.client.duration&lt;/code&gt; becomes &lt;code&gt;rpc.client.call.duration&lt;/code&gt;, ms to s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MOVED_OUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gen_ai.*&lt;/code&gt; moved to a separate repository in v1.42.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DROPPED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http.server.duration&lt;/code&gt;, last defined in v1.21.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REMOVED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;No replacement; delete it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPLIT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http.target&lt;/code&gt; becomes &lt;code&gt;url.path&lt;/code&gt; plus &lt;code&gt;url.query&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MERGED_INTO&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;code.function&lt;/code&gt; folds into &lt;code&gt;code.function.name&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPAN_KIND_DEPENDENT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;net.peer.name&lt;/code&gt;, &lt;code&gt;net.peer.port&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CONDITIONAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;db.sql.table&lt;/code&gt;, &lt;code&gt;http.host&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;USE_SIGNAL_FIELD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;event.name&lt;/code&gt; moves to the log record's EventName field&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The structure carries the details that make answers correct. Each replacement records the condition it applies under (&lt;code&gt;always&lt;/code&gt;, &lt;code&gt;client spans&lt;/code&gt;, &lt;code&gt;server spans&lt;/code&gt;, &lt;code&gt;together&lt;/code&gt;). Twenty-four enum values carry their own &lt;code&gt;replacementValue&lt;/code&gt;. When a renamed metric's replacement uses a different unit, the importer records a &lt;code&gt;unitChange&lt;/code&gt; by comparing the two metric documents.&lt;/p&gt;

&lt;p&gt;That comparison also uncovered a genuine error in the upstream specification: two deprecated &lt;code&gt;system.linux.memory.*&lt;/code&gt; entries carry the description and unit of a network packet counter. Rather than report a false unit change, Attrition stores the finding as a &lt;code&gt;specErratum&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I reviewed every verdict by hand, and no name remains in the &lt;code&gt;NEEDS_REVIEW&lt;/code&gt; state.&lt;/p&gt;

&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%2F53m496xlhpdf5ve2hjqe.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%2F53m496xlhpdf5ve2hjqe.png" alt="A metric with a unit change in Sanity Studio" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Querying the dataset through Sanity Context
&lt;/h3&gt;

&lt;p&gt;The dataset is served by an organization-level Context MCP endpoint named &lt;code&gt;attrition&lt;/code&gt;. Its GROQ filter limits access to the convention types, and its instructions explain what each verdict means and forbid inventing a replacement.&lt;/p&gt;

&lt;p&gt;A scan sends a single &lt;code&gt;groq_query&lt;/code&gt; covering every name found in the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "release": *[_type == "specRelease"][0].tag,
  "attrs": *[_type in ["attribute", "metric", "event"] &amp;amp;&amp;amp; key in ["http.method", "net.peer.name", "http.server.duration"]]{
    _id, _type, key, status, lastSeenIn, unit, specErratum, "source": source{url, release},
    "deprecatedMembers": members[defined(deprecated)]{value, deprecated, replacementValue},
    deprecation{verdict, note, deprecatedIn, valueChanges, unitChange{from, to}, movedTo{label, url},
      "replacements": replacements[]{key, when, "stability": coalesce(attribute-&amp;gt;stability, metric-&amp;gt;stability)}}
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code determines the span kind and the data determines the answer. Because no model sits in this path, a scan cannot invent a name.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A Knowledge Base for what the registry leaves out
&lt;/h3&gt;

&lt;p&gt;The registry records what a name became. It does not record what else changed, and for dropped names it records nothing at all. That knowledge lives in the official migration guides.&lt;/p&gt;

&lt;p&gt;I built the Knowledge Base entirely with the Sanity CLI (&lt;code&gt;sanity context create&lt;/code&gt;, &lt;code&gt;context imports create&lt;/code&gt; and &lt;code&gt;context build&lt;/code&gt;) from &lt;strong&gt;144 sources&lt;/strong&gt;, within the 150 document budget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;137 documents&lt;/strong&gt; bound from the dataset: the retired attributes and the HTTP, database, RPC and messaging metrics that most instrumentation uses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 official migration guides&lt;/strong&gt;: HTTP, database, RPC, code attributes and version selection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 older specification pages&lt;/strong&gt; that still use the retired names&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A second organization endpoint, &lt;code&gt;attrition-kb&lt;/code&gt;, serves the Knowledge Base. For each retired name, a scan calls &lt;code&gt;knowledge_base_search&lt;/code&gt; and then &lt;code&gt;knowledge_base_read&lt;/code&gt; on the results, keeping the guide entry that discusses that name. Entry paths are never hard-coded, because each rebuild can rename them.&lt;/p&gt;

&lt;p&gt;This is where several of the most valuable answers come from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;http.server.duration&lt;/code&gt; maps to &lt;code&gt;http.server.request.duration&lt;/code&gt;, with the unit changing from ms to s. The registry has no record of this at all.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db.query.text&lt;/code&gt;, the replacement for &lt;code&gt;db.statement&lt;/code&gt;, &lt;em&gt;"SHOULD be collected by default only if sanitization excludes sensitive information."&lt;/em&gt; A rename alone would never surface that privacy requirement.&lt;/li&gt;
&lt;li&gt;Each area's dual-emit setting, such as &lt;code&gt;OTEL_SEMCONV_STABILITY_OPT_IN=database/dup&lt;/code&gt;, which lets teams emit old and new names side by side during a migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Resolving conflicts between sources
&lt;/h3&gt;

&lt;p&gt;The Knowledge Base build raised &lt;strong&gt;four genuine conflicts&lt;/strong&gt;. My dataset stated that &lt;code&gt;http.server.duration&lt;/code&gt; and &lt;code&gt;http.resend_count&lt;/code&gt; left the registry with no replacement, while the official guides stated that they were renamed.&lt;/p&gt;

&lt;p&gt;Both statements are accurate at different levels. The registry stops listing a name once it is gone, while the guide records where it went. I resolved each conflict in favour of the guide using &lt;code&gt;client.context.issues.resolve()&lt;/code&gt;, applied the resulting page updates with &lt;code&gt;issues.apply()&lt;/code&gt;, and Sanity converted each decision into a &lt;strong&gt;standing instruction&lt;/strong&gt; that every future build follows.&lt;/p&gt;

&lt;p&gt;The effect was immediately visible. Before the decisions, asking about &lt;code&gt;http.resend_count&lt;/code&gt; returned "no replacement". Afterwards, the rewritten entry correctly returned &lt;code&gt;http.request.resend_count&lt;/code&gt;. Every conflict, both claims and the chosen side are published on the Decisions page.&lt;/p&gt;

&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%2Fsmwgoitimbvmo7lb0hmb.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%2Fsmwgoitimbvmo7lb0hmb.png" alt="Knowledge Base decisions" width="800" height="1126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Three agents, one source of truth
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The scanner&lt;/strong&gt; is fully deterministic. Extraction happens in code, verdicts come from &lt;code&gt;groq_query&lt;/code&gt;, and guidance comes from &lt;code&gt;knowledge_base_search&lt;/code&gt; and &lt;code&gt;knowledge_base_read&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The chat agent&lt;/strong&gt; retrieves its evidence first through the same Context calls, then answers in a single model call restricted to that evidence. It cites the dataset or the exact Knowledge Base entry and lists the calls beneath each answer. This design also keeps it within the limits of a free model tier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Python agent&lt;/strong&gt; takes the conventional route: the model calls &lt;code&gt;groq_query&lt;/code&gt;, &lt;code&gt;knowledge_base_search&lt;/code&gt; and &lt;code&gt;knowledge_base_read&lt;/code&gt; directly through the official Python MCP SDK. It demonstrates that the same endpoints work from any agent framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Results on real code
&lt;/h3&gt;

&lt;p&gt;I ran the Go CLI against five open-source repositories at pinned commits, and the Rust offline scanner reproduced every count:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repository&lt;/th&gt;
&lt;th&gt;Retired names in code&lt;/th&gt;
&lt;th&gt;Files to update&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;open-telemetry/opentelemetry-demo&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jaegertracing/jaeger&lt;/td&gt;
&lt;td&gt;67&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;redis/go-redis&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;go-gorm/opentelemetry&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uptrace/opentelemetry-go-extra&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The most significant finding: go-redis's official &lt;code&gt;redisotel&lt;/code&gt; package still registers the old &lt;code&gt;db.client.connections.*&lt;/code&gt; pool metrics and records &lt;code&gt;create_time&lt;/code&gt; and &lt;code&gt;use_time&lt;/code&gt; in milliseconds. Renaming them to the new names without converting the values would make every reading a thousand times too large. This is exactly why Attrition never auto-patches a name whose unit changed.&lt;/p&gt;

&lt;p&gt;The clean result for &lt;code&gt;go-gorm/opentelemetry&lt;/code&gt; matters as much: a reliable tool must say nothing when the code is current. Every finding links to its source line in &lt;a href="https://github.com/vignesh2027/attrition/blob/main/bench/RESULTS.md" rel="noopener noreferrer"&gt;bench/RESULTS.md&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design decisions and limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Patches are conservative by design.&lt;/strong&gt; Only unconditional renames of string keys are patched. Span-kind choices, unit changes, merges and disagreements between sources are always left for a person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A finding is not always a bug.&lt;/strong&gt; Test fixtures that read historical data, or libraries that intentionally emit both old and new names during a migration, may keep a retired name on purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next steps:&lt;/strong&gt; mapping pinned SDK versions to the exact specification release they ship, and adding the remaining migration guides to the Knowledge Base as the 150 document limit allows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project ID:&lt;/strong&gt; &lt;code&gt;y9raau23&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt; (public)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public dataset query:&lt;/strong&gt; &lt;a href="https://y9raau23.apicdn.sanity.io/v2025-02-19/data/query/production?query=*%5B_type%20in%20%5B%22attribute%22%2C%22metric%22%2C%22event%22%5D%20%26%26%20status%20!%3D%20%22current%22%5D%7B_type%2Ckey%2Cstatus%2Cdeprecation%7D" rel="noopener noreferrer"&gt;every retired name as JSON&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanity Studio:&lt;/strong&gt; &lt;a href="https://attrition.sanity.studio" rel="noopener noreferrer"&gt;https://attrition.sanity.studio&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Base:&lt;/strong&gt; &lt;code&gt;kbI5ncVyqDpc&lt;/code&gt;, served by the organization Context MCP endpoint &lt;code&gt;attrition-kb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset Context MCP endpoint:&lt;/strong&gt; &lt;code&gt;attrition&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Base decisions:&lt;/strong&gt; &lt;a href="https://attrition-otel.vercel.app/decisions" rel="noopener noreferrer"&gt;https://attrition-otel.vercel.app/decisions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;a href="https://dev.to/agent_sessions/new"&gt;https://dev.to/agent_sessions/new&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>A HOOK U NEED TO LOOK</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sun, 16 Aug 2026 10:55:27 +0000</pubDate>
      <link>https://dev.to/vignesh_one/a-hook-u-need-to-look-3c9e</link>
      <guid>https://dev.to/vignesh_one/a-hook-u-need-to-look-3c9e</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/vignesh_one/16-redis-commands-0-spans-a-hook-that-looked-perfectly-correct-4cka" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" 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%2F2lcr18jcmx5f68da0t8q.png" height="351" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/vignesh_one/16-redis-commands-0-spans-a-hook-that-looked-perfectly-correct-4cka" rel="noopener noreferrer" class="c-link"&gt;
            16 Redis commands. 0 spans. A hook that looked perfectly correct. - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry.  I spent an...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>16 Redis commands. 0 spans. A hook that looked perfectly correct.</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sun, 16 Aug 2026 10:53:08 +0000</pubDate>
      <link>https://dev.to/vignesh_one/16-redis-commands-0-spans-a-hook-that-looked-perfectly-correct-4cka</link>
      <guid>https://dev.to/vignesh_one/16-redis-commands-0-spans-a-hook-that-looked-perfectly-correct-4cka</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I spent an afternoon reading four lines of Go and agreeing with them. They were wrong.&lt;/p&gt;

&lt;p&gt;Not subtly wrong. The function was supposed to attach telemetry to every shard in a Redis ring, and it attached telemetry to none of them. Ring clients ran in production emitting nothing at all, and the code that failed to do it reads like textbook Go.&lt;/p&gt;

&lt;p&gt;Here is how it hid, how I found it, and what it looks like in Sentry when you finally put a light on it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What the project does
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-go-compile-instrumentation" rel="noopener noreferrer"&gt;opentelemetry-go-compile-instrumentation&lt;/a&gt; is OpenTelemetry's compile time instrumentation for Go.&lt;/p&gt;

&lt;p&gt;You do not add tracing calls to your code. The toolchain rewrites your binary during the build, so the tracing is already inside it when it ships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a bug here is worse than most
&lt;/h3&gt;

&lt;p&gt;That property is the entire appeal, and it is also what makes a defect in it dangerous.&lt;/p&gt;

&lt;p&gt;You did not write the instrumentation. You are not reading the instrumentation. You are reading the dashboard it feeds, and you trust it completely, because trusting it is the point.&lt;/p&gt;

&lt;p&gt;The project ships hooks for a lot of common libraries. &lt;code&gt;go-redis&lt;/code&gt; gets six of them, one per client type. Each is roughly four lines: something constructs a client, the hook runs afterwards, the hook attaches an OpenTelemetry hook to that client.&lt;/p&gt;

&lt;p&gt;The one for &lt;code&gt;redis.Ring&lt;/code&gt; did nothing at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The four lines
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;afterNewRingClientV9&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HookContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ring&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnNewNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newOtelRedisHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="p"&gt;))&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;Read that on its own and it is fine.&lt;/p&gt;

&lt;p&gt;A ring is a set of shards. &lt;code&gt;OnNewNode&lt;/code&gt; registers a callback that runs for each shard. The callback attaches the telemetry hook. Therefore every shard gets instrumented.&lt;/p&gt;

&lt;p&gt;I read it three times and agreed with it three times. Then I went and read &lt;code&gt;NewRing&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What actually happens
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;OnNewNode&lt;/code&gt; only fires for shards created &lt;strong&gt;after&lt;/strong&gt; you register the callback.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;NewRing&lt;/code&gt; builds a shard for every entry in &lt;code&gt;RingOptions.Addrs&lt;/code&gt; during construction, and construction finishes before this hook ever runs.&lt;/p&gt;

&lt;p&gt;So by the time &lt;code&gt;afterNewRingClientV9&lt;/code&gt; registers its callback, every shard the caller configured already exists. The callback will never see a single one of them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you build a ring the normal way, by listing your Redis addresses in the options, you get zero telemetry. Not degraded. Not partial. Zero. Every command, to every shard, invisible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only way to get even one instrumented shard was to construct a ring with no addresses and add them later through &lt;code&gt;SetAddrs&lt;/code&gt;. Nobody builds a ring that way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this class of bug is the worst class
&lt;/h3&gt;

&lt;p&gt;There is no error. No warning. No partial data that looks suspicious.&lt;/p&gt;

&lt;p&gt;Your Redis spans are simply absent, and absence reads as health.&lt;/p&gt;

&lt;p&gt;If you opened a service map and saw no Redis calls, your first thought is not "the instrumentation is broken." It is "I guess Redis is fine." A bug that produces wrong numbers eventually gets caught by somebody who notices the numbers are wrong. A bug that produces no numbers can sit there forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why nobody had reported it
&lt;/h3&gt;

&lt;p&gt;The entire package had no test coverage.&lt;/p&gt;

&lt;p&gt;Six client hooks, zero tests. Nothing anywhere was asserting that any of them attached anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Upstream PR:&lt;/strong&gt; &lt;a href="https://github.com/open-telemetry/opentelemetry-go-compile-instrumentation/pull/1098" rel="noopener noreferrer"&gt;open-telemetry/opentelemetry-go-compile-instrumentation#1098&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;

&lt;p&gt;Keep the &lt;code&gt;OnNewNode&lt;/code&gt; registration, since it is still correct for shards added later through &lt;code&gt;SetAddrs&lt;/code&gt;, and additionally walk the shards that already exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; func afterNewRingClientV9(call hook.HookContext, client *redis.Ring) {
    client.OnNewNode(func(rdb *redis.Client) {
        rdb.AddHook(newOtelRedisHook(rdb.Options().Addr))
    })
&lt;span class="gi"&gt;+   // NewRing builds a shard for every entry in RingOptions.Addrs before this
+   // hook runs, and OnNewNode only fires for shards created after it is
+   // registered. Without this pass the shards a caller configured up front
+   // are never instrumented, which is the common case.
+   attachHookToExistingShards(client)
&lt;/span&gt; }
&lt;span class="gi"&gt;+
+// attachHookToExistingShards instruments the shards a ring already holds.
+// ForEachShard returns the first error a callback produces; this callback
+// cannot fail, so there is nothing to report.
+func attachHookToExistingShards(client *redis.Ring) {
+   _ = client.ForEachShard(context.Background(), func(_ context.Context, rdb *redis.Client) error {
+       rdb.AddHook(newOtelRedisHook(rdb.Options().Addr))
+       return nil
+   })
+}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both paths are now covered. Shards present at construction get instrumented by the &lt;code&gt;ForEachShard&lt;/code&gt; pass. Shards added later get instrumented by &lt;code&gt;OnNewNode&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  On that comment
&lt;/h3&gt;

&lt;p&gt;I left it deliberately, and I would fight to keep it in review.&lt;/p&gt;

&lt;p&gt;The next person to read this function will have exactly the reaction I had, which is that &lt;code&gt;OnNewNode&lt;/code&gt; looks sufficient. It is not sufficient. The only way to know that is to know when &lt;code&gt;NewRing&lt;/code&gt; builds its shards relative to when the hook runs.&lt;/p&gt;

&lt;p&gt;That fact belongs in a comment, not in somebody's head.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing a Redis hook without a Redis server
&lt;/h3&gt;

&lt;p&gt;This is the part I expected to be hard, because instrumenting a Redis client normally means having a Redis server, and needing a server in CI is how tests end up skipped.&lt;/p&gt;

&lt;p&gt;It turns out you do not need one.&lt;/p&gt;

&lt;p&gt;Each test builds a client pointed at a port nothing is listening on, then issues a command. The dial fails. But the hook opens its span &lt;strong&gt;before&lt;/strong&gt; handing the command to the next hook in the chain, so a failed connection exercises the instrumentation completely.&lt;/p&gt;

&lt;p&gt;Assert that a client span came out carrying the right endpoint and you have tested the thing you actually care about. No server. No container. No fixture.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Test that pins the bug&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TestAfterNewRingClientV9_AttachesHookToEachNode&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails on old code&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other hooks covered&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package coverage&lt;/td&gt;
&lt;td&gt;89.2% to 96.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What changed
&lt;/h3&gt;

&lt;p&gt;Ring clients went from producing no telemetry to producing telemetry for every shard, in the configuration basically everybody uses. Six previously untested hooks now have tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callback registration order is a whole family of bugs
&lt;/h3&gt;

&lt;p&gt;Any API shaped like "register a callback and it will fire for each X" has a question hiding inside it: what about the Xs that already exist?&lt;/p&gt;

&lt;p&gt;Some libraries replay for existing items. Some only fire going forward. The method name almost never tells you which.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OnNewNode&lt;/code&gt; is arguably honest, the word is right there in the name. But I would bet most people read it as "on each node," because that is what you want it to mean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instrumentation needs tests more than normal code, not less
&lt;/h3&gt;

&lt;p&gt;Missing telemetry is harder to notice than wrong telemetry.&lt;/p&gt;

&lt;p&gt;Nothing downstream will ever complain on its behalf. A dashboard cannot tell you it is missing a line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Point it at a dead port
&lt;/h3&gt;

&lt;p&gt;To test a client library hook, aim it somewhere nothing is listening.&lt;/p&gt;

&lt;p&gt;The failure path runs through the same instrumentation as the success path, and you skip the entire problem of standing up a real server in CI. I will be reusing this one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Use of Sentry
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The problem with proving a negative
&lt;/h3&gt;

&lt;p&gt;This bug has an unusual property. The symptom &lt;strong&gt;is&lt;/strong&gt; absent telemetry.&lt;/p&gt;

&lt;p&gt;You cannot screenshot a missing span. So the only honest way to prove it is to put both versions in front of a real tracing backend and show the shape of the hole.&lt;/p&gt;

&lt;p&gt;I built a reproduction that ships OpenTelemetry spans straight to Sentry over OTLP and runs an identical workload under both attachment strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/vignesh2027/bugsmash-sentry-demo" rel="noopener noreferrer"&gt;github.com/vignesh2027/bugsmash-sentry-demo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three shard ring. Sixteen Redis commands. One &lt;code&gt;cart-checkout&lt;/code&gt; transaction wrapping all of them. The only variable in the entire program is which attachment function runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before: the empty waterfall
&lt;/h3&gt;

&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%2F93ds3vzv6d4111c21nx0.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%2F93ds3vzv6d4111c21nx0.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One bar. 4.49 seconds. Nothing underneath it.&lt;/p&gt;

&lt;p&gt;Sixteen Redis commands executed inside that window, across three shards, and the trace shows none of them.&lt;/p&gt;

&lt;p&gt;Sit with that image for a second. If somebody handed it to you during an incident, you would conclude this service does not talk to Redis. It talks to Redis sixteen times.&lt;/p&gt;

&lt;h3&gt;
  
  
  After: the same code, traced
&lt;/h3&gt;

&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%2Ff3gj6mb5k6fj9br3gyni.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%2Ff3gj6mb5k6fj9br3gyni.png" alt=" " width="799" height="393"&gt;&lt;/a&gt;&lt;br&gt;
Same code. Same commands. Same 4.5 seconds.&lt;/p&gt;

&lt;p&gt;Eleven &lt;code&gt;redis.get&lt;/code&gt; and &lt;code&gt;redis.set&lt;/code&gt; spans, each one tagged with the shard that served it.&lt;/p&gt;
&lt;h3&gt;
  
  
  The span math, because the two screenshots do not obviously agree
&lt;/h3&gt;

&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%2Fz2dry2siz3h2ch2izwro.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%2Fz2dry2siz3h2ch2izwro.png" alt=" " width="799" height="398"&gt;&lt;/a&gt;&lt;br&gt;
The fixed run produces &lt;strong&gt;20&lt;/strong&gt; Redis spans in total. Only &lt;strong&gt;11&lt;/strong&gt; land inside the &lt;code&gt;cart-checkout&lt;/code&gt; trace.&lt;/p&gt;

&lt;p&gt;The other &lt;strong&gt;9&lt;/strong&gt; are &lt;code&gt;redis.ping&lt;/code&gt; shard health checks. go-redis runs those on its own goroutines, outside the request context, so Sentry correctly files them as separate root traces.&lt;/p&gt;

&lt;p&gt;That detail makes the bug worse than I first understood. The ring's own health monitoring was untraced too, which means a ring quietly losing a shard would not have surfaced either.&lt;/p&gt;
&lt;h3&gt;
  
  
  Which Sentry tools did the work
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it did here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Distributed Tracing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ingested the real OTel spans over OTLP, so I am watching the actual instrumentation, not a reimplementation of it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Monitoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The failed commands are captured on a scope tagged with operation, key, and hook mode, so the Issue says what happened&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trace linked errors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sentryotel.NewOtelIntegration()&lt;/code&gt; attaches captures to the active span, so the error and its span land together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Span attributes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every span carries &lt;code&gt;redis.shard&lt;/code&gt;, which proves &lt;em&gt;every&lt;/em&gt; shard is covered, not merely that something fired&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&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%2F7u3yqxjv7ui49melynqu.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%2F7u3yqxjv7ui49melynqu.png" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;br&gt;
That last row matters more than it sounds. A partial fix that instrumented one shard out of three would look perfectly healthy on a span count, and would still be broken. Shard level attributes are what turn "some spans exist" into "coverage is complete."&lt;/p&gt;
&lt;h3&gt;
  
  
  Two things that cost me time
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The OTLP endpoint has a segment you will miss.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;DSN&lt;/span&gt;    &lt;span class="n"&gt;https&lt;/span&gt;://&amp;lt;&lt;span class="n"&gt;key&lt;/span&gt;&amp;gt;@&lt;span class="n"&gt;o&lt;/span&gt;&amp;lt;&lt;span class="n"&gt;org&lt;/span&gt;&amp;gt;.&lt;span class="n"&gt;ingest&lt;/span&gt;.&amp;lt;&lt;span class="n"&gt;region&lt;/span&gt;&amp;gt;.&lt;span class="n"&gt;sentry&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt;/&amp;lt;&lt;span class="n"&gt;project&lt;/span&gt;&amp;gt;
&lt;span class="n"&gt;OTLP&lt;/span&gt;   &lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;o&lt;/span&gt;&amp;lt;&lt;span class="n"&gt;org&lt;/span&gt;&amp;gt;.&lt;span class="n"&gt;ingest&lt;/span&gt;.&amp;lt;&lt;span class="n"&gt;region&lt;/span&gt;&amp;gt;.&lt;span class="n"&gt;sentry&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt;/&lt;span class="n"&gt;api&lt;/span&gt;/&amp;lt;&lt;span class="n"&gt;project&lt;/span&gt;&amp;gt;/&lt;span class="n"&gt;integration&lt;/span&gt;/&lt;span class="n"&gt;otlp&lt;/span&gt;/&lt;span class="n"&gt;v1&lt;/span&gt;/&lt;span class="n"&gt;traces&lt;/span&gt;
&lt;span class="n"&gt;auth&lt;/span&gt;   &lt;span class="n"&gt;x&lt;/span&gt;-&lt;span class="n"&gt;sentry&lt;/span&gt;-&lt;span class="n"&gt;auth&lt;/span&gt;: &lt;span class="n"&gt;sentry&lt;/span&gt; &lt;span class="n"&gt;sentry_key&lt;/span&gt;=&amp;lt;&lt;span class="n"&gt;key&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leave out &lt;code&gt;/integration/&lt;/code&gt; and you get &lt;code&gt;404 Not Found&lt;/code&gt; with an empty body, which tells you nothing about which half of the URL was wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sentry-go&lt;/code&gt; v0.48 removed &lt;code&gt;NewSentrySpanProcessor&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tracer provider pattern most tutorials still show will not compile. OTLP export is the current path, and the &lt;code&gt;otel&lt;/code&gt; package is now reduced to linking errors onto the trace. Also worth knowing: OTLP ingestion is in open beta and span &lt;em&gt;events&lt;/em&gt; are dropped during ingest, which is why the diagnostic detail here lives in attributes. That turned out to be the better design regardless.&lt;/p&gt;

&lt;h3&gt;
  
  
  The evidence travels with the code
&lt;/h3&gt;

&lt;p&gt;I added a local span counter as a span processor, so the demo prints its own tally. You do not have to take my word for what the Sentry UI showed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUGGY                          FIXED
ran:    16 commands            ran:    16 commands
redis spans observed: 0        redis spans observed: 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone it, point it at your own DSN, and you will get the same two numbers.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>opensource</category>
      <category>go</category>
    </item>
    <item>
      <title>I benchmarked 7 LLMs on 100 identical prompts. The cost gap shocked me.</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Mon, 08 Jun 2026 05:43:29 +0000</pubDate>
      <link>https://dev.to/vignesh_one/i-benchmarked-7-llms-on-100-identical-prompts-the-cost-gap-shocked-me-3m85</link>
      <guid>https://dev.to/vignesh_one/i-benchmarked-7-llms-on-100-identical-prompts-the-cost-gap-shocked-me-3m85</guid>
      <description>&lt;p&gt;Everyone asks: which LLM is the best?&lt;/p&gt;

&lt;p&gt;Wrong question.&lt;/p&gt;

&lt;p&gt;The right question: &lt;strong&gt;which LLM is best for your use case, at your scale, at your budget?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I ran 100 identical prompts across 7 major LLMs. Here's what the data actually showed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers Nobody Shows You
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;th&gt;Cost/1K&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4o&lt;/td&gt;
&lt;td&gt;88.2%&lt;/td&gt;
&lt;td&gt;$0.0080&lt;/td&gt;
&lt;td&gt;892ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3.5 Sonnet&lt;/td&gt;
&lt;td&gt;87.6%&lt;/td&gt;
&lt;td&gt;$0.0090&lt;/td&gt;
&lt;td&gt;1240ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4o-mini&lt;/td&gt;
&lt;td&gt;78.4%&lt;/td&gt;
&lt;td&gt;$0.0003&lt;/td&gt;
&lt;td&gt;432ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 1.5 Flash&lt;/td&gt;
&lt;td&gt;76.8%&lt;/td&gt;
&lt;td&gt;$0.0001&lt;/td&gt;
&lt;td&gt;380ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Haiku&lt;/td&gt;
&lt;td&gt;74.2%&lt;/td&gt;
&lt;td&gt;$0.0010&lt;/td&gt;
&lt;td&gt;410ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral Small&lt;/td&gt;
&lt;td&gt;71.0%&lt;/td&gt;
&lt;td&gt;$0.0010&lt;/td&gt;
&lt;td&gt;520ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 3 8B&lt;/td&gt;
&lt;td&gt;64.4%&lt;/td&gt;
&lt;td&gt;$0.0002&lt;/td&gt;
&lt;td&gt;680ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GPT-4o vs Gemini Flash:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;11% accuracy gap&lt;/li&gt;
&lt;li&gt;80x cost gap&lt;/li&gt;
&lt;li&gt;2.3x speed gap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For 90% of production apps — &lt;strong&gt;Gemini wins&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Every AI leaderboard ranks by accuracy.&lt;/p&gt;

&lt;p&gt;Your production AWS bill ranks by cost per request.&lt;/p&gt;

&lt;p&gt;They are not the same list.&lt;/p&gt;

&lt;p&gt;I built an open source &lt;strong&gt;LLM Evaluation Framework&lt;/strong&gt; that benchmarks any model across all 5 dimensions simultaneously:&lt;/p&gt;

&lt;h3&gt;
  
  
  5 Metrics in One Run
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Accuracy&lt;/strong&gt;&lt;br&gt;
Four-strategy cascade scorer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact string match (case-normalized)&lt;/li&gt;
&lt;li&gt;Prefix normalization (strips "The answer is...")&lt;/li&gt;
&lt;li&gt;Multiple-choice letter extraction&lt;/li&gt;
&lt;li&gt;Fuzzy Levenshtein match at 0.85 threshold&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Latency (full percentile breakdown)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;p50, p75, p90, p95, p99&lt;/li&gt;
&lt;li&gt;SLA violation rate against configurable threshold&lt;/li&gt;
&lt;li&gt;Async parallel evaluation via LiteLLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Cost per 1K tokens&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From real token counts in API responses&lt;/li&gt;
&lt;li&gt;Not estimates — actual billing data&lt;/li&gt;
&lt;li&gt;Supports 15+ model providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Hallucination Rate&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linguistic signal analysis&lt;/li&gt;
&lt;li&gt;Detects hedging phrases, uncertainty markers, ungrounded claims vs grounding signals&lt;/li&gt;
&lt;li&gt;Runs entirely locally, zero extra API cost&lt;/li&gt;
&lt;li&gt;Score: 0.0 (grounded) to 1.0 (heavily hallucinating)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Reasoning Quality&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chain-of-thought depth scoring&lt;/li&gt;
&lt;li&gt;Counts reasoning markers, grounding signals, response calibration&lt;/li&gt;
&lt;li&gt;Score: 1 (one-word answer) to 10 (structured multi-step reasoning)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;llm-evaluation-framework

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-key
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-key

llm-eval compare &lt;span class="nt"&gt;--models&lt;/span&gt; gpt-4o-mini &lt;span class="nt"&gt;--models&lt;/span&gt; gemini/gemini-1.5-flash &lt;span class="nt"&gt;--benchmark&lt;/span&gt; mmlu &lt;span class="nt"&gt;--samples&lt;/span&gt; 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model              Accuracy  Latency p95  Cost/1K    Hallucination  Reasoning
gpt-4o-mini        78.4%     891ms        $0.000300  0.12           7.2
gemini-1.5-flash   76.8%     743ms        $0.000100  0.15           6.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Under the Hood
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async parallel evaluation&lt;/strong&gt; — runs all samples concurrently with configurable semaphore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MMLU benchmark&lt;/strong&gt; — 57 subjects, ~14K questions (Massive Multitask Language Understanding)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TruthfulQA benchmark&lt;/strong&gt; — 817 questions designed to expose common misconceptions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom benchmarks&lt;/strong&gt; — bring your own JSON: &lt;code&gt;[{"prompt": "...", "expected": "..."}]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI REST API&lt;/strong&gt; — 12 endpoints, OpenAPI docs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamlit dashboard&lt;/strong&gt; — radar charts, scatter plots, histograms&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI&lt;/strong&gt; — 7 subcommands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite persistence&lt;/strong&gt; — all runs stored, queryable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF report generation&lt;/strong&gt; — shareable evaluation reports&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Uncomfortable Truth About AI Benchmarks
&lt;/h2&gt;

&lt;p&gt;Leaderboards rank models by accuracy on standardized tests.&lt;/p&gt;

&lt;p&gt;Production systems rank models by &lt;strong&gt;accuracy per dollar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Those are very different rankings.&lt;/p&gt;

&lt;p&gt;GPT-4o vs Gemini Flash:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On a leaderboard: GPT-4o wins by 11%&lt;/li&gt;
&lt;li&gt;At 10M requests/month: $80,000 vs $1,000&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most apps, the correct answer 11% more often is NOT worth $79,000/month.&lt;/p&gt;

&lt;p&gt;Stop picking LLMs from leaderboards. Start picking them from your data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Live Demo
&lt;/h2&gt;

&lt;p&gt;Try the accuracy scorer and hallucination detector live — no API key needed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/spaces/vigneshwar234/llm-eval-demo" rel="noopener noreferrer"&gt;https://huggingface.co/spaces/vigneshwar234/llm-eval-demo&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/vignesh2027/LLM-Evaluation-Framework" rel="noopener noreferrer"&gt;https://github.com/vignesh2027/LLM-Evaluation-Framework&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;HuggingFace Space: &lt;a href="https://huggingface.co/spaces/vigneshwar234/llm-eval-demo" rel="noopener noreferrer"&gt;https://huggingface.co/spaces/vigneshwar234/llm-eval-demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dataset (1,200 benchmark samples): &lt;a href="https://huggingface.co/datasets/vigneshwar234/llm-eval-benchmark" rel="noopener noreferrer"&gt;https://huggingface.co/datasets/vigneshwar234/llm-eval-benchmark&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;71 tests. 82% coverage. Full CI/CD on GitHub Actions. Open source. Free forever.&lt;/p&gt;




&lt;p&gt;If this helped — drop a star on GitHub. Building in public, feedback welcome.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>opensource</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>I Spent 4 Months Building a RAG System That Actually Understands Causality — Here's What I Learned (and the Math Behind It)</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sun, 07 Jun 2026 11:29:58 +0000</pubDate>
      <link>https://dev.to/vignesh_one/i-spent-4-months-building-a-rag-system-that-actually-understands-causality-heres-what-i-learned-3cpn</link>
      <guid>https://dev.to/vignesh_one/i-spent-4-months-building-a-rag-system-that-actually-understands-causality-heres-what-i-learned-3cpn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I spent 4 months building something the entire ML community said was already solved. Turns out, it wasn't."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I need to tell you something uncomfortable about every RAG system running in production today.&lt;/p&gt;

&lt;p&gt;They're all broken in the same way. And almost nobody is talking about it.&lt;/p&gt;

&lt;p&gt;I'm not saying they don't work. They do — most of the time. But there are two silent failure modes that cause them to hallucinate even when they retrieve the &lt;strong&gt;correct document&lt;/strong&gt;. After months of banging my head against this problem, I built VORTEXRAG to fix both of them. This is that story.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Day I Realized Something Was Deeply Wrong
&lt;/h2&gt;

&lt;p&gt;I was building a financial Q&amp;amp;A system. Simple enough — index a corpus of SEC filings, answer questions about why companies performed the way they did.&lt;/p&gt;

&lt;p&gt;The query: &lt;em&gt;"Why did Company X's revenue drop in Q3?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My RAG pipeline retrieved the right document. I could see it in the logs — the actual earnings call transcript where the CEO explained the supply chain disruption. Cosine similarity: &lt;strong&gt;0.91&lt;/strong&gt;. Perfect.&lt;/p&gt;

&lt;p&gt;But the LLM's answer was completely wrong. It talked about macroeconomic conditions, interest rate sensitivity, sector-wide headwinds. All factually true things — about the &lt;em&gt;industry&lt;/em&gt;. None of them the &lt;em&gt;actual cause&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I dug into the context window. The correct chunk was there. But it was surrounded by 7 other chunks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The company's 10-K risk factors (similarity: 0.87)
&lt;/li&gt;
&lt;li&gt;An analyst report on sector performance (similarity: 0.84)&lt;/li&gt;
&lt;li&gt;Fed reserve commentary on the quarter (similarity: 0.82)&lt;/li&gt;
&lt;li&gt;Three more topically-related but causally-irrelevant passages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM saw all of them. It averaged them. It hallucinated a narrative that sounded exactly right but was factually wrong about &lt;em&gt;this specific company&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I had discovered &lt;strong&gt;Context Window Poisoning&lt;/strong&gt; — and I'd been unknowingly fighting it for months.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Two Problems Nobody Fully Solves
&lt;/h2&gt;

&lt;p&gt;After that moment, I went deep. I read every RAG paper published in the last 3 years. Self-RAG, CRAG, RAG-Fusion, FiD, REALM, Atlas, Toolformer — all of them. Great papers. Smart people. Significant advances.&lt;/p&gt;

&lt;p&gt;But none of them fully addressed what I was seeing. Here's why:&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 1: Semantic Drift 🎯
&lt;/h3&gt;

&lt;p&gt;Every RAG system today retrieves by &lt;strong&gt;cosine similarity&lt;/strong&gt;. This works great for finding topically related content. But it fundamentally cannot distinguish between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A chunk that &lt;strong&gt;caused&lt;/strong&gt; something&lt;/li&gt;
&lt;li&gt;A chunk that is merely &lt;strong&gt;associated&lt;/strong&gt; with it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask &lt;em&gt;"Why did Lehman Brothers collapse?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Standard RAG returns:&lt;br&gt;
| Chunk | Similarity | Causal? |&lt;br&gt;
|-------|-----------|---------|&lt;br&gt;
| Dodd-Frank Act provisions | 0.87 | ❌ Response to collapse |&lt;br&gt;
| CDS mispricing mechanism | 0.91 | ✅ Actual cause |&lt;br&gt;
| Systemic risk reports | 0.85 | ❌ Consequences |&lt;br&gt;
| Bear Stearns comparison | 0.83 | ❌ Parallel event |&lt;/p&gt;

&lt;p&gt;The LLM gets all four. It produces a response about regulatory failure and systemic risk. It never mentions CDSs. The answer is 100% hallucination — constructed from real documents, assembled into a false causal chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is Semantic Drift&lt;/strong&gt;: the retrieved context drifts from causal relevance toward topical association.&lt;/p&gt;
&lt;h3&gt;
  
  
  Problem 2: Context Window Poisoning ☠️
&lt;/h3&gt;

&lt;p&gt;Even when you retrieve the &lt;em&gt;right&lt;/em&gt; chunk, if 7 wrong chunks surround it, the LLM's attention gets diluted. This isn't speculation — it's backed by the "Lost in the Middle" paper (Liu et al., 2023): LLMs have a &lt;strong&gt;U-shaped recall curve&lt;/strong&gt;. They remember the beginning and end of context best, and systematically lose information in the middle.&lt;/p&gt;

&lt;p&gt;So even if your correct chunk is in the context window, if it lands at position 4 of 8 chunks, the LLM may functionally ignore it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is Context Window Poisoning&lt;/strong&gt;: the noise-to-signal ratio in the context window destroys the LLM's ability to use the correct information.&lt;/p&gt;


&lt;h2&gt;
  
  
  Building VORTEXRAG: 4 Months, 7 Layers, One Obsession
&lt;/h2&gt;

&lt;p&gt;I started with a simple question: &lt;em&gt;What would it take to fix both problems simultaneously?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer turned out to be a 7-layer pipeline. Each layer solves a specific failure mode. Let me walk you through each one — not just what it does, but &lt;strong&gt;why I built it&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  Layer 1: TVE — Tri-Vector Encoding 🔺
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; If similarity retrieval can't capture causality, we need to encode causality directly.&lt;/p&gt;

&lt;p&gt;Standard RAG embeds text into a single semantic vector (usually 768 dimensions). VORTEXRAG encodes every chunk into a &lt;strong&gt;864-dimensional tri-vector&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TVE score = α·cos_sem + β·cos_syn + γ·cos_cau

Where:
  sem = 768d SBERT all-mpnet-base-v2    (semantic meaning)
  syn = 64d  spaCy dependency parse     (syntactic structure)
  cau = 32d  PropBank SRL events        (causal relationships)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The causal arm (32 dimensions) encodes the PropBank-style semantic role labels: ARG0 (agent), ARG1 (patient), ARGM-CAU (cause), ARGM-EFF (effect). A chunk about "CDSs caused Lehman's collapse" has a very different causal vector than a chunk about "Dodd-Frank responded to the collapse" — even if they have identical semantic similarity to the query.&lt;/p&gt;

&lt;p&gt;This is the foundation everything else builds on.&lt;/p&gt;




&lt;h3&gt;
  
  
  Layer 2: VRC — Vortex Retrieval Cone 🌀
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; Retrieval isn't a list — it's a &lt;em&gt;geometry&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Traditional top-k retrieval treats candidates as a ranked list. VORTEXRAG models retrieval as a &lt;strong&gt;spiral probability surface&lt;/strong&gt; in causal vector space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spiral_rank = TVE · e^(−λr) · cos(nθ)

Where:
  θ = angle between query's causal vector and chunk's causal vector
  r = rank position in initial retrieval
  λ = 0.5 (radial decay, adaptive with corpus size)
  n = 2 (angular frequency)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key term is &lt;code&gt;cos(nθ)&lt;/code&gt;. Chunks whose causal direction is more than π/4 (45°) from the query's causal direction get &lt;strong&gt;geometrically suppressed&lt;/strong&gt; — their spiral rank drops toward zero regardless of semantic similarity. The "vortex" shape comes from combining the radial decay with the angular suppression: retrieved chunks form a cone, not a list.&lt;/p&gt;




&lt;h3&gt;
  
  
  Layer 3: SDC — Semantic Drift Corrector 🛡️
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; Measure the drift explicitly. Filter on it.&lt;/p&gt;

&lt;p&gt;For each candidate chunk, SDC computes a &lt;strong&gt;Semantic Drift Score&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D = v_cau(query) − v_cau(chunk)    ← causal drift vector
SDS = 1 − tanh(‖D‖ / τ)           ← drift score ∈ [0, 1]

Accept chunk if SDS ≥ 0.72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The higher the &lt;code&gt;‖D‖&lt;/code&gt;, the more the chunk's causal structure has drifted from the query's. &lt;code&gt;τ&lt;/code&gt; controls the sensitivity — and this is where the &lt;strong&gt;11 domain presets&lt;/strong&gt; come in:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;τ&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scientific&lt;/td&gt;
&lt;td&gt;0.30&lt;/td&gt;
&lt;td&gt;Strict: cause-effect chains must be tight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medical&lt;/td&gt;
&lt;td&gt;0.35&lt;/td&gt;
&lt;td&gt;Strict: diagnosis → treatment causality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legal&lt;/td&gt;
&lt;td&gt;0.40&lt;/td&gt;
&lt;td&gt;Strict: precedent → ruling chains&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Financial&lt;/td&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;Moderate: multi-factor causation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General&lt;/td&gt;
&lt;td&gt;0.80&lt;/td&gt;
&lt;td&gt;Default: relaxed filtering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Creative&lt;/td&gt;
&lt;td&gt;1.20&lt;/td&gt;
&lt;td&gt;Lenient: loose associations acceptable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Layer 4: CPG — Context Poison Guard ⚗️
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; The entire window must be healthy, not just individual chunks.&lt;/p&gt;

&lt;p&gt;Even if each chunk individually passes SDC, the &lt;em&gt;combination&lt;/em&gt; of chunks can still poison the context. CPG measures the &lt;strong&gt;Effective Signal Ratio&lt;/strong&gt; of the entire window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ESR = Σ(SDS_i · w_i) / (P + ε)

Where:
  P = 1/k normalization penalty (penalizes large windows)
  ε = smoothing constant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If ESR &amp;lt; 3.5, CPG runs a &lt;strong&gt;greedy purge&lt;/strong&gt;: remove the chunk with the lowest SDS score. Recompute ESR. Repeat until ESR ≥ 3.5.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theorem 5.1&lt;/strong&gt; (proved in the paper): Removing the minimum-SDS chunk maximizes ESR improvement per step. The greedy algorithm is provably optimal — no other single-step removal produces a better ESR increase.&lt;/p&gt;

&lt;p&gt;This theorem is what separates CPG from heuristic approaches. It's not "try to remove bad chunks." It's a mathematical guarantee that the greedy approach is the best possible approach.&lt;/p&gt;




&lt;h3&gt;
  
  
  Layer 5: RFG — Rank Fusion Gate 🔀
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; Additive fusion lets weak links through. Multiplication doesn't.&lt;/p&gt;

&lt;p&gt;Most multi-signal retrieval systems use &lt;strong&gt;additive fusion&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score = w1·signal1 + w2·signal2 + w3·signal3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem: a chunk with &lt;code&gt;(0.9, 0.9, 0.1)&lt;/code&gt; scores the same as one with &lt;code&gt;(0.63, 0.63, 0.63)&lt;/code&gt;. But the first chunk is clearly wrong — one signal is terrible.&lt;/p&gt;

&lt;p&gt;VORTEXRAG uses &lt;strong&gt;multiplicative fusion&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Φ = TVE^α × SDS^β × ESR_contrib^γ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;(0.9 × 0.9 × 0.1)^(1/3) = 0.45&lt;/code&gt; vs &lt;code&gt;(0.63 × 0.63 × 0.63)^(1/3) = 0.63&lt;/code&gt;. The chunk with one bad signal scores lower, as it should. &lt;strong&gt;No weak link can be compensated by strong links in other dimensions.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Layer 6: CCB — Causal Context Builder 🏗️
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; Where you put information in the context window matters enormously.&lt;/p&gt;

&lt;p&gt;From "Lost in the Middle": LLMs recall information best at position 0 and near the end of context. The middle is a graveyard for information.&lt;/p&gt;

&lt;p&gt;CCB builds a causal dependency graph and assigns positions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pos = rank(Φ+) × causal_depth

depth-0 root-cause chunks → always placed at pos = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The chunk that is the &lt;em&gt;causal root&lt;/em&gt; — the one that explains &lt;em&gt;why&lt;/em&gt; — always goes first. Supporting evidence follows in causal order. The LLM gets the most important information exactly where it's best at attending to it.&lt;/p&gt;




&lt;h3&gt;
  
  
  Layer 7: FV — Faithfulness Verifier ✅
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The insight:&lt;/strong&gt; Don't trust the LLM. Measure it.&lt;/p&gt;

&lt;p&gt;After generation, FV computes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ΔR = 1 − ROUGE-L(answer, context) × NLI_score(answer, context)

Accept if ΔR ≤ 0.15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If ΔR &amp;gt; 0.15 (more than 15% of the answer isn't grounded in the context), FV rejects the response, reranks the context, and retries — up to 3 times. Uses DeBERTa-v3-small CrossEncoder for NLI.&lt;/p&gt;

&lt;p&gt;This is the final catch. Even if all 6 previous layers work perfectly, the LLM can still hallucinate. FV makes hallucination &lt;strong&gt;measurable and catchable&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Results — After 229 Tests and 6 Benchmarks
&lt;/h2&gt;

&lt;p&gt;I tested VORTEXRAG on the standard QA benchmark suite: NQ, TriviaQA, WebQ, PopQA, HotpotQA, and 2WikiMultiHopQA.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall Performance
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;EM&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;th&gt;Faithfulness&lt;/th&gt;
&lt;th&gt;Semantic Drift&lt;/th&gt;
&lt;th&gt;Context Poisoning&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VORTEXRAG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;74.8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;82.6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.94&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;185ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-RAG&lt;/td&gt;
&lt;td&gt;68.4&lt;/td&gt;
&lt;td&gt;77.1&lt;/td&gt;
&lt;td&gt;0.81&lt;/td&gt;
&lt;td&gt;28%&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;td&gt;410ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CRAG&lt;/td&gt;
&lt;td&gt;66.9&lt;/td&gt;
&lt;td&gt;75.8&lt;/td&gt;
&lt;td&gt;0.79&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;td&gt;320ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG-Fusion&lt;/td&gt;
&lt;td&gt;62.8&lt;/td&gt;
&lt;td&gt;71.9&lt;/td&gt;
&lt;td&gt;0.73&lt;/td&gt;
&lt;td&gt;33%&lt;/td&gt;
&lt;td&gt;21%&lt;/td&gt;
&lt;td&gt;280ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Naive RAG&lt;/td&gt;
&lt;td&gt;61.2&lt;/td&gt;
&lt;td&gt;69.4&lt;/td&gt;
&lt;td&gt;0.71&lt;/td&gt;
&lt;td&gt;36%&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;td&gt;95ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;+13.6 EM over Naive RAG. +6.4 EM over Self-RAG. 2.2× faster than Self-RAG.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Per-Dataset Breakdown
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;VORTEXRAG&lt;/th&gt;
&lt;th&gt;Self-RAG&lt;/th&gt;
&lt;th&gt;Δ&lt;/th&gt;
&lt;th&gt;Why VORTEXRAG wins here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NQ&lt;/td&gt;
&lt;td&gt;74.1&lt;/td&gt;
&lt;td&gt;67.2&lt;/td&gt;
&lt;td&gt;+6.9&lt;/td&gt;
&lt;td&gt;Single-hop causal queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TriviaQA&lt;/td&gt;
&lt;td&gt;81.3&lt;/td&gt;
&lt;td&gt;77.8&lt;/td&gt;
&lt;td&gt;+3.5&lt;/td&gt;
&lt;td&gt;Fact retrieval, less causal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebQ&lt;/td&gt;
&lt;td&gt;68.4&lt;/td&gt;
&lt;td&gt;61.9&lt;/td&gt;
&lt;td&gt;+6.5&lt;/td&gt;
&lt;td&gt;Entity-centric causal chains&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PopQA&lt;/td&gt;
&lt;td&gt;71.2&lt;/td&gt;
&lt;td&gt;63.4&lt;/td&gt;
&lt;td&gt;+7.8&lt;/td&gt;
&lt;td&gt;Long-tail causal knowledge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HotpotQA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;67.9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;61.1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+6.8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-hop: biggest gains&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2WikiMH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;69.8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;62.3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+7.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-hop: biggest gains&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The biggest gains are on &lt;strong&gt;multi-hop datasets&lt;/strong&gt; — exactly where causal reasoning matters most. This is the validation I was hoping for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ablation: Every Layer Earns Its Place
&lt;/h3&gt;

&lt;p&gt;One of my proudest moments was running the ablation study. I was terrified some layers would show no contribution. They all did.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;EM&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;th&gt;Faithfulness&lt;/th&gt;
&lt;th&gt;+EM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A: Naive RAG baseline&lt;/td&gt;
&lt;td&gt;61.2&lt;/td&gt;
&lt;td&gt;69.4&lt;/td&gt;
&lt;td&gt;0.71&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B: +TVE&lt;/td&gt;
&lt;td&gt;65.3&lt;/td&gt;
&lt;td&gt;72.8&lt;/td&gt;
&lt;td&gt;0.74&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+4.1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C: +VRC&lt;/td&gt;
&lt;td&gt;67.8&lt;/td&gt;
&lt;td&gt;75.1&lt;/td&gt;
&lt;td&gt;0.76&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+2.5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D: +SDC&lt;/td&gt;
&lt;td&gt;70.4&lt;/td&gt;
&lt;td&gt;78.3&lt;/td&gt;
&lt;td&gt;0.80&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+2.6&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E: +CPG&lt;/td&gt;
&lt;td&gt;72.1&lt;/td&gt;
&lt;td&gt;80.2&lt;/td&gt;
&lt;td&gt;0.85&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+1.7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F: +RFG&lt;/td&gt;
&lt;td&gt;73.4&lt;/td&gt;
&lt;td&gt;81.4&lt;/td&gt;
&lt;td&gt;0.89&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+1.3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G: +CCB&lt;/td&gt;
&lt;td&gt;73.9&lt;/td&gt;
&lt;td&gt;81.9&lt;/td&gt;
&lt;td&gt;0.91&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+0.5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H: +FV (full VORTEXRAG)&lt;/td&gt;
&lt;td&gt;74.8&lt;/td&gt;
&lt;td&gt;82.6&lt;/td&gt;
&lt;td&gt;0.94&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+0.9&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every single layer contributes. There's no dead weight.&lt;/p&gt;




&lt;h2&gt;
  
  
  Human Evaluation — The Number That Matters Most
&lt;/h2&gt;

&lt;p&gt;Automatic metrics only go so far. I had 3 domain experts (an NLP researcher, a practicing lawyer, and a biomedical scientist) evaluate 150 responses each on 4 dimensions using 5-point Likert scales.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;VORTEXRAG&lt;/th&gt;
&lt;th&gt;Self-RAG&lt;/th&gt;
&lt;th&gt;Naive RAG&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Factual Accuracy&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.5/5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.9/5&lt;/td&gt;
&lt;td&gt;3.2/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Causal Coherence&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.3/5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.4/5&lt;/td&gt;
&lt;td&gt;2.8/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Completeness&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.2/5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.8/5&lt;/td&gt;
&lt;td&gt;3.5/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conciseness&lt;/td&gt;
&lt;td&gt;4.1/5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.2/5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.0/5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;+0.9 on Causal Coherence&lt;/strong&gt; vs Self-RAG is the one I'm most proud of. It means real humans, in real domains, found the causal reasoning in VORTEXRAG's answers to be significantly better. No automatic metric fully captures this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It Right Now
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5-Minute Quickstart
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/vignesh2027/VORTEXRAG
&lt;span class="nb"&gt;cd &lt;/span&gt;VORTEXRAG
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python examples/basic_usage.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Your First Causal Query
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;vortexrag&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VortexRAG&lt;/span&gt;

&lt;span class="c1"&gt;# Pick your domain — parameters auto-calibrate
&lt;/span&gt;&lt;span class="n"&gt;rag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VortexRAG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Why do SSRIs take 2-4 weeks to work?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;my_medical_chunks&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# Causally grounded answer
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sds_score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# Drift score: should be &amp;gt;= 0.72
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;faithfulness&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# Hallucination delta: &amp;lt;= 0.15
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer_trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# Full 7-layer trace for debugging
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer-by-Layer Trace (What You Actually See)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Layer 1 [TVE]: Encoded 847 chunks as 864-dim tri-vectors (8.2ms)
Layer 2 [VRC]: Spiral-ranked top-50 candidates (2.1ms)
              Angular suppression: 12 chunks suppressed (θ &amp;gt; π/4)
Layer 3 [SDC]: Drift filtering with τ=0.35 (medical preset)
              Accepted: 31/50 chunks (SDS range: 0.72-0.97)
Layer 4 [CPG]: Initial ESR: 2.84 (below threshold 3.5)
              Purging: removed 4 low-signal chunks
              Final ESR: 4.12 ✓
Layer 5 [RFG]: Multiplicative Φ-scores computed (1.8ms)
              Top-5 selected: Φ ∈ [0.71, 0.89]
Layer 6 [CCB]: Causal graph built (3 root-cause chunks at pos=0)
              Context ordered by causal depth
Layer 7 [FV]:  Generated answer, ΔR = 0.09 ✓ (&amp;lt; 0.15 threshold)
              Faithfulness verified on first attempt

Total: 183ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What I Learned Building This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Cosine similarity is a local optima.&lt;/strong&gt; The entire field optimized around it so heavily that we forgot it was a proxy, not the thing itself. Causal relevance is the thing itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Every layer needs a mathematical reason to exist.&lt;/strong&gt; I threw out 3 layers during development because I couldn't prove they were optimal or even justified. Theorem 5.1 (CPG optimality) took me 3 weeks to prove. Worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Latency is a feature.&lt;/strong&gt; At 185ms, VORTEXRAG is 2.2× faster than Self-RAG despite doing far more work. Why? Because Self-RAG generates multiple draft responses and selects. VORTEXRAG's pre-generation filtering means the LLM sees a clean, small context and generates once. Less is more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Human evaluation is irreplaceable.&lt;/strong&gt; My biomedical expert caught failure modes on multi-step enzyme pathway questions that EM, F1, and faithfulness all missed. Automatic metrics are necessary but not sufficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part I Almost Didn't Share
&lt;/h2&gt;

&lt;p&gt;I'm a student at Takshashila University. This wasn't done in a research lab with 40 GPUs and a team of PhD students. This was done on my laptop, in my room, across 4 months of evenings and weekends, after getting frustrated with every RAG system I used giving me wrong causal answers.&lt;/p&gt;

&lt;p&gt;I don't have institutional affiliation. I don't have a PhD supervisor. I just had a problem that bothered me and enough stubbornness to not stop until I could prove I'd solved it.&lt;/p&gt;

&lt;p&gt;If you're a student or independent researcher reading this: the problems worth solving are the ones that bother you personally. Not the ones that are impressive on a CV. The ones that make you think &lt;em&gt;"this is broken and nobody seems to notice."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's what VORTEXRAG was for me. I hope it's useful for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links &amp;amp; Citation
&lt;/h2&gt;

&lt;p&gt;🌀 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://huggingface.co/spaces/vigneshwar234/VORTEXRAG" rel="noopener noreferrer"&gt;https://huggingface.co/spaces/vigneshwar234/VORTEXRAG&lt;/a&gt;&lt;br&gt;&lt;br&gt;
💻 &lt;strong&gt;Code (MIT, 229 tests):&lt;/strong&gt; &lt;a href="https://github.com/vignesh2027/VORTEXRAG" rel="noopener noreferrer"&gt;https://github.com/vignesh2027/VORTEXRAG&lt;/a&gt;&lt;br&gt;&lt;br&gt;
📄 &lt;strong&gt;Paper (Zenodo v3.0):&lt;/strong&gt; &lt;a href="https://doi.org/10.5281/zenodo.20579702" rel="noopener noreferrer"&gt;https://doi.org/10.5281/zenodo.20579702&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔬 &lt;strong&gt;ORCID:&lt;/strong&gt; &lt;a href="https://orcid.org/0009-0004-9777-7592" rel="noopener noreferrer"&gt;https://orcid.org/0009-0004-9777-7592&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight bibtex"&gt;&lt;code&gt;&lt;span class="nc"&gt;@article&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;vignesh2026vortexrag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{VORTEXRAG: Vector Orthogonal Resonance-Tuned EXtraction
             Retrieval-Augmented Generation — A 7-Layer Framework for
             Simultaneous Elimination of Semantic Drift and Context
             Window Poisoning}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;author&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{Vignesh, L}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;year&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{2026}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;doi&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{10.5281/zenodo.20579702}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{https://doi.org/10.5281/zenodo.20579702}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;If this helped you, or if you tried VORTEXRAG and have feedback, drop a comment below. Every reaction, unicorn, and share genuinely helps this reach more people. Thank you for reading.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; #machinelearning #python #rag #nlp #ai #deeplearning #opensource #research&lt;/p&gt;

</description>
      <category>python</category>
      <category>rag</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sun, 24 May 2026 04:20:40 +0000</pubDate>
      <link>https://dev.to/vignesh_one/-b1b</link>
      <guid>https://dev.to/vignesh_one/-b1b</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/vignesh_one/i-lost-3-enterprise-clients-in-one-night-because-of-a-github-repo-so-i-built-a-tool-to-make-sure-4fbc" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl95s1znl73xtbvuccuzt.png" height="414" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/vignesh_one/i-lost-3-enterprise-clients-in-one-night-because-of-a-github-repo-so-i-built-a-tool-to-make-sure-4fbc" rel="noopener noreferrer" class="c-link"&gt;
            I lost 3 enterprise clients in one night because of a GitHub repo. So I built a tool to make sure it never happens again. - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            It was 11:47 PM on a Tuesday.  I had just pushed to production.  Closed my...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>I lost 3 enterprise clients in one night because of a GitHub repo. So I built a tool to make sure it never happens again.</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Sun, 24 May 2026 04:19:35 +0000</pubDate>
      <link>https://dev.to/vignesh_one/i-lost-3-enterprise-clients-in-one-night-because-of-a-github-repo-so-i-built-a-tool-to-make-sure-4fbc</link>
      <guid>https://dev.to/vignesh_one/i-lost-3-enterprise-clients-in-one-night-because-of-a-github-repo-so-i-built-a-tool-to-make-sure-4fbc</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.amazonaws.com%2Fuploads%2Farticles%2Fvacgg2lcy2m0d9n2r2yw.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.amazonaws.com%2Fuploads%2Farticles%2Fvacgg2lcy2m0d9n2r2yw.png" alt=" " width="800" height="411"&gt;&lt;/a&gt;                   &lt;/p&gt;

&lt;p&gt;It was 11:47 PM on a Tuesday.&lt;/p&gt;

&lt;p&gt;I had just pushed to production.&lt;/p&gt;

&lt;p&gt;Closed my laptop. Made tea. Felt good about myself.&lt;/p&gt;

&lt;p&gt;By 3:14 AM my phone was a disaster.&lt;/p&gt;

&lt;p&gt;17 missed calls. 43 Slack messages. 6 emails.&lt;br&gt;
The subject line on the first email read:&lt;br&gt;
"URGENT — Platform completely down"&lt;/p&gt;

&lt;p&gt;My hands were shaking before I even opened it.&lt;/p&gt;

&lt;p&gt;Three weeks earlier I had been under insane deadline pressure.&lt;/p&gt;

&lt;p&gt;We were building a SaaS product for enterprise clients.&lt;br&gt;
Launch was in 72 hours.&lt;br&gt;
I needed an authentication library fast.&lt;/p&gt;

&lt;p&gt;I went to GitHub.&lt;/p&gt;

&lt;p&gt;Found one that looked incredible.&lt;br&gt;
Clean name. Professional README.&lt;br&gt;
2,400 stars. 340 forks.&lt;br&gt;
The code looked solid on first glance.&lt;/p&gt;

&lt;p&gt;I did what most developers do under deadline pressure.&lt;/p&gt;

&lt;p&gt;I added it. Shipped it. Went to sleep.&lt;/p&gt;

&lt;p&gt;What I didn't check:&lt;/p&gt;

&lt;p&gt;The last commit was 9 months ago.&lt;br&gt;
There were 47 open issues marked as critical.&lt;br&gt;
Zero CI/CD pipeline.&lt;br&gt;
Zero test files in the entire repo.&lt;br&gt;
The maintainer had responded to exactly 0 issues in 6 months.&lt;br&gt;
There was a known security vulnerability reported 4 months ago.&lt;br&gt;
Still open. No response. No fix.&lt;/p&gt;

&lt;p&gt;In 3 seconds I could have seen all of this.&lt;/p&gt;

&lt;p&gt;I didn't check. So I didn't know.&lt;/p&gt;

&lt;p&gt;Until 3am.&lt;/p&gt;

&lt;p&gt;The bug triggered under high concurrent load.&lt;/p&gt;

&lt;p&gt;Our enterprise demo that night had 200 simultaneous users.&lt;br&gt;
The library collapsed. Took the auth system with it.&lt;br&gt;
Every single user got logged out.&lt;br&gt;
Sessions destroyed. Data in a corrupted state.&lt;br&gt;
The whole platform returned a 500 error for 14 straight hours.&lt;/p&gt;

&lt;p&gt;We lost 3 enterprise clients that week.&lt;br&gt;
Each worth $40,000 annually.&lt;/p&gt;

&lt;p&gt;$120,000 gone because I didn't spend 3 minutes&lt;br&gt;
checking a GitHub repo properly.&lt;/p&gt;

&lt;p&gt;My manager didn't fire me.&lt;br&gt;
But the look on his face in that Monday meeting&lt;br&gt;
is something I will never forget as long as I live.&lt;/p&gt;

&lt;p&gt;After that I became obsessive.&lt;/p&gt;

&lt;p&gt;I started checking every single dependency manually.&lt;br&gt;
Every library. Every tool. Every npm package.&lt;br&gt;
Every GitHub repo anyone on the team suggested.&lt;/p&gt;

&lt;p&gt;I built a personal checklist:&lt;/p&gt;

&lt;p&gt;→ When was the last commit?&lt;br&gt;
→ Is there a CI/CD pipeline?&lt;br&gt;
→ Are there test files?&lt;br&gt;
→ How many open issues vs closed?&lt;br&gt;
→ What is the average time to close an issue?&lt;br&gt;
→ Who are the contributors and are they still active?&lt;br&gt;
→ Is there a license?&lt;br&gt;
→ How long and detailed is the README?&lt;br&gt;
→ What does the community size look like?&lt;br&gt;
→ Are there known CVEs in the dependencies?&lt;/p&gt;

&lt;p&gt;20 to 30 minutes per repo.&lt;br&gt;
Every single time.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F7cbmrrj17owhqzzv81uw.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.amazonaws.com%2Fuploads%2Farticles%2F7cbmrrj17owhqzzv81uw.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;br&gt;
My team thought I was paranoid.&lt;/p&gt;

&lt;p&gt;I thought I was just finally doing my job properly.&lt;/p&gt;

&lt;p&gt;Four months later I had evaluated hundreds of repos this way.&lt;/p&gt;

&lt;p&gt;And I was completely burned out from doing it manually.&lt;/p&gt;

&lt;p&gt;Every evaluation felt like the same work.&lt;br&gt;
The same checks. The same tabs. The same mental process.&lt;br&gt;
Over and over and over.&lt;/p&gt;

&lt;p&gt;I started thinking about the developers who don't do this at all.&lt;br&gt;
The ones who are exactly where I was at 11:47 PM on that Tuesday.&lt;br&gt;
Feeling good. Laptop closed. Tea in hand.&lt;/p&gt;

&lt;p&gt;Not knowing what's coming.&lt;/p&gt;

&lt;p&gt;So I spent three weeks and built RepoLens.&lt;/p&gt;

&lt;p&gt;Not for clout. Not for a portfolio piece.&lt;br&gt;
Because I genuinely needed it.&lt;br&gt;
And I was pretty sure millions of other developers did too.&lt;/p&gt;

&lt;p&gt;Here is what it does:&lt;/p&gt;

&lt;p&gt;Paste any GitHub URL.&lt;/p&gt;

&lt;p&gt;In 3 seconds you get:&lt;/p&gt;

&lt;p&gt;🏥 Repository Health Score — 0 to 100&lt;br&gt;
A single score computed across 7 quality dimensions.&lt;br&gt;
README quality. Commit activity. Test detection.&lt;br&gt;
CI/CD presence. License. Community size. Issue resolution.&lt;br&gt;
One number that tells you everything.&lt;br&gt;
With a letter grade. A B C D.&lt;br&gt;
So you know in 1 second if this is production-ready.&lt;/p&gt;

&lt;p&gt;🥧 Language Breakdown&lt;br&gt;
A beautiful interactive pie chart showing every single language&lt;br&gt;
used in the codebase with exact percentages.&lt;br&gt;
Know the full technical makeup before you touch it.&lt;/p&gt;

&lt;p&gt;🔥 52-Week Commit Heatmap&lt;br&gt;
A GitHub-style activity grid showing every week of the past year.&lt;br&gt;
See at a glance — is this project alive or abandoned?&lt;br&gt;
Spot burnout periods. Spot release sprints.&lt;br&gt;
Spot the exact week the maintainer stopped caring.&lt;/p&gt;

&lt;p&gt;👥 Top Contributor Graph&lt;br&gt;
Who actually built this thing?&lt;br&gt;
Are they still active?&lt;br&gt;
Is it one person or a healthy team?&lt;br&gt;
Bar chart. Avatars. Contribution share visualization.&lt;br&gt;
Everything you need to know about who drives this project.&lt;/p&gt;

&lt;p&gt;📦 Smart Dependency Detection&lt;br&gt;
Automatically parses every ecosystem file:&lt;br&gt;
package.json for Node.&lt;br&gt;
requirements.txt and pyproject.toml for Python.&lt;br&gt;
Cargo.toml for Rust.&lt;br&gt;
go.mod for Go.&lt;br&gt;
pom.xml for Java.&lt;br&gt;
Gemfile for Ruby.&lt;br&gt;
Every package. Every version. Automatically.&lt;/p&gt;

&lt;p&gt;🗂 Interactive File Tree&lt;br&gt;
Collapsible directory explorer with file type icons.&lt;br&gt;
See the structure of any codebase instantly.&lt;br&gt;
Search and filter in real time.&lt;/p&gt;

&lt;p&gt;📖 Beautiful README Renderer&lt;br&gt;
Full GitHub Flavored Markdown.&lt;br&gt;
Images. Tables. Code blocks. Everything.&lt;br&gt;
Read the documentation without leaving the tool.&lt;/p&gt;

&lt;p&gt;📤 One-Click Share Card&lt;br&gt;
Export a beautiful PNG summary card.&lt;br&gt;
Share on LinkedIn. Post on Twitter.&lt;br&gt;
Send to your team before a code review.&lt;/p&gt;

&lt;p&gt;I ran the library that destroyed my production server through it.&lt;/p&gt;

&lt;p&gt;31 out of 100. Grade D.&lt;/p&gt;

&lt;p&gt;In 3 seconds.&lt;/p&gt;

&lt;p&gt;The exact score I needed at 11:47 PM on that Tuesday&lt;br&gt;
instead of at 3:14 AM the next morning.&lt;/p&gt;

&lt;p&gt;I've been using RepoLens every single day since I built it.&lt;/p&gt;

&lt;p&gt;My entire team uses it now before every dependency decision.&lt;br&gt;
We have a rule — no new library gets added without a score.&lt;/p&gt;

&lt;p&gt;We haven't had a single library-related production incident since.&lt;/p&gt;

&lt;p&gt;Not one.&lt;/p&gt;

&lt;p&gt;I'm sharing it completely free.&lt;/p&gt;

&lt;p&gt;No sign-up required.&lt;br&gt;
No account.&lt;br&gt;
No credit card.&lt;br&gt;
No limits.&lt;br&gt;
Works on every public GitHub repository on the planet.&lt;br&gt;
Instant results. Every time.&lt;/p&gt;

&lt;p&gt;And the entire thing is open source.&lt;/p&gt;

&lt;p&gt;React 18 frontend. Vite. Tailwind CSS.&lt;br&gt;
FastAPI Python backend. GitHub REST API only.&lt;br&gt;
File-based caching. Rate limiting. Security headers.&lt;br&gt;
Full type hints. Clean architecture.&lt;/p&gt;

&lt;p&gt;If you want to see how it's built — every line of code is there.&lt;br&gt;
If you want to contribute — PRs are open.&lt;br&gt;
If you want to self-host it — full Docker support.&lt;/p&gt;

&lt;p&gt;🌐 Try it free:&lt;br&gt;
&lt;a href="https://vignesh2027.github.io/GitHub-Repo-Analyzer/&lt;br&gt;%0A![%20](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ajjw00y33e6olrhqpda.png)" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub:&lt;br&gt;
github.com/vignesh2027/GitHub-Repo-Analyzer&lt;/p&gt;

&lt;p&gt;Drop any GitHub repo URL in the comments below.&lt;/p&gt;

&lt;p&gt;I will personally reply to every single one&lt;br&gt;
with its health score and what I'd fix first.&lt;/p&gt;

&lt;p&gt;And tell me —&lt;/p&gt;

&lt;p&gt;What's the worst GitHub repo you ever trusted?&lt;/p&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;Because I have a feeling I'm not the only one&lt;br&gt;
who learned this lesson the hard way.&lt;/p&gt;

</description>
      <category>github</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>awesome claude skills</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Thu, 21 May 2026 03:29:02 +0000</pubDate>
      <link>https://dev.to/vignesh_one/awesome-claude-skills-64n</link>
      <guid>https://dev.to/vignesh_one/awesome-claude-skills-64n</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/vignesh_one/awesome-claude-skills-i-built-135-claude-skills-with-real-formulas-heres-what-ae" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgivdqorwfnnyb249wp2.png" height="630" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/vignesh_one/awesome-claude-skills-i-built-135-claude-skills-with-real-formulas-heres-what-ae" rel="noopener noreferrer" class="c-link"&gt;
            Awesome-Claude-Skills I built 135 Claude Skills with real formulas. Here's what "production-grade" actually means. - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I've been frustrated for a long time.  Every "awesome Claude prompts" repo I found looked like...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Awesome-Claude-Skills I built 135 Claude Skills with real formulas. Here's what "production-grade" actually means.</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Thu, 21 May 2026 03:16:43 +0000</pubDate>
      <link>https://dev.to/vignesh_one/awesome-claude-skills-i-built-135-claude-skills-with-real-formulas-heres-what-ae</link>
      <guid>https://dev.to/vignesh_one/awesome-claude-skills-i-built-135-claude-skills-with-real-formulas-heres-what-ae</guid>
      <description>&lt;p&gt;I've been frustrated for a long time.&lt;/p&gt;

&lt;p&gt;Every "awesome Claude prompts" repo I found looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Act as a senior software engineer. Be helpful, thorough, 
and professional. Consider edge cases."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not a skill. That's a costume.&lt;/p&gt;

&lt;p&gt;Real expertise has &lt;strong&gt;frameworks&lt;/strong&gt;. Named responsibilities. &lt;br&gt;
Actual formulas. Code that runs. Constraints that prevent &lt;br&gt;
the model from giving you the easy wrong answer.&lt;/p&gt;

&lt;p&gt;So I spent 6 months building what I actually wanted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AgentOS 2.0 — 135 production-grade Claude Skills.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article explains exactly what's inside and why it's &lt;br&gt;
different from every other prompt collection on GitHub.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem With Every Other Prompt Repo
&lt;/h2&gt;

&lt;p&gt;Most prompt repositories fall into one of three traps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trap 1: The costume prompt&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"You are an expert financial analyst. 
Help the user with their finance questions."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero frameworks. Zero formulas. Zero depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trap 2: The instruction dump&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"When answering, always:
- Be professional
- Consider multiple angles  
- Cite sources
- Format your response clearly"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just asking Claude to be Claude. It changes nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trap 3: The persona prompt&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"You are Alex, a no-nonsense McKinsey consultant 
with 20 years of experience..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Roleplay, not expertise. The model doesn't suddenly &lt;br&gt;
know DCF models because you named it Alex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually works:&lt;/strong&gt; Named sub-agents with &lt;br&gt;
distinct responsibilities, actual domain formulas &lt;br&gt;
in code, and explicit forbidden behaviors that &lt;br&gt;
prevent hallucination in critical areas.&lt;/p&gt;

&lt;p&gt;Here's what that looks like in practice.&lt;/p&gt;


&lt;h2&gt;
  
  
  What "Production-Grade" Actually Looks Like
&lt;/h2&gt;
&lt;h3&gt;
  
  
  FinanceOracle — The Apex Skill
&lt;/h3&gt;

&lt;p&gt;This is the most complete skill in the repo. &lt;br&gt;
Here's a fraction of what's inside:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12 Sub-Agents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OptionsDesk&lt;/code&gt; — derivatives pricing and structuring&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MacroStrategist&lt;/code&gt; — macro regime analysis&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HedgeFundArchitect&lt;/code&gt; — strategy design&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FamilyOfficeCIO&lt;/code&gt; — multi-generational allocation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TaxOptimizer&lt;/code&gt; — harvest and structure optimization&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DerivativesStructurer&lt;/code&gt; — exotic product design
&lt;em&gt;(+ 6 more)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Actual runnable Python:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;black_scholes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sigma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;call&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sigma&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sigma&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sigma&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;option_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;call&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;gamma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sigma&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;vega&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="n"&gt;theta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sigma&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
             &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;365&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gamma&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gamma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vega&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vega&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;theta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Black-Litterman portfolio construction:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;black_litterman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Sigma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;market_weights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views_P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                    &lt;span class="n"&gt;views_Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views_omega&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tau&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Sigma&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;market_weights&lt;/span&gt;
    &lt;span class="n"&gt;M_inv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tau&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Sigma&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
        &lt;span class="n"&gt;views_P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;views_omega&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;views_P&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mu_bl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;M_inv&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tau&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Sigma&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
        &lt;span class="n"&gt;views_P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;views_omega&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;views_Q&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expected_returns&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mu_bl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't pseudocode. This runs.&lt;/p&gt;




&lt;h3&gt;
  
  
  OKREngine — Catches Failures Before They Kill Your Quarter
&lt;/h3&gt;

&lt;p&gt;I've watched two startups waste entire quarters on &lt;br&gt;
broken OKRs. This skill exists because of that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The objective quality scorer:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_okr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objective&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;obj_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;obj_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objective&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;obj_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;objective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;improve&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;obj_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; 
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;best&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lead&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transform&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redefine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;kr_scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;key_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;kr_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;kr_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metric&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;kr_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baseline&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;kr_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;kr_scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kr_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Good&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kr_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Needs work&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;objective_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;obj_score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/10&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;key_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kr_scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recommendation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Strong OKR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;obj_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Needs revision&lt;/span&gt;&lt;span class="sh"&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 skill also catches the &lt;strong&gt;12 most common OKR failure modes&lt;/strong&gt; — including sandbagging, health metrics disguised as OKRs, and the single most destructive mistake: tying OKR scores to bonuses.&lt;/p&gt;




&lt;h3&gt;
  
  
  VentureIntelligence — Term Sheet Red Flag Detector
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_term_sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;red_flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;liq_pref_multiple&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Liquidation preference &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;liq_pref_multiple&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;x — above 1x is punishing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;participating_preferred&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Participating preferred — VCs get paid twice in exits below threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anti_dilution&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_ratchet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Full ratchet anti-dilution — catastrophic in a down round&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;board_seats_investor&lt;/span&gt;&lt;span class="sh"&gt;"&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;board_seats_founder&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Investor has majority board control — you can be fired from your company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;red_flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;max&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="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sign it&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Negotiate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get a lawyer NOW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;red_flags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;red_flags&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;12 sub-agents including &lt;code&gt;TermSheetDecoder&lt;/code&gt;, &lt;code&gt;ValuationNegotiator&lt;/code&gt;, &lt;code&gt;ChampionDeveloper&lt;/code&gt;, and &lt;code&gt;BoardRelationshipManager&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  CrisisIntelligence — War Room OS
&lt;/h3&gt;

&lt;p&gt;Every company will face a crisis. Almost none prepare.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;classify_crisis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crisis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;crisis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_impact_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;crisis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;revenue_at_risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

    &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;local&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;national&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viral&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crisis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;media_coverage&lt;/span&gt;&lt;span class="sh"&gt;"&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;crisis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;regulatory_involvement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;crisis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;legal_liability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CRITICAL (P0)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CEO leads. War room activated NOW.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HIGH (P1)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VP-level lead. External comms needed.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MEDIUM (P2)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Director-level. Monitor externally.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;immediate_action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;time_to_first_response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1 hour&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;severity_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4 hours&lt;/span&gt;&lt;span class="sh"&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 5Rs framework (Recognize → Respond → Responsible → Remediate → Restore) is built into every communication template.&lt;/p&gt;




&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.amazonaws.com%2Fuploads%2Farticles%2F9knwykwn4a88fwtmwdms.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.amazonaws.com%2Fuploads%2Farticles%2F9knwykwn4a88fwtmwdms.png" alt=" " width="799" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works (60-Second Setup)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Claude.ai Projects:&lt;/strong&gt;&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;# 1. Open Claude.ai → Projects → New Project&lt;/span&gt;
&lt;span class="c"&gt;# 2. Paste SKILL.md into "Project Instructions"  &lt;/span&gt;
&lt;span class="c"&gt;# 3. Start chatting&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Claude Code:&lt;/strong&gt;&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="nb"&gt;cat &lt;/span&gt;finance-oracle/SKILL.md &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .claude/CLAUDE.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Claude API:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;startup-cto/SKILL.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;skill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Audit our tech stack decision&lt;/span&gt;&lt;span class="sh"&gt;"&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;That's it. Claude is now that specialist.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full 135-Skill Index
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🚀 Startup &amp;amp; Team Management (11)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;startup-cto&lt;/code&gt; &lt;code&gt;team-performance-os&lt;/code&gt; &lt;code&gt;startup-hiring-machine&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;culture-architect&lt;/code&gt; &lt;code&gt;remote-team-commander&lt;/code&gt; &lt;code&gt;okr-engine&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;startup-finance-controller&lt;/code&gt; &lt;code&gt;venture-intelligence&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;startup-legal-shield&lt;/code&gt; &lt;code&gt;talent-management-os&lt;/code&gt; &lt;code&gt;talent-brand-builder&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏆 Apex Legendary (4)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;finance-oracle&lt;/code&gt; &lt;code&gt;claude-mythos&lt;/code&gt; &lt;code&gt;ceo-war-room&lt;/code&gt; &lt;code&gt;founder-to-ceo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🤖 AI &amp;amp; Engineering (14)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;rag-architect&lt;/code&gt; &lt;code&gt;mlops-engineer&lt;/code&gt; &lt;code&gt;system-architect&lt;/code&gt; &lt;code&gt;senior-dev&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;ai-red-teamer&lt;/code&gt; &lt;code&gt;voice-agent-builder&lt;/code&gt; &lt;code&gt;knowledge-graph-builder&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;incident-commander&lt;/code&gt; &lt;code&gt;mcp-builder&lt;/code&gt; &lt;code&gt;agentic-workflow-builder&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;api-integrator&lt;/code&gt; &lt;code&gt;realtime-data-agent&lt;/code&gt; &lt;code&gt;agent-smith&lt;/code&gt; &lt;code&gt;prompt-engineer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📊 Data &amp;amp; Analytics (10)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;data-scientist-pro&lt;/code&gt; &lt;code&gt;sql-analyzer&lt;/code&gt; &lt;code&gt;data-pipeline-pro&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;business-intelligence-pro&lt;/code&gt; &lt;code&gt;timeseries-oracle&lt;/code&gt; &lt;code&gt;quant-trader&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;synthetic-data-generator&lt;/code&gt; &lt;code&gt;arxiv-researcher&lt;/code&gt; &lt;code&gt;abtest-scientist&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;data-governance-agent&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💹 Finance (9)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;finance-oracle&lt;/code&gt; &lt;code&gt;financial-model-builder&lt;/code&gt; &lt;code&gt;cfo-intelligence&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;portfolio-optimizer&lt;/code&gt; &lt;code&gt;quant-researcher&lt;/code&gt; &lt;code&gt;saas-metrics-analyst&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;insurance-actuary&lt;/code&gt; &lt;code&gt;ma-dealmaker&lt;/code&gt; &lt;code&gt;risk-sentinel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏢 Operations &amp;amp; Business (20)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ceo-war-room&lt;/code&gt; &lt;code&gt;founder-to-ceo&lt;/code&gt; &lt;code&gt;go-to-market-commander&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;enterprise-sales-os&lt;/code&gt; &lt;code&gt;sales-enablement-os&lt;/code&gt; &lt;code&gt;board-deck-builder&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;crisis-intelligence&lt;/code&gt; &lt;code&gt;partnership-intelligence&lt;/code&gt; &lt;code&gt;pricing-strategist&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;project-command&lt;/code&gt; &lt;code&gt;marketing-os&lt;/code&gt; &lt;code&gt;supply-chain-oracle&lt;/code&gt; &lt;em&gt;(+ 8 more)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👤 Product &amp;amp; Customer (11)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;product-roadmap-os&lt;/code&gt; &lt;code&gt;sprint-master&lt;/code&gt; &lt;code&gt;engineering-manager&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;ai-product-manager&lt;/code&gt; &lt;code&gt;user-research-os&lt;/code&gt; &lt;code&gt;customer-interview-analyst&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;product-analytics-os&lt;/code&gt; &lt;code&gt;network-effects-analyst&lt;/code&gt; &lt;code&gt;marketplace-strategist&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;performance-marketing-os&lt;/code&gt; &lt;code&gt;churn-analyst&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛠 Developer Tools (19)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;developer-experience-os&lt;/code&gt; &lt;code&gt;api-design-architect&lt;/code&gt; &lt;code&gt;data-warehouse-architect&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;cloud-cost-optimizer&lt;/code&gt; &lt;code&gt;design-system-architect&lt;/code&gt; &lt;code&gt;technical-pm&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;code-reviewer&lt;/code&gt; &lt;code&gt;load-tester&lt;/code&gt; &lt;code&gt;code-migrator&lt;/code&gt; &lt;code&gt;webapp-tester&lt;/code&gt; &lt;em&gt;(+ 9 more)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌐 Specialized Domains (12)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;healthcare-analytics&lt;/code&gt; &lt;code&gt;web3-developer&lt;/code&gt; &lt;code&gt;climate-tech-analyst&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;biotech-analyst&lt;/code&gt; &lt;code&gt;cybersecurity-analyst&lt;/code&gt; &lt;code&gt;real-estate-intelligence&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;legal-eagle&lt;/code&gt; &lt;code&gt;patent-analyst&lt;/code&gt; &lt;code&gt;esg-compass&lt;/code&gt; &lt;em&gt;(+ 3 more)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes This Different From Every Other Repo
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Generic repos&lt;/th&gt;
&lt;th&gt;AgentOS 2.0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sub-agents&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ 10-12 per skill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual formulas&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Black-Scholes, DCF, MEDDPICC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runnable code&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Python, TypeScript, Go, Shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forbidden behaviors&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Every skill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Benchmark data&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Industry standards built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total skills&lt;/td&gt;
&lt;td&gt;~10-20&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;135+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Try It Right Now
&lt;/h2&gt;

&lt;p&gt;The fastest way to understand the depth is to try one.&lt;/p&gt;

&lt;p&gt;I recommend starting with &lt;strong&gt;&lt;code&gt;okr-engine&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;startup-cto&lt;/code&gt;&lt;/strong&gt; — they're the most complete and immediately useful regardless of what you're building.&lt;/p&gt;

&lt;p&gt;Paste the SKILL.md into Claude Projects. Ask it to review your current OKRs or tech stack. You'll see the difference immediately.&lt;/p&gt;

&lt;p&gt;GitHub link in the comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What skill would you build your work around?&lt;/strong&gt; Drop it below — I read every comment and I'm actively building more.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;MIT License. Free forever. Star it if it's useful — helps others find it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Spent 6 Months Fixing RAG. Here's What I Found (And Built)</title>
      <dc:creator>vigneshwar</dc:creator>
      <pubDate>Tue, 19 May 2026 15:59:07 +0000</pubDate>
      <link>https://dev.to/vignesh_one/i-spent-6-months-fixing-rag-heres-what-i-found-and-built-43ff</link>
      <guid>https://dev.to/vignesh_one/i-spent-6-months-fixing-rag-heres-what-i-found-and-built-43ff</guid>
      <description>&lt;p&gt;This is the story of a debugging session that turned into a research paper.&lt;/p&gt;

&lt;p&gt;The Bug That Started Everything&lt;br&gt;
I was building a document Q&amp;amp;A system — nothing exotic. Standard RAG setup. FAISS index, SBERT embeddings, GPT as the reader. Classic.&lt;/p&gt;

&lt;p&gt;It worked fine on simple questions. "What is the refund policy?" → correct answer.&lt;/p&gt;

&lt;p&gt;Then I tested it on a multi-hop question: "What are the environmental compliance requirements for facilities that process the chemicals used in the manufacturing process described in section 4.2?"&lt;/p&gt;

&lt;p&gt;The model's answer was confident. Detailed. And completely wrong.&lt;/p&gt;

&lt;p&gt;The retrieved documents were all there. Every piece of information needed to answer correctly was in the context window. But the model still hallucinated a number that appeared nowhere in any document.&lt;/p&gt;

&lt;p&gt;I started logging. What I found was two distinct failure modes happening simultaneously:&lt;/p&gt;

&lt;p&gt;Failure Mode 1: Semantic Drift. By the time the query had been reformulated for multi-hop retrieval, the embedding had drifted so far from the original intent that we were retrieving the wrong documents. Not slightly wrong. Documents from a completely different section of the corpus.&lt;/p&gt;

&lt;p&gt;Failure Mode 2: Context Poisoning. Even when we retrieved mostly correct documents, 1–2 tangentially related but contradictory chunks were slipping through. And those poison chunks were enough to derail the model.&lt;/p&gt;

&lt;p&gt;Standard RAG has no defense against either of these. The pipeline is essentially: embed → retrieve → stuff into context → hope.&lt;/p&gt;

&lt;p&gt;I needed something better.&lt;/p&gt;

&lt;p&gt;Six Months Later: VORTEXRAG&lt;br&gt;
I'm releasing the full framework today. 7 layers, each targeting a specific failure mode. Here's what I built and why each layer exists.&lt;/p&gt;

&lt;p&gt;Layer 1: Tri-Vector Encoding (TVE)&lt;br&gt;
The problem: Single-vector embeddings collapse too much information. "The bank charged a fee" and "The river bank was steep" share a close embedding in SBERT space even though they're semantically unrelated in most retrieval contexts.&lt;/p&gt;

&lt;p&gt;The solution: Three encoding arms:&lt;/p&gt;

&lt;h1&gt;
  
  
  Semantic arm: standard SBERT 768d
&lt;/h1&gt;

&lt;p&gt;s = sbert_model.encode(chunk)  # shape: (768,)&lt;/p&gt;

&lt;h1&gt;
  
  
  Syntactic arm: POS + dependency structure
&lt;/h1&gt;

&lt;p&gt;t = syntactic_encoder(chunk)   # shape: (64,)&lt;/p&gt;

&lt;h1&gt;
  
  
  Causal arm: verb-argument chains
&lt;/h1&gt;

&lt;p&gt;c = causal_encoder(chunk)      # shape: (32,)&lt;/p&gt;

&lt;h1&gt;
  
  
  Fused vector
&lt;/h1&gt;

&lt;p&gt;v = concat([α·s, β·t, γ·c])   # shape: (864,)&lt;br&gt;
The causal arm is the key innovation. It captures "X causes Y" relationships that pure semantic similarity misses entirely. This is what allows the pipeline to distinguish between a document that mentions a concept and a document that explains the causal mechanism behind it.&lt;/p&gt;

&lt;p&gt;Layer 2: Vortex Retrieval Cone (VRC)&lt;br&gt;
The problem: Flat cosine similarity treats all high-similarity documents equally. But document #1 and document #47 in your ranked list shouldn't have equal weight — there's a natural falloff in relevance.&lt;/p&gt;

&lt;p&gt;The solution: Spiral ranking inspired by vortex dynamics:&lt;/p&gt;

&lt;p&gt;spiral_rank = TVE · e^(−λr) · cos(nθ)&lt;br&gt;
Where r is the radial distance (rank position) and θ is an angular phase that encodes causal depth. Documents with high causal relevance get a phase advantage that can overcome a slightly lower semantic similarity score.&lt;/p&gt;

&lt;p&gt;In practice: the top-k documents returned by VRC are causally denser than those returned by a flat cosine search on the same index.&lt;/p&gt;

&lt;p&gt;Layer 3: Semantic Drift Corrector (SDC)&lt;br&gt;
The problem: Multi-hop queries reformulate themselves at each hop. Each reformulation can drift slightly from the original intent. Over 3–4 hops, this compounds into a completely different query.&lt;/p&gt;

&lt;p&gt;The solution: Track the embedding trajectory. At each hop:&lt;/p&gt;

&lt;p&gt;drift = query_embedding - anchor_embedding&lt;br&gt;
SDS = 1 - tanh(np.linalg.norm(drift) / τ)&lt;/p&gt;

&lt;p&gt;if SDS &amp;lt; 0.72:&lt;br&gt;
    query_embedding = re_anchor(query_embedding, anchor_embedding)&lt;br&gt;
The SDS score (Semantic Drift Score) measures how far we've drifted. Below 0.72, we re-anchor to the original query intent. This single intervention eliminated most of our multi-hop hallucinations.&lt;/p&gt;

&lt;p&gt;Layer 4: Context Poison Guard (CPG)&lt;br&gt;
The problem: 1–2 contradictory or off-topic chunks in the context window is enough to poison the model's answer. We needed a way to identify and remove these before they reach the LLM.&lt;/p&gt;

&lt;p&gt;The solution: Entity-salience ratio per chunk:&lt;/p&gt;

&lt;p&gt;ESR = sum(SDS_i * w_i for each entity i) / (num_propositions + ε)&lt;/p&gt;

&lt;p&gt;if ESR &amp;lt; 3.5:&lt;br&gt;
    flag_for_purging(chunk)&lt;br&gt;
The purging algorithm is provably greedy-optimal (I include the formal proof in the paper). It maximizes total ESR across the retained context while respecting the token budget.&lt;/p&gt;

&lt;p&gt;In ablation studies, removing CPG alone dropped faithfulness from 0.94 to 0.75 — an 0.19 point drop from a single layer.&lt;/p&gt;

&lt;p&gt;Layer 5: Rank Fusion Gate (RFG)&lt;br&gt;
The problem: Most rank fusion methods are additive. A single terrible signal gets diluted but doesn't eliminate a bad document.&lt;/p&gt;

&lt;p&gt;The solution: Multiplicative fusion:&lt;/p&gt;

&lt;p&gt;Φ = TVE^α × SDS^β × ESR^γ&lt;br&gt;
If any of the three signals is near zero, Φ collapses toward zero. A document that scores 0.9 on semantic similarity but 0.1 on CPG gets Φ ≈ 0.09 — effectively eliminated.&lt;/p&gt;

&lt;p&gt;This was a deliberate design choice. In high-stakes retrieval (medical, legal, financial), you want a veto mechanism, not a popularity contest.&lt;/p&gt;

&lt;p&gt;Layer 6: Causal Context Builder (CCB)&lt;br&gt;
The problem: LLMs have dramatically higher attention to the beginning and end of their context window. Documents buried in the middle get "lost" — the Lost-in-the-Middle problem (Liu et al., 2023).&lt;/p&gt;

&lt;p&gt;The solution: Reorder chunks by causal depth:&lt;/p&gt;

&lt;p&gt;position = rank * causal_depth&lt;/p&gt;

&lt;h1&gt;
  
  
  High causal depth → lower position number → placed at context start
&lt;/h1&gt;

&lt;p&gt;Chunks that are causally central to answering the question get placed at the beginning of the context window, where attention weights are highest. Peripheral context gets pushed to the middle where it does less damage if ignored.&lt;/p&gt;

&lt;p&gt;Layer 7: Faithfulness Verifier (FV)&lt;br&gt;
The problem: Even with all 6 preceding layers, some hallucinations slip through. We need a final gate.&lt;/p&gt;

&lt;p&gt;The solution: Score the candidate answer against the retrieved context:&lt;/p&gt;

&lt;p&gt;ΔR = 1 - (ROUGE_L * NLI_entailment_score)&lt;/p&gt;

&lt;p&gt;if ΔR &amp;gt; 0.15:&lt;br&gt;
    regenerate_answer()&lt;br&gt;
If the answer diverges more than 15% from the source documents (measured by ROUGE-L weighted by NLI entailment), it gets thrown out and regenerated. This catches the subtle hallucinations — cases where the model paraphrases correctly but changes a critical number or name.&lt;/p&gt;

&lt;p&gt;Results&lt;br&gt;
Tested on 4 standard benchmarks (NQ, HotpotQA, MuSiQue, 2WikiMultiHopQA):&lt;/p&gt;

&lt;p&gt;System  EM  F1  Faithfulness&lt;br&gt;
Naive RAG   61.2    68.4    0.71&lt;br&gt;
HyDE    63.8    71.2    0.74&lt;br&gt;
Self-RAG    65.4    73.1    0.79&lt;br&gt;
FLARE   64.9    72.8    0.77&lt;br&gt;
VORTEXRAG   74.8    82.6    0.94&lt;br&gt;
+13.6 EM. +14.2 F1. +0.23 Faithfulness over naive RAG.&lt;/p&gt;

&lt;p&gt;The ablation shows all 7 layers contribute. The two biggest individual contributors are CPG (+0.19 faithfulness) and SDC (+0.08 EM on multi-hop benchmarks specifically).&lt;/p&gt;

&lt;p&gt;Quick Start&lt;/p&gt;

&lt;p&gt;pip install vortexrag&lt;/p&gt;

&lt;p&gt;from vortexrag import VortexRAG, VortexConfig&lt;/p&gt;

&lt;p&gt;config = VortexConfig(&lt;br&gt;
    sdc_threshold=0.72,&lt;br&gt;
    cpg_esr_threshold=3.5,&lt;br&gt;
    fv_delta_r_threshold=0.15,&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;rag = VortexRAG(config)&lt;br&gt;
rag.index(your_documents)&lt;/p&gt;

&lt;p&gt;answer = rag.query("Your complex multi-hop question here")&lt;br&gt;
What's Next&lt;br&gt;
The framework is MIT licensed. The full research paper (with formal proofs) is on Zenodo.&lt;/p&gt;

&lt;p&gt;If you're building RAG systems and hitting hallucination walls — especially on multi-hop or domain-specific queries — this framework is designed for exactly that problem.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/vignesh2027/VORTEXRAG" rel="noopener noreferrer"&gt;https://github.com/vignesh2027/VORTEXRAG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paper: &lt;a href="https://doi.org/10.5281/zenodo.20285144" rel="noopener noreferrer"&gt;https://doi.org/10.5281/zenodo.20285144&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo docs: &lt;a href="https://vignesh2027.github.io/VORTEXRAG" rel="noopener noreferrer"&gt;https://vignesh2027.github.io/VORTEXRAG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Questions? Drop them in the comments — happy to go deep on any of the layers.&lt;/p&gt;

&lt;p&gt;Post these tonight at 9:00 PM IST. Reddit first (r/MachineLearning, then r/LocalLLaMA 30 minutes apart), then Dev.to. Cross-link the Dev.to article in your Reddit comments with "I wrote a deeper walkthrough here" — that drives traffic both ways.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
