<?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: ethantao14</title>
    <description>The latest articles on DEV Community by ethantao14 (@ethantao14).</description>
    <link>https://dev.to/ethantao14</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%2F4095983%2F7fa09170-be78-45cf-9f23-051fdb4e5c8b.png</url>
      <title>DEV Community: ethantao14</title>
      <link>https://dev.to/ethantao14</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ethantao14"/>
    <language>en</language>
    <item>
      <title>Three Bugs That Survived Every Automated Check (And How Line-by-Line Review Caught Them)</title>
      <dc:creator>ethantao14</dc:creator>
      <pubDate>Wed, 16 Sep 2026 20:45:30 +0000</pubDate>
      <link>https://dev.to/ethantao14/three-bugs-that-survived-every-automated-check-and-how-line-by-line-review-caught-them-401h</link>
      <guid>https://dev.to/ethantao14/three-bugs-that-survived-every-automated-check-and-how-line-by-line-review-caught-them-401h</guid>
      <description>&lt;p&gt;Game Mode Sandbox is a new project our team is building alongside our stock market game: an app-store-style site where each app is a front-end-only version of the stock draft game running on fake data, one per rule variant, so we can playtest which rules feel best before locking anything into the real product. Kenny owns the store pages and data, Jane owns the gameplay screens, and I own the engine, the pure logic layer that decides what a player can do and what happens when they do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design principles for the engine
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pure functions, no UI&lt;/strong&gt;: every rule can be tested directly, no clicking through screens required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seeded randomness&lt;/strong&gt;: every random draw, like which stocks appear each round, comes from the game's seed, so the same seed replays the same game and bugs are reproducible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalid actions are no-ops&lt;/strong&gt;: they leave the game state unchanged instead of crashing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Money is always rounded to whole cents&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Market data is passed in, never hardcoded&lt;/strong&gt;, so tests can supply their own&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What shipped
&lt;/h2&gt;

&lt;p&gt;Four pull requests merged this week, +1,703/-25 lines total:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Config validation&lt;/strong&gt; (+792/-10): checks whether a rule setup is actually playable and explains any problem in plain English, pointing at the setting to fix&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Board drawing&lt;/strong&gt; (+456/-5): picks which stocks appear each round across all three board types, greys out unpickable stocks with a reason, and guarantees at least one pickable stock every round&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An off-by-one fix&lt;/strong&gt; (+30/-5), covered below&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spend validation&lt;/strong&gt; (+425/-5): works out how much a player can spend per pick under four different money rules, holding back enough cash to cover remaining picks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;140 tests pass on main, 122 of them for the engine, roughly two lines of test code for every line of engine code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three bugs, all caught after everything was green
&lt;/h2&gt;

&lt;p&gt;Lint, typecheck, the full test suite, and the build all passed on every pull request. An automated code reviewer ran on two of them and reported no actionable defects. It also could not run the tests in its own sandbox. All three bugs below were found by reading the code line by line against the written spec, not by any of the automated tooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 1: the shrinking board
&lt;/h3&gt;

&lt;p&gt;Classic Draft is supposed to show 5 stocks every round. Instead it went 5, 5, 5, 5, 4, 3, 2, 1.&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="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unownedIndustries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;industriesWithStock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;industry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;ownsIndustry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;industry&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;The one-per-industry board type was filtering out sectors the player already owned before drawing, a rule meant only for the same-industry board type. One committed test even asserted the shrinking 1-card board as correct behavior, since it was written from the buggy code instead of the spec. The fix draws from every industry with an available stock and greys out owned ones instead of removing them. Verified against 5,000 randomly generated game states across five rule sets: 0 violations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 2: the hold that never ends
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="nx"&gt;holdYears&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;rounds&lt;/span&gt;
&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="nx"&gt;holdYears&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;rounds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A stock bought in round 1 of a 5-round game with a 5-year hold needs a 6th round to auto-sell, which never comes. The check only warned when the hold was strictly longer than the game, not equal to it, so this exact setup passed with no warning. The original tests asserted that this case should not warn, which is how it slipped through.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 3: the lost cent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cash&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;picks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cash&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;picks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Floating point decimals like $0.57 are stored as something closer to 0.5699999, and flooring that drops a cent. Tested across every dollar amount from $1.00 to $10,000.00, split 2, 3, 5, and 8 ways: the old formula was wrong in 98,440 cases. The fix does the arithmetic in whole cents, which are exact integers. After the fix: 0 errors across 714,215 checked combinations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;A green checkmark tells you the code matches the tests. It does not tell you the code matches the spec, and a test written from the code instead of the spec can lock in a bug with just as much confidence as it confirms a fix.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/AryamanGandhi/app-store" rel="noopener noreferrer"&gt;https://github.com/AryamanGandhi/app-store&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Two Cline Features That Actually Changed How I Work: Permissions and Diff Explanations</title>
      <dc:creator>ethantao14</dc:creator>
      <pubDate>Wed, 26 Aug 2026 19:19:49 +0000</pubDate>
      <link>https://dev.to/ethantao14/two-cline-features-that-actually-changed-how-i-work-permissions-and-diff-explanations-1mk4</link>
      <guid>https://dev.to/ethantao14/two-cline-features-that-actually-changed-how-i-work-permissions-and-diff-explanations-1mk4</guid>
      <description>&lt;p&gt;I have been building the draft and portfolio builder side of a stock draft game using Cline, running on Sonnet through a Claude Console API key. Most of the writing about AI coding tools focuses on whether the code is good. That matters, but two other things ended up mattering just as much day to day: how much control I actually had over what the tool could do, and whether I could tell what it had just done. Here is a concrete look at both, pulled directly from this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permissions: a settings menu, not a guessing game
&lt;/h2&gt;

