Blog

Essays, playbooks, and product updates.

hotspots v1.36.0: risk isn't the only axis

Stephen Collins · Sep 6, 2026

The headline feature here started as a research question, not a product idea: do coupling and ownership actually predict something different from complexity-times-activity, or are …

hotspots v1.35.1–v1.35.4: an audit, twelve fixes, four days

Stephen Collins · Aug 30, 2026

Four releases, twelve PRs, and a pattern once I lined them up: most of these weren't reported by users hitting a wall. They were found by someone going looking — auditing coverage …

Rust Code Health: Patterns Across 27 Open-Source Repositories

Stephen Collins · Aug 27, 2026

I analyzed 27 open-source Rust codebases to identify recurring structural antipatterns. Every single repository contained long functions, and 24 of 27 had god functions.

hotspots v1.35.0: the CLI can finally tell you it's out of date

Stephen Collins · Aug 24, 2026

One feature, three rounds of scope-narrowing: I asked for a self-updating CLI, got talked down to check-and-report, then had that check moved from an explicit subcommand to somethi…

hotspots v1.34.1: a parser hang, a coupling regression, and a hedge I owed the docs

Stephen Collins · Aug 20, 2026

Three merged PRs, one patch release: a real repro against llvm-project, a performance fix that almost undid a validated research finding, and a docs gap I caught before merging.

Go Code Health: Patterns Across 31 Open-Source Repositories

Stephen Collins · Aug 2, 2026

I analyzed 31 open-source Go repositories to find the most common structural antipatterns. Every single repo exhibited exit-heavy functions and deep nesting.

JavaScript Code Health: Patterns Across 47 Open-Source Repositories

Stephen Collins · Aug 2, 2026

I analyzed 47 popular JavaScript repositories for structural antipatterns. The results show remarkably consistent patterns—exit-heavy functions appear in nearly every codebase.

Python Code Health: Patterns Across 37 Open-Source Repositories

Stephen Collins · Aug 2, 2026

I analyzed 37 Python repositories and found complex branching in every single one. Here's what the data reveals about structural risk in Python codebases.

I Shipped a Scoring Bug That Made Improvement Impossible — Here's the Fix

Stephen Collins · Jul 26, 2026

burst_score was computed over a file's entire commit history, which made it a one-way ratchet in the live risk score. A single bursty period years ago could keep a file stuck at CR…

Hotspots v1.25.1–v1.31.0: Explanations, a Regime-Aware Ranker, and a Burst-Score Formula Term

Stephen Collins · Jul 14, 2026

Six versions in four weeks. Most of it is quieter infrastructure — easier installs, a cleaner ranker feature set, tighter CI policy control. The two releases worth reading closely …

Why I let AI train on this

Stephen Collins · Jul 2, 2026

I just flipped ai-train=yes in robots.txt. Here's the reasoning, not just the setting.

How phrasing affects LLM compliance with spec security clauses

Stephen Collins · Jun 29, 2026

I tested five ways to phrase a security requirement across four language models. The phrasing most commonly used in practice was near the bottom on all four of them. The phrasing t…

How hotspots measures itself

Stephen Collins · Jun 28, 2026

A ranking tool that can't measure its own accuracy is just vibes with syntax highlighting. Here's how hotspots keeps itself honest.

When You Don't Have Enough History to Train

Stephen Collins · Jun 24, 2026

Every new repo starts with the same problem: no defect labels, no training signal, no basis for a risk ranking beyond 'how often does this file change?'

