Case Study - One job, one link: the cleanup that almost erased my progress

A private job search tracker where an AI agent finds roles and every application lives in one place.

Client
JobSeeker
Year
Service
Senior web development, code review

The product

JobSeeker is a private, invite-only job search tracker. An AI scout agent searches for roles that match what I'm looking for, skips ones it has already seen, and adds new ones to a dashboard. From there I move each job through its status, keep notes, and track which version of my resume and cover letter went with each application. It's kept out of search engines on purpose.

One ticket, start to merged PR

The scout checks whether it has already seen a job before saving it. But the same job can show up with a slightly different link, such as one ending in a slash, and then it gets saved twice. The request was to store every link in one standard form and clean up the duplicates already saved.

  1. The ticket. I wrote the request with clear acceptance criteria: store each link in the same standard form the scout uses to check for duplicates, keep saving and checking consistent, and decide how to handle the duplicates already saved.
  2. The build. My AI coding tools built the change on its own branch and opened one pull request, with a one-time cleanup that merges old duplicates.
  3. Review, round one. The change to how links are saved was sound. The cleanup was not. In the most likely real case, an older copy I had already moved to Applied next to a fresh copy the scout saved again, it kept the fresh copy and deleted mine. My progress would be gone and the job would show up as new. Jobs I had dismissed would have come back the same way. It would also have merged copies it couldn't tie to an owner.
  4. The fix. The cleanup now keeps whichever copy I last acted on, skips anything it can't tie to an owner, writes a backup before it changes anything, and undoes a merge if any step fails. It runs as a dry run unless it is told to apply.
  5. Review, round two. A second review re-ran every case, including a crash partway through a merge, and approved it.
  6. Human review and merge. I reviewed the final diff and merged.

32 minutes from starting the work to merged PR, including one review round and the fix.

The follow-up: bad links and smarter matching

The first review flagged two things for a later ticket: links that aren't web addresses at all, and links that differ only by things like tracking tags or capital letters. The follow-up rejects anything that isn't a normal web link and matches links more carefully.

  1. Review, round one. Review found two problems, and both mattered because the cleanup rewrites saved links for good the first time it runs. Removing a tracking tag quietly changed the rest of the link, so the same job could still end up saved twice. And some career sites put the job inside the part of the link after the # sign, so stripping that part would have merged different jobs into one and overwritten one with the other.
  2. The fix. The rest of the link now stays exactly as it was when a tracking tag is removed, and links that use that part to point at a specific job keep it.
  3. Review, round two. The re-review checked both fixes on a test database and approved them.
  4. Human review and merge. I reviewed the final diff and merged, 18 minutes after the pull request opened.

What review caught

  • The duplicate cleanup would have deleted jobs I had already applied to and brought back jobs I had dismissed.
  • It would have merged copies it couldn't tie to an owner.
  • Removing a tracking tag changed the rest of the link, so duplicates could slip through.
  • Different jobs on some career sites would have been merged into one.

The fix for duplicate jobs looked simple. Review found the cleanup would have deleted the jobs I'd already applied to.

Where it stands

Both changes are live. Every link the scout saves now goes through the same standard form, and links that aren't real web addresses are turned away, so new duplicates are caught before they are saved. I ran the one-time cleanup for older duplicates on my real data, as a dry run first and then applied. With its dry run, backup and rollback, it now runs safely against real data.

Between October 1 and November 8, 2026, the project closed 41 tickets and merged 37 pull requests.

next

Want to talk it through first?

Book a free intro call and we'll see if we're a good fit.

Schedule a call