Trace Callers Before the Diff: A Blast-Radius Card for Shared OSS Helpers

When a contributor tweaks a shared helper, hidden callers can break downstream modules. A blast‑radius card documents all call sites before the diff, allowing reviewers to see the full impact. The article explains how to harvest callers, build a contract table, and run a frozen review to catch regr…

Open‑source projects often rely on small, shared helpers that live behind multiple import paths, generated shims, and optional extras. When a contributor proposes a change—such as tightening a timeout—file‑local tests may pass, but the patch can still break other modules that import the helper through a different route. The solution is to build a blast‑radius card that lists every place the helper is called, so reviewers can see the full impact before the code lands.

Why File‑Local Tests Aren’t Enough

File‑local tests answer a narrow question: does the hunk under the cursor still work with its immediate fixtures? They do not guarantee that other import paths, generated files, or optional extras still compile, type‑check, or honor the new timeout. A green test in the same directory can hide a failing call in a different module that the contributor never touched.

Creating the Blast‑Radius Card

The card is a single Markdown file—BLAST_RADIUS.md—kept in the branch as a merge gate. It contains a template that the author fills from the working tree, not from memory:

  • Issue: link to the PR or issue
  • Symbol(s) under change: the helper name
  • Public signature before / after: old and new signatures
  • Intended behavior change: one‑sentence description
  • Forbidden behavior change: what must not happen
  • Call sites harvested: path:line for each caller
  • Call sites excluded, with reason: e.g., generated file
  • Tests that must change / stay green: list of test files
  • New dependency allowed: yes/no
  • Rollback note: any special instructions

Three rules keep the card honest:

  • Every listed call site must be reproducible from a clean checkout.
  • Every excluded path must cite an import boundary or generated file.
  • The intended behavior change must fit in one sentence.

Harvesting Call Sites

Start from a clean branch that tracks the issue. Record the helper’s symbol names—including aliases and re‑exports—before editing. Use a combination of git status, git rev‑parse, and ripgrep to find every occurrence of the helper name in the tree, excluding test directories and generated files. For example, to find calls to apply_timeout you might run:

rg -g '!vendor/**' -g '!dist/**' -g '!__pycache__/**' 'apply_timeout' --files-with-matches

Each hit is added to the card with its path and line number. Classify each hit as a direct caller, re‑export, wrapper, test double, or noise. Noise is removed only when the file cannot import the symbol at runtime, and the reason is noted beside the exclusion.

Building the Contract Table

After the harvest, freeze a contract table that maps each caller to its observable behavior before and after the change. The table has columns for input, old observable, new observable, and owner. For example:

| Input | Old observable | New observable | Owner |
|-------|----------------|----------------|-------|
| cmd/sync.py:88 | HTTP timeout 30s | 5s | tests/cmd/test_sync.py |
| worker/retry.py:41 | retry wrapper timeout inherits helper | 30s | tests/worker/test_retry.py |
| compat/old_api.py:12 | re‑export same signature | same signature | tests/compat/test_export.py |

If the table has more than five rows, split the work into separate issues to keep each patch focused.

Writing the Diff Against the Card

Once the card and table are committed, edit the production code only within the symbols listed in the card. Reject any drive‑by formatting changes in files that are not call sites. When a wrapper needs a new argument, add it as an explicit keyword with a default that preserves the forbidden behavior change. After the diff, run the owner tests first to confirm the new observable. A patch that leaves every owner test untouched demonstrates that the change behaves as promised.

Frozen Review with a Language Model

After the blast‑radius card, contract table, and tests exist, a second pass can interrogate those files without extra narrative. The reviewer feeds the card, harvest file, contract table, and diff into a language model prompt that asks for:

  • Call sites in the diff not listed in the card.
  • Call sites on the card that the diff does not touch.
  • Owner tests that did not move for a changed observable.
  • Signature changes that violate the forbidden behavior line.

Any finding must be confirmed with a failing test or a reproducible call before the author changes code. This checklist keeps the review focused on the actual risk, not on narrative or speculation.

When to Skip the Card

The workflow assumes searchable call sites and tests that can name an observable. It may be noisy in monorepos with generated parsers or binary plugins. Authors should skip the full card for minor comment fixes, changelog‑only PRs, or lockfile updates that do not touch runtime symbols. Maintainability also requires that the intended change fit one sentence; otherwise, the issue likely needs a staged migration plan.

Conclusion

A blast‑radius card makes the dependents of a shared helper visible before the diff lands. It turns hidden risk into a concrete, reviewable artifact, reducing the chance of regressions and speeding up merge decisions. By following the steps above, contributors and maintainers can keep open‑source projects robust even as they evolve.

Why it matters

In open‑source, a single helper can be used by dozens of modules. Without a clear view of all call sites, a small change can silently break downstream code, causing costly release failures.

Key points

  • File‑local tests miss hidden callers; a blast‑radius card exposes all call sites.
  • The card is a Markdown file that lists the change, call sites, and tests.
  • Harvest call sites with ripgrep and classify each hit before the diff.
  • Freeze a contract table that maps old and new observables for each caller.
  • Run owner tests first to confirm the new behavior before merging.
  • Use a language‑model prompt for a frozen review that flags missing callers or tests.
  • Skip the card for trivial changes that don’t touch runtime symbols.

Frequently asked questions

What is a blast‑radius card?

A Markdown file that lists every place a shared helper is called, the intended change, and the tests that must change or stay green.

Why can’t file‑local tests catch all regressions?

They only test the hunk under the cursor and its immediate fixtures, not other import paths or generated files that also use the helper.

How do I harvest call sites?

Use tools like ripgrep to search the repository for the helper name, exclude test and generated directories, and record each hit’s path and line number.

What if the contract table has more than five rows?

Split the work into separate issues so each patch remains focused and manageable.

Reporting drawn from

More from WAR

Felo News, House 42, Bridge Colony, Kot Lakhpat, Lahore, Pakistan
+92 308 4354717 · felopronews@gmail.com