The Signal That Evaporated (And the One That Didn't)

Stephen Collins · Jun 24, 2026

Two signals looked nearly identical on paper. One collapsed under temporal holdout. The other survived — and the difference tells you something important about how to design defect…

Spearman ρ Looked Fine. P@10 Was Zero.

Stephen Collins · Jun 24, 2026

Spearman ρ can be positive and meaningful while the top-ranked files contain zero future bugs. Here's how I found that out, why it happens, and how to catch it before it reaches a …

Tabular Beats LLM, and That's the Right Answer

Stephen Collins · Jun 24, 2026

On most codebases, a small XGBoost model trained on git history features outperforms a fine-tuned 7B LLM at defect risk ranking — not because the LLM is bad, but because the data i…

Hotspots v1.25.0: Repo Screener, CI Workflows, and Cleaner TypeScript Names

Stephen Collins · Jun 16, 2026

Three things that should have existed already: a way to know if training is worth running, a one-command CI setup, and TypeScript functions that show up under their actual names.

The Coupling Signal That Kept Inverting Itself

Stephen Collins · Jun 10, 2026

I tried three formulations of co-change coupling for defect risk ranking. Raw co-occurrence inverted on dense codebases. Mutual information made it worse.

Your Transformer Featurizer Only Helps When Your History Is Broken

Stephen Collins · Jun 10, 2026

Transformer embeddings on source code improved defect ranking on exactly the repos where git history had already failed — and added near-zero or negative signal everywhere else. He…

Java Code Health: Patterns Across 10 Open-Source Repositories

Stephen Collins · Jun 6, 2026

I analyzed 10 popular Java repositories and found the same three antipatterns in every single one. Here's what that tells us about Java development practices at scale.

The Defect Prediction Trap

Stephen Collins · Jun 5, 2026

I fine-tuned a model that scored Spearman ρ=+0.678 on defect risk. Then I zeroed out the git history fields and it dropped to −0.142. The model wasn't reading code. It was relaying…

The Metric That Hides Failure

Stephen Collins · Jun 5, 2026

Spearman ρ measures average rank agreement across all files. Precision@K measures whether the files engineers actually review are in the right place. On mature, stable codebases, a…

Which LLM Vendor Wins at Defect Risk Prediction?

Stephen Collins · Jun 5, 2026

When evaluating open-weight models for code analysis, the vendor comparison you run in 2024 might give you the wrong answer in 2025.

When Your Labels Lie: File-Level Bug Attribution Inflates Defect Rates

Stephen Collins · May 31, 2026

Most defect prediction pipelines share a quiet assumption: if a file was touched in a bug-fix commit, every function in that file was 'buggy' — and that assumption silently inflate…

How to Know If Fine-Tuning Will Help Before You Run It

Stephen Collins · May 25, 2026

Before you spend compute on per-repo fine-tuning, one scalar from the codebase's bug-fix history can tell you whether it's worth running. Here's how it works and what it can't pred…

Go Code Health: Patterns Across 12 Open-Source Repositories

Stephen Collins · May 22, 2026

I analyzed 12 Go repositories and found the same structural antipatterns in every single one. Here's what the data shows.

JavaScript Code Health: Patterns Across 19 Open-Source Repositories

Stephen Collins · May 22, 2026

I analyzed 19 open-source JavaScript repositories and found exit-heavy functions in 89% of them. Here's what the data reveals about structural debt in the JavaScript ecosystem.

Python Code Health: Patterns Across 12 Open-Source Repositories

Stephen Collins · May 22, 2026

I analyzed 12 open-source Python repositories and found complex branching in 100% of them. Here's what the data reveals about Python code health patterns.

Rust Code Health: Patterns Across 11 Open-Source Repositories

Stephen Collins · May 22, 2026

I analyzed 11 popular Rust repositories to find the most common code health antipatterns. Every single one had exit-heavy functions and long functions — Rust's ownership model does…

TypeScript Code Health: Patterns Across 44 Open-Source Repositories

Stephen Collins · May 22, 2026

I analyzed 44 TypeScript repositories and found structural antipatterns in nearly all of them. Here's what the data shows about where complexity accumulates.

Hotspots v1.18.0: Compact Storage

Stephen Collins · May 21, 2026

Snapshot history is valuable. Unbounded snapshot growth is not. v1.18.0 ships two compaction levels that shrink your .hotspots directory without losing the history that matters.

Hotspots v1.17.0: Model Risk Map and Monorepo Subsystems

Stephen Collins · May 20, 2026

Hotspots already tells you which functions are risky. v1.17.0 tells you which models those functions cluster around — and makes risk scores meaningful inside monorepo package bound…

Can a Fine-Tuned LLM Learn Which Code Is Risky?

Stephen Collins · May 16, 2026

I spent a few weeks running a controlled experiment: can a small language model, fine-tuned on a specific codebase's history, learn to rank code by defect risk better than a hand-t…

Hotspots now handles monorepos — what changed from v1.11 to v1.15.1

Stephen Collins · Apr 24, 2026

The diff command shipped in v1.11. Since then: four months of OOM fixes, a new SQLite pipeline, hybrid touch mode, and --auto-analyze. Hotspots now handles 28k-function monorepos a…

TypeScript produces less exit-heavy code than Go or Python — and more branching

Stephen Collins · Apr 17, 2026

exit_heavy averages 5.3 in non-TypeScript repos and 4.5 in TypeScript. complex_branching has the highest max-out rate of any pattern in TS. The flip is structural, not stylistic — …

Hub functions are a frontend framework problem — here's the data

Stephen Collins · Apr 17, 2026

hub_function barely appears in Go, Rust, or Python repos. In TypeScript UI framework code it's concentrated in coordinator functions with fan-out values of 37–112. Here's why.

Five structural patterns appear in nearly every TypeScript OSS repo I've analysed

Stephen Collins · Apr 17, 2026

Five structural patterns — god_function, long_function, exit_heavy, complex_branching, deeply_nested — appear in 86–100% of the 28 TypeScript OSS repos I've analysed. Here's what t…

Running Hotspots on expo/expo Without Running Out of Memory

Stephen Collins · Apr 12, 2026

expo/expo crashed Hotspots with an OOM. Here's the full account: what broke, the systematic fixes across memory and CPU, and the new escape-hatch flags that make very large repos p…

hotspots diff: Compare Complexity Between Any Two Branches, Tags, or Commits

Stephen Collins · Mar 26, 2026

Delta mode compares a commit to its parent. That's fine for local development — but CI needs to compare a PR branch to main, and tag comparisons need to reach back further. hotspot…

What Happens When You Run Hotspots on 102,000 Functions

Stephen Collins · Mar 14, 2026

I stress-tested Hotspots against VS Code (102k functions) and found an O(N³) bug, a sampling tail exclusion bug, and a philosophical question about approximation accuracy — all in …

AI Agents Can Pass Tests. They Still Can't Maintain Systems.

Stephen Collins · Mar 11, 2026

AI coding tools have made writing software dramatically easier. A new benchmark shows maintaining it is still the hard part — and the failure modes are predictable.

AI Made Code Cheap. The Bottleneck Is Now Understanding Systems.

Stephen Collins · Mar 8, 2026

AI removed code production as the engineering bottleneck. The new constraint is comprehension - and most developer tooling wasn't built for that problem.

The 20% Rule for Codebases: A Practical Refactoring Playbook

Stephen Collins · Feb 22, 2026

Use this practical worksheet to intersect change and complexity, pick three high‑leverage targets, and add simple guardrails to prevent backslide.

Stop Missing Regressions in PRs: Complexity Policy Checks in CI

Stephen Collins · Feb 22, 2026

Code review misses slow creep. Use Hotspots policies in CI to stop risky complexity changes before they merge — start warn‑only, then flip to blocking.

Introducing Hotspots: Find Risky Functions and Stop Regressions

Stephen Collins · Feb 21, 2026

Meet Hotspots — a lightweight analyzer with explainable risk, shareable reports, and CI policies so you fix what matters and keep it from slipping back.

Repository Analyses

Nightly hotspot reports for popular open-source repos. Browse all →

moby/moby

moby/moby's daemon init carries the highest activity risk — 5 hotspots to fix first

go exit_heavygod_function
Sep 8
influxdata/influxdb

influxdb's query planner carries the highest structural debt — 5 functions to fix first

rust exit_heavylong_function
Sep 7
astral-sh/uv

uv's CLI command layer carries the highest activity risk — 5 functions to fix first

rust complex_branchingdeeply_nested
Sep 6
rust-lang/mdBook

mdBook's front-end search carries the highest structural risk — 5 functions to review

rust complex_branchinggod_function
Sep 6
PyCQA/pylint

Pylint's checker layer carries the highest activity risk — 5 functions to address first

python exit_heavygod_function
Sep 5
valyala/fasthttp

fasthttp's connection-serving loop hits CC 219 — a class apart from everything else

go exit_heavygod_function
Sep 4
surrealdb/surrealdb

surrealdb's search and value layer hides 77-day-old complexity debt in 5 functions

rust long_functionexit_heavy
Sep 3
gin-gonic/gin

gin's tree.go carries 3 of the top 5 hotspots — routing internals need a hard look

go exit_heavycomplex_branching
Sep 2
starship/starship

Starship's git status parser carries the highest debt risk — 5 functions to fix first

rust long_functionexit_heavy
Sep 1
gorilla/mux

gorilla/mux's route regexp parser leads a 5-function risk list to fix first

go exit_heavycomplex_branching
Aug 30
streadway/amqp

amqp's protocol codec carries the oldest structural debt — 5 functions untouched for years

go exit_heavystale_complex
Aug 30
hashicorp/nomad

Nomad's scheduler and job-registration paths lead a 5-function risk cluster to fix first

go complex_branchingexit_heavy
Aug 30
brettwooldridge/HikariCP

HikariCP's config utilities carry the highest risk — 5 to fix first

java complex_branchingdeeply_nested
Aug 29
beetbox/beets

beetbox/beets' import and update layer — highest activity risk, 5 functions

python complex_branchingexit_heavy
Aug 28
validatorjs/validator.js

validator.js's string validators carry the highest risk — 5 to fix first

javascript exit_heavycomplex_branching
Aug 28
11ty/eleventy

eleventy's template and plugin layer carries the most structural debt

javascript exit_heavylong_function
Aug 27
fish-shell/fish-shell

fish-shell's core subsystems carry the highest activity risk

rust complex_branchingdeeply_nested
Aug 26
GyulyVGC/sniffnet

sniffnet's networking and GUI layers carry the highest activity risk

rust complex_branchingdeeply_nested
Aug 25
DioxusLabs/dioxus

DioxusLabs/dioxus: harness.rs carries the highest risk — 5 functions to address

rust long_functiongod_function
Aug 24
servo/servo

servo/servo's test infrastructure carries the highest risk — 5 functions to fix

rust long_functioncomplex_branching
Aug 23
spacedriveapp/spacedrive

Spacedrive's indexing core carries the highest structural debt

rust exit_heavygod_function
Aug 22
pola-rs/polars

polars' query engine carries the highest activity risk — 5 functions to address first

rust complex_branchingexit_heavy
Aug 21
nushell/nushell

nushell's parser carries the highest activity risk — 5 functions to address first

rust complex_branchingdeeply_nested
Aug 20
juspay/hyperswitch

hyperswitch's payment core carries the highest activity risk

rust complex_branchingdeeply_nested
Aug 19