&lt;p&gt;Every agentic coding tool has to answer the same question. How much should it be allowed to do without asking first. Too restrictive and you spend your day approving trivial actions. Too permissive and one bad command becomes a real problem.&lt;/p&gt;

&lt;p&gt;Cline handles this with a straightforward auto-approve menu rather than anything hidden or inferred from a conversation. Here is the exact configuration used throughout this project.&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%2Fzywuwk9ut0p85ex4jlu3.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%2Fzywuwk9ut0p85ex4jlu3.png" alt="Cline's auto-approve settings menu" width="668" height="746"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Cline's auto-approve settings menu.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Breaking down what each toggle actually does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read project files / Read all files&lt;/strong&gt;, both on. The first scopes reads to files inside the current project. The second extends that to anywhere on disk. With this on, Cline never had to ask before opening a file for context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit project files&lt;/strong&gt;, on. &lt;strong&gt;Edit all files&lt;/strong&gt;, off. Cline could freely modify anything inside the project without asking, but editing something outside the project's boundaries required explicit approval each time. This is the one I would flag as the most important default. It gives an agent real freedom inside the sandbox of your repo while keeping a hard stop at the edge of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute safe commands&lt;/strong&gt;, on. &lt;strong&gt;Execute all commands&lt;/strong&gt;, off. Cline distinguishes between commands it considers safe, things like running a linter or test suite, and anything it cannot classify that way. Safe commands ran without interruption. Anything else needed a manual yes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the browser&lt;/strong&gt;, off. Cline never had a reason to browse during this project, so this stayed off by default rather than being something to remember to disable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use MCP servers&lt;/strong&gt;, on. This project used MCP tooling, so it was left enabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical effect: Cline moved quickly on everything that mattered for iteration speed, reading context, running lint and test commands, while the higher risk categories, editing arbitrary files outside the project, running arbitrary shell commands, browsing, stayed off unless deliberately turned on. None of this required trusting an opaque memory system or hoping a written instruction got remembered three sessions later. It was a set of checkboxes, visible at any time, adjustable in seconds.&lt;/p&gt;

&lt;p&gt;If you are evaluating a coding agent for a real project, this is worth checking early. Can you see, in one place, exactly what it is allowed to do, or do you have to infer it from behavior?&lt;/p&gt;
&lt;h2&gt;
  
  
  Clarity: a diff explanation you actually get, not one you have to ask for twice
&lt;/h2&gt;

&lt;p&gt;After Cline finishes a task, it shows two buttons next to its summary: View Changes and Explain Changes. View Changes is the raw diff. Explain Changes, when clicked, generates a plain-language explanation placed directly under the relevant code, file by file, with a reply box so you can ask a follow-up question right there, the same way you would comment on a pull request.&lt;/p&gt;

&lt;p&gt;Here is a real example from this project. A review pass caught that four tickers in the shared sector data list had no matching historical price file, meaning a user could draft one and have it silently vanish from their results. The fix was a small, scoped helper function rather than editing the shared data file directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/available-stocks.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;STOCKS_BY_SECTOR&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/data/sectors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Sector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Stock&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// A handful of tickers in the shared sector lists (data/sectors.ts) don't have&lt;/span&gt;
&lt;span class="c1"&gt;// a matching file in data/historical/, so picking them would silently show&lt;/span&gt;
&lt;span class="c1"&gt;// "No data" on the results page. Filtered out here, scoped to the draft flow,&lt;/span&gt;
&lt;span class="c1"&gt;// rather than editing the shared sectors list.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TICKERS_WITHOUT_HISTORICAL_DATA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HES&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="s2"&gt;PXD&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="s2"&gt;EMR&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="s2"&gt;ETN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAvailableStocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sector&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Stock&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="nx"&gt;STOCKS_BY_SECTOR&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sector&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;TICKERS_WITHOUT_HISTORICAL_DATA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clicking Explain Changes on the commit that wired this helper into the draft page produced this, directly under the diff:&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%2Fc10znvkdu1c6ev23tucd.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%2Fc10znvkdu1c6ev23tucd.png" alt="Cline explaining why the getAvailableStocks wiring change mattered" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Cline explaining why the getAvailableStocks wiring change mattered.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That explanation is not a changelog entry someone wrote after the fact. It is generated at the point of the change, describing not just what moved but why the one-line wiring change was the part that actually made the fix take effect in the running app. The reply box underneath means if that explanation is not enough, you do not have to open a new conversation and re-explain your own codebase to ask a follow-up. You ask it right there, with the diff still on screen.&lt;/p&gt;

&lt;p&gt;The same pattern showed up when a review pass flagged that the homepage was still 100% unmodified &lt;code&gt;create-next-app&lt;/code&gt; boilerplate, with zero link into the actual feature:&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%2F2x9opc3xzksu2bm8rxdn.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%2F2x9opc3xzksu2bm8rxdn.png" alt="Cline explaining the homepage rewrite" width="800" height="695"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Cline explaining the homepage rewrite.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Across a project where a dozen or more files can change in a single task, this is the difference between being able to explain your own code to a teammate afterward and quietly hoping they do not ask too many questions about a diff you half remember.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why both of these matter together
&lt;/h2&gt;

&lt;p&gt;Permissions and clarity solve different problems, but they compound. A tool that moves fast without asking permission for every action is only comfortable to use if you also know, clearly and immediately, what it just did and why. Cline's auto-approve menu gives you control over the blast radius. Explain Changes gives you visibility into what happened inside that radius. Neither one alone would have been enough to make me comfortable handing over a real feature build. Together, they made it a normal part of the workflow rather than something to babysit.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ethantao14/cline-stock-market-game" rel="noopener noreferrer"&gt;github.com/ethantao14/cline-stock-market-game&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
