DEV Community

Vojta Holeš
Vojta Holeš

Posted on

The 3am Production Incident That Made Me Build BreakShield CI

It was 3am when my phone started ringing.

Our API was down. Half the app was broken. Users were angry. The on-call engineer was panicking.

After two hours of debugging we found it. Someone had removed the email field from UserResponse. Three other services were using it. Nobody caught it in code review. Nobody even knew those services existed.

We fixed it. Deployed at 5am. Wrote the post-mortem. Added it to the "lessons learned" doc that nobody reads.

Three months later it happened again.


The problem nobody talks about

Every team I've worked with has the same issue.

You have a TypeScript interface. It's used in 6 places across 4 different files. You remove one field. You open a PR. Your teammates review it. Nobody catches it because nobody knows about those 6 places.

The tests pass. The build passes. You merge.

And then production breaks.

The scary part? This isn't a skill issue. Senior engineers with 10 years of experience make this mistake. It's a tooling problem. Code review wasn't designed to catch this.


What I built

I spent a weekend building BreakShield CI — a GitHub App that does one thing:

Catches breaking API changes before you merge.

When you open a pull request, it automatically:

  1. Parses your TypeScript interfaces and OpenAPI specs with a full AST
  2. Finds every place in your codebase that uses the changed API
  3. Shows you exactly which file and which line will break
  4. Posts a report directly in your PR
  5. Blocks merge if the risk is HIGH or CRITICAL

No config. No CLI. No YAML. Install once, works on every PR forever.


What it looks like in practice

You remove email from UserResponse. BreakShield CI posts this in your PR:

🔴 HIGH RISK — 1 breaking change

UserResponse.email — removed field File: src/types/user.ts Confidence: 94% — AST-verified

2 consumers affected:

src/components/UserCard.tsx:23 return ${user.name} <${user.email}>

src/pages/profile.tsx:41 const { email, name } = user

Your teammate sees this. They don't need to know the codebase. They don't need to grep for usages. The information is right there.


Why AST and not regex

Most tools use regex to find breaking changes. Regex lies.

If your interface has a field called emailAddress and you search for email, regex will find it. AST won't — because AST actually understands your code.

BreakShield CI uses ts-morph to parse a full TypeScript AST. It knows the difference between a property access, a destructuring, and a type annotation. Every finding is verified at the compiler level.

If there's no evidence — there's no warning. No noise, no false positives.


The 3am call I didn't get

Last week a teammate removed a field from a shared interface. BreakShield CI caught it. The PR comment listed 4 consumer files. We updated them before merging.

I didn't get a 3am call.

That's the whole point.


Try it

BreakShield CI is free during beta. It takes 30 seconds to install.

👉 breakshield-ci.vercel.app

If you've ever had a 3am production incident caused by a breaking change — you know exactly why I built this.

Top comments (0)