<?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: Nilamadhab Senapati</title>
    <description>The latest articles on DEV Community by Nilamadhab Senapati (@madhabcoder).</description>
    <link>https://dev.to/madhabcoder</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%2F4141691%2F533211a9-c040-4b9e-97b1-e840e303cebf.jpg</url>
      <title>DEV Community: Nilamadhab Senapati</title>
      <link>https://dev.to/madhabcoder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/madhabcoder"/>
    <language>en</language>
    <item>
      <title>I Resurrected a Dead F1 Project and Accidentally Built a Race Intelligence OS</title>
      <dc:creator>Nilamadhab Senapati</dc:creator>
      <pubDate>Sun, 11 Oct 2026 13:22:56 +0000</pubDate>
      <link>https://dev.to/madhabcoder/i-resurrected-a-dead-f1-project-and-accidentally-built-a-race-intelligence-os-580m</link>
      <guid>https://dev.to/madhabcoder/i-resurrected-a-dead-f1-project-and-accidentally-built-a-race-intelligence-os-580m</guid>
      <description>&lt;p&gt;&lt;em&gt;I first wrote this for the &lt;a href="https://dev.to/challenges/github-2026-05-21"&gt;GitHub Finish-Up-A-Thon Challenge&lt;/a&gt; on my old account. I'm reposting it here, where I now build in public.&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;I built &lt;strong&gt;F1 Intelligence Studio&lt;/strong&gt; — a full-stack Formula 1 race intelligence dashboard that turns raw telemetry data into a living, breathing visualization of any race from 2024 to 2026.&lt;/p&gt;

&lt;p&gt;Think of it as a race engineer's war room. Twenty animated cars chase each other around circuits drawn from real GPS telemetry. An AI race engineer (Claude) analyzes strategy in real-time. A spring-physics camera zooms into wheel-to-wheel battles like an actual broadcast. ElevenLabs voices the commentary. A strategy simulator answers F1's eternal question: &lt;em&gt;pit or stay out?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can scrub through any moment of any race with frame-perfect precision. You can compare two drivers' telemetry traces side-by-side, watch tyre stints unfold, monitor team radio, and get AI-powered insights on developing battles.&lt;/p&gt;

&lt;p&gt;It started as a single API call dumping data into a table. It ended as a 12-panel drag-and-drop dashboard with twelve interactive components. Somewhere in between, I lost track of where the line was — and that's the whole point of this story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this project means to me:&lt;/strong&gt; It's the first side project I've actually shipped in years. My GitHub is a graveyard of half-built ideas. This one made it out alive.&lt;/p&gt;




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

&lt;p&gt;🏎️ &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://raceosf1.one/" rel="noopener noreferrer"&gt;https://raceosf1.one/&lt;/a&gt;&lt;br&gt;
📦 &lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/nilamadhab47/raceosf1" rel="noopener noreferrer"&gt;https://github.com/nilamadhab47/raceosf1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick screenshots:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🟢 &lt;em&gt;The animated track map with 20 cars on a real telemetry-derived circuit&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgm965xoe2ift2lau6q4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgm965xoe2ift2lau6q4.png" alt="animated track" width="800" height="520"&gt;&lt;/a&gt;&lt;br&gt;
🟢 &lt;em&gt;Telemetry comparison — two drivers, speed/throttle/brake overlaid on the same distance axis&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0gxvf68ra6nfbsykbvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0gxvf68ra6nfbsykbvd.png" alt="Telemetry comparison" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🟢 &lt;em&gt;The AI insights panel — Claude analyzing strategy in real-time and Strategy simulator showing pit vs stay-out delta&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsvsbu1vi43wag81fa5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsvsbu1vi43wag81fa5x.png" alt="The AI insights panel" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Next.js 14, TypeScript, Zustand, GSAP, Recharts, react-grid-layout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; FastAPI (Python 3.12), FastF1, WebSocket broadcasting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; Anthropic Claude (race insights + chat), ElevenLabs (voice commentary)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; Vercel (free tier) + Railway ($5/month)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total infrastructure cost: less than my monthly coffee budget. The spring-damper camera system took more math than my engineering degree.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Comeback Story
&lt;/h2&gt;

&lt;p&gt;Here's the honest version.&lt;/p&gt;

&lt;p&gt;My GitHub looks like a graveyard. Landing pages with no backend. ChatGPT chats about apps that never left the chat. Ideas rotting in a documents folder. I'm a full-stack engineer who builds production systems for a living — but my own projects? Couldn't finish a README.&lt;/p&gt;

