<?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: Darsh Ayde</title>
    <description>The latest articles on DEV Community by Darsh Ayde (@pixie2468).</description>
    <link>https://dev.to/pixie2468</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%2F2991081%2Fa8555d2f-813f-49e2-afa0-3d3b177c22c7.png</url>
      <title>DEV Community: Darsh Ayde</title>
      <link>https://dev.to/pixie2468</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pixie2468"/>
    <language>en</language>
    <item>
      <title>DiagramFlow: Turning Whiteboard Sketches into Deterministic Mermaid Diagrams with Gemma 4</title>
      <dc:creator>Darsh Ayde</dc:creator>
      <pubDate>Sun, 18 Oct 2026 13:35:05 +0000</pubDate>
      <link>https://dev.to/pixie2468/diagramflow-turning-whiteboard-sketches-into-deterministic-mermaid-diagrams-with-gemma-4-177a</link>
      <guid>https://dev.to/pixie2468/diagramflow-turning-whiteboard-sketches-into-deterministic-mermaid-diagrams-with-gemma-4-177a</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;Every engineering team has experienced this: you spend an hour in an energetic whiteboard session designing a microservice architecture, a distributed auth flow, or a database schema. At the end of the meeting, someone takes a smartphone photo of the whiteboard with glare, uneven fluorescent lighting, and faint dry-erase markers.&lt;/p&gt;

&lt;p&gt;Then comes the painful part: &lt;strong&gt;the post-meeting tax&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Someone—usually a senior developer or solutions architect—spends 45 to 60 minutes manually transcribing boxes, diamonds, and arrow labels into Draw.io, Lucidchart, or Mermaid syntax so the architecture can be documented in Git and Confluence. Alternatively, the photo gets tossed into a Slack thread and is forgotten forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DiagramFlow&lt;/strong&gt; turns whiteboard photos, hand-drawn paper sketches, and architecture drafts into clean, editable, and deterministic &lt;a href="https://mermaid.js.org/" rel="noopener noreferrer"&gt;Mermaid.js&lt;/a&gt; diagrams in seconds.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A["Whiteboard / Sketch Image"] --&amp;gt; B["In-Memory Preprocessing\n(Auto-contrast &amp;amp; Grayscale)"]
    B --&amp;gt; C["Vision AI (Gemma 4)\nGemini API / OpenRouter"]
    C --&amp;gt; D["Intermediate Graph JSON\n(Strict Pydantic Schema + Confidence)"]
    D --&amp;gt; E["Deterministic Compiler\n(Pure Python Function)"]
    E --&amp;gt; F["Rendered Mermaid Diagram\n(Interactive Canvas · SVG · PNG)"]&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;
  
  
  Who Would Pay For It? (The Side Hustle Thesis)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target Customers&lt;/strong&gt;: Solutions architects, freelance technical consultants, engineering managers, dev agencies, and developer relations teams who produce system architecture documentation weekly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ROI Calculation&lt;/strong&gt;: Senior engineers cost \$80–\$150/hour. If a consultant runs 3–4 architecture design sessions a month, they burn 3+ billable hours just redrawing boxes and arrows. DiagramFlow cuts that to 10 seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing &amp;amp; Monetization Model&lt;/strong&gt;:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Freelancer / Pro Tier (\$12 / month)&lt;/strong&gt;: Unlimited whiteboard-to-Mermaid conversions, high-resolution SVG and 2x crisp PNG exports, and 1-click Markdown copying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agency &amp;amp; Team Tier (\$29 / seat / month)&lt;/strong&gt;: Shared team diagram workspaces, custom company Mermaid styling themes, and direct GitHub/GitLab PR integration for living documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pay-as-you-go API (\$0.05 / diagram)&lt;/strong&gt;: Headless extraction endpoint for Obsidian plugins, Notion integrations, and internal Slack bots.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Saving just 30 minutes of a developer's time pays for the tool for an entire month.&lt;/p&gt;


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

