Technology Aug 23, 2026 · 5 min read

I built a robot that applies for jobs. The hard part was proving it worked.

The demo was never the problem. A browser agent that opens a job posting, reads the form, writes your history into it and clicks submit is a weekend of work now. It looks like magic in a screen recording. You can film one this afternoon. The problem is the sentence you have to say afterwards: it w...

DE
DEV Community
by Ava Bagherzadeh
I built a robot that applies for jobs. The hard part was proving it worked.

The demo was never the problem.

A browser agent that opens a job posting, reads the form, writes your history into it and clicks submit is a weekend of work now. It looks like magic in a screen recording. You can film one this afternoon.

The problem is the sentence you have to say afterwards: it worked.

I spent one full day, eight hours and seventeen minutes, and twelve real applications on real postings, chasing four failures. I landed none of them. Every experiment cost about fifty-six minutes, because most of that was waiting for a deploy to reach the machines that run the applications before the test could even begin.

Three separate fixes to one small function shipped fifty-five minutes apart, then fifty-four minutes apart. All three were properties of the same HTML element, and all three were findable in a single pass with a browser open in front of me.

The whole time, a local test rig was running on my own laptop. Thirty-six hours of uptime. Its log recorded zero bytes during my entire working day.

The actual bug, when I finally opened the page like a person instead of reading logs like a detective, took two minutes. A field I was reading as a textarea was an input.

Production is a verifier, not a debugger

That is the rule I got out of the day, and it cost enough that I now enforce it in writing.

A production run answers exactly one question: does this hold in the real world. It answers that question expensively, slowly, and once. Using it to find a bug means paying full price for every guess, and you will guess a lot, because the feedback arrives an hour later stripped of everything you needed.

A local rig answers a hundred cheap questions badly and one expensive question not at all. That is the correct division. Look at the page, fix it locally, verify it locally, and only then spend a real run on the things a laptop structurally cannot answer: capacity, queueing, anti-bot behaviour, the employer's actual response.

The order matters more than the tooling. Look, then fix, then verify, then spend. I had it backwards for a day.

The instrument is the thing that lies

Here is the deeper version, and it is the single most useful idea I have taken out of building this.

Most of my hardest bugs were not bugs in the system. They were bugs in the thing measuring the system.

  • A form field reported as filled, because the check read back our own typing rather than asking the widget what it had committed. Seventeen fields, all confirmed, all empty.
  • A metric that read zero for a feature that was working perfectly, because the measurement armed itself eighteen seconds after the event it was supposed to measure.
  • A watchdog that killed live sessions for going quiet, when quiet was what a long submission looks like. Its own reset then removed the signal that would have told it so, which made it produce the next reason to fire.
  • A daily alarm that paged me at full severity for an incident I had already fixed the previous afternoon, because it computed its rate over a rolling twenty-four hours and the burst was still inside the window.

Every one of those looked exactly like a broken product and was in fact a broken measurement. The failure mode is symmetrical and horrible: you fix things that were never wrong, and you ignore things that are.

So I wrote a rule and put it where I cannot avoid reading it:

An absence is not evidence until you have proved you were watching. Prove the instrument was armed at all, prove it was armed before the event and still armed after, and prove the mechanism works when a human does it by hand. If you cannot prove all three, the correct word is unobserved, not absent.

The distance between absent and unobserved is where most of my wasted engineering time has lived.

Why this ends up being the product

Once you have been fooled by your own telemetry enough times, you stop trusting any signal you generate yourself. And the moment you apply that to a job application tool, the entire design falls out of it.

Our own click is not evidence. Our own screenshot is not evidence. Our own status field is not evidence. The only thing that proves an application exists is the company's own system replying, and that reply arrives at an address we control, gets classified, and is the only thing that moves an application to sent.

It is a harder product to build and a much easier product to trust, and it means the number on the dashboard is the one number I cannot fake for myself.

That is not a marketing position. It is what is left after you stop believing your own instruments.

I am Ava Bagherzadeh, building AI Applyd as a solo founder. It scores, tailors and submits applications on the company's own hiring system, and only counts one as sent when that company confirms it. Interviews on your calendar, not rejection emails in your inbox.

DE
Source

This article was originally published by DEV Community and written by Ava Bagherzadeh.

Read original article on DEV Community
Back to Discover

Reading List