by Winch Labs

Reviews

Blast radius and the dependency graph

“If I change this module, what else is affected?” — answered from parser facts, with no model involved and without leaving the process.

How the graph is built

Nodes are directories: a Terraform root, a local module, a Terragrunt unit — keyed by repo-relative path.

Directories are what Terraform and Terragrunt actually address, and normalising the path is the whole point. source = "../../modules/queue" written in envs/dev and the same line written in envs/prod name the same module. Both must resolve to modules/queue, or a dependent count means nothing at all.

Consumers are transitive, and each one carries its own evidence — you can see which unit depends on the thing you edited, and where that dependency is declared.

The score

Σ (consumers × environment weight), with weights production 3, staging 2, everything else 1.

The weights are ordinal on purpose. They are not a claim that production is three times as important as development; they are a claim that production ranks above staging ranks above everything else, expressed as the smallest numbers that produce that order. Reading them as a ratio is reading more than is there.

When it comments

A score at or above blast_radius.comment_above comments on its own, even on an otherwise clean pull request. The default is 3 — the lowest score a change reaching production can have. So the default reads: tell me when this reaches production, or when it reaches three or more units anywhere. A change consumed only by dev stays silent.

It renders as a context blockquote: no severity, never one of the three finding slots.

> **Blast radius** — touches `modules/vpc` · consumed by 4 units across 2 envs (prod: 3)

Across repos

Everything above is measured inside one repository. A second labelled paragraph in the same blockquote answers the question one repository outward — which other repositories in your organisation consume the module that just moved, which of them track this branch and which are pinned, and how old the scans behind that answer are.

> **Blast radius** — touches `modules/vpc` · consumed by 4 units across 2 envs (prod: 3)
>
> **Across repos** — consumed by 3 repos across 2 envs (prod: 2) · `acme/api`, `acme/edge`, `acme/web` · 2 pinned, picked up on upgrade · 1 on a different branch · as of 6 consumer scans, oldest 12d · only what this org has scanned is counted, so this is a lower bound

It has its own score, on the same scale over a different population, and the two are never added. The in-repo score above is still the only one blast_radius.block_above reads. See cross-repo reach for how each clause is built and what it cannot see.

Measured, or not at all

If the graph could not be measured, Deltz says so rather than drawing a zero. An unmeasured estate and an estate with no consumers are different facts, and a count you cannot distinguish from “we did not look” is worse than no count.

Where a consumer list is capped for display, the true total is shown beside it, so a reader can never mistake a cap for a smaller estate.