Christopher L. Y. K. Rodrigues
Back to work

Overlap

Side project, 2026

Git only tells you about a conflict when you merge, so you find out late, at the pull request, after both sides have diverged enough to make the merge painful. Running several agents in parallel makes it worse, because there are more branches and more chances that two of them are quietly rewriting the same file.

Overlap watches the active branches on a repo and compares which files each one is changing. When two branches start overlapping, it tells you while the divergence is still small, and it grades how bad it is by how many files are involved.

The clearest picture of why it exists is a pull request where GitHub says there are no conflicts and merging can proceed automatically, while Overlap says three other branches are editing the same files right now. Both are right. Git is answering a question about the base branch at merge time, and Overlap is answering one about the work that’s still in progress.

It started as three deployed services plus a worker that never stopped running, which is a strange setup for something that only has work to do when someone pushes. It’s one app now. I folded the API into the web server and replaced the worker with durable workflows that wake up on a webhook and go back to sleep. It runs on Postgres with Drizzle, hosted on Vercel and Neon.

Built with

TypeScript, Turborepo, Drizzle, Postgres, Vercel

github.com/crodris/Overlap

What I decided

I replaced the job queues with a durable workflow
The old version ran two independent queues. One synced a branch’s changed files and the other compared them, and nothing ordered them, so the code had a 5 second delay and a comment hoping the sync finished first. When it didn’t, detection read a stale file list and reported the wrong overlaps without any error. The durable workflow guarantees the sync finishes before the comparison starts, and the delay is gone. That ordering is the whole reason I picked workflows, since two queue topics would have had the same race.
I let the database rebuild itself from GitHub
Almost every table here is a cache of something GitHub already knows: repositories, branches, which files a branch touched, and which overlaps exist. Only a handful of rows were actually mine. So when I moved hosts, I created an empty schema, let the app repopulate itself from GitHub, and didn’t restore a dump. That made the cutover its own test. If the pipeline rebuilt the same branches and overlaps the old host was showing, the migration worked. It also meant I didn’t carry over any rows a bug had already corrupted.
The move off Railway had to actually save money
Most of what I was paying for was a worker that ran all day and sat idle most of the time. I nearly replaced a $5 a month worker with a $10 a month database, because the free credit on the host I picked first was already spent on another project. Checking that before I committed turned a migration that would have cost more into one that costs less. Now the compute scales to zero between webhooks, which suits an app that only has work to do when someone pushes.
The rewrite turned up bugs I didn’t know I had
Porting the worker made me read error handlers I hadn’t looked at in months. One caught a failed GitHub call, set the file list to empty, and then deleted every tracked file for that branch, so a brief GitHub outage could wipe a branch’s index and make real overlaps disappear from the UI with no error anywhere. Another swallowed check run failures entirely. Neither would have shown up as a bug report. Overlap would just have been wrong sometimes, for no reason anyone could see.