&lt;p&gt;Experience DiagramFlow in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live URL&lt;/strong&gt;: &lt;a href="https://diagramflow-okft.vercel.app/" rel="noopener noreferrer"&gt;https://diagramflow-okft.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Quickstart&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;# 1. Clone &amp;amp; setup backend&lt;/span&gt;
  git clone https://github.com/Pixie2468/diagramflow.git
  &lt;span class="nb"&gt;cd &lt;/span&gt;diagramflow/backend
  pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
  uvicorn src.backend.main:app &lt;span class="nt"&gt;--port&lt;/span&gt; 8000

  &lt;span class="c"&gt;# 2. Launch React 19 Frontend&lt;/span&gt;
  &lt;span class="nb"&gt;cd&lt;/span&gt; ../frontend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What the User Experience Looks Like:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Drop Any Image&lt;/strong&gt;: Drag and drop a phone photo of a whiteboard flowchart, sequence diagram, database ER schema, or UML class diagram (PNG, JPEG, WebP up to 10 MB).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Vision Perception&lt;/strong&gt;: Gemma 4 identifies nodes, shapes, connectors, and directionality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Workspace&lt;/strong&gt;: Pan, zoom, and inspect your diagram rendered live via Mermaid.js 12.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Ambiguity Resolution&lt;/strong&gt;: If an arrow in your sketch was smudged, DiagramFlow flags it with candidate alternative connections that you can toggle locally in 0ms without re-running the AI model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export Ready&lt;/strong&gt;: 1-click copy of standard Mermaid markdown, or direct download as scalable &lt;strong&gt;SVG&lt;/strong&gt; or crisp &lt;strong&gt;2x PNG&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&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/Pixie2468" rel="noopener noreferrer"&gt;
        Pixie2468
      &lt;/a&gt; / &lt;a href="https://github.com/Pixie2468/diagramflow" rel="noopener noreferrer"&gt;
        diagramflow
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;DiagramFlow&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
  &lt;strong&gt;Turn whiteboard photos, hand-drawn sketches, and architecture drafts into clean, editable, and deterministic Mermaid diagrams.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://github.com/Pixie2468/diagramflow/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b93043c303f2ed873714ac97e6bcd8399a391ea7bb4f4b53aaaf37fee3516b1b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c75653f6c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/b93043c303f2ed873714ac97e6bcd8399a391ea7bb4f4b53aaaf37fee3516b1b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c75653f6c6f676f3d707974686f6e" alt="Python 3.11+"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f4a903c298bbf5d4c16fc55bbd43f2ff083f35d617370966299834e8301e6516/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3134332532422d3030393638383f6c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/f4a903c298bbf5d4c16fc55bbd43f2ff083f35d617370966299834e8301e6516/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3134332532422d3030393638383f6c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e60320c5d99fc86fbe369cd429977c14ff9bfe8990faa535ffe5587ceb2c8ee3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52656163742d31392d3631444146423f6c6f676f3d7265616374"&gt;&lt;img src="https://camo.githubusercontent.com/e60320c5d99fc86fbe369cd429977c14ff9bfe8990faa535ffe5587ceb2c8ee3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52656163742d31392d3631444146423f6c6f676f3d7265616374" alt="React 19"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/cfcd8c46fcc7fa45028dd03b57d10ceeff241f6c2e37eeba98666b56f3cbe265/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f566974652d382d3634364346463f6c6f676f3d76697465"&gt;&lt;img src="https://camo.githubusercontent.com/cfcd8c46fcc7fa45028dd03b57d10ceeff241f6c2e37eeba98666b56f3cbe265/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f566974652d382d3634364346463f6c6f676f3d76697465" alt="Vite"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/cd5610e9625ed88cd46057b083dd90d5d5a0859f2e87c8c719e0ea6c7356cfaf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d65726d6169642e6a732d31322d6666333637303f6c6f676f3d6d65726d616964"&gt;&lt;img src="https://camo.githubusercontent.com/cd5610e9625ed88cd46057b083dd90d5d5a0859f2e87c8c719e0ea6c7356cfaf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d65726d6169642e6a732d31322d6666333637303f6c6f676f3d6d65726d616964" alt="Mermaid.js"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/062b2dd3bfdd77945bfa468a713122f3a28bd9c4d9c3fe19f2db9be219ff3f73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6f64656c2d47656d6d61253230342d3432383546343f6c6f676f3d676f6f676c65"&gt;&lt;img src="https://camo.githubusercontent.com/062b2dd3bfdd77945bfa468a713122f3a28bd9c4d9c3fe19f2db9be219ff3f73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6f64656c2d47656d6d61253230342d3432383546343f6c6f676f3d676f6f676c65" alt="Gemma 4"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Whiteboard photos and whiteboard sketches are notoriously tricky for AI vision models: uneven lighting, glare, low contrast, messy handwriting, and ambiguous connectors make directly generating raw diagram syntax error-prone and brittle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DiagramFlow&lt;/strong&gt; solves this with a &lt;strong&gt;three-stage pipeline&lt;/strong&gt;:&lt;/p&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;flowchart LR
    A["📷 Whiteboard / Sketch Image"] --&amp;gt; B["⚙️ In-Memory Preprocessing\n(Auto-contrast &amp;amp; Grayscale)"]
    B --&amp;gt; C["🧠 Vision AI (Gemma 4)\nGemini API / OpenRouter"]
    C --&amp;gt; D["📐 Intermediate Graph JSON\n(Strict Pydantic Schema + Confidence)"]
    D --&amp;gt; E["⚡ Deterministic Compiler\n(Pure Function)"]
    E --&amp;gt; F["📊 Rendered Mermaid Diagram\n(Interactive Canvas · SVG · PNG)"]
&lt;/pre&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;/div&gt;
&lt;br&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;&lt;br&gt;
    &lt;span&gt;&lt;br&gt;
  &lt;br&gt;
    &lt;span class="sr-only"&gt;Loading&lt;/span&gt;&lt;br&gt;
