<?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: amzi smith</title>
    <description>The latest articles on DEV Community by amzi smith (@amzi_smith_dcf6ed9560d191).</description>
    <link>https://dev.to/amzi_smith_dcf6ed9560d191</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%2F4136159%2Fff0e8a95-1570-4679-ba3d-c7e4a164e078.png</url>
      <title>DEV Community: amzi smith</title>
      <link>https://dev.to/amzi_smith_dcf6ed9560d191</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amzi_smith_dcf6ed9560d191"/>
    <language>en</language>
    <item>
      <title>What was your win this week?</title>
      <dc:creator>amzi smith</dc:creator>
      <pubDate>Tue, 29 Sep 2026 15:31:00 +0000</pubDate>
      <link>https://dev.to/amzi_smith_dcf6ed9560d191/what-was-your-win-this-week-3e7e</link>
      <guid>https://dev.to/amzi_smith_dcf6ed9560d191/what-was-your-win-this-week-3e7e</guid>
      <description>&lt;p&gt;I wasn't a programmer. With Claude, I built ad software with paying customers for $10,000 and 2,200 hours.&lt;br&gt;
My day job is making wood finishes. My business sells them on Amazon, Shopify, Walmart and through wholesale reps. Nobody would have picked me to build software.&lt;/p&gt;

&lt;p&gt;I built it anyway. RedHen Labs is Amazon advertising software with paying customers. It tracks profit by campaign, automates bids and harvests keywords from search-term reports. It charges a flat monthly fee instead of a percentage of ad spend, which is how most agencies bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$10,000&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;About 2,200 hours&lt;/strong&gt;, roughly one full-time working year&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few years ago, competing with Helium 10 and the big Amazon ad agencies took a development team and a couple of million dollars.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI changed, and what it didn't
&lt;/h2&gt;

&lt;p&gt;AI didn't make this easy. 2,200 hours is a year of work.&lt;/p&gt;

&lt;p&gt;It changed which barrier stands in the way. The old barrier was money and connections: you had to raise capital and hire developers before you could even find out whether your idea worked. The new barrier is time and stubbornness. Most people will never have $2 million, but a lot of people can find the hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access, not ability
&lt;/h2&gt;

&lt;p&gt;Daniel He4rt recently wrote &lt;a href="https://dev.to/danielhe4rt/youre-not-an-impostor-you-just-started-from-a-different-line-2lph"&gt;"You're not an impostor, you just started from a different line"&lt;/a&gt;. His argument is that many developers who feel like impostors are up against unequal access, not a lack of ability. I think AI is starting to close that gap, including for people like me, who weren't on any starting line at all.&lt;/p&gt;

&lt;p&gt;Anthropic just launched a $200 million fund to study AI's economic effects. It only funds institutions, and every research priority assumes AI will leave ordinary people behind. I wrote them an open letter. Here it is in full.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Crisis Is Access, and AI Is the Cure, Not the Cause
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;An open letter to the Anthropic Economic Futures team&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your new $200 million fund starts from the assumption that AI's big economic story is disruption: displaced workers, weaker safety nets, jobs to replace. All five of your research priorities are about cushioning the losses.&lt;/p&gt;

&lt;p&gt;I think you're studying the wrong crisis.&lt;/p&gt;

&lt;p&gt;The crisis of our time is not AI taking jobs. It's wealth piling up with the small group of people who have always had access: to capital, to developers, to expertise, to education and to the right networks. For generations, that access has been the dividing line between people who build wealth and people who work for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI is erasing that line.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I make wood finishes in central Pennsylvania, and I'm not a programmer. A few years ago, competing with Helium 10 and the big Amazon ad agencies took a development team and a couple of million dollars. Working with Claude, I built RedHen Labs, an Amazon advertising platform with paying customers, for &lt;strong&gt;$10,000 and about 2,200 hours of my own time&lt;/strong&gt;, roughly one working year. I'm not telling you this to sell anything. I'm telling you because it would have been impossible for someone like me five years ago.&lt;/p&gt;

&lt;p&gt;And I'm not unusual. Picture the man who paints lines on city roads, sick of sitting in the traffic his crew creates. Tonight, with a $20 AI subscription, he can build a small tool that predicts traffic from public data and schedules the work around it. Five years ago, that idea died in his truck. Someone with no degree and no connections can now dig into ideas deep enough to redefine how distributed systems work. And AI is becoming the teacher Google never quite became: patient, personal and available to anyone for twenty dollars a month.&lt;/p&gt;

&lt;p&gt;This isn't redistribution by taxes or programs. It's redistribution by competition. When the barriers fall, markets locked up by a few players open to millions of people with good ideas. That is capitalism working the way it's supposed to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which is why your fund's design is so troubling.&lt;/strong&gt; It takes no individuals, funds nothing under $1 million, and routes every dollar through institutions. It predicts that AI will leave ordinary people behind while building a fund that leaves them out. That's the old model of access, the very thing AI is dismantling.&lt;/p&gt;

&lt;p&gt;Anthropic, of all companies, should want the other side of this story studied: where AI is creating new owners, not just displaced workers, and how fast wealth moves when access stops being scarce. That research doesn't exist yet. The evidence for it is being created right now, by people your fund can't hear from.&lt;/p&gt;

&lt;p&gt;I'd like to talk about what that research could look like. Let's change the conversation from doom to access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. Smith&lt;/strong&gt;&lt;br&gt;
Rowdy Rooster Woodworks · RedHen Labs · Pennsylvania&lt;br&gt;
&lt;a href="mailto:Contact@rrw-ads.com"&gt;Contact@rrw-ads.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>weeklyretro</category>
      <category>ai</category>
      <category>showdev</category>
      <category>startup</category>
    </item>
    <item>
      <title>Amazon's advertising API docs return HTTP 200 for every URL, including ones that don't exist</title>
      <dc:creator>amzi smith</dc:creator>
      <pubDate>Mon, 21 Sep 2026 17:01:35 +0000</pubDate>
      <link>https://dev.to/amzi_smith_dcf6ed9560d191/amazons-advertising-api-docs-return-http-200-for-every-url-including-ones-that-dont-exist-55ao</link>
      <guid>https://dev.to/amzi_smith_dcf6ed9560d191/amazons-advertising-api-docs-return-http-200-for-every-url-including-ones-that-dont-exist-55ao</guid>
      <description>&lt;p&gt;That project is now 2,140 commits, 189 database migrations and 3,436 tests. It runs my account every night, and a handful of other people's.&lt;/p&gt;

&lt;p&gt;Almost nothing that slowed me down was code. What slowed me down was that the documentation described a system slightly different from the one that was actually answering my requests. These are the specific things I wish someone had told me on day one. Four of the five are not Amazon-specific at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The docs site returns 200 for pages that were never real
&lt;/h2&gt;

&lt;p&gt;Run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://advertising.amazon.com/API/docs/en-us/sponsored-products/3-0/openapi"&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://advertising.amazon.com/API/docs/en-us/this-page-does-not-exist-abc123"&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://advertising.amazon.com/API/docs/en-us/completely/made/up/nonsense/xyz789"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three return &lt;code&gt;200&lt;/code&gt;. I invented the last two.&lt;/p&gt;

&lt;p&gt;It is a single-page app. The server hands back the same HTML shell for every path and the route gets resolved in the browser, so anything that judges a page by its status code gets a confident yes for a URL that never existed. That includes your link checker, your scraper, and any AI agent you hand a documentation URL to.&lt;/p&gt;

&lt;p&gt;I lost most of a day to this. I had asked an assistant to read a docs page, it fetched a URL that resolved to the shell, and it summarized the shell back to me as though it were the page. The summary was plausible and entirely invented. Nothing in the pipeline failed loudly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson that generalizes:&lt;/strong&gt; for any SPA-served docs site, a status code is not an existence check. Assert on something only the real page contains.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The real OpenAPI specs are not on the docs site
&lt;/h2&gt;

&lt;p&gt;I spent a long time trying to scrape endpoint definitions out of rendered HTML before finding that the actual machine-readable specs sit on a CDN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://d1y2lf8k3vrkfu.cloudfront.net/openapi/en-us/dest/SponsoredProducts_prod_3p.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a 652 KB OpenAPI document — every endpoint, every model, every enum. Swap the product name for the other ad types.&lt;/p&gt;

&lt;p&gt;It is not linked from anywhere obvious. Once I had it, a whole category of guesswork disappeared: I stopped inferring request shapes from prose and started reading them from the schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson that generalizes:&lt;/strong&gt; before you scrape a docs site, spend twenty minutes looking for the artifact the docs site is itself rendering. It is usually there and it is usually better.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. A 429 does not always come from the API
&lt;/h2&gt;

&lt;p&gt;We started getting throttled on one endpoint. The obvious reading was that we were calling it too much, so the obvious fix was to slow down.&lt;/p&gt;

