Across 2,757 functions analyzed at commit a67fc64, mitmproxy carries 202 in the critical band — and the most urgent is flowsReducer in web/src/js/ducks/flows/index.ts, which holds a risk score of 19.92. It sits in the ‘fire’ quadrant: cyclomatic complexity of 39, max nesting depth of 9, and fan-out of 39, touched once in the last 30 days just 8 days ago — structurally extreme and still moving, which makes it a live regression risk, not a cleanup backlog item. Behind it, four more critical-band functions — two generated PEG parsers, a command parser, and a test-infrastructure boolean evaluator — have gone untouched for 31 days each, representing structural debt with a high blast radius the moment development resumes.
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 |
|---|---|---|---|---|---|
flowsReducer | web/src/js/ducks/flows/index.ts | 19.9 | 39 | 9 | 39 |
peg$parse | web/src/js/filt/filt.js | 19.4 | 32 | 32 | 129 |
__bool__ | test/mitmproxy/proxy/tutils.py | 16.4 | 57 | 6 | 25 |
peg$parse | web/src/js/filt/command.js | 16.2 | 11 | 6 | 56 |
peg$parseExpr | web/src/js/filt/filt.js | 15.9 | 196 | 32 | 37 |
Large Repo Analysis
mitmproxy 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 5 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.
Codemod / Tooling Files in Results
Two files in the top hotspots — web/src/js/filt/filt.js and web/src/js/filt/command.js — are PEG.js-generated parser artifacts, not handwritten source. Their extreme cyclomatic complexity (196 and 32 respectively) and fan-out values (129 and 56) are structural properties of machine-generated recursive-descent parsers, not indicators of handwritten quality problems. To exclude them from future Hotspots analyses, add the following to your .hotspotsrc.json: { "exclude": ["web/src/js/filt/filt.js", "web/src/js/filt/command.js"] }. The grammar source files (likely .pegjs files) are the appropriate targets for review and test coverage, not the generated output.
mitmproxy is a Python-based interactive TLS-capable proxy with a TypeScript/React web UI. I analyzed it at commit a67fc64 and found 2,757 total functions, of which 202 land in the critical band.
2,757 functions analyzed
The quadrant picture is telling: 648 functions in the debt quadrant versus only 29 in fire means the dominant risk is structural complexity that has accumulated without recent activity — high blast radius waiting for the next development push. But the top hotspot is one of those 29 fire-quadrant functions, and it is moving right now.
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Long Function×8Long Function
Function body is too long to review in a single pass; likely contains multiple distinct responsibilities.Complex Branching×6Complex Branching
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.Deeply Nested×6Deeply Nested
Control structures nested 4+ levels deep, making it hard to reason about the full execution state at inner branches.Exit Heavy×6Exit Heavy
Multiple return or throw paths dispersed through the body — each exit needs separate test coverage.
Nine god-function hits across the top hotspots is the single most important pattern signal here. In Python especially, a function that calls dozens of distinct callees creates coupling that is wider than it appears, because duck typing means those call targets are resolved at runtime — the static fan-out number understates the true coupling surface.
flowsReducer — web/src/js/ducks/flows/index.ts
This is the function I would address first, because it is both structurally extreme and actively changing. One commit touched it 8 days ago, and the structural profile — CC 39, nesting depth of 9, fan-out of 39 — puts it firmly in god-function territory.
From the source excerpt, flowsReducer is a Redux reducer that owns the entire flows state shape: it handles at least FLOWS_RECEIVE, FLOWS_ADD, and FLOWS_UPDATE actions in a chain of if/else if branches, each branch performing index rebuilding, view sorting, selection reconciliation, and highlight-set management. That is a large number of distinct responsibilities packed into one function. The nesting depth of 9 is a direct consequence: each action branch contains its own filter-check conditionals, sorted-insertion logic, and Map-mutation paths, stacked inside one another.
The fan-out of 39 is particularly consequential here. flowsReducer calls into index builders, sort utilities, lookup builders, and view-insertion helpers — a change to any of those callees can change reducer behavior in ways that are hard to trace because the reducer itself is already doing so much. The exit_heavy pattern compounds the testing burden: with 39 independent paths and 9 nesting levels, achieving meaningful branch coverage requires a large test matrix.
The external signals are clean — no bug-linked commits, no reverts — so I am not flagging this as defective. But a CC-39 reducer that is still being modified is exactly the kind of function where a subtle state-mutation bug gets introduced and only surfaces under a specific combination of WebSocket race conditions and sort order. The source excerpt even contains an explicit comment noting a WebSocket/HTTP race for the FLOWS_ADD path, which confirms the function is navigating non-trivial concurrency concerns.
My recommendation: decompose flowsReducer by action type. Each FLOWS_* action has enough distinct logic to warrant its own handler function. A parent reducer delegates by action type and each child function owns one state transition. This converts a CC-39 monolith into several sub-10 functions, each independently testable.
peg$parse — web/src/js/filt/filt.js
This function has not been touched in 31 days and sits in the debt quadrant — high structural complexity with no recent activity. The numbers are extraordinary nonetheless. A fan-out of 129 is the highest in this analysis: peg$parse calls into 129 distinct functions. A nesting depth of 32 matches the cyclomatic complexity of 32, which is characteristic of machine-generated recursive-descent parsers — the excerpt confirms this is a PEG.js-generated parser for mitmproxy’s filter expression language (~all, ~a, ~b, ~bq, and so on).
The peg$c0 through peg$c70+ constant definitions visible in the excerpt — each encoding a grammar terminal or action function — are the scaffolding of a generated parser. Every filter keyword gets its own parse sub-function, and peg$parse orchestrates them all. That explains both the extreme fan-out and the deeply nested control flow: the parser tries each alternative in sequence, backtracking on failure, which produces deeply nested if (s !== peg$FAILED) chains.
The single author touching this file in the last 90 days and zero bug-linked commits suggest it is stable under current usage. The risk is blast-radius: if mitmproxy’s filter language needs a new keyword, or if the grammar source (likely a .pegjs file not directly measured here) changes, peg$parse will be regenerated in its entirety, and anyone reviewing that diff will face a 129-fan-out, depth-32 function with no obvious manual entry points.
My recommendation: do not hand-edit peg$parse. Instead, ensure the grammar source file is well-documented and that the generation step is clearly scripted and committed. Add integration tests that cover every filter keyword at the language level — they will catch regressions without requiring anyone to reason through the generated code directly.
__bool__ — test/mitmproxy/proxy/tutils.py
__bool__ in tutils.py has not been touched in 31 days and sits in the debt quadrant, but its CC of 57 is the highest of any non-generated function in this list — a strong refactoring signal on its own.
From the source excerpt, this __bool__ method is the evaluation engine for a proxy test playbook. It drives a while loop over expected vs. actual events, dispatching through isinstance checks for Command, OpenConnectionCompleted, ConnectionClosed, CloseTcpConnection, CloseConnection, Log, and StartHook — each branch mutating connection state, inserting auto-replies, or catching exceptions from self.layer.handle_event(x). The 57 independent paths through this function reflect the combinatorial space of proxy event types the playbook framework must handle.
This is test infrastructure, not production code, but that framing does not reduce the risk. A buggy playbook evaluator produces false-positive test passes — it can mask regressions in the proxy layers it is supposed to exercise. The god-function pattern is evident: __bool__ is simultaneously a state machine driver, an event dispatcher, a hook auto-emitter, and an exception logger. The long-function and complex-branching patterns follow naturally from that scope.
The naming itself is a signal worth noting: overloading Python’s __bool__ dunder to run a full playbook evaluation is an unconventional contract. Any developer unfamiliar with this class will not expect bool(playbook) to mutate proxy connection state and drive a layer’s event loop.
My recommendation: extract the per-event-type dispatch logic into named methods (e.g., _handle_open_connection, _handle_hook_command). The outer while loop becomes a thin orchestrator. This brings CC down substantially and makes the playbook’s event-handling contract explicit and independently testable. Renaming the public API away from __bool__ would also make the contract far more discoverable.
peg$parse — web/src/js/filt/command.js
This is the command-expression counterpart to the filter parser above, also PEG.js-generated, also untouched for 31 days, also sitting in the debt quadrant. Its CC of 11 is far lower than the filter peg$parse, which makes sense — the command grammar (handling quoted strings, escape sequences, whitespace, and control characters) is simpler than the full filter expression grammar. But the fan-out of 56 still means changes to this file’s generated output will touch 56 distinct internal functions.
The excerpt shows the same PEG.js scaffolding pattern: peg$c0 through peg$c34 define terminals for string delimiters, escape characters, and whitespace classes, and peg$parse bootstraps the rule function table. The exit-heavy pattern is present here too — each parse attempt either advances peg$currPos or resets it on peg$FAILED, creating a branchy backtracking structure.
The same advice applies as for the filter parser: treat this as generated output, protect it with grammar-level tests, and ensure the .js file is never hand-edited. The difference from filt.js is that the command parser has a single author in the last 90 days and one total commit, suggesting it is even more frozen than the filter parser.
My recommendation: if mitmproxy’s command language ever needs to evolve, the grammar source should be the single point of change. Verify that the generation toolchain is documented in the contributing guide so that future maintainers do not attempt to patch command.js directly.
peg$parseExpr — web/src/js/filt/filt.js
peg$parseExpr is the most structurally complex function in this entire analysis by cyclomatic complexity, with a CC of 196 — nearly five times the already-high CC of flowsReducer. It lives in the same generated file as peg$parse above, has not been touched in 31 days, and sits in the debt quadrant. The source excerpt confirms it is the generated parse function for the filter expression rule: it tries each filter keyword (~all, ~a, ~b, ~bq, etc.) in sequence, using the PEG backtracking pattern of save-position, attempt match, reset on failure.
A CC of 196 means 196 independent execution paths — one for each grammar alternative the function must try. In a handwritten function, that number would be catastrophic. In a generated parser, it is expected and correct: each path corresponds to one filter keyword or subexpression form, and the generator guarantees they are exercised by the grammar’s own structure. Nesting depth of 32 mirrors this — each nested if (s0 === peg$FAILED) block represents one layer of alternative-trying.
The practical risk is the same as for peg$parse: this function will be wholesale regenerated if the grammar changes, and it cannot be meaningfully reviewed at the diff level. The zero touches in 30 days and single total commit confirm it is dormant structural debt, not active risk. But its CC of 196 means any tool or process that flags high-CC functions without understanding generation provenance will surface it repeatedly.
My recommendation: add a file-level comment or a .hotspotsrc.json exclusion (see vendor note below) marking filt.js and command.js as generated artifacts. This suppresses noise in future analyses without hiding the grammar source from review.
Looking beyond the top five, a few additional functions are worth brief mention. get_connection in mitmproxy/proxy/layers/http/__init__.py carries a CC of 42 and has been untouched for 31 days — it is a critical-band debt function in the HTTP proxy layer itself, not the web UI. That makes its blast radius potentially larger than anything in the web layer, because changes there sit on every proxied request path. onKeyDown in web/src/js/ducks/ui/keyboard.tsx is a fire-quadrant function with CC 30, touched once in the last 30 days with the most recent change 27 days ago — worth monitoring as the web UI keyboard handling evolves.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
god_function | 9 |
long_function | 8 |
complex_branching | 6 |
deeply_nested | 6 |
exit_heavy | 6 |
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/mitmproxy/mitmproxy
cd mitmproxy
git checkout a67fc64596c472cb468be6b3ac188511e8e9ff94
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5
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 →