← all posts

My Pipeline Emailed Me Jobs I Already Applied For

August 2026

Yesterday morning, my job-search pipeline sent me its daily digest: 28 carefully ranked roles, LLM-scored against my CV. I opened it, and one thing was obvious.

Eight of those 28 jobs, I had already applied to.

Not *almost* applied. Not "worth re-checking." Applied. Submitted. All eight were sitting in my application tracker, some with the confirmation email still in my inbox. And the pipeline that was supposed to be *saving me time* had just spent its nightly GPU budget telling me to go do work I'd already done.

Two Systems, One Shared Fact

Here's the part that stings: nothing about this was mysterious. The data existed. My application tracker knew exactly which job IDs I'd applied to. The pipeline knew exactly which job IDs it was recommending. They were sitting on two different machines, writing to two different files, and nobody had bothered to teach one about the other.

This is the nature of rapid iterative development — if you don't pause and come up for air, you'll miss something obvious.

That's the real lesson, and it's not a job-search lesson. It's an architecture lesson. While you drive to business value, you may well want to check how much gas you're burning with the pedal always down to the floor. Microsoft just put the final nail in the coffin of the token-max phase of vibe coding, but in the rush to stand up the next new thing, frequent checkpoints can be a lifesaver.

This is a common problem space in automation projects. You build what was ordered, but your user base is still learning. If you don't pause and sync up, those automations you built will hit a wall eventually — the moment where two systems each hold half of a fact, and neither one knows the other half exists. The scraper knows what jobs are out there. The tracker knows what I've done. The gap between them is where the duplicate work lives.

The cost isn't the GPU cycles or the email; it's the *decisions* you almost make on bad information. You read a digest, see a strong fit, and start tailoring a CV for a role you already have an application in flight for. That's not a time sink — it's a compounding loss. Take a breath, pause, and evaluate your work.

The Fix Was Boring

The fix wasn't an LLM. It wasn't a clever new agent. It was a shared file and a rule:

1. The pipeline pulls the canonical tracker every morning.

2. Before it sends the digest, it marks every job in the ranked list that's already in the tracker.

3. The digest splits into "new jobs" and "already applied — skipped."

One file. One cross-reference. Twenty lines of Python. The next digest came back "22 new jobs analyzed (skipped 8 already applied)" — and I could trust it in a way I couldn't trust the previous one.

Testing a net-new workflow is already difficult; doing it at speed opens the door to mistakes. Making sure you can validate the data the system provides is a critical step in moving from MVP to production.

The Hard Part Was Testing the Loop, Not Building It

Anyone could have written that cross-reference. The part that took real work was convincing ourselves it actually *stayed* working — and that meant testing the loop the way it would actually be used, not the way it looked on paper.

My agent and I each checked the other's work. It built the filter; I sent the digest through it and read the output until the numbers lined up. Then we turned the test around: instead of waiting for a real rejection email to prove the scanner worked, we injected a fake one — a simulated "we've decided to move forward with other candidates" — and watched it flow through the whole chain.

Scan it. Classify it. Match it to the right application. Flip the status. Log it. Then we deleted the fake and confirmed the real tracker was untouched.

That last step matters more than it sounds. Testing a loop isn't just checking that happy path works — it's proving you can *undo* the test, that the system doesn't get confused by the machinery you used to verify it. A loop you can't cleanly test isn't a loop you can trust.

There's a temptation to treat agent-built systems as a black box — set it loose, assume it works, assume it'll keep working. But the same collaboration that built the pipeline is what keeps it honest. I spot what it can't see; it checks what I'd miss. Each of us is the other's test suite.

State Is the Product

We spend a lot of energy on the flashy parts of agentic systems — the models, the tools, the prompts. But the thing that actually makes an agent *reliable* is that it remembers what it's already done. An agent that doesn't share state with its own history isn't an agent; it's a function being called twice.

I built the same fix into the rejection side of the loop the same day. A daily scanner watches my inbox for status emails, classifies them, and writes them into the same tracker the pipeline reads. Now a rejection lands in the tracker automatically, the application's status flips, and nothing gets re-suggested. One state file. Everything reads it. Everything writes it. No system operates on a stale picture of what's already happened.

The Test for Any Automation

Before you ship your next pipeline, agent, or bot, ask one question: *does it know what's already been done?*

  • Does your CI re-run the work your deployment already did?
  • Does your alerting page you about the incident your on-call already acknowledged?
  • Does your sales tool re-queue the lead your team already contacted?
  • And once you've fixed the gap — can you prove the fix end to end, with a test you can undo?
  • If the answer is "no" — or worse, "it's on a different machine, it can't know" — you've found your next bug. It's not a hard one to fix. But it's a surprisingly expensive one to leave alone.

    My pipeline emailed me jobs I already applied for, and now it can't. That's the entire story — and it's the entire difference between a collection of tools and a system you can trust.

    #Automation #AgenticAI #Reliability #JobSearch

    Built on a home lab, powered by local models, and owned by Andrew Katana.

    Connect on LinkedIn →