<?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: YunHyeon Lee</title>
    <description>The latest articles on DEV Community by YunHyeon Lee (@yunhyeon_lee_ef1d57c43a41).</description>
    <link>https://dev.to/yunhyeon_lee_ef1d57c43a41</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3885573%2F35e9db91-5c2a-40b8-8784-4167959c804b.png</url>
      <title>DEV Community: YunHyeon Lee</title>
      <link>https://dev.to/yunhyeon_lee_ef1d57c43a41</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yunhyeon_lee_ef1d57c43a41"/>
    <language>en</language>
    <item>
      <title>The Unfiltered Log of Shipping Open-Source v2 with AI Agents</title>
      <dc:creator>YunHyeon Lee</dc:creator>
      <pubDate>Sat, 18 Apr 2026 06:37:51 +0000</pubDate>
      <link>https://dev.to/yunhyeon_lee_ef1d57c43a41/the-unfiltered-log-of-shipping-open-source-v2-with-ai-agents-3i0o</link>
      <guid>https://dev.to/yunhyeon_lee_ef1d57c43a41/the-unfiltered-log-of-shipping-open-source-v2-with-ai-agents-3i0o</guid>
      <description>&lt;p&gt;&lt;em&gt;Six weeks, 146 commits, and every hallucination along the way&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Sometime in 2024 I opened a GitHub notification from &lt;a href="https://github.com/slash9494/react-modern-audio-player" rel="noopener noreferrer"&gt;&lt;code&gt;react-modern-audio-player&lt;/code&gt;&lt;/a&gt;, read the issue, started typing a reply, and closed the tab. I don't remember the issue. I remember the tab closing. That was the pattern for three years: someone would file a bug or ask about accessibility, and I would care about it for about ninety seconds before the weight of everything the library needed crushed the motivation to start.&lt;/p&gt;

&lt;p&gt;The last real commit was v1.4.0-rc.2, February 2023. I had a full-time job, the library worked well enough, and nobody was furious enough to fork it. So it sat.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;On March 1, 2026, I made the first commit of what became v2. The catalyst wasn't inspiration. It was Claude Code.&lt;/p&gt;

&lt;p&gt;Not because Claude wrote the library for me. Because it lowered the activation energy enough that I could start. When the gap between "I should fix this" and "here is a concrete first step" shrinks from two hours of re-reading your own code to fifteen minutes of conversation, starting stops feeling impossible. That's the only honest way I can describe what happened.&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%2Fk8cojuqrp9cb1zuxuq6h.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%2Fk8cojuqrp9cb1zuxuq6h.png" alt="react-modern-audio-player waveform with progress" width="800" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The overhaul ran about six weeks. 146 commits, roughly 20 PRs numbered #31 through #53, a complete rewrite of the test infrastructure, the CSS layer, the bundle composition, and the accessibility surface. My primary tools were Claude (Opus and Sonnet) for code generation, refactoring, and review, and CodeRabbit for automated PR review. CodeRabbit runs a multi-model ensemble under the hood, selecting different frontier models per review task. I also consulted Gemini and GPT occasionally for documentation references and terminology checks, though they weren't part of the daily workflow.&lt;/p&gt;

&lt;p&gt;Early on, I ran an experiment that changed how I worked with all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four models, four confessions
&lt;/h2&gt;

&lt;p&gt;On 2026-03-18, I gave the same PR review task to four models side by side: Claude Sonnet, Gemini 3 Flash, GPT 5.3, and CodeRabbit. Every model got something wrong. Here is each one admitting it, in their own words:&lt;/p&gt;

