Across 1,037 functions analyzed in roboflow/supervision at commit 937ed4a, 162 are in the critical band — and every one of the top 5 hotspots sits in the “fire” quadrant, meaning they are both structurally complex and actively changing right now. The top-ranked function, from_google_gemini_2_5, carries an activity-weighted risk score of 18.71 with a cyclomatic complexity of 58 and was last changed 8 days ago. I would start there, then move immediately to process_video, which was touched 4 times in the last 30 days and last modified today. supervision is a widely-used Python computer vision toolkit, and with 472 of 1,037 functions in the fire quadrant, the structural risk is not a backlog concern — it is a live shipping risk.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
from_google_gemini_2_5 | src/supervision/detection/vlm.py | 18.7 | 58 | 6 | 29 |
process_video | src/supervision/utils/video.py | 18.4 | 38 | 6 | 24 |
_compute | src/supervision/metrics/f1_score.py | 17.7 | 46 | 5 | 21 |
_compute | src/supervision/metrics/precision.py | 17.5 | 46 | 5 | 20 |
_compute | src/supervision/metrics/recall.py | 17.3 | 39 | 5 | 21 |
Large Repo Analysis
supervision is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 20 or more commits in the last 30 days; other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.
The shape of the risk
Before getting into individual functions, it’s worth seeing the full distribution. Every function in the repository falls into one of four quadrants based on structural complexity and recent commit activity.
1,037 functions analyzed
There are no debt-quadrant or ok-quadrant functions in this repository at all — every structurally complex function is also actively changing. That is an unusual profile. It tells me that supervision is under heavy, broad development, and that structural complexity has accumulated in code that maintainers are actively shipping against. The watch-quadrant functions are moving but structurally simpler; the fire-quadrant functions are where both dimensions compound.
The antipattern distribution across the top 5 reinforces this picture:
Function body is too long to review in a single pass; likely contains multiple distinct responsibilities.Complex Branching×5Complex Branching
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.Deeply Nested×5Deeply Nested
Control structures nested 4+ levels deep, making it hard to reason about the full execution state at inner branches.Exit Heavy×5Exit Heavy
Multiple return or throw paths dispersed through the body — each exit needs separate test coverage.God Function×5God Function
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Cyclic Hub×1Cyclic Hub
Participates in a call cycle with other high-traffic functions, creating circular dependency risk.
Every top hotspot is simultaneously long, branchy, deeply nested, exit-heavy, and god-function-sized. These are not independent problems — they tend to co-occur when a single function absorbs too many responsibilities over time.
Top 5 hotspots
from_google_gemini_2_5 — vlm.py
This function parses and scales bounding boxes and segmentation masks from Google Gemini 2.5 JSON output. From the source excerpt I can see it handles the full input lifecycle: stripping markdown code fences from the raw string, JSON parsing with a fallback empty result on decode failure, type-checking the parsed structure, and then iterating over each detection item to validate fields, resolve class names, decode base64 mask images, and rescale box coordinates. That breadth is what drives the numbers.
A cyclomatic complexity of 58 means there are at least 58 independent execution paths through this function — each one a required test case and a potential bug surface. In Python, where duck typing means that type checks like isinstance(item, dict) are doing real runtime work rather than being caught at compile time, each branch is genuinely load-bearing. The max nesting depth of 6 means that at the deepest point, a reader is tracking six simultaneous layers of control flow — the item loop, field validation, class filtering, mask decoding, coordinate scaling, and edge-case guards all interleaving. Fan-out of 29 means 29 distinct functions are called, which in Python’s dynamic dispatch model implies more implicit coupling than that number alone suggests.
The god-function and exit-heavy patterns are visible directly in the excerpt: there are at least two early-return paths before the main loop even begins (one for JSON parse failure, one for non-list data), and the loop itself branches heavily per item. Each exit point is a separate test scenario.
The file has only 1 commit in total and a single author in the last 90 days. There are no bug-linked commits or reverts, which is worth noting — the historical signal here is the novelty of the code rather than accumulated defects. This is a brand-new integration with Gemini 2.5, touched 8 days ago, and the complexity is all original design rather than accreted patches. That makes it a different kind of risk: not a function that has been broken and fixed repeatedly, but one that has never had the chance to be stress-tested.
Recommendation: Extract the JSON extraction and validation logic (fence-stripping, json.loads, type checks) into a dedicated _parse_gemini_json helper, and extract the per-item decoding logic (mask base64 decoding, box rescaling, class resolution) into a _decode_gemini_item function. That split alone would likely reduce the cyclomatic complexity of the main function below 20 and isolate the most failure-prone paths — JSON parsing and base64 mask decoding — into individually testable units.
process_video — video.py
This is the most actively changing function in the top 5: 4 commits in the last 30 days, last modified today. The source excerpt confirms it orchestrates a three-stage threaded pipeline — a reader thread filling a bounded frame queue, a main-thread processor applying a user callback, and a writer thread draining a second bounded queue to disk. It also handles optional audio preservation via PyAV remuxing with a silent fallback on failure.
A cyclomatic complexity of 38 across that design reflects real control surface: queue sentinel management, max_frames capping, preserve_audio branching, show_progress tqdm integration, and error handling for the audio mux step, all layered inside thread orchestration code. The nesting depth of 6 reflects the interleaving of thread management with frame-level loop logic. Fan-out of 24 is broad for a utility function — it touches video I/O, queue management, threading primitives, progress display, and audio muxing, making it a genuine hub across the video subsystem.
The rate of review comments per commit is the highest of any function in the top 5, which tells me this function has attracted meaningful review attention even with only 4 total commits. That is consistent with the kind of function that reviewers instinctively scrutinize — threaded pipeline code with multiple failure modes is hard to review and hard to get right.
Recommendation: The audio preservation path is self-contained enough to extract into a _mux_audio helper that takes source and target paths and returns a success/failure signal. The reader and writer thread bodies — currently likely defined as closures or nested functions — deserve promotion to named module-level functions with explicit signatures. Those two changes would reduce process_video to a coordinator function whose complexity derives primarily from pipeline wiring rather than implementation detail, and would make the threading behavior independently testable.
_compute — f1_score.py
This method builds per-image statistics tuples — covering matches, ignored matches, confidence arrays, class IDs, and ground-truth class IDs — before delegating to class-level F1 aggregation. From the source excerpt, the branching structure is explicit: the function separately handles the case where both predictions and targets are empty (skip), targets are empty but predictions are present (all false positives), and targets are present (IoU matching). Within the targets-present branch, it further branches on whether predictions exist, what the metric target type is (boxes, masks, oriented bounding boxes), and whether required fields like class_id and confidence are present.
A cyclomatic complexity of 46 for a metrics computation method is high. Two of its three recent commits are tagged as fixes — a 67% fix rate — and it has 3 distinct authors active in the last 90 days, which is the highest author count of any function in the top 5. Multi-author ownership of a CC-46 function with a high fix fraction is a meaningful combination: it suggests different contributors are each encountering edge cases that require patching, which is the kind of pattern that accumulates when a function’s branching logic is difficult to reason about as a whole.
Recommendation: The three top-level cases (both empty, targets only, both present) map naturally to helper methods: _handle_fp_only_image, _handle_fn_only_image, and _handle_matched_image. Each would be independently testable against the IoU threshold grid, and the main _compute loop would reduce to a dispatcher. This mirrors the structure already implicit in the docstring.
_compute — precision.py
The precision _compute method is structurally nearly identical to its F1 counterpart — same cyclomatic complexity of 46, same nesting depth of 5, fan-out of 20 versus 21, and the same three-case branching logic over the empty/present combinations of predictions and targets. The source excerpt confirms the parallel structure: the same size-category masking, the same false-positive handling branch, the same IoU-threshold linspace, and nearly identical field-validation raises.
This is the clearest signal of a shared abstraction that hasn’t been extracted. Two functions in the same metrics package with CC 46 and nearly identical shape, both actively changing (2 commits each in the last 30 days, last touched 2 days ago), and both with half their recent commits tagged as fixes, means that fixes applied to one are likely being manually mirrored to the other — a process that is itself error-prone. The 2 distinct authors active in the last 90 days and a review comment attached to roughly every commit suggest this file is getting real review attention, which is appropriate given the complexity.
Recommendation: The shared skeleton — size-mask construction, the three-case dispatch, and the IoU matching block — should live in a base class or shared module-level helper, parameterized on which metric is being accumulated. The _compute methods in f1_score.py, precision.py, and recall.py (see below) could then reduce to thin overrides that specify what gets accumulated into the stats tuple. That refactoring eliminates the synchronization burden between three parallel implementations.
_compute — recall.py
The recall _compute completes the trio. At cyclomatic complexity 39 it is the structurally simplest of the three metrics implementations, but the source excerpt shows it handles the same IoU-threshold grid across boxes, masks, and oriented bounding boxes, with the same size-category masking logic and the same multi-branch empty/present dispatch. One difference visible in the excerpt is that the false-positive-only branch is absent — recall has no notion of false positives without ground truth, so that path simply doesn’t exist. That explains the slightly lower CC relative to the precision and F1 variants.
Like its siblings, this function was touched twice in the last 30 days and last modified 2 days ago, with half of its 2 recent commits tagged as fixes. The 2 distinct authors confirm the same multi-contributor dynamic. The fan-out of 21 includes calls to box_iou_batch, mask_iou_batch, and oriented_box_iou_batch — the IoU dispatch block is explicit in the excerpt and is present in all three metrics files, which is another instance of duplicated logic that would benefit from shared extraction.
Recommendation: In addition to the base-class refactoring described above, the IoU-dispatch block — the if self._metric_target == MetricTarget.BOXES / MASKS / ORIENTED_BOUNDING_BOXES chain — should be extracted into a shared _compute_iou(self, targets, predictions) method. It appears in identical form across all three files, and centralizing it means IoU-related bugs or new metric target types are fixed once rather than three times.
What the context functions tell me
The lower-priority functions surfaced alongside the top 5 reinforce where the active development pressure is concentrated. _rle_counts_to_mask in detection/utils/converters.py was touched 4 times in the last 30 days — the same frequency as process_video — and draw_text in draw/utils.py was touched 3 times. Both are in the watch quadrant: their structural complexity is low enough that they are not a refactoring priority today, but their activity level means they are worth monitoring as complexity accumulates. Similarly, sum in compact_mask.py has been touched twice recently, which tracks with the broader mask-handling work visible in the metrics layer.
None of these rise to the priority of the top 5, but they suggest the detection utilities and drawing subsystems are also in active flux.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
long_function | 6 |
complex_branching | 5 |
deeply_nested | 5 |
exit_heavy | 5 |
god_function | 5 |
cyclic_hub | 1 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
Reproduce This Analysis
git clone https://github.com/roboflow/supervision
cd supervision
git checkout 937ed4af37b0e77d3644dabbb60fcef2189c5413
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 20
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
I use Hotspots to highlight structural and activity risk — not “bad code.” I treat these findings as a prioritization aid, not a bug predictor. Editorial policy →