<?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: Govind raj</title>
    <description>The latest articles on DEV Community by Govind raj (@govind_raj_9f136507c07899).</description>
    <link>https://dev.to/govind_raj_9f136507c07899</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%2F4054085%2Ff9316242-af73-41cc-8664-f6e4879184f8.png</url>
      <title>DEV Community: Govind raj</title>
      <link>https://dev.to/govind_raj_9f136507c07899</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/govind_raj_9f136507c07899"/>
    <language>en</language>
    <item>
      <title>I turned a dead HP laptop into a home server—and a Broadcom Wi-Fi chip fought me for 3 hours</title>
      <dc:creator>Govind raj</dc:creator>
      <pubDate>Sat, 12 Sep 2026 19:57:04 +0000</pubDate>
      <link>https://dev.to/govind_raj_9f136507c07899/i-turned-a-dead-hp-laptop-into-a-home-server-and-a-broadcom-wi-fi-chip-fought-me-for-3-hours-3b0a</link>
      <guid>https://dev.to/govind_raj_9f136507c07899/i-turned-a-dead-hp-laptop-into-a-home-server-and-a-broadcom-wi-fi-chip-fought-me-for-3-hours-3b0a</guid>
      <description>&lt;p&gt;My phone storage was full. Instead of paying for more cloud, I decided to repurpose an old HP laptop that had been collecting dust into a home server — somewhere to offload photos and, eventually, run a self-hosted photo library with AI search.&lt;/p&gt;

&lt;p&gt;The install went fine. Then the Wi-Fi chip decided to make me earn it — and just when I thought it was over, the machine started shutting itself off for a reason I never would have guessed. This is the honest writeup, both fights included, in case someone Googling "BCM43142 Ubuntu Server no wifi" — or "laptop server shuts off under load" — at midnight needs it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hardware&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Old HP laptop, 1 TB spinning drive&lt;/li&gt;
&lt;li&gt;Realtek Gigabit Ethernet—but no cable could reach the router from where the laptop lives.&lt;/li&gt;
&lt;li&gt;Broadcom &lt;strong&gt;BCM43142&lt;/strong&gt; Wi-Fi—the villain of this story&lt;/li&gt;
&lt;li&gt;Ubuntu Server 24.04 LTS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That "no ethernet + Broadcom Wi-Fi" combo is the whole plot. Hold onto it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1: Installing Ubuntu Server (one gotcha worth catching)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The install is mostly next-next-next. Two things I'd flag:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tick "Install OpenSSH server"&lt;/strong&gt; on the profile screen. This is a headless box — SSH is how you'll talk to it once it's shelved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The disk gotcha.&lt;/strong&gt; With guided LVM storage, the installer only allocates 100 GB to the root volume by default, even on a 1 TB disk. For a storage server that's a disaster — you'd waste ~900 GB. On the storage screen, edit the &lt;em&gt;ubuntu-lv&lt;/em&gt; logical volume and bump its size to the full volume group (mine was ~928 GB) before continuing. After the edit, free space should read zero.&lt;/p&gt;

&lt;p&gt;Install, reboot, log in. So far, so smooth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: The chicken-and-egg problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First command on any fresh server:&lt;/p&gt;

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

&lt;p&gt;I saw &lt;em&gt;lo&lt;/em&gt; and the ethernet interface. No &lt;em&gt;wl*&lt;/em&gt; interface at all. Confirmed the chip with:&lt;/p&gt;

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

&lt;p&gt;The hardware is there — it just has no driver. The BCM43142 needs the proprietary &lt;em&gt;bcmwl-kernel-source&lt;/em&gt; (a.k.a. &lt;em&gt;broadcom-sta&lt;/em&gt;) driver, which is not in the base install.&lt;/p&gt;

&lt;p&gt;Here's the trap: &lt;strong&gt;to install the Wi-Fi driver, you need internet. To get internet, you need the Wi-Fi driver&lt;/strong&gt;. And I had no ethernet cable that could reach the router.&lt;/p&gt;

&lt;p&gt;The way out: borrow a phone's connection over USB once, just long enough to install the driver.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: Phone USB tethering (the painful part)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'll be honest — this was two hours of whack-a-mole. Lessons, so you don't repeat them:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;dhclient&lt;/em&gt; isn't on Ubuntu Server 24.04&lt;/p&gt;

&lt;p&gt;The classic DHCP client is gone. Use busybox instead:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Android tethering renamed its interface constantly&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every reconnect, the USB interface came back with a new name (&lt;em&gt;enx32481b&lt;/em&gt;…, then &lt;em&gt;enxe6ec39&lt;/em&gt;…, then &lt;em&gt;enx8e63&lt;/em&gt;…). Any variable I'd set pointed at a ghost. The defensive move — always grab the current name fresh:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The key insight: address FIRST, then route&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This one cost me the most time. &lt;em&gt;udhcpc&lt;/em&gt; would report a lease but not actually apply it, so adding the default route failed with &lt;em&gt;Nexthop has invalid gateway&lt;/em&gt;. The fix is ordering — put the address on the interface before the route:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;DNS kept silently breaking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ping 8.8.8.8&lt;/em&gt; worked while &lt;em&gt;ping google.com&lt;/em&gt; gave &lt;em&gt;"Temporary failure in name resolution."That signature = DNS not set. The _resolv.conf&lt;/em&gt; line above fixes it; sometimes you have to re-apply it because something overwrites the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android vs iPhone&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Samsung tether was miserable — flaky DHCP, dropped routes, an MTU quirk where pings passed but package downloads failed. Switching to an iPhone Personal Hotspot over USB-C was night and day: stable interface name, gateway always &lt;em&gt;172.20.10.1&lt;/em&gt;, clean &lt;em&gt;/28&lt;/em&gt; subnet. If you have the choice, start with the iPhone.&lt;/p&gt;

&lt;p&gt;Once that held, the payoff:&lt;/p&gt;

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

&lt;p&gt;⚠️ It's &lt;em&gt;bcmwl&lt;/em&gt; — b-c-m-w-l. I fat-fingered it as &lt;em&gt;bcwl&lt;/em&gt; more than once and got &lt;em&gt;"Unable to locate package."&lt;/em&gt; Learn from my typos.&lt;/p&gt;

&lt;p&gt;DKMS compiled the module against the running kernel:&lt;/p&gt;

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

&lt;p&gt;Then:&lt;/p&gt;

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

&lt;p&gt;After the reboot:&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;wlp4s0&lt;/em&gt; exists. The chip that had no driver all night is now a real interface. It scanned and saw my network:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Part 4: netplan alone wasn't enough — the real fix was NetworkManager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I did the "correct" Ubuntu Server thing and wrote a netplan Wi-Fi config:&lt;/p&gt;

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

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

&lt;p&gt;It came up UP but never got an address. &lt;em&gt;netplan status&lt;/em&gt; showed the damning line:&lt;/p&gt;

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

&lt;p&gt;_"(null)" _= associated with nothing. I checked the supplicant logs:&lt;/p&gt;

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

&lt;p&gt;That was the real clue. No entries means the handshake was never even attempted — the networkd backend wasn't starting &lt;em&gt;wpa_supplicant&lt;/em&gt; for this driver at all. It wasn't a wrong-password problem; the join never happened.&lt;/p&gt;

&lt;p&gt;The fix: hand Wi-Fi to NetworkManager, which manages the supplicant itself.&lt;/p&gt;

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

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

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

&lt;p&gt;And:&lt;/p&gt;

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

&lt;p&gt;Address assigned. &lt;em&gt;ping google.com&lt;/em&gt; — 0% loss. iPhone unplugged. Still online. Survives reboots and auto-reconnects. Done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 5: making it behave like a server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So it keeps running with the lid shut:&lt;/p&gt;

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

&lt;p&gt;Charger stays plugged in permanently, lid closed, tucked somewhere with airflow. From here on it's all SSH from my main machine:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Part 6: the sequel — it booted, then kept dying&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I thought I was done. Lid closed, shelved, walked away. The next day it started shutting itself off.&lt;/p&gt;

&lt;p&gt;The pattern was maddening: it booted cleanly, showed the &lt;em&gt;login&lt;/em&gt;: prompt, let me log in — then the instant I ran an actual command, the whole thing cut to black. No kernel panic, no error, no shutdown message. Just gone. Every time, right when the CPU had to do something.&lt;/p&gt;

&lt;p&gt;My first assumption was the worst one: dead motherboard. It wasn't.&lt;/p&gt;

&lt;p&gt;Here's the context that solved it. This laptop's battery no longer holds a charge, so I'd taken it out and was running on the charger alone — seemed reasonable for a machine that lives plugged into the wall. That was the mistake.&lt;/p&gt;

&lt;p&gt;A laptop battery isn't just an energy store. Even at 0% it acts as a buffer/shock-absorber on the power rail. When the CPU suddenly ramps (spinning up services at login, running a command), it briefly draws more than the charger can deliver on its own. With a battery in the circuit, the battery covers that spike. With no battery, the rail sags below spec and the board browns out and instantly powers off — which looks exactly like a fatal hardware death but isn't.&lt;/p&gt;

&lt;p&gt;The fix was almost stupidly simple:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Put the dead battery back in. Even though it holds no charge, it smooths the power spikes. Then leave the charger plugged in permanently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To confirm it rather than guess, I hammered the CPU on purpose:&lt;/p&gt;

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

&lt;p&gt;Before (battery out): dead within seconds of any load. After (dead battery back in): rock solid through a full-core stress loop. Confirmed — it was never the motherboard, it was a power-buffering problem.&lt;/p&gt;

&lt;p&gt;If your always-plugged-in laptop server randomly powers off under load — especially if you removed a "useless" dead battery — put the battery back in before you suspect anything else. One caveat: if the battery is swollen or puffy, don't reinsert it (fire risk) — recycle it and use a cheap replacement as the buffer instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd tell my past self&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BCM43142 needs&lt;/strong&gt; &lt;em&gt;bcmwl-kernel-source&lt;/em&gt;, &lt;strong&gt;and that needs one internet connection to install&lt;/strong&gt;. Everything else is downstream of solving that once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer an iPhone hotspot over Android&lt;/strong&gt; for the temporary tether — far more stable interface and DHCP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address before route&lt;/strong&gt;. The _&lt;em&gt;invalid gateway&lt;/em&gt; error_ is almost always ordering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On this driver, netplan's networkd backend didn't start wpa_supplicant — NetworkManager&lt;/strong&gt; did. If &lt;em&gt;journalctl -u wpa_supplicant&lt;/em&gt; says "&lt;em&gt;No entries,&lt;/em&gt;" stop debugging the password and switch renderers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The disk default is 100 GB&lt;/strong&gt;. Expand the LV during install or lose most of your drive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't run a laptop server with the battery removed&lt;/strong&gt;. Even a dead battery buffers power spikes. Charger-only means the board browns out and powers off under load — and it looks exactly like a dead motherboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What's next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The whole point was storage, so next up is a Samba share for phone photo offload, then a self-hosted photo library with on-device AI search. But the server itself — full disk, SSH, auto-connecting Wi-Fi on a chip that ships with no Linux driver — is alive and standing on its own.&lt;/p&gt;

&lt;p&gt;A "dead" laptop, a $0 budget, and one genuinely stubborn Wi-Fi chip. Worth it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this saved you an evening, drop a note — and if your BCM43142 did something new and cursed, I want to hear it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>homelab</category>
      <category>ubuntu</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>AI Agent #2: Requirements-to-Test Mapper — Here's What I Learned</title>
      <dc:creator>Govind raj</dc:creator>
      <pubDate>Sat, 08 Aug 2026 02:45:56 +0000</pubDate>
      <link>https://dev.to/govind_raj_9f136507c07899/ai-agent-2-requirements-to-test-mapper-heres-what-i-learned-3o4e</link>
      <guid>https://dev.to/govind_raj_9f136507c07899/ai-agent-2-requirements-to-test-mapper-heres-what-i-learned-3o4e</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're drowning in requirements.&lt;/p&gt;

&lt;p&gt;Your product manager hands you a 20-page requirements document. Each requirement has 3-5 acceptance criteria. You need to create test cases for ALL of them.&lt;/p&gt;

&lt;p&gt;That's 3-4 hours of manual work. Per project.&lt;/p&gt;

&lt;p&gt;And here's the painful part: You create the test cases. You document them. You maintain them. Then someone updates a requirement and you have to manually re-trace everything.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;For QA teams handling multiple projects, this becomes a bottleneck. Especially if you need traceability (ISO 9001, FDA, CSA compliance requires it).&lt;/p&gt;

&lt;p&gt;The Real Cost&lt;/p&gt;

&lt;p&gt;Manual test case creation = more than just time wasted.&lt;/p&gt;

&lt;p&gt;It means:&lt;/p&gt;

&lt;p&gt;❌ Inconsistent test case quality (depends on who writes them)&lt;br&gt;
❌ Coverage gaps (easy to miss edge cases when writing manually)&lt;br&gt;
❌ Traceability breaks (requirements and tests fall out of sync)&lt;br&gt;
❌ Compliance risk (auditors ask: "Can you prove all requirements are tested?")&lt;br&gt;
❌ Team bottleneck (only senior QA can write good test cases)&lt;/p&gt;

&lt;p&gt;I wanted to eliminate this. So I built an AI agent that does it in seconds.&lt;/p&gt;

&lt;p&gt;The Solution: Requirements Mapper AI Agent&lt;/p&gt;

&lt;p&gt;Instead of manually reading requirements and writing test cases, what if Claude API did it?&lt;/p&gt;

&lt;p&gt;The agent:&lt;/p&gt;

&lt;p&gt;Parses your requirements document&lt;br&gt;
Sends each requirement to Claude API&lt;br&gt;
Generates 3-4 detailed test cases per requirement&lt;br&gt;
Creates a traceability matrix (REQ ↔ TC mapping)&lt;br&gt;
Identifies coverage gaps&lt;br&gt;
Exports a professional Excel report&lt;/p&gt;

&lt;p&gt;Result: Same work in 35 seconds.&lt;/p&gt;

&lt;p&gt;Not 3-4 hours. 35 seconds.&lt;/p&gt;

&lt;p&gt;Here's How It Works&lt;br&gt;
Step 1: Requirements Parser&lt;/p&gt;

&lt;p&gt;Upload a requirements document with this format:&lt;/p&gt;

&lt;p&gt;REQ-001: User Authentication&lt;br&gt;
Description: The system shall authenticate users.&lt;br&gt;
Details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support email/password login&lt;/li&gt;
&lt;li&gt;Failed attempts logged&lt;/li&gt;
&lt;li&gt;Account lock after 5 failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;REQ-002: Email Verification&lt;br&gt;
Description: System shall verify user emails.&lt;br&gt;
Details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send verification email within 2 seconds&lt;/li&gt;
&lt;li&gt;Link expires after 24 hours&lt;/li&gt;
&lt;li&gt;Resend limit: 3 per hour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The parser extracts:&lt;/p&gt;

&lt;p&gt;Requirement ID&lt;br&gt;
Title&lt;br&gt;
Description&lt;br&gt;
Detailed criteria&lt;br&gt;
Step 2: Claude API Test Case Generator&lt;/p&gt;

&lt;p&gt;For each requirement, the agent asks Claude:&lt;/p&gt;

&lt;p&gt;"REQ-001: User Authentication&lt;br&gt;
Description: The system shall authenticate users.&lt;/p&gt;

&lt;p&gt;Generate 3-4 detailed test cases.&lt;br&gt;
Include test ID, title, steps, and expected result."&lt;/p&gt;

&lt;p&gt;Claude returns:&lt;/p&gt;

&lt;p&gt;TC-001-001: Valid Credentials Login&lt;br&gt;
Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to login page&lt;/li&gt;
&lt;li&gt;Enter valid email&lt;/li&gt;
&lt;li&gt;Enter valid password&lt;/li&gt;
&lt;li&gt;Click Login
Expected: Dashboard displays successfully&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TC-001-002: Invalid Password Rejection&lt;br&gt;
Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to login page&lt;/li&gt;
&lt;li&gt;Enter valid email&lt;/li&gt;
&lt;li&gt;Enter wrong password&lt;/li&gt;
&lt;li&gt;Click Login
Expected: "Invalid password" error message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TC-001-003: Account Lock After 5 Failures&lt;br&gt;
Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attempt login 5 times with wrong password&lt;/li&gt;
&lt;li&gt;Attempt 6th login with correct password
Expected: "Account locked" message (not "invalid credentials")&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why Claude? Because it understands intent, not just keywords.&lt;/p&gt;

&lt;p&gt;"User shall authenticate" and "System authenticates users" mean the same thing. A regex-based tool would miss this. Claude gets it.&lt;/p&gt;

&lt;p&gt;Step 3: Traceability Matrix&lt;/p&gt;

&lt;p&gt;Automatically maps requirements to test cases:&lt;/p&gt;

&lt;p&gt;REQ-001: User Authentication&lt;br&gt;
├─ TC-001-001: Valid credentials ✅&lt;br&gt;
├─ TC-001-002: Invalid password ✅&lt;br&gt;
├─ TC-001-003: Account lockout ✅&lt;br&gt;
└─ TC-001-004: Password reset ✅&lt;br&gt;
Coverage: 100%&lt;/p&gt;

&lt;p&gt;REQ-002: Email Verification&lt;br&gt;
├─ TC-002-001: Email sent within 2s ✅&lt;br&gt;
├─ TC-002-002: Link expires after 24h ✅&lt;br&gt;
├─ TC-002-003: Resend limit enforced ✅&lt;br&gt;
└─ TC-002-004: Unverified account deletion ✅&lt;br&gt;
Coverage: 100%&lt;br&gt;
Step 4: Gap Analysis&lt;/p&gt;

&lt;p&gt;Identifies requirements with insufficient test coverage:&lt;/p&gt;

&lt;p&gt;Coverage Report:&lt;br&gt;
✅ Total Coverage: 95%&lt;br&gt;
⚠️  Coverage Gaps: 2 requirements&lt;/p&gt;

&lt;p&gt;Gap #1: REQ-005 (Dark Mode)&lt;br&gt;
Issue: Only 2 test cases&lt;br&gt;
Recommendation: Add tests for theme persistence, &lt;br&gt;
                toggle behavior, accessibility&lt;/p&gt;

&lt;p&gt;Gap #2: REQ-008 (Data Export)&lt;br&gt;
Issue: Missing edge case tests&lt;br&gt;
Recommendation: Add tests for large datasets, &lt;br&gt;
                character encoding, file corruption&lt;br&gt;
Step 5: Excel Report Generation&lt;/p&gt;

&lt;p&gt;Generates a professional, audit-ready Excel file:&lt;/p&gt;

&lt;p&gt;Sheet 1: Summary&lt;/p&gt;

&lt;p&gt;Total requirements: 10&lt;br&gt;
Coverage %: 95%&lt;br&gt;
Gaps identified: 2&lt;br&gt;
Total test cases: 38&lt;/p&gt;

&lt;p&gt;Sheet 2: Traceability Matrix&lt;/p&gt;

&lt;p&gt;Req ID  Requirement Test Count  Test IDs    Coverage&lt;br&gt;
REQ-001 Authentication  4   TC-001-001, TC-001-002, TC-001-003, TC-001-004  100%&lt;br&gt;
REQ-002 Email Verification  4   TC-002-001, TC-002-002, TC-002-003, TC-002-004  100%&lt;/p&gt;

&lt;p&gt;Sheet 3: Coverage Gaps&lt;/p&gt;

&lt;p&gt;Lists what's not tested&lt;br&gt;
Suggests additional test cases&lt;br&gt;
Prioritizes by risk&lt;/p&gt;

&lt;p&gt;Sheet 4: Test Cases&lt;/p&gt;

&lt;p&gt;Full test specifications&lt;br&gt;
All steps and expected results&lt;br&gt;
Ready for QA to execute&lt;br&gt;
Real Example: Medical Device Requirements&lt;/p&gt;

&lt;p&gt;To demo this, I used 10 realistic medical device requirements:&lt;/p&gt;

&lt;p&gt;REQ-001: User Authentication&lt;br&gt;
REQ-002: Password Security&lt;br&gt;&lt;br&gt;
REQ-003: Email Verification&lt;br&gt;
REQ-004: Device Connection&lt;br&gt;
REQ-005: Data Collection&lt;br&gt;
REQ-006: Real-time Alerts&lt;br&gt;
REQ-007: Dashboard Display&lt;br&gt;
REQ-008: Data Export&lt;br&gt;
REQ-009: HIPAA Compliance&lt;br&gt;
REQ-010: Role-Based Access&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;p&gt;✅ 40 test cases generated&lt;br&gt;
✅ 100% coverage&lt;br&gt;
✅ Excel report ready for audit&lt;br&gt;
✅ Time elapsed: 35 seconds&lt;/p&gt;

&lt;p&gt;Without automation: 3-4 hours of manual work.&lt;/p&gt;

&lt;p&gt;With this agent: 35 seconds.&lt;/p&gt;

&lt;p&gt;Why This Matters&lt;br&gt;
For QA Teams&lt;br&gt;
✅ Eliminate manual test case writing&lt;br&gt;
✅ Ensure consistent quality&lt;br&gt;
✅ Maintain complete traceability&lt;br&gt;
✅ Save 3-4 hours per project&lt;br&gt;
For Compliance&lt;br&gt;
✅ ISO 9001: Complete traceability matrix&lt;br&gt;
✅ FDA: All requirements documented and tested&lt;br&gt;
✅ CSA: Coverage gaps identified and addressed&lt;br&gt;
✅ Audit-ready reports in minutes&lt;br&gt;
For Business&lt;br&gt;
✅ Faster time-to-test&lt;br&gt;
✅ Better quality assurance&lt;br&gt;
✅ Reduced rework&lt;br&gt;
✅ Scalable QA process&lt;br&gt;
The Architecture&lt;/p&gt;

&lt;p&gt;The tool is built with Python + Claude API:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
class RequirementsParser:&lt;br&gt;
    # Reads requirements, extracts structured data&lt;/p&gt;

&lt;p&gt;class TestCaseGenerator:&lt;br&gt;
    # Sends to Claude API, generates test cases&lt;br&gt;
    # Includes robust JSON extraction with 4 fallback strategies&lt;/p&gt;

&lt;p&gt;class TraceabilityMapper:&lt;br&gt;
    # Maps REQ ↔ TC, calculates coverage %&lt;/p&gt;

&lt;p&gt;class GapAnalyzer:&lt;br&gt;
    # Finds untested requirements&lt;br&gt;
    # Suggests missing test scenarios&lt;/p&gt;

&lt;p&gt;class ExcelGenerator:&lt;br&gt;
    # Creates professional 4-sheet report&lt;br&gt;
    # Includes formatting, colors, styling&lt;/p&gt;

&lt;p&gt;Performance:&lt;/p&gt;

&lt;p&gt;Parse 10 requirements: &amp;lt; 1 sec&lt;br&gt;
Generate 40 test cases: ~30 sec (Claude API latency)&lt;br&gt;
Create matrix + gaps: &amp;lt; 1 sec&lt;br&gt;
Generate Excel: ~2 sec&lt;br&gt;
Total: ~35 seconds&lt;br&gt;
Why Claude API, Not ML Models?&lt;/p&gt;

&lt;p&gt;I considered TensorFlow, PyTorch, custom ML models.&lt;/p&gt;

&lt;p&gt;But here's why Claude API is better:&lt;/p&gt;

&lt;p&gt;ML models (❌ not ideal):&lt;/p&gt;

&lt;p&gt;Require training data&lt;br&gt;
Need fine-tuning for accuracy&lt;br&gt;
Hard to reason about edge cases&lt;br&gt;
Black box results&lt;/p&gt;

&lt;p&gt;Claude API (✅ perfect fit):&lt;/p&gt;

&lt;p&gt;Understands requirement semantics&lt;br&gt;
Generates complete test cases with reasoning&lt;br&gt;
Consistent quality&lt;br&gt;
Transparent reasoning&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Requirement: "System shall validate email format"&lt;/p&gt;

&lt;p&gt;ML model might generate:&lt;/p&gt;

&lt;p&gt;"Test: enter email"&lt;br&gt;
"Test: enter invalid email"&lt;/p&gt;

&lt;p&gt;Claude generates:&lt;/p&gt;

&lt;p&gt;"Test: RFC 5322 compliant email"&lt;br&gt;
"Test: Missing @"&lt;br&gt;
"Test: Multiple @ symbols"&lt;br&gt;
"Test: Invalid domain"&lt;br&gt;
"Test: Internationalized domain names"&lt;/p&gt;

&lt;p&gt;Claude thinks semantically. ML models pattern-match.&lt;/p&gt;

&lt;p&gt;For QA, semantic understanding wins.&lt;/p&gt;

&lt;p&gt;Three Lessons Learned&lt;br&gt;
Lesson 1: JSON Extraction is Harder Than You Think&lt;/p&gt;

&lt;p&gt;When Claude returns test cases as JSON, it's not always perfect.&lt;/p&gt;

&lt;p&gt;Sometimes it wraps JSON in text. Sometimes the formatting is inconsistent.&lt;/p&gt;

&lt;p&gt;My first attempt had a simple regex: re.search(r'{.*}', text)&lt;/p&gt;

&lt;p&gt;That failed 80% of the time.&lt;/p&gt;

&lt;p&gt;I built 4 fallback strategies:&lt;/p&gt;

&lt;p&gt;Find JSON object with nested braces&lt;br&gt;
Find JSON array of objects&lt;br&gt;
Look for triple-backtick code blocks&lt;br&gt;
Clean markdown and extract&lt;/p&gt;

&lt;p&gt;Now: 95%+ success rate.&lt;/p&gt;

&lt;p&gt;Lesson: When integrating with LLMs, assume the response will be messy. Plan for it.&lt;/p&gt;

&lt;p&gt;Lesson 2: Fallback Test Cases Are Actually Good&lt;/p&gt;

&lt;p&gt;When Claude's JSON fails, my code creates 3 automatic test cases:&lt;/p&gt;

&lt;p&gt;TC-001: Basic functionality&lt;br&gt;
TC-002: Error handling&lt;br&gt;
TC-003: Edge cases&lt;/p&gt;

&lt;p&gt;These fallback test cases are actually good. They cover the important scenarios.&lt;/p&gt;

&lt;p&gt;So "failures" become wins. Full coverage maintained even when JSON parsing fails.&lt;/p&gt;

&lt;p&gt;Lesson: Smart fallbacks can be as valuable as the primary path.&lt;/p&gt;

&lt;p&gt;Lesson 3: Traceability Drives Quality&lt;/p&gt;

&lt;p&gt;Once you make coverage visible (REQ ↔ TC matrix), teams prioritize filling gaps.&lt;/p&gt;

&lt;p&gt;Before: "We have test cases" (nobody knows coverage) After: "We have 95% coverage, here are the 2 gaps" (teams fix gaps immediately)&lt;/p&gt;

&lt;p&gt;Visibility drives action.&lt;/p&gt;

&lt;p&gt;Lesson: For QA automation, measurement and visibility matter as much as automation itself.&lt;/p&gt;

&lt;p&gt;Use Cases&lt;br&gt;
✅ Medical device software (FDA traceability required)&lt;br&gt;
✅ Enterprise applications (ISO 9001, CSA compliance)&lt;br&gt;
✅ Financial software (regulatory requirements)&lt;br&gt;
✅ Any project requiring documented test coverage&lt;/p&gt;

&lt;p&gt;Next Steps&lt;/p&gt;

&lt;p&gt;The code is open source:&lt;/p&gt;

&lt;p&gt;👉 GitHub: github.com/gov466/requirements-mapper&lt;/p&gt;

&lt;p&gt;Features:&lt;/p&gt;

&lt;p&gt;Parse requirements from text files&lt;br&gt;
Generate test cases with Claude API&lt;br&gt;
Create professional Excel reports&lt;br&gt;
Identify coverage gaps&lt;br&gt;
Ready for production use&lt;/p&gt;

&lt;p&gt;Installation:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
pip install -r requirements.txt&lt;br&gt;
python requirements_mapper.py&lt;/p&gt;

&lt;p&gt;Output: Professional Excel file with complete traceability.&lt;/p&gt;

&lt;p&gt;Cost&lt;/p&gt;

&lt;p&gt;Claude API for 10 requirements:&lt;/p&gt;

&lt;p&gt;Input tokens: ~10,000&lt;br&gt;
Output tokens: ~5,000&lt;br&gt;
Cost: ~$0.01&lt;/p&gt;

&lt;p&gt;Per 100 requirements: ~$0.10&lt;/p&gt;

&lt;p&gt;Essentially free compared to 3-4 hours of manual work.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;Test case generation is one of QA's biggest bottlenecks.&lt;/p&gt;

&lt;p&gt;Manual work = inconsistent, slow, error-prone.&lt;/p&gt;

&lt;p&gt;AI + Claude API = fast, consistent, comprehensive.&lt;/p&gt;

&lt;p&gt;The future of QA isn't just automation. It's intelligent automation.&lt;/p&gt;

&lt;p&gt;Semantic understanding + traceability + compliance = modern QA tools.&lt;/p&gt;

&lt;p&gt;That's what I'm building.&lt;/p&gt;

&lt;p&gt;Have you built anything with Claude API? I'd love to hear about it in the comments.&lt;/p&gt;

&lt;p&gt;Want the code? GitHub link above. It's production-ready.&lt;/p&gt;

&lt;p&gt;Want to learn more? Read the full technical write-up on GitHub.&lt;/p&gt;

&lt;p&gt;Thanks for reading! 🚀&lt;/p&gt;

&lt;h1&gt;
  
  
  QA #AI #Automation #Claude #Python #Testing #ComplianceFirst
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>python</category>
    </item>
    <item>
      <title>I Built an AI Bot to Find Duplicate Defects in Jira — Here's What I Learned</title>
      <dc:creator>Govind raj</dc:creator>
      <pubDate>Sat, 01 Aug 2026 03:07:57 +0000</pubDate>
      <link>https://dev.to/govind_raj_9f136507c07899/i-built-an-ai-bot-to-find-duplicate-defects-in-jira-heres-what-i-learned-3nni</link>
      <guid>https://dev.to/govind_raj_9f136507c07899/i-built-an-ai-bot-to-find-duplicate-defects-in-jira-heres-what-i-learned-3nni</guid>
      <description>&lt;p&gt;I built a Jira bot powered by Claude API that comments on new tickets with likely duplicates. It reasons about root cause instead of keyword matching. Here's the architecture and what surprised me.&lt;/p&gt;

&lt;p&gt;The Problem Every QA Team Faces&lt;/p&gt;

&lt;p&gt;You're triaging defects. A new bug comes in: "Device disconnects after 2 minutes."&lt;/p&gt;

&lt;p&gt;You've got 50 open issues. One of them is probably the same root cause, but it's buried in your backlog with a different symptom: "Connection loss during thermal stress."&lt;/p&gt;

&lt;p&gt;How do you know they're the same issue without reading every single ticket?&lt;/p&gt;

&lt;p&gt;Traditional duplicate detection fails:&lt;/p&gt;

&lt;p&gt;Keyword matching misses issues with different symptoms but identical root causes&lt;br&gt;
Manual review takes 30 minutes per ticket&lt;br&gt;
You inevitably miss connections&lt;br&gt;
The Solution: A Bot That Reasons About Root Cause&lt;/p&gt;

&lt;p&gt;I decided to build a bot that does what I wish I could do instantly: read a new defect, compare it to all open issues, and identify likely duplicates by reasoning about the actual root cause.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;p&gt;New defect submitted to Jira → Webhook fires&lt;br&gt;
Bot fetches the new ticket + all open issues&lt;br&gt;
Send to Claude API with a prompt like:&lt;br&gt;
   "Here's a new defect: [full description]&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here are 50 open issues: [list with details]

Which issues likely share the same root cause?
Explain your reasoning. Confidence score for each."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Claude analyzes and returns ranked matches&lt;br&gt;
Bot comments on the ticket with suggestions&lt;br&gt;
Engineer reviews — human makes the final call&lt;/p&gt;

&lt;p&gt;The key: Claude understands causation, not just word overlap.&lt;/p&gt;

&lt;p&gt;The Bot in Action&lt;/p&gt;

&lt;p&gt;Here's what it looks like when it works in real time:&lt;/p&gt;

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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/48P6n8b2lvc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Real Example: Two Bugs, Same Root Cause&lt;/p&gt;

&lt;p&gt;I tested this with two actual defects:&lt;/p&gt;

&lt;p&gt;Bug #1: Display backlight flickers when device runs on battery&lt;/p&gt;

&lt;p&gt;When the unit is unplugged and running on battery, the screen backlight &lt;br&gt;
flickers noticeably. Doesn't happen while it's plugged into mains power — &lt;br&gt;
only on battery.&lt;/p&gt;

&lt;p&gt;Bug #2: Screen brightness unstable during unplugged operation&lt;/p&gt;

&lt;p&gt;Running the device without external power, the display keeps fluctuating &lt;br&gt;
in brightness. As soon as it's back on wall power the screen is steady &lt;br&gt;
again. Seems tied to running off the internal cell.&lt;/p&gt;

&lt;p&gt;The Challenge: These bugs describe the exact same problem with completely different wording. Bug #1 mentions "backlight flickers on battery." Bug #2 says "brightness unstable when unplugged." Same root cause (battery power delivery), different symptom descriptions.&lt;/p&gt;

&lt;p&gt;Keyword matching would miss this. The words don't overlap much. But the root cause is identical: power delivery instability on battery.&lt;/p&gt;

&lt;p&gt;The Bot's Response:&lt;/p&gt;

&lt;p&gt;When I submitted Bug #2, the bot immediately flagged Bug #1 as a likely duplicate. It explained:&lt;/p&gt;

&lt;p&gt;"Both defects describe the same root cause (battery power delivery instability) affecting the same subsystem (display backlight) with identical behavior pattern (flickering/fluctuating brightness on battery, stable on mains power)."&lt;/p&gt;

&lt;p&gt;Confidence: High (duplicate)&lt;/p&gt;

&lt;p&gt;That's not pattern matching. That's reasoning about causation.&lt;/p&gt;

&lt;p&gt;Why Claude API, Not Machine Learning?&lt;/p&gt;

&lt;p&gt;You might think: "Shouldn't you build an ML model for this?"&lt;/p&gt;

&lt;p&gt;Short answer: No. Here's why:&lt;/p&gt;

&lt;p&gt;ML approach would require:&lt;/p&gt;

&lt;p&gt;Training data (100+ labeled duplicate pairs)&lt;br&gt;
Weeks of experimentation&lt;br&gt;
GPU compute&lt;br&gt;
Ongoing model refinement&lt;br&gt;
Retraining when patterns change&lt;/p&gt;

&lt;p&gt;Claude API approach:&lt;/p&gt;

&lt;p&gt;Works immediately&lt;br&gt;
$0.50/month&lt;br&gt;
Handles novel patterns (Claude generalizes)&lt;br&gt;
No training data needed&lt;br&gt;
Reasoning is transparent (you see why it flagged something)&lt;/p&gt;

&lt;p&gt;For a QA team's duplicate detection problem, semantic reasoning beats statistical learning.&lt;/p&gt;

&lt;p&gt;Architecture: Simple and Elegant&lt;br&gt;
Jira Webhook (new defect)&lt;br&gt;
    ↓&lt;br&gt;
Google Apps Script&lt;br&gt;
    ├─ Fetch new ticket details&lt;br&gt;
    ├─ Query Jira for open issues&lt;br&gt;
    ├─ Build prompt with context&lt;br&gt;
    └─ Call Claude API&lt;/p&gt;

&lt;p&gt;Claude API&lt;br&gt;
    ├─ Analyze for root-cause similarity&lt;br&gt;
    ├─ Return ranked matches + confidence&lt;br&gt;
    └─ Return reasoning&lt;/p&gt;

&lt;p&gt;Bot Action&lt;br&gt;
    ├─ Post comment to ticket&lt;br&gt;
    ├─ Link likely duplicates&lt;br&gt;
    └─ Flag for human review&lt;/p&gt;

&lt;p&gt;Total: ~200 lines of code. Zero infrastructure.&lt;/p&gt;

&lt;p&gt;Three Things That Surprised Me&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude understood domain context without training&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I didn't need to teach it what "battery power delivery" means or what makes two display issues related. It understood from context that both bugs point to a power-related instability affecting the backlight circuit.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confidence scores were surprisingly accurate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the bot ranked matches with confidence percentages, those rankings matched my intuition perfectly. Higher confidence = stronger root-cause connection.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The "human-in-the-loop" note matters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I added: "Suggestions only — please confirm before linking or closing."&lt;/p&gt;

&lt;p&gt;That line is critical. It tells engineers: This is assistance, not automation. That actually builds trust faster than auto-closing tickets would.&lt;/p&gt;

&lt;p&gt;Lessons for Building QA Automation&lt;/p&gt;

&lt;p&gt;If you're thinking about adding AI to your QA workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Root-cause reasoning &amp;gt; pattern matching For debugging, duplicate detection, or root cause analysis, semantic understanding beats keyword overlap every time. Use Claude for reasoning tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Human-in-the-loop is a feature Don't try to fully automate. Surface candidates, let humans decide. That friction is actually what makes the tool trustworthy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start with APIs, not models You don't need to train ML models. Claude API costs $1-3/month and solves most QA reasoning problems. Save complex ML for truly custom use cases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transparency helps adoption Show your reasoning. "Why did you flag this?" is more important than "I flagged this." Engineers trust tools that explain themselves.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test before deploying Obvious, but: validate that your duplicates are actually duplicates before letting the bot loose. One bad match kills engineer trust.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Takeaway&lt;/p&gt;

&lt;p&gt;Building this bot taught me that the best automation tools aren't the ones that eliminate human judgment — they're the ones that amplify it.&lt;/p&gt;

&lt;p&gt;A bot that comments "Here are 3 issues that might be related, here's why" is infinitely more useful than one that auto-closes tickets.&lt;/p&gt;

&lt;p&gt;If you're automating QA workflows, think about where reasoning matters more than matching. That's where Claude API shines.&lt;/p&gt;

&lt;p&gt;Built with Claude API + Google Apps Script + Jira Webhooks&lt;/p&gt;

&lt;p&gt;Have you built bots for your team? What problem did it solve? Drop a comment.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