&lt;p&gt;The F1 project was no exception. I started it months ago when Instagram served me a dev reel about FastF1, that incredible Python package for Formula 1 telemetry data. My brain did its usual thing: &lt;em&gt;"Oh that's cool, I should build something."&lt;/em&gt; I made a repo. Wrote a few API endpoints. Got driver data into a table.&lt;/p&gt;

&lt;p&gt;Then? Procrastination. The classic excuses kicked in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Who's going to use this?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"There's no monetization."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"You're a backend engineer pretending to do frontend."&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repo sat there for weeks. Untouched. Just another tombstone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I made myself one rule. Sit down after work. Fifteen minutes minimum. No "let me plan the architecture first" (the ultimate procrastination disguise). No "I'll start fresh on Monday." Just open the laptop and ship one small thing.&lt;/p&gt;

&lt;p&gt;The beginning was ugly. Just ugly. But I kept showing up.&lt;/p&gt;

&lt;p&gt;Then the escalation started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 1:&lt;/strong&gt; Tables turned into graphs. Slightly less boring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 2:&lt;/strong&gt; Graphs turned into driver comparisons. Wait, this is actually interesting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 3:&lt;/strong&gt; Comparisons turned into full race simulations. Now I need actual circuit maps?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 4:&lt;/strong&gt; Drawing SVG tracks from raw GPS telemetry. I googled "what is a viewBox" at 11pm. No shame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 5:&lt;/strong&gt; Twenty animated cars chasing each other at 60fps. Bypassed React's render cycle entirely because &lt;code&gt;setState&lt;/code&gt; 60 times a second is a war crime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 6:&lt;/strong&gt; Added an AI race engineer. Then voice commentary. Then a spring-physics camera that zooms into battles like an actual TV broadcast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I looked up from my keyboard and realized what started as "let me show F1 data in a table" had turned into a complete Race Intelligence Operating System. My scope creep could lap Verstappen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The finish-up grind:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When this challenge dropped, the project was &lt;em&gt;mostly&lt;/em&gt; working but full of rough edges — the kind of rough edges that keep you from actually showing it to anyone. The "I'll polish it later" backlog. Sound familiar?&lt;/p&gt;

&lt;p&gt;Here's what I cleaned up for the final push:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation.&lt;/strong&gt; The README was a single sentence. Now it's a proper onboarding doc with setup, architecture diagrams, and contribution guidelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error boundaries on every panel.&lt;/strong&gt; Before, one panel crashing could take down the whole dashboard. Now each panel fails gracefully on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loading skeletons.&lt;/strong&gt; Previously the dashboard flashed empty boxes during data fetch. Now everything has proper loading states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The YouTube content-ID disaster.&lt;/strong&gt; F1 videos kept showing "Video unavailable" in production because FOM blocks third-party embeds. Built a three-tier fallback: Dailymotion → non-blocked YouTube → thumbnail cards with external links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment.&lt;/strong&gt; Three Dockerfile failures on Railway. Path resolution, build context, and the infamous &lt;code&gt;$PORT&lt;/code&gt; variable not expanding because Railway's startCommand doesn't run through a shell. Finally got everything green.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polish pass.&lt;/strong&gt; Onboarding tour, keyboard shortcuts, mobile-responsive grid presets, dark mode that doesn't look like an afterthought.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The before-and-after gap is the difference between "a thing on my laptop" and "a thing I can show people without apologizing."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The biggest lesson&lt;/strong&gt; wasn't technical. It's that the beginning lies to you. It whispers &lt;em&gt;"this is pointless"&lt;/em&gt; and &lt;em&gt;"you're not good enough"&lt;/em&gt; — and if you listen, you add another repo to the graveyard and open Instagram instead.&lt;/p&gt;

&lt;p&gt;The only answer is to keep showing up. Fifteen minutes at a time.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Experience with GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;I used Copilot heavily during the finishing-up phase, and honestly? It's where it shined the most.&lt;/p&gt;