&lt;p&gt;Primary (daily drivers):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Self-admission&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet&lt;/td&gt;
&lt;td&gt;Config file review&lt;/td&gt;
&lt;td&gt;"I explained existing file content as if valid without verifying."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CodeRabbit (multi-model)&lt;/td&gt;
&lt;td&gt;PR blocker&lt;/td&gt;
&lt;td&gt;"My original blocker was wrong — your config is correct."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Reference (doc checks, terminology):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Self-admission&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3 Flash&lt;/td&gt;
&lt;td&gt;Doc consistency&lt;/td&gt;
&lt;td&gt;"I mixed past data with current documentation."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT 5.3&lt;/td&gt;
&lt;td&gt;Bundle config&lt;/td&gt;
&lt;td&gt;"I confused 'condition bundle' vs 'rule array' concept."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy6xawjkw8hnpcaij18j.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%2Fcy6xawjkw8hnpcaij18j.png" alt="CodeRabbit admitting its blocker was wrong after user pushback (PR #32)" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On any given question, roughly two of four got it right. But the two that got it right rotated. Claude would nail a state management question and hallucinate about a Vite config. That experiment killed my trust in any single model's output. From that point on, my rule was: if Claude and CodeRabbit agree and the official docs confirm, proceed. Otherwise, run the code and find out. The validation stack wasn't overhead. It was the actual product of the overhaul.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI caught that I missed
&lt;/h2&gt;

&lt;p&gt;The initial analysis of v1.4.0-rc.2 produced a scorecard I already half-knew but had never written down:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Functionality&lt;/td&gt;
&lt;td&gt;9/10&lt;/td&gt;
&lt;td&gt;Feature-complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;4/10&lt;/td&gt;
&lt;td&gt;0% test coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;6/10&lt;/td&gt;
&lt;td&gt;Degrades at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accessibility&lt;/td&gt;
&lt;td&gt;1/10&lt;/td&gt;
&lt;td&gt;No WCAG support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintainability&lt;/td&gt;
&lt;td&gt;5/10&lt;/td&gt;
&lt;td&gt;Technical debt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bundle Size&lt;/td&gt;
&lt;td&gt;5/10&lt;/td&gt;
&lt;td&gt;~380 KB, 6 runtime deps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Overall production-readiness: 5/10. I had shipped a feature-complete component that was nearly unusable for screen-reader users and had no safety net against regressions.&lt;/p&gt;

&lt;p&gt;PR #41 addressed the accessibility gaps across player components. PR #42 split the React context and added memoization to fix a re-render storm I'd been ignoring. PR #43 replaced direct DOM mutations with React state. These weren't AI ideas, exactly. They were problems I already knew about, surfaced and organized by models that could scan the whole codebase in seconds instead of the hours it would have taken me to re-orient after three years away.&lt;/p&gt;

&lt;h2&gt;
  
  
  The validation stack
&lt;/h2&gt;

&lt;p&gt;Here is what I actually ran before tagging v2.0.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CodeRabbit on every PR, configured to block merge on unresolved findings&lt;/li&gt;
&lt;li&gt;32 test files (up from zero): unit tests via Vitest, integration with React Testing Library, end-to-end via Playwright&lt;/li&gt;
&lt;li&gt;axe-core for automated accessibility checks&lt;/li&gt;
&lt;li&gt;Manual VoiceOver testing on Safari&lt;/li&gt;
&lt;li&gt;A docs-first workflow where I wrote the README change before the implementation&lt;/li&gt;
&lt;li&gt;Cross-validation: no architectural decision accepted unless Claude and CodeRabbit agreed and official documentation confirmed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one sounds paranoid. It saved me from shipping hallucinated configs at least three times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it more robust now?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;v1.4.0 (Before)&lt;/th&gt;
&lt;th&gt;v2.1.0 (After)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;0 files&lt;/td&gt;
&lt;td&gt;32 files (unit + integration + e2e)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bundle&lt;/td&gt;
&lt;td&gt;~380 KB, 6 runtime deps&lt;/td&gt;
&lt;td&gt;~79 KB unminified, 1 dep (wavesurfer.js)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accessibility&lt;/td&gt;
&lt;td&gt;1/10, no ARIA&lt;/td&gt;
&lt;td&gt;ARIA + keyboard + VoiceOver tested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Re-renders&lt;/td&gt;
&lt;td&gt;All consumers on any state change&lt;/td&gt;
&lt;td&gt;Split context + memoization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DOM control&lt;/td&gt;
&lt;td&gt;Direct manipulation outside React&lt;/td&gt;
&lt;td&gt;React state driven&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public API&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;useAudioPlayer()&lt;/code&gt; hook&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ai09jh63p54d78ggh6x.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%2F2ai09jh63p54d78ggh6x.png" alt="Bundle size: 380 KB to 79 KB" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bundle number looks like roughly 80% smaller, but I haven't verified against gzipped production builds, so treat it as approximate.&lt;/p&gt;

&lt;p&gt;I'm not going to claim a specific new accessibility score because I haven't run a formal audit against v2.1.0 yet. The keyboard interface covers play, pause, seek, and volume, and VoiceOver navigation works. Whether that's a 7 or an 8, I honestly don't know.&lt;/p&gt;

&lt;p&gt;So yes, more robust. Also still a small library maintained by one person with a day job. The tests exist now, which means regressions will be caught. That is the win. Not "production-grade enterprise audio solution." Just: maintained.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Just vibe-code your own player"
&lt;/h2&gt;

&lt;p&gt;I've seen the argument. Why depend on a library at all when you can prompt an AI to generate a custom audio player in an afternoon? I've thought about it more than I'd like to admit, because if the answer is "no reason," then six weeks of my life just evaporated.&lt;/p&gt;

&lt;p&gt;Here is what I think. A generated audio player works on the demo. Then you discover that Safari fires &lt;code&gt;canplaythrough&lt;/code&gt; differently than Chrome, and your loading state breaks on iOS. Then you add wavesurfer.js for waveform rendering and find out its lifecycle hooks need careful cleanup or you leak memory on every track change. Then a user wants shuffle, repeat, and drag-to-reorder in the playlist, and suddenly you're maintaining a state machine. Then someone files an accessibility issue and you realize that aria attributes alone don't make a screen reader experience. Then you deploy on Next.js App Router and learn that half your hooks assume a browser environment.&lt;/p&gt;

&lt;p&gt;Each one of these is a week. Not because any single problem is hard, but because they compound, and the generated version hasn't paid that tax yet. The question isn't whether you can build a player from scratch. Of course you can. The question is whether you want to maintain one from scratch, because that's what the six weeks actually bought: not a player, but the accumulated scar tissue of integration problems already solved, tested, and documented. Whether you'd rather spend six weeks or use a library that already did, I'll leave to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm left with
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/slash9494/react-modern-audio-player" rel="noopener noreferrer"&gt;&lt;code&gt;react-modern-audio-player&lt;/code&gt;&lt;/a&gt; v2.1.0 shipped on April 14, 2026. It is still a small library. It is maintained now, which is more than I could say for three years. If you use it and something breaks, file an issue and I'll see it. I won't close the tab this time.&lt;/p&gt;

&lt;p&gt;I don't know if AI-assisted maintenance scales to larger projects or longer timelines. I know it worked for this one, this time, with constant supervision. That's a narrower claim than I wanted to make, but it's the one the evidence supports.&lt;/p&gt;




&lt;p&gt;P.S. This article was drafted with AI assistance (Claude) and then edited by hand. All metrics, commit references, and timeline claims were verified against the actual git history and project documentation.&lt;/p&gt;




&lt;p&gt;Repo: &lt;a href="https://github.com/slash9494/react-modern-audio-player" rel="noopener noreferrer"&gt;https://github.com/slash9494/react-modern-audio-player&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
