<?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: AI Applyd</title>
    <description>The latest articles on DEV Community by AI Applyd (aiapplyd).</description>
    <link>https://dev.to/aiapplyd</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%2Forganization%2Fprofile_image%2F14876%2F375b7b60-e514-4d40-a0f3-38b0e28e4d3b.png</url>
      <title>DEV Community: AI Applyd</title>
      <link>https://dev.to/aiapplyd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aiapplyd"/>
    <language>en</language>
    <item>
      <title>Four things that cost us money while automating job applications</title>
      <dc:creator>Ava Bagherzadeh</dc:creator>
      <pubDate>Tue, 22 Sep 2026 14:52:46 +0000</pubDate>
      <link>https://dev.to/aiapplyd/four-things-that-cost-us-money-while-automating-job-applications-1l51</link>
      <guid>https://dev.to/aiapplyd/four-things-that-cost-us-money-while-automating-job-applications-1l51</guid>
      <description>&lt;p&gt;Filling a job application is a browser-automation problem that looks solved and is not.&lt;/p&gt;

&lt;p&gt;We run an MCP server that applies to jobs end to end on the employer's own hiring system. Fifteen applicant tracking systems: Greenhouse, Lever, Ashby, Workday, iCIMS, Personio, Teamtailor, SmartRecruiters, Recruitee, Breezy, Workable, Rippling, BambooHR, JazzHR and softgarden. Here are four things that cost us real money to learn.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Scoring on your own input is not evidence
&lt;/h2&gt;

&lt;p&gt;The first version reported success when the upload call returned &lt;code&gt;staged: true&lt;/code&gt; and the field read back &lt;code&gt;files: 1&lt;/code&gt;. Both were true. Zero bytes reached the server.&lt;/p&gt;

&lt;p&gt;The automation library took a different code path on a remote browser and sent nothing, while every counter we owned said it had worked. We were reading our own writes back and calling it proof.&lt;/p&gt;

&lt;p&gt;The rule we run on now: &lt;strong&gt;never score on a read-back of your own input.&lt;/strong&gt; Only score on something the other side produced. A request on the wire. A confirmation page. An email from the employer. &lt;code&gt;submitted: true&lt;/code&gt; is a variable you set. It is not a receipt.&lt;/p&gt;

&lt;p&gt;This generalises well past job forms. If your integration test asserts on state your own code wrote, it asserts nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. An empty result is not a zero until you prove you were watching
&lt;/h2&gt;

&lt;p&gt;We spent 23 debugging sessions reading logs that showed nothing wrong. Nothing was wrong in the logs. The instrument started 18 seconds after the event it was supposed to measure, so a working fix and a total failure produced identical output: silence.&lt;/p&gt;

&lt;p&gt;Before you believe any empty list, prove three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The instrument was armed at all, at the right scope.&lt;/li&gt;
&lt;li&gt;It was armed &lt;strong&gt;before&lt;/strong&gt; the event and still armed after.&lt;/li&gt;
&lt;li&gt;The mechanism works when a human does it. Then diff the human run against yours. The divergence is the bug.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you cannot prove all three, the correct word is not "absent". It is &lt;strong&gt;unobserved&lt;/strong&gt;. Write that down instead, and go fix the instrument before you touch the subject.&lt;/p&gt;

&lt;p&gt;We found the upload bug in minutes once we stopped reading logs and opened the page in a real browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. HTTP 200 is not success, and a 200 from an SPA is not even a page
&lt;/h2&gt;

&lt;p&gt;Two separate versions of this one bit us.&lt;/p&gt;

&lt;p&gt;A provider returning an overloaded-service message &lt;strong&gt;inside the body of a 200&lt;/strong&gt; made our SDK classify it as a schema validation failure. We spent a day looking for drift in a parser that was fine. Match the error text, not the status code.&lt;/p&gt;

&lt;p&gt;Separately, while surveying sites this week, several returned 200 for &lt;code&gt;/submit&lt;/code&gt;, &lt;code&gt;/add-tool&lt;/code&gt;, &lt;code&gt;/new&lt;/code&gt; and four other paths that do not exist. They are single-page apps with a catch-all route. A 200 there proves the server answered. It says nothing about whether the page exists. Read the body.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A list that is still rendering is not a list
&lt;/h2&gt;

&lt;p&gt;Dropdowns were harvesting exactly one option. The code waited for a loading placeholder to disappear, which it did, correctly, while the list kept painting rows behind it.&lt;/p&gt;

&lt;p&gt;Waiting for the absence of a spinner is not the same as waiting for the presence of the data. We now settle on &lt;strong&gt;count stability&lt;/strong&gt;: read the option count, wait, read it again, and only proceed when it stops changing. One field went from 1 option to 7.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that has no clever fix
&lt;/h2&gt;

&lt;p&gt;The distinction we built the product around is that an application is not "sent" because we clicked submit. It is sent when the employer's system says it received it. Those are different events and only one of them is checkable.&lt;/p&gt;

&lt;p&gt;Most of the engineering above exists to keep that honest, because the tempting version, where your own click counts as the outcome, is much easier to build and quietly useless to the person waiting for an interview.&lt;/p&gt;




&lt;p&gt;The MCP server is public and works in Claude, ChatGPT and Cursor over streamable HTTP at &lt;code&gt;https://mcp.aiapplyd.com/mcp&lt;/code&gt;. Source mirror: &lt;a href="https://github.com/aiapplyd/aiapplyd-mcp" rel="noopener noreferrer"&gt;github.com/aiapplyd/aiapplyd-mcp&lt;/a&gt;. The product is &lt;a href="https://aiapplyd.com" rel="noopener noreferrer"&gt;AI Applyd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy to answer anything about the ATS-specific parts. Workday alone is worth its own post.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