&lt;p&gt;The interesting thing about reviving an abandoned project is that the &lt;em&gt;fun&lt;/em&gt; parts are already built. What's left is the unsexy stuff — polish, edge cases, drag-and-resize logic, design system consistency. Things I'd normally rage-quit before finishing. This is exactly where Copilot earned its keep.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Copilot genuinely helped:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;Drag-and-resize architecture for the dashboard panels.&lt;/strong&gt; This was the single biggest unlock. I needed every panel to be draggable, resizable, and auto-adjustable based on its container — without breaking the internal components inside each one. Copilot helped me architect the layout system and walked through how to wire &lt;code&gt;react-grid-layout&lt;/code&gt; with my existing panel components. The hardest part was making sure that resizing didn't break the SVG track map, the Recharts graphs, or the WebSocket-driven animations inside. Copilot suggested the right patterns — &lt;code&gt;ResizeObserver&lt;/code&gt; for container-aware children, debounced resize handlers, key-based remounting for stubborn charts — without me having to re-architect each panel from scratch.&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;Type definitions for FastF1 responses.&lt;/strong&gt; FastF1 returns deeply nested pandas DataFrames that I was serializing into JSON. Writing TypeScript types for these by hand was tedious. Copilot inferred most of them from my Python serializer code and saved me from manually transcribing field names.&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;Design system consistency + performance tuning.&lt;/strong&gt; When I was unifying the visual language across twelve panels (spacing, colors, typography, motion timings), Copilot was great at suggesting consistent token-based patterns and flagging where I'd diverged. It also helped with performance decisions — when to memoize, when to use refs over state, when to virtualize, when not to. Not always right, but a useful second opinion.&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;Edge case handling.&lt;/strong&gt; When I was hardening the API endpoints, Copilot was great at suggesting validation cases I hadn't considered. &lt;em&gt;"What if &lt;code&gt;lap_number&lt;/code&gt; is negative?"&lt;/em&gt; &lt;em&gt;"What if the session hasn't loaded yet?"&lt;/em&gt; The kind of paranoid checks that production code needs but you forget when you're prototyping.&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;Test stubs.&lt;/strong&gt; I wrote one test for the gap-calculation logic. Copilot generated the rest of the test cases by varying the inputs. About 70% were useful, 30% were noise — but the useful ones caught two real bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Copilot was less useful:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔴 &lt;strong&gt;The creative architecture decisions.&lt;/strong&gt; The spring-damper camera, the 1000-point SVG sampling trick, the ref-based animation loop bypassing React — these required actually thinking about the problem. Copilot suggested generic solutions when I needed weird ones. That's fine. It's a tool, not a teammate.&lt;/p&gt;

&lt;p&gt;🔴 &lt;strong&gt;Anything involving FastF1's quirks.&lt;/strong&gt; FastF1 has a lot of session-specific behavior (sprint weekends, qualifying formats, telemetry availability) that Copilot's training data didn't cover well. It would suggest plausible-looking code that didn't actually work for the data shape.&lt;/p&gt;

&lt;p&gt;🔴 &lt;strong&gt;Genuinely novel logic.&lt;/strong&gt; The first time I wrote the gap-to-track-fraction conversion (&lt;code&gt;offset = gap_seconds / avg_lap_time&lt;/code&gt;), Copilot wasn't going to help me derive it. I had to actually understand the math first.&lt;/p&gt;

&lt;p&gt;🔴 &lt;strong&gt;Hallucinations when my prompt was vague.&lt;/strong&gt; This is the honest catch. Whenever I got lazy with my prompting — vague intent, no constraints, no examples — Copilot confidently hallucinated APIs that didn't exist, function signatures from imaginary library versions, or completely overengineered a solution I didn't ask for. I'd ask for a small utility and get back a 200-line abstraction with three layers of inheritance. The lesson learned the hard way: the quality of Copilot's output is directly tied to how precisely I describe what I want. Vague in, garbage out. It's not the AI's fault — it's mine for not being specific.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest takeaway:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copilot is at its best when you know what you want and need to type less to get there. It's at its worst when you don't know what you want and hope the autocomplete will figure it out for you. For finishing up an abandoned project — where the hard creative work is already done and what remains is execution polish — it's nearly perfect.&lt;/p&gt;

&lt;p&gt;It didn't write my project. But it absolutely helped me finish it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The graveyard still has occupants. This is the first exhumation, not the last. I've got a backlog of half-built ideas and I'm coming for every single one of them.&lt;/p&gt;

&lt;p&gt;Because it's not about the money. &lt;em&gt;~ Brad Pitt, F1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Massive shoutout to &lt;a href="https://github.com/theOehrly" rel="noopener noreferrer"&gt;theOehrly&lt;/a&gt; — the FastF1 maintainer. This entire project exists because you built something incredible and open-sourced it. That's the energy.&lt;/p&gt;