&lt;p&gt;That was wrong, and it took real measurement to see it. Our total call volume had been flat for ten days. The refusal rate climbed while that particular endpoint's volume &lt;em&gt;fell&lt;/em&gt;. And the API's own logs showed zero throttles — because the requests were never reaching the API. Something in front of it was answering.&lt;/p&gt;

&lt;p&gt;The tell is in the headers. A response that genuinely came from Amazon's API carries &lt;code&gt;x-amzn-requestid&lt;/code&gt;. An edge or CDN layer refusing you before the request lands does not have one to give.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x-amzn-requestid present  -&amp;gt; the service throttled you. Back off.
x-amzn-requestid absent   -&amp;gt; something in front of the service refused you.
                             Backing off may not help at all.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those two situations look identical in a log line that only records the status code, and they need opposite responses. Log the request id, or you will spend a week tuning a backoff against a wall that does not care how slowly you knock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson that generalizes:&lt;/strong&gt; when an external system rejects you, establish &lt;em&gt;which&lt;/em&gt; system rejected you before you design around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The query that quietly returns exactly 1,000 rows
&lt;/h2&gt;

&lt;p&gt;Not Amazon. This one is PostgREST, which means Supabase, which means a lot of people reading this.&lt;/p&gt;

&lt;p&gt;A plain select has a default ceiling. Ask for 4,000 rows and you get 1,000, with no error, no warning, and no flag on the response saying it truncated. Your code carries on and treats a quarter of the data as all of it.&lt;/p&gt;

&lt;p&gt;The reason it is nasty is that it is invisible until you cross the line, and it stays invisible afterward. Every symptom looks like a data problem somewhere else.&lt;/p&gt;

&lt;p&gt;Two habits fixed it for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat a result length of exactly your limit as &lt;em&gt;suspicious by default&lt;/em&gt;, not as a complete answer.&lt;/li&gt;
&lt;li&gt;Page explicitly with &lt;code&gt;.range()&lt;/code&gt; when a set can plausibly grow past the cap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I now have a shared helper for this, because I did not want the decision to be made independently in forty places.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. An update that changed nothing reports success
&lt;/h2&gt;

&lt;p&gt;Also PostgREST, same family of problem.&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;campaigns&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;daily_budget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no row matches that id, this is not an error. It is a successful update of zero rows. You get no exception and, unless you asked for the rows back, nothing to tell you the write did not land.&lt;/p&gt;

&lt;p&gt;I had writes silently doing nothing for a while before I noticed. Where the row genuinely ought to exist, &lt;code&gt;.upsert()&lt;/code&gt; says what I actually meant. Where it might not, I check the returned count instead of trusting the absence of an exception.&lt;/p&gt;

&lt;p&gt;Related, and it caught me twice: &lt;code&gt;.eq()&lt;/code&gt; never matches &lt;code&gt;NULL&lt;/code&gt;. That is correct SQL, and it is still surprising when a filter you think is exhaustive silently excludes every row where the column was never set. A two-value filter quietly becomes a three-value problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  What building this as a non-engineer actually taught me
&lt;/h2&gt;

&lt;p&gt;I use AI assistants heavily. I could not have built this without them. But the thing that made the difference was not the code they wrote — it was learning, slowly and expensively, that a confident answer is not a verified one.&lt;/p&gt;

&lt;p&gt;Every problem above has the same shape. Something returned a value that &lt;em&gt;looked&lt;/em&gt; like an answer. A 200 that was a shell. A thousand rows that were four thousand. A successful write that wrote nothing. A 429 from something that was not the API.&lt;/p&gt;

&lt;p&gt;None of those announce themselves. They all read as success. And an AI assistant reading the same signals will tell you everything is fine, in fluent and reassuring prose, because everything it can see says so.&lt;/p&gt;

&lt;p&gt;So the habit I have built, which is the only real skill I have picked up in ten months, is to ask one question before believing anything:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If this had failed, what would I be looking at right now?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the honest answer is "exactly what I am looking at," then I have not checked anything yet. That question has caught more bugs than any tool I own.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://rrw-ads.com" rel="noopener noreferrer"&gt;RedHen Labs&lt;/a&gt;, flat-fee Amazon advertising software. The SP-API code examples and an MIT-licensed search term report parser are public at &lt;a href="https://github.com/elementenergy41-cell/RedHen-Labs" rel="noopener noreferrer"&gt;github.com/elementenergy41-cell/RedHen-Labs&lt;/a&gt;, along with a break-even calculator you are welcome to host on your own site.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>documentation</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
