Back to Writing
AI Engineering 2026-05-01

Blast Radius Analysis: Knowing What You'll Break Before You Ship

Fetch the PR diff, parse changed functions, filter generic noise names, then run ripgrep locally to trace every call site. A producer-consumer table generated in seconds — no SSH, no staging environment required. Here's the implementation.


The most common source of “looked right in isolation, broke a caller” regressions is shipping a change whose consumer impact was never measured.

You change a function. The change is correct for the ticket you’re fixing. You don’t know that 14 other files call that function, three of them with assumptions your change invalidates. The PR gets merged. Something breaks in production that has nothing to do with the reported bug.

Blast radius analysis is the practice of mapping the consumer impact of every change before the PR is created.


The Core Algorithm

  1. Fetch the PR diff from GitHub’s API
  2. Parse the diff to extract changed symbols: functions, classes, constants, interfaces, traits
  3. Filter out noise names — generic identifiers that produce false-positive matches
  4. For each remaining symbol, run a local ripgrep search to find every file that references it
  5. Return a producer-consumer table with risk levels

All of this runs locally. No SSH. No staging environment. No waiting for CI.


Parsing Changed Symbols from a Diff

The diff is unified diff format. Changed symbols appear on lines starting with + (added) or - (removed). For PHP, the patterns are:

function symbolName(
class ClassName
interface InterfaceName
const CONSTANT_NAME

For TypeScript/JavaScript:

function symbolName(
export function symbolName(
const symbolName =
class ClassName

A simple regex pass over the diff lines extracts candidate names. The important part is extracting name only — not the full signature — so the ripgrep search can find all call sites regardless of how the function is invoked.


The Noise Filter

Some function names are so generic that ripgrep returns hundreds of matches, most of them unrelated to the function you actually changed. These flood the output and make it useless.

Maintain a blocklist of noise names:

const NOISE_NAMES = new Set([
  'execute', 'render', 'run', 'get', 'set', 'init', 'index', 'handle',
  'create', 'update', 'delete', 'find', 'save', 'load', 'process',
  '__construct', '__destruct', '__toString', '__get', '__set', '__call',
]);

Any symbol in this set is skipped. The analysis only runs on symbols specific enough to have meaningful ripgrep results.


For each non-noise symbol, run ripgrep against the codebase:

const result = execSync(
  `rg --json -l "${symbol}" ${repoPath} --include="*.php"`,
  { maxBuffer: 10 * 1024 * 1024 }
);

The -l flag returns only file paths (not line content), keeping the output manageable. For each file found, run a second pass with line numbers to get context:

const lines = execSync(
  `rg -n "${symbol}" ${file}`,
  { maxBuffer: 1024 * 1024 }
);

The result is a list of { file, line, context } entries for each symbol — every place in the codebase that references the changed code.


Risk Levels and Thresholds

Not all consumer counts are equal. Apply risk tiers:

  • 0–3 consumers: low risk, proceed normally
  • 4–10 consumers: medium risk, include blast radius summary in PR description
  • 11–25 consumers: high risk, open PR as draft, flag for human review
  • 25+ consumers AND low confidence: block PR creation entirely

The block threshold exists because high consumer count combined with low confidence in the fix is the exact signature of “we might be about to break something important.” A human needs to review this before it merges.


The PR as Artifact

The blast radius summary becomes part of the PR description:

## Blast Radius

**Changed:** `calculateInvoiceTotal()`
**Consumers:** 8 files

Top consumers:
- `InvoiceController.php:142` — direct call in POST handler
- `InvoiceReport.php:89` — used in monthly summary export
- `SubscriptionRenewal.php:201` — called during billing cycle
- `InvoiceTest.php:44` — test coverage exists ✓

This makes the impact visible to human reviewers without requiring them to run their own analysis. The information that would have been discovered in a post-merge incident is now surfaced before the merge decision.


The ROI

Blast radius analysis takes 2–5 seconds for a typical codebase. It requires no infrastructure beyond a local checkout and ripgrep. The cost of running it on every PR is essentially zero.

The cost of not running it is a production regression that takes hours to diagnose because the connection between the change and the breakage isn’t obvious.

Build it as a mandatory pre-PR step. Make skipping it an explicit choice that has to be justified, not the default.