&lt;p&gt;If you're sitting on an abandoned project right now, this is your sign. Open the laptop. Fifteen minutes. The beginning is lying to you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with too many late-night qualifying sessions, more cans of energy drink than I'm willing to admit, and a refusal to add one more tombstone to the GitHub graveyard.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>nextjs</category>
      <category>ai</category>
    </item>
    <item>
      <title>LLMs are great writers and terrible referees: why my PR roaster has a strict judge</title>
      <dc:creator>Nilamadhab Senapati</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:46:46 +0000</pubDate>
      <link>https://dev.to/madhabcoder/llms-are-great-writers-and-terrible-referees-why-my-pr-roaster-has-a-strict-judge-4857</link>
      <guid>https://dev.to/madhabcoder/llms-are-great-writers-and-terrible-referees-why-my-pr-roaster-has-a-strict-judge-4857</guid>
      <description>&lt;p&gt;I built a Chrome extension that roasts GitHub pull requests.&lt;/p&gt;

&lt;p&gt;It sits on the PR page, reads the diff, asks Claude for a short punchline plus a GIF, and then you paste it yourself. Nothing auto-dunks on your coworkers. I'm not that brave.&lt;/p&gt;

&lt;p&gt;The funny part was easy. The hard part was the referee.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with letting the LLM decide
&lt;/h2&gt;

&lt;p&gt;Early versions of &lt;a href="https://roastmypr.xyz" rel="noopener noreferrer"&gt;RoastMyPR&lt;/a&gt; had the same model write the joke &lt;em&gt;and&lt;/em&gt; decide if the joke was good enough to post.&lt;/p&gt;

&lt;p&gt;That felt clever for about a day.&lt;/p&gt;

&lt;p&gt;Then I watched it do things I would never let a human reviewer get away with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent.&lt;/strong&gt; Same PR, two runs, two moods. One roast was sharp. The next one was a soft "nice work" wearing a comedy hat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talked into things.&lt;/strong&gt; If the prompt got a little eager, the model started writing multi-issue checklists. "Consider refactoring…" is not a roast. That is a LinkedIn post that wandered into your comment box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Made stuff up.&lt;/strong&gt; Invented a file that was not in the diff. Complained about a bug that did not exist. Hyperbole is fine. Hallucinated &lt;code&gt;auth.ts&lt;/code&gt; when the PR is a README typo is not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LLMs are great at writing. They are bad at being the same person twice. I needed the comedy to stay weird, and the pass/fail line to stay boring.&lt;/p&gt;

&lt;p&gt;So I split the jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude writes. Jev judges.
&lt;/h2&gt;

&lt;p&gt;Flow today:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extension grabs the PR title, description, and diff&lt;/li&gt;
&lt;li&gt;Claude writes a short roast JSON (punchline, archetype, GIF search terms)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://typesafe.ai" rel="noopener noreferrer"&gt;Jev&lt;/a&gt; scores that roast against the &lt;em&gt;real&lt;/em&gt; PR state&lt;/li&gt;
&lt;li&gt;You get a draft + GIF. You decide whether to post it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Jev is TypeSafe's decision model. It does not write essays. One API call answers typed yes/no, choice, and scale questions. My gate then applies fixed thresholds in code.&lt;/p&gt;

&lt;p&gt;Writer vs referee. That is the whole architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Jev actually checks
&lt;/h2&gt;

&lt;p&gt;The gate packs the PR title, body, file count, changed lines, and a slice of the diff, plus the roast text. Then it asks questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this roast the &lt;strong&gt;code&lt;/strong&gt;, not the person?&lt;/li&gt;
&lt;li&gt;Is it &lt;strong&gt;grounded in the diff&lt;/strong&gt; (hyperbole ok, inventing files not ok)?&lt;/li&gt;
&lt;li&gt;Is it &lt;strong&gt;safe&lt;/strong&gt; as a public GitHub comment?&lt;/li&gt;
&lt;li&gt;Is it still a &lt;strong&gt;light roast&lt;/strong&gt;, not a patch list or linter dump?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those four are hard checks. Soft ones cover punchline length, whether the archetype fits this diff, tone, and how specific the joke is to &lt;em&gt;this&lt;/em&gt; PR.&lt;/p&gt;