&lt;/span&gt;&lt;br&gt;
  &lt;/span&gt;&lt;br&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-processing&lt;/strong&gt;: Normalizes contrast and converts to grayscale in-memory via Pillow to make faint marker strokes pop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediate Graph Extraction&lt;/strong&gt;: Instructs vision models (Gemma 4 via Gemini or OpenRouter) to extract structured nodes, shapes, connectors, confidence scores, and alternative candidates rather than…&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/Pixie2468/diagramflow" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;
  
  
  Key Architectural Highlights:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pixie2468/diagramflow/blob/main/backend/src/backend/compiler.py" rel="noopener noreferrer"&gt;&lt;code&gt;backend/src/backend/compiler.py&lt;/code&gt;&lt;/a&gt;: Pure Python deterministic compiler converting graph data structures into valid Mermaid syntax.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pixie2468/diagramflow/blob/main/backend/src/backend/models.py" rel="noopener noreferrer"&gt;&lt;code&gt;backend/src/backend/models.py&lt;/code&gt;&lt;/a&gt;: Pydantic v2 discriminated union schemas guaranteeing structural validation, shape classifications, and edge confidence.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pixie2468/diagramflow/blob/main/backend/src/backend/providers.py" rel="noopener noreferrer"&gt;&lt;code&gt;backend/src/backend/providers.py&lt;/code&gt;&lt;/a&gt;: Multi-backend driver layer integrating Google's open-weights Gemma 4 (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; and &lt;code&gt;gemma-4-31b-it&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pixie2468/diagramflow/blob/main/backend/src/backend/image_processing.py" rel="noopener noreferrer"&gt;&lt;code&gt;backend/src/backend/image_processing.py&lt;/code&gt;&lt;/a&gt;: In-memory Pillow contrast normalization for faint whiteboard marker strokes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pixie2468/diagramflow/blob/main/frontend/src/App.tsx" rel="noopener noreferrer"&gt;&lt;code&gt;frontend/src/App.tsx&lt;/code&gt;&lt;/a&gt;: Modern React 19, Tailwind CSS v4, and Mermaid.js interactive canvas with SVG/PNG rasterization.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Open-Source AI Engine: Gemma 4
&lt;/h3&gt;

&lt;p&gt;DiagramFlow is powered by &lt;strong&gt;Google's Gemma 4&lt;/strong&gt; open-weights multimodal models (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; and &lt;code&gt;gemma-4-31b-it&lt;/code&gt;). &lt;/p&gt;
&lt;h3&gt;
  
  
  The Core Architectural Problem: Why Direct LLM Output Fails
&lt;/h3&gt;

&lt;p&gt;When developers try building diagram tools, the naive approach is: &lt;em&gt;Take image -&amp;gt; prompt model: "Give me Mermaid markdown" -&amp;gt; render in browser.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This fails in production.&lt;/strong&gt; Whiteboards have crossed lines, smudged text, and ambiguous arrowheads. When an LLM outputs raw Mermaid syntax directly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It combines perception, syntax formatting, and error-repair into a single brittle string output.&lt;/li&gt;
&lt;li&gt;It hallucinates syntax tokens (like mixing brackets &lt;code&gt;[{"label"}]&lt;/code&gt; or missing &lt;code&gt;end&lt;/code&gt; tags on subgraphs), completely crashing Mermaid's parser.&lt;/li&gt;
&lt;li&gt;Any minor mistake requires re-running the entire multimodal model, introducing latency and billing costs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Three-Stage Decoupled Pipeline
&lt;/h3&gt;

