croc, the peer-to-peer file transfer tool, has 33 critical-band functions out of 161 total — and its four highest-risk hotspots are all in the ‘fire’ quadrant, meaning they combine structural complexity with active recent commit churn. The top-ranked function, Send in src/croc/croc.go, carries a recent commit activity of 16.37 and a fan-out of 50, making every change to it a potential ripple across half the codebase. These aren’t cleanup candidates sitting in a backlog — they are live regression surfaces being modified today.
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 |
|---|---|---|---|---|---|
Send | src/croc/croc.go | 17.2 | 8 | 7 | 50 |
send | src/cli/cli.go | 16.2 | 12 | 4 | 40 |
receive | src/cli/cli.go | 15.4 | 15 | 3 | 32 |
Receive | src/croc/croc.go | 15.2 | 12 | 4 | 43 |
processMessageFileInfo | src/croc/croc.go | 14.6 | 10 | 5 | 23 |
Hotspot Analysis
Send — src/croc/croc.go
As the core library-level entry point for initiating a file transfer, Send is almost certainly responsible for orchestrating the entire outbound transfer lifecycle — connection setup, file preparation, relay negotiation, and progress reporting. Its fan-out of 50 is the highest in the dataset, meaning it directly invokes 50 distinct functions, giving it an enormous blast radius: a signature change or behavioral shift here propagates across virtually the entire codebase. A max nesting depth of 7 signals deeply layered conditional logic that is hard to reason about in isolation, and with a recent commit activity of 16.37 in the fire quadrant, this function is being actively modified while already carrying that structural load — a textbook live regression risk. The god_function and long_function patterns confirm it is doing far more than any single function should.
Recommendation: Before the next commit touches Send, write characterization tests that capture its current input/output behavior across transfer scenarios; then begin extracting sub-responsibilities — connection orchestration, file chunking coordination, and progress lifecycle — into dedicated functions to reduce the fan-out from 50 toward something reviewable.
send — src/cli/cli.go
The lowercase send in src/cli/cli.go is the CLI-layer counterpart to the library’s Send — it likely parses user flags, validates arguments, builds the options struct, and delegates to the library. Its cyclomatic complexity of 12 means there are at least 12 independent execution paths through its branching logic, each a required test case, and its fan-out of 40 shows it reaches broadly into the codebase despite being a CLI entry point. The neighbor_risk pattern is a notable flag here: changes to send in cli.go are correlated with required edits in adjacent code, meaning a focused change here tends to become a wider, coordinated edit. With a recent commit activity of 14.31 in the fire quadrant, this function is actively changing under those conditions right now.
Recommendation: Decompose the 12-path branching logic by extracting flag validation and options construction into separate, independently testable functions; address the neighbor_risk signal by auditing which adjacent functions in cli.go are most frequently co-edited with send and consider co-locating shared logic.
receive — src/cli/cli.go
The receive function in src/cli/cli.go is the CLI entry point for inbound file transfers, and at a cyclomatic complexity of 15 it is the most branch-heavy of the CLI-layer functions — 15 independent execution paths representing every combination of flags, error conditions, and user prompts the receiver must handle. Its fan-out of 32 shows it still reaches broadly across the codebase, and the exit_heavy pattern indicates multiple return paths that are each a gap in test coverage. In the fire quadrant with a recent commit activity of 13.63, it is actively being changed at a complexity level that makes each edit risky to get right.
Recommendation: Use the CC of 15 as a decomposition target: identify the dominant branching axes — likely overwrite prompts, relay selection, and password handling based on what a CLI receiver must do — and extract each into a named function so that individual paths can be unit-tested in isolation.
Receive — src/croc/croc.go
Receive is the library-level entry point for inbound file transfers — the counterpart to the CLI’s receive in cli.go. Its fan-out of 43 is second only to Send in this dataset, meaning it reaches into 43 distinct functions to coordinate the receiving side of a transfer: relay negotiation, decryption, file assembly, and progress handling. A cyclomatic complexity of 12 adds at least 12 independent execution paths through its branching logic, and those two factors together earn it the god_function label. Unlike its CLI counterpart, Receive operates at the library layer where callers outside croc’s own CLI can invoke it directly, making its interface harder to change safely. At Risk 15.2 in the fire quadrant, it is under active change pressure right now.
Recommendation: Audit Receive’s 43 callees and group them by responsibility — relay setup, cryptographic handshake, file I/O, and progress reporting are likely natural seams. Extracting each group into a dedicated coordinator function reduces fan-out to a reviewable number and makes the inbound transfer lifecycle readable at a glance.
processMessageFileInfo — src/croc/croc.go
processMessageFileInfo is the one debt-quadrant function in the top five: its Risk score of 14.6 reflects structural weight rather than recent churn, meaning it is complex but not currently under heavy modification. A nesting depth of 5 signals layered conditional logic — likely parsing and validating the file metadata messages exchanged during a transfer — and a fan-out of 23 combined with a cyclomatic complexity of 10 means any future edit to this function must navigate significant branching and callee coupling. Debt-quadrant functions are lower urgency than fire-quadrant ones, but they become live risks the moment a new feature or protocol change forces a modification.
Recommendation: Before the next change to the file-info message protocol touches this function, extract the validation logic for each metadata field into a named helper — this reduces both the CC and the nesting depth, and leaves the function as a thin dispatcher that is straightforward to follow when the next change arrives.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
god_function | 10 |
long_function | 9 |
exit_heavy | 8 |
deeply_nested | 4 |
complex_branching | 4 |
neighbor_risk | 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.
Key Takeaways
Sendin src/croc/croc.go has a fan-out of 50 and is in the fire quadrant — add characterization tests before any further modifications to contain blast radius.- The
receivefunction in src/cli/cli.go has the highest cyclomatic complexity of the top hotspots at 15, meaning at minimum 15 test cases are needed to cover its branches; audit current test coverage against that number. processMessageFileInfoin src/croc/croc.go is the one debt-quadrant function in the top five — it hasn’t been under recent pressure, but its nesting depth of 5 and fan-out of 23 mean it carries high blast radius when next touched; treat it as a refactoring prerequisite before the next feature push into croc.go.
Reproduce This Analysis
git clone https://github.com/schollz/croc
cd croc
git checkout 9a3d42ae7d4eecbf99266dafb79330e5774f81f3
hotspots analyze . --mode snapshot --explain-patterns --force
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →