Hotspots lets you refactor with precision — but the real win is preventing regressions from landing at all. This post shows how to add risk policies to CI so problematic changes fail pre‑merge.
Quick start (10 minutes)
hotspots analyze . --mode delta --policy --format text
Copy‑paste a GitHub Actions workflow (or adapt for your CI):
name: hotspots-ci
on: { pull_request: {} }
jobs:
risk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo build --release --bin hotspots
- run: ./target/release/hotspots analyze . --mode delta --policy --format text
The problem: subjective reviews miss slow creep
Reviewers aren’t CPUs. They miss gradual increases in nesting or branching, especially in busy files. Over time, “just one more condition” turns a healthy function into a critical hotspot.
Delta mode + policies
In CI you want to evaluate the change, not the whole repo. Delta mode compares the current snapshot with the parent (or merge‑base in PRs), then evaluates policies against the diff.
hotspots analyze . --mode delta --policy --format json
Exit codes:
- 0: no blocking failures (warnings may be present)
- 1: blocking failures (e.g., critical introduction, excessive regression)
Built‑in policies
- Critical Introduction: New function enters the critical band (e.g., LRS ≥ 9.0)
- Excessive Regression: LRS delta exceeds a threshold (e.g., +1.0)
- Watch/Attention: Approaching thresholds (warn only)
- Rapid Growth: Complexity growing unusually fast
- Repository Net Regression: Total LRS increases beyond a threshold (warn or fail)
Tune thresholds and weights via config (e.g., .hotspotsrc.json).
Minimal CI example
GitHub Actions (CLI installed from source or cached):
name: hotspots-ci
on:
pull_request:
jobs:
risk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo build --release --bin hotspots
- run: |
./target/release/hotspots analyze . \
--mode delta --policy --format text
For native Workers/other CIs, call the same CLI command. If you want HTML artifacts, run snapshot mode and upload the report.
Handling real‑world constraints
Suppressions — Some complex code can’t be touched yet. Add a suppression comment with a reason:
// hotspots-ignore: legacy integration; rewrite scheduled Q3
function legacyBillingLogic() {
// ...
}
Suppressed functions remain visible in reports but won’t fail policy checks.
Merge‑base awareness — On PRs, delta mode compares against the merge‑base when available, so you don’t fail for unrelated history.
Co‑change context — Policy output can include co‑change deltas (hidden coupling) so reviewers see why a change may be riskier than it looks.
Rollout plan (week 1)
- Baseline only (no fail): Run
--mode delta --policywith warn‑only thresholds. Share a few PR screenshots. - Flip on failers: Enable “critical introduction.”
- Tighten gradually: Add “excessive regression” with a modest threshold.
- Monitor trends: Track counts of critical/high functions; adjust.
Developer experience matters
- Keep logs concise: Use
--format textfor humans;--format jsonfor bots. - Fast path first: Start without per‑function touches; enable deeper metrics if needed.
- Make policies actionable: Pair with explain mode during reviews and refactors.
Bottom line
Turn code review from “I think this is too complex” into “this change exceeds our risk policy.”
It’s clearer. It’s fairer. And it keeps your codebase from slowly boiling the frog.
FAQ (Policies)
- Which policies fail the build? Critical Introduction and Excessive Regression (by default). Others warn only.
- Can I tune thresholds? Yes — via
.hotspotsrc.jsonor CLI flags. - What if a spike is justified? Add a suppression with a reason; it’s tracked but won’t block.