&lt;p&gt;To solve this, DiagramFlow decouples vision perception from syntax compilation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stage 1: In-Memory Preprocessing (Pillow)&lt;/strong&gt;
Whiteboard photos suffer from low contrast, phone camera glare, and washed-out dry-erase markers. Before inference, the image is contrast-stretched and normalized to grayscale purely in-memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage 2: Structured Graph Extraction (Gemma 4 + Pydantic Contract)&lt;/strong&gt;
Gemma 4 is instructed to output a strict, typed JSON intermediate schema (&lt;code&gt;DiagramGraph&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"diagram_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"flowchart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Auth Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"shape_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rectangle"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User DB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"shape_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cylinder"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"edges"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"alternatives"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If an edge is ambiguous, Gemma 4 assigns &lt;code&gt;confidence: "low"&lt;/code&gt; and populates &lt;code&gt;alternatives&lt;/code&gt;. Pydantic validates the response before any syntax is created.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stage 3: Deterministic Pure Compiler&lt;/strong&gt;
A pure-Python compiler translates the validated graph into Mermaid markdown. The compiler handles HTML escaping, node shapes (rectangles, diamonds, cylinders, hexagons), subgraphs, and connection styles. Because the compiler is a pure function, client-side edits recompile in sub-milliseconds without calling the AI model again.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Multi-Diagram Support Out of the Box
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flowcharts &amp;amp; Architecture (&lt;code&gt;flowchart TD | LR&lt;/code&gt;)&lt;/strong&gt;: VPCs, subgraphs, edge labels, and 6 node shapes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequence Diagrams (&lt;code&gt;sequenceDiagram&lt;/code&gt;)&lt;/strong&gt;: Lifelines, synchronous calls, asynchronous replies, and autonumbering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity-Relationship Diagrams (&lt;code&gt;erDiagram&lt;/code&gt;)&lt;/strong&gt;: Database tables, typed fields, Primary/Foreign keys (&lt;code&gt;PK&lt;/code&gt;, &lt;code&gt;FK&lt;/code&gt;), and cardinalities (&lt;code&gt;1:1&lt;/code&gt;, &lt;code&gt;1:N&lt;/code&gt;, &lt;code&gt;M:N&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UML Class Diagrams (&lt;code&gt;classDiagram&lt;/code&gt;)&lt;/strong&gt;: Classes, methods, attributes, and relationships (inheritance &lt;code&gt;&amp;lt;|--&lt;/code&gt;, composition &lt;code&gt;*--&lt;/code&gt;, aggregation &lt;code&gt;o--&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Open innovation and open-weight models like Gemma 4 are not just an alternative to closed APIs—they are the &lt;strong&gt;fundamental requirement&lt;/strong&gt; that makes DiagramFlow viable as a privacy-respecting, profitable business:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Architecture Confidentiality &amp;amp; Data Sovereignty&lt;/strong&gt;:
Whiteboards contain sensitive intellectual property: proprietary authentication logic, internal microservice topographies, and database schemas. Enterprises and engineering consultancies often have strict compliance policies prohibiting internal architecture diagrams from being sent to closed, third-party proprietary APIs that may retain data for model training. Because Gemma 4 is open-weights, DiagramFlow can run inside private customer VPCs, air-gapped on-premise servers, or locally via Ollama/vLLM without a single byte of confidential architectural design leaving the company firewall.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable Unit Economics for a Micro-SaaS&lt;/strong&gt;:
Proprietary vision APIs with fluctuating token pricing create unpredictable cost structures. A single complex high-resolution image can cost \$0.02–\$0.05 on closed multimodal endpoints, eliminating profit margins on an unlimited \$12/mo subscription. With open weights, inference can be hosted on fixed-cost GPU infrastructure (or run directly on developer machines), making unit economics predictable and scalable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freedom from API Deprecation and Lock-in&lt;/strong&gt;:
Building on open weights means no sudden vendor deprecations, unexpected pricing hikes, or forced API schema changes. Furthermore, open weights give us the future ability to fine-tune Gemma on domain-specific sketching datasets (like AWS/GCP cloud icon doodles or specialized electrical diagrams)—something closed APIs cannot offer.&lt;/li&gt;
&lt;/ol&gt;


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

&lt;p&gt;Developing DiagramFlow involved pairing with AI to design the intermediate graph contract, refine Pydantic validation rules, and build out deterministic compiler tests across four diagram specifications.&lt;/p&gt;

&lt;p&gt;You can inspect the full curated agent session transcript on DEV:&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Gemini CLI"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building DiagramFlow: Gemma 4 Vision Pipeline &amp;amp; Deterministic Mermaid Compiler&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;We need to turn messy whiteboard diagrams into clean Mermaid syntax using open-weight Gemma 4 vision models. Asking the model to output raw Mermaid directly produces syntax hallucinations and broken syntax on complex connections. How should we structure the architecture?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Let's decouple perception from syntax generation using a three-stage pipeline:\n1. In-memory image preprocessing (auto-contrast &amp;amp; grayscale via Pillow) to sharpen faint whiteboard strokes.\n2. Open-weight vision extraction (Gemma 4) targeting a strict Pydantic JSON contract (&lt;code&gt;DiagramGraph&lt;/code&gt;) with nodes, shapes, connectors, confidence scores, and alternative candidates.\n3. A deterministic pure-Python compiler (&lt;code&gt;compiler.py&lt;/code&gt;) that translates the validated graph into guaranteed error-free Mermaid syntax in milliseconds. This also allows the frontend to resolve ambiguous connections locally without re-running inference.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Let's implement the deterministic compiler and Pydantic schema supporting Flowcharts, Sequence Diagrams, ER Diagrams, and UML Class Diagrams.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Implemented the pure-Python deterministic compiler in &lt;code&gt;backend/src/backend/compiler.py&lt;/code&gt; and models in &lt;code&gt;backend/src/backend/models.py&lt;/code&gt;. Validated with comprehensive unit tests for all diagram types, escaping HTML/special characters, and ensuring privacy-first in-memory processing.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        4 of 4 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Direct Session Link: &lt;a href="https://dev.to/agent_sessions/building-diagramflow-gemma-4-vision-pipeline-deterministic-mermaid-compiler-jegxt4"&gt;View Agent Session on DEV&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;To test whether real developers would actually find this valuable, I shared DiagramFlow with &lt;strong&gt;Aryan&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Alex had just wrapped up a 45-minute discovery call where he sketched an event-driven payment reconciliation pipeline on an office whiteboard. Normally, he spends his Friday afternoons manually redrawing these diagrams in Draw.io before submitting formal client architecture proposals.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Test
&lt;/h3&gt;

&lt;p&gt;We fed his phone snapshot into DiagramFlow. Within 4 seconds, DiagramFlow recognized the 7 microservice nodes, classified the message queues as cylinder shapes, mapped the payment gateway as an external subgraph, and produced a pristine Mermaid flowchart.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Alex Said:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I usually block out 45 minutes after every client workshop just to redraw whiteboard sketches so they look professional in proposal decks. DiagramFlow gave me clean Mermaid code that I dropped directly into my markdown deliverables and rendered as high-res SVGs in under a minute. If you charge \$15 a month for this, I'm buying it today—it pays for itself in the first hour of every sprint."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;h3&gt;
  
  
  Featured Category: Best Use of Gemma
&lt;/h3&gt;

&lt;p&gt;DiagramFlow is built from the ground up around &lt;strong&gt;Google's Gemma 4&lt;/strong&gt; open-weight multimodal vision models (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; and &lt;code&gt;gemma-4-31b-it&lt;/code&gt;). We leverage Gemma 4's spatial perception and structural reasoning to extract complex topological graphs from real-world, hand-drawn sketches, turning messy ink into deterministic, compile-ready code.&lt;/p&gt;







&lt;h3&gt;
  
  
  Community Wisdom
&lt;/h3&gt;

&lt;p&gt;As highlighted by &lt;a href="https://dev.to/eme_gug_0821b41b948be6516/diagrams-as-code-keep-your-architecture-docs-alive-inside-the-repo-40co"&gt;Eme Gug in &lt;em&gt;Diagrams as Code&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://dev.to/agasta/i-got-tired-of-ai-diagram-slop-so-i-built-an-open-source-ai-diagram-generator-on-excalidraw-32c4"&gt;Agasta in &lt;em&gt;I got tired of AI diagram slop&lt;/em&gt;&lt;/a&gt;, raw image diagrams in repositories quickly rot, while prompting LLMs directly for syntax yields broken diagrams. By bridging physical whiteboard sketches with text-based Mermaid code through an intermediate validated graph, DiagramFlow solves both problems simultaneously.&lt;/p&gt;
&lt;/div&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Building KNN from Scratch (Because import sklearn Feels Like Cheating)</title>
      <dc:creator>Darsh Ayde</dc:creator>
      <pubDate>Sun, 14 Jun 2026 07:02:50 +0000</pubDate>
      <link>https://dev.to/pixie2468/building-knn-from-scratch-because-import-sklearn-feels-like-cheating-3h0p</link>
      <guid>https://dev.to/pixie2468/building-knn-from-scratch-because-import-sklearn-feels-like-cheating-3h0p</guid>
      <description>&lt;h2&gt;
  
  
  Building K-Nearest Neighbors (KNN) From Scratch
&lt;/h2&gt;

&lt;p&gt;Let's be real: in a production machine learning environment, we all just import &lt;code&gt;scikit-learn&lt;/code&gt; and call it a day. But treating algorithms like black boxes can come back to bite you when those abstractions leak. Building K-Nearest Neighbors (KNN) from scratch is a fantastic exercise to actually understand the mechanics working under the hood.&lt;/p&gt;

&lt;p&gt;At its core, KNN relies on a surprisingly simple geometric premise: a data point probably belongs to the same category as its closest spatial neighbors. Rebuilding this classifier from the ground up forces you to tackle some critical engineering challenges, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Computing spatial geometry efficiently&lt;/li&gt;
&lt;li&gt;Managing state during the voting process&lt;/li&gt;
&lt;li&gt;Handling edge cases and algorithmic ties deterministically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we'll walk through the architectural decisions behind a pure Python implementation of KNN, translating textbook math into functional code.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Distance Metric
&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;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Ensure both vectors have the same length.&lt;/span&gt;&lt;span class="sh"&gt;"""&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;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Vectors must be of same length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;euclidean_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Compute Euclidean distance between two vectors.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;_check_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;sum_of_sq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;math&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;sum_of_sq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  The Goal
&lt;/h4&gt;

&lt;p&gt;Calculate spatial similarity between vectors using Euclidean distance.&lt;/p&gt;
&lt;h4&gt;
  
  
  How It Works
&lt;/h4&gt;

&lt;p&gt;KNN is fundamentally a geometry problem. The entire algorithm hinges on quantifying exactly how far apart points are in a given space.&lt;/p&gt;

&lt;p&gt;If we're looking at a 2D plane, Euclidean distance comes straight from the Pythagorean theorem:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord sqrt"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span class="svg-align"&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="hide-tail"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;In machine learning, however, we're rarely dealing with just two dimensions. Fortunately, the formula generalizes neatly to an arbitrary number of dimensions:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathbf"&gt;x&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;y&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord sqrt"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span class="svg-align"&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mop op-limits"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;span class="mrel mtight"&gt;=&lt;/span&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="mop op-symbol large-op"&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="hide-tail"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the total number of dimensions.&lt;/li&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 are the coordinates of vectors 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 along dimension 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;euclidean_distance()&lt;/code&gt; function above, notice the generator expression inside &lt;code&gt;sum()&lt;/code&gt;. It evaluates lazily, meaning we avoid constructing an intermediate list of squared differences in memory. This is a deliberate design choice that scales well when working with high-dimensional data.&lt;/p&gt;

&lt;p&gt;Also, don't overlook the &lt;code&gt;_check_length()&lt;/code&gt; guard—it is structurally critical. Comparing vectors of different dimensions is mathematically invalid. Since Python's &lt;code&gt;zip()&lt;/code&gt; function silently truncates to the shortest iterable, omitting this check could allow the function to fail silently and return incorrect results.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Voting Mechanism and Tie-Breakers
&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;_get_majority_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ... early-exit validation skipped ...
&lt;/span&gt;
    &lt;span class="n"&gt;vote_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;min_distance_per_label&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;neighbor&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;vote_count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vote_count&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;label&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;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="n"&gt;min_distance_per_label&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;min_distance_per_label&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;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inf&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;span class="n"&gt;best_label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;best_vote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;best_distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&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;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vote_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;votes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vote_count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min_distance_per_label&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&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;votes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;best_vote&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;votes&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;best_vote&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;best_distance&lt;/span&gt;
        &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;best_label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;
            &lt;span class="n"&gt;best_vote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;votes&lt;/span&gt;
            &lt;span class="n"&gt;best_distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best_label&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  The Goal
&lt;/h4&gt;

&lt;p&gt;Tally the neighbors' labels to determine the final classification while using spatial proximity as a deterministic tie-breaker.&lt;/p&gt;
&lt;h4&gt;
  
  
  How It Works
&lt;/h4&gt;

&lt;p&gt;Counting votes is straightforward with a hash map, but robust edge-case management is what separates a demo implementation from production-ready code.&lt;/p&gt;

&lt;p&gt;Imagine a scenario where 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;k&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and your query point sits exactly halfway between two &lt;strong&gt;Class A&lt;/strong&gt; neighbors and two &lt;strong&gt;Class B&lt;/strong&gt; neighbors. A naive implementation might simply choose whichever label appears first. That makes the classifier non-deterministic and biased by data ordering.&lt;/p&gt;

&lt;p&gt;To address this, the implementation maintains a secondary dictionary:&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="n"&gt;min_distance_per_label&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As the algorithm iterates through the neighbors, it tracks the minimum distance observed for each class label. If a voting tie occurs,&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;votes&lt;/span&gt;&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;votes&lt;/span&gt;&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;the algorithm chooses the class whose nearest representative is closest to the query point.&lt;/p&gt;

&lt;p&gt;Mathematically:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mop"&gt;ar&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mop op-limits"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="mop"&gt;min&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;&lt;span class="delimsizing size2"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="mop op-limits"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;x&lt;/span&gt;&lt;span class="mrel mtight"&gt;∈&lt;/span&gt;&lt;span class="mord mathnormal mtight"&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="mop"&gt;min&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;q&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;&lt;span class="delimsizing size2"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is a class label.&lt;/li&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the query point.&lt;/li&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;q&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the distance between a training sample and the query point.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach anchors tie-breaking in actual spatial proximity rather than arbitrary ordering or randomness.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Orchestrator
&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;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;knn_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_point&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="c1"&gt;# ... input validation skipped ...
&lt;/span&gt;
    &lt;span class="n"&gt;distances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;euclidean_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_point&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;sample&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;training_data&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;nearest_idx&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;argsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distances&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;neighbors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;distances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nearest_idx&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_get_majority_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  The Goal
&lt;/h4&gt;

&lt;p&gt;Create a controller function that computes distances, isolates the top 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 candidates, and delegates classification to the voting logic.&lt;/p&gt;
&lt;h4&gt;
  
  
  How It Works
&lt;/h4&gt;

&lt;p&gt;Although a production implementation would include comprehensive validation and optimization, the core algorithm relies on one key operation:&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distances&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Keeping multiple arrays synchronized during sorting can quickly become messy. Rather than zipping distances and labels together, sorting them, and then unpacking them again, we sort only the distance values and retrieve the corresponding indices.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;numpy.argsort()&lt;/code&gt; returns the indices that would sort an array. This allows us to select the nearest neighbors without mutating the original data structures.&lt;/p&gt;

&lt;p&gt;Mathematically, we're selecting:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mop"&gt;&lt;span class="mord mathrm"&gt;argsort&lt;/span&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;D&lt;/span&gt;&lt;span class="mclose"&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;where 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the vector of computed distances.&lt;/p&gt;

&lt;p&gt;This is a common scientific-computing pattern because it preserves the relationship between distances and labels while avoiding unnecessary data transformations.&lt;/p&gt;

&lt;p&gt;After selecting the nearest indices, we package the neighbors into lightweight dictionaries and pass them directly to the voting mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;K-Nearest Neighbors is a unique machine learning algorithm because it behaves less like a traditional parameter-learning model and more like a combination of geometric reasoning and voting heuristics.&lt;/p&gt;

&lt;p&gt;Unlike algorithms such as linear regression or neural networks, KNN performs no explicit training. It simply stores the dataset and uses distance as a proxy for similarity during prediction.&lt;/p&gt;

&lt;p&gt;Building algorithms from scratch is one of the fastest ways to demystify machine learning. You quickly discover that much of the perceived complexity comes from standard software engineering concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance optimization&lt;/li&gt;
&lt;li&gt;State management&lt;/li&gt;
&lt;li&gt;Data validation&lt;/li&gt;
&lt;li&gt;Numerical stability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mathematics matters, but so does thoughtful implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;To explore more machine learning projects and software engineering content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Pixie2468" rel="noopener noreferrer"&gt;https://github.com/Pixie2468&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/darsh-ayde/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/darsh-ayde/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>datascience</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Stop Trusting Every JWT: How I Handle OIDC Claims in My Go Gateway</title>
      <dc:creator>Darsh Ayde</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:06:22 +0000</pubDate>
      <link>https://dev.to/pixie2468/stop-trusting-every-jwt-how-i-handle-oidc-claims-in-my-go-gateway-1kf1</link>
      <guid>https://dev.to/pixie2468/stop-trusting-every-jwt-how-i-handle-oidc-claims-in-my-go-gateway-1kf1</guid>
      <description>&lt;h2&gt;
  
  
  Building a Secure OIDC Verification Layer in Go
&lt;/h2&gt;

&lt;p&gt;Authentication is one of those things every backend engineer eventually has to build—and secretly dreads getting wrong. When I started architecting the auth layer for my Go API gateway, I naturally reached for OpenID Connect (OIDC). It’s the industry standard, so how hard could it be?&lt;/p&gt;

&lt;p&gt;As it turns out, parsing a JWT is trivial. &lt;em&gt;Trusting&lt;/em&gt; a JWT is where the trapdoors hide. If you blindly decode a token and trust the payload, you are exactly one spoofed signature away from a major security incident. I needed a way to dynamically discover my identity provider’s keys, cryptographically verify incoming requests, and strictly enforce the claims my backend actually cares about (like ensuring a user &lt;em&gt;actually&lt;/em&gt; owns the email address they claim to).&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through how I built the OIDC verification layer for my gateway. We won't just look at the happy path; we’ll look at why I used interfaces to keep the auth logic mockable, how to avoid network traps during startup, and why an unassuming &lt;code&gt;email_verified&lt;/code&gt; pointer is your gateway’s best friend.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-Level Flow
&lt;/h3&gt;

&lt;p&gt;Before we dive into the Go code, here is the basic verification flow this architecture follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  | ID Token (JWT)
  v
API Gateway
  |
  | 1. Discover OIDC provider metadata
  | 2. Verify JWT signature (via JWKS)
  | 3. Validate issuer and audience
  | 4. Extract strongly-typed claims
  | 5. Enforce application-specific rules (e.g., email verification)
  v
Authenticated User

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note: The complete source code for this example is available on my GitHub: &lt;a href="https://github.com/Pixie2468/dearai-backend" rel="noopener noreferrer"&gt;dearai-backend&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Breaking Down the Implementation
&lt;/h3&gt;

&lt;p&gt;Let's look at how this breaks down in Go, starting from the core domain types and moving into runtime validation.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Designing for Testability
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"errors"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/coreos/go-oidc/v3/oidc"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;TokenVerifier&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenString&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ExternalClaims&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;Notice that the package exports a &lt;code&gt;TokenVerifier&lt;/code&gt; interface rather than forcing consumers to use a concrete struct. This is classic dependency inversion.&lt;/p&gt;

&lt;p&gt;When you're writing unit tests for your HTTP handlers or middleware, you really don't want them making live network calls to Google, Okta, or Auth0. By depending on this interface, you can easily inject a mock verifier that simply returns dummy claims for testing, keeping your test suite fast, offline, and deterministic.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Defining Expected Claims
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ExternalClaims&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Subject&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"sub"`&lt;/span&gt;
    &lt;span class="n"&gt;Email&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"email"`&lt;/span&gt;
    &lt;span class="n"&gt;EmailVerified&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;  &lt;span class="s"&gt;`json:"email_verified"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;OIDCVerifier&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;verifier&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;oidc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDTokenVerifier&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We map the JWT payload into an &lt;code&gt;ExternalClaims&lt;/code&gt; struct. The &lt;code&gt;sub&lt;/code&gt; (subject) claim should always be treated as your primary user identifier. It is immutable and stable, making it the perfect key to link to your internal user records. While it's tempting to use the user's &lt;code&gt;email&lt;/code&gt; as a unique identifier, emails change, which can break data relationships later.&lt;/p&gt;

&lt;p&gt;You'll also notice &lt;code&gt;EmailVerified&lt;/code&gt; is defined as a &lt;code&gt;*bool&lt;/code&gt; (a pointer to a boolean) rather than a primitive &lt;code&gt;bool&lt;/code&gt;. This is a deliberate choice. It allows us to differentiate between a claim that is explicitly set to &lt;code&gt;false&lt;/code&gt; and a claim that is completely missing from the token payload (which evaluates to &lt;code&gt;nil&lt;/code&gt;). Both scenarios should result in a rejected token, and a pointer allows us to catch both cleanly.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Discovery and the Network Trap
&lt;/h4&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;NewOIDCVerifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TokenVerifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;issuer&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;clientID&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"issuer and clientID are required"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;provider&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;oidc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProvider&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;issuer&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to discover OIDC configuration: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;OIDCVerifier&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;verifier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Verifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;oidc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ClientID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clientID&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Before any network activity occurs, the constructor validates its inputs to fail fast. Then, we call &lt;code&gt;oidc.NewProvider&lt;/code&gt;. This is where OIDC discovery happens. The library hits the issuer's &lt;code&gt;.well-known/openid-configuration&lt;/code&gt; endpoint to fetch metadata, including the JWKS (JSON Web Key Set) URL which contains the public keys needed to verify token signatures.&lt;/p&gt;

&lt;p&gt;This is the only place in the setup phase where network I/O occurs. Because of this, it is critical to pass a &lt;code&gt;context.Context&lt;/code&gt; with a reasonable timeout into this function. If the identity provider goes down during a deployment and you don't have a timeout, your application startup will block indefinitely.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. The Verification Pipeline
&lt;/h4&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OIDCVerifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenString&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ExternalClaims&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;idToken&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;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Verify&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;tokenString&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cryptographic token verification failed: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt; &lt;span class="n"&gt;ExternalClaims&lt;/span&gt;
    &lt;span class="k"&gt;if&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;idToken&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Claims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;claims&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="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to unmarshal token claims: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid token: missing 'sub' claim"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid token: missing 'email' claim"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailVerified&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!*&lt;/span&gt;&lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailVerified&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid token: email address is unverified"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Verify&lt;/code&gt; method acts as our gatekeeper, enforcing rules in a very specific order.&lt;/p&gt;

&lt;p&gt;First, we establish &lt;strong&gt;cryptographic trust&lt;/strong&gt; by passing the raw token to &lt;code&gt;v.verifier.Verify()&lt;/code&gt;. This leverages the provider's public keys to ensure the signature is mathematically valid, checks that the token hasn't expired, and verifies that the &lt;code&gt;ClientID&lt;/code&gt; (Audience) matches your app. This last part is crucial—it prevents your gateway from accepting valid tokens that were actually minted for an entirely different application.&lt;/p&gt;

&lt;p&gt;Once we trust the signature, we unmarshal the payload into our &lt;code&gt;ExternalClaims&lt;/code&gt; struct to get strongly-typed Go values. Finally, we enforce our &lt;strong&gt;business logic trust&lt;/strong&gt;. We ensure the &lt;code&gt;sub&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt; aren't blank, and we evaluate that &lt;code&gt;*bool&lt;/code&gt; to guarantee the identity provider has verified the user's email. If a token fails any of these steps, execution halts immediately and the request is dropped.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Quick Note on Token Types
&lt;/h3&gt;

&lt;p&gt;It’s worth mentioning that this specific implementation is designed to verify OIDC &lt;strong&gt;ID tokens&lt;/strong&gt;, which are meant to communicate identity information (who the user is). &lt;strong&gt;Access tokens&lt;/strong&gt;, on the other hand, are meant for API authorization (what the user can do) and often follow different validation rules depending on the provider. Make sure you are verifying the right token for your specific architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Verifying an OIDC token requires a lot more rigor than just base64-decoding a JSON payload. By leveraging OIDC discovery and the &lt;code&gt;go-oidc&lt;/code&gt; library, we get automatic key rotation handling and cryptographic certainty. Combine that with strictly typed claims and interface-driven design, and you end up with an auth layer that is secure, resilient, and highly testable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;If you'd like to see how this fits into the broader API gateway, or if you want to follow along with my future backend engineering articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Pixie2468" rel="noopener noreferrer"&gt;github.com/Pixie2468&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/darsh-ayde/" rel="noopener noreferrer"&gt;linkedin.com/in/darsh-ayde/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>security</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