&lt;p&gt;Pass needs high confidence (0.80 on the yes/no scores). A hard check only blocks when confidence crashes below 0.50. Soft misses get logged; they do not force a rewrite by themselves.&lt;/p&gt;

&lt;p&gt;A simplified version of the hard-check idea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HARD_CHECKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;roasts_code_not_person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grounded_in_diff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;safe_github_comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light_touch_review&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Fixed thresholds in code, not "does the model feel good about this"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noul&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blocking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hard&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noul&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The roast still has to be funny. The gate just refuses to pretend a personal insult or a fake file is "quality."&lt;/p&gt;

&lt;h2&gt;
  
  
  Fail open on purpose
&lt;/h2&gt;

&lt;p&gt;If there is no &lt;code&gt;TYPESAFE_API_KEY&lt;/code&gt;, the gate skips and marks the roast as passed.&lt;/p&gt;

&lt;p&gt;If Jev times out or returns an error, same thing: fail open. Insert still works.&lt;/p&gt;

&lt;p&gt;That was a product choice, not a bug. RoastMyPR is a comedy draft tool. I would rather ship a joke without a stamp than brick the whole extension because the quality API had a bad afternoon.&lt;/p&gt;

&lt;p&gt;When a hard check &lt;em&gt;does&lt;/em&gt; fail for real, I give Claude &lt;strong&gt;one&lt;/strong&gt; retry with a short hint: rewrite, roast the code, stay under ~18 words, no invented files. One shot. Then we move on. Endless rewrite loops are how you get polite sludge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Archetypes, because "generic roast" is boring
&lt;/h2&gt;

&lt;p&gt;Claude picks a comic label for the diff from a fixed list. Favorites that show up a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The 2AM Hotfix&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Copy-Paste Special&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Kitchen Sink&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Ghost PR&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Quick Change&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Accidental Rewrite&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The One-Liner That Changed 47 Files&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jev also checks whether the archetype fits &lt;em&gt;this&lt;/em&gt; change. "The Ghost PR" on a two-line typo fails. "The Quick Change" on that same typo passes.&lt;/p&gt;

&lt;p&gt;There is also a chaos score in the UI. Entertainment only. Not CI. Please do not put it in your merge rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roast the code, not the people
&lt;/h2&gt;

&lt;p&gt;This is non-negotiable for me.&lt;/p&gt;

&lt;p&gt;"847 lines for a typo is incredible commitment" is fair game.&lt;/p&gt;

&lt;p&gt;"You are an idiot" is a hard fail.&lt;/p&gt;

&lt;p&gt;I am an introvert who ships side projects after a day job. I do not want to be the guy who built a harassment machine with a GIF picker. The gate's first hard check exists so the product stays mean to diffs and polite to humans.&lt;/p&gt;

&lt;p&gt;You still post the comment yourself. The bot drafts. You own the Send button.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is still rough
&lt;/h2&gt;

&lt;p&gt;Honest list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Weird diffs still confuse the roast tone. Tiny docs PRs and giant refactors need different energy, and I have not nailed both.&lt;/li&gt;
&lt;li&gt;GIF picks miss. There is a search box for a reason.&lt;/li&gt;
&lt;li&gt;Soft fails are noisy in logs and quiet in the UI. I want clearer "Jev · checked" feedback without turning the panel into a report card.&lt;/li&gt;
&lt;li&gt;Fail-open is the right default for a joke tool. It would be the wrong default for a real merge gate. Do not copy this blindly into production CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it on a real PR and it whiffs, tell me where. That is the feedback I actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, then tell me how you'd build the judge
&lt;/h2&gt;

&lt;p&gt;Chrome Web Store: &lt;a href="https://chromewebstore.google.com/detail/roastmypr/bkljncjfnfnhbedbjiaaeojljckcaaeo" rel="noopener noreferrer"&gt;RoastMyPR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Site: &lt;a href="https://roastmypr.xyz" rel="noopener noreferrer"&gt;roastmypr.xyz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code for the gate: &lt;a href="https://github.com/nilamadhab47/roastmypr/blob/main/server/jev-gate.js" rel="noopener noreferrer"&gt;&lt;code&gt;server/jev-gate.js&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am curious how you would design the referee. Same questions, different thresholds? No AI in the gate at all? Something stricter than fail-open?&lt;/p&gt;

&lt;p&gt;Drop a comment. Roast my architecture if you want. Just roast the code.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>buildinpublic</category>
    </item>
  </channel>
</rss>
