twentyhq/twenty sandbox and rendering hotspots — 5 functions to address first

In twentyhq/twenty, a Python xlsx recalculation function and a React halftone canvas renderer both score critical activity-weighted risk, flagged as god functions with extreme branching complexity actively changing within the last three days.

Stephen Collins ·
oss typescript refactoring code-health
Activity Risk19.01Low
Hottest Functionrecalc

Antipatterns Detected

complex_branching5god_function5long_function5deeply_nested4exit_heavy4

Key Points

What is a god function and why does it matter in twenty?

A god function is one that has accumulated so many responsibilities — branching logic, direct calls to numerous other functions, and inline handling of multiple concerns — that it becomes the structural centre of gravity for a module. In measurable terms, god functions typically combine high cyclomatic complexity with high fan-out: the number of distinct functions they directly call. In twenty's current hotspot set, both `recalc` and `HalftoneCanvas` are flagged as god functions; `HalftoneCanvas` alone calls into 140 distinct functions. The concrete problem is coupling: a change anywhere in those 140 callees can silently alter the behavior of `HalftoneCanvas`, and a change inside it can ripple outward just as unpredictably. God functions are also extremely difficult to unit-test in isolation because spinning up one test case effectively exercises a large fraction of the surrounding system.

How do I reduce cyclomatic complexity in TypeScript?

The most reliable technique is extract-method refactoring: identify cohesive clusters of branches or logic within a high-complexity function and move them into named, single-purpose functions with their own tests. For TypeScript specifically, decomposing large React components into custom hooks is an effective form of this pattern — it moves stateful logic out of the render function and into testable units. A cyclomatic complexity above 15 is a strong signal to split; above 30, like `recalc`'s CC of 51, warrants immediate decomposition. A concrete first step for `recalc` would be to identify the top-level conditional branches — the ones contributing most to the count — and extract each arm into a named helper function, which alone could cut the CC of the parent function by more than half.

Is twenty actively maintained?

Yes — the "fire" quadrant classification of the two top-ranked functions is direct evidence of active development. Both `recalc` and `HalftoneCanvas` were each touched once in the last 30 days, with the most recent change just three days before this analysis. Across the full dataset, 2,237 functions fall into the "fire" quadrant, meaning they combine structural complexity with recent commit activity. Active maintenance and accumulated structural complexity are not mutually exclusive: twenty is clearly under active development, and the critical-band functions identified here are the natural result of a codebase evolving quickly — they represent the areas where that velocity carries the most near-term risk.

How do I reproduce this analysis?

The Hotspots CLI is available at github.com/hotspots-dev/hotspots. This analysis was run against twentyhq/twenty at commit be39702. To reproduce it, check out that commit with `git checkout be39702` and then run `hotspots analyze . --mode snapshot --explain-patterns --force` from the repository root. The same command works on any local git repository without additional configuration.

What does activity-weighted risk mean?

Activity-weighted risk is a score that combines a function's structural complexity — derived from cyclomatic complexity, maximum nesting depth, and fan-out — with how frequently it has been changed in recent commits. A function with extremely high cyclomatic complexity that has not been touched in years scores lower than a moderately complex function being changed every few days, because the dormant function poses less near-term regression risk. The logic is that bugs are most likely to be introduced when developers are actively editing code they struggle to reason about. In twenty's case, `recalc` scores an activity-weighted risk of 19.01 because it combines a cyclomatic complexity of 51 and nesting depth of 7 with a commit just three days ago — structurally hard to change safely, and being changed right now.

At commit be39702, Hotspots surfaces two critical-band functions in twentyhq/twenty that combine high structural complexity with recent commit activity — each touched within the last three days, each carrying an activity-weighted risk score above 19. Twenty is an open-source CRM platform with 16,560 analyzed functions, 647 of which rank as critical. The top two functions — recalc in the xlsx sandbox script and HalftoneCanvas in the website renderer — both land in the “fire” quadrant, meaning they are simultaneously hard to reason about and actively changing right now, not problems deferred to a future sprint.

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

FunctionFileRiskCCNDFO
recalcpackages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/xlsx/recalc.py19.051716
HalftoneCanvaspackages/twenty-website/src/lib/halftone/components/HalftoneCanvas.tsx19.0436140
HalftoneStudiopackages/twenty-website/src/app/[locale]/halftone/_components/HalftoneStudio.tsx17.424581
validate_all_relationship_idspackages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/docx/validation/base.py17.440721
apply_replacementspackages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/pptx/replace.py17.354432

Large Repo Analysis

twenty 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.

The headline numbers tell a clear story: both top-ranked functions carry activity-weighted risk scores above 19.0, flag every structural antipattern in the dataset — complex branching, deep nesting, god-function coupling, multiple exit paths, and excessive length — and were each modified within the last 72 hours. That combination is the definition of live regression risk.

recalcpackages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/xlsx/recalc.py

With a cyclomatic complexity of 51 and a max nesting depth of 7, recalc is the most structurally dense function in this hotspot set, carrying an activity-weighted risk score of 19.01. Its file path places it inside a sandboxed code-interpreter module responsible for processing xlsx data — a context where correctness is non-negotiable and edge cases proliferate. CC 51 means there are at least 51 independent execution paths through this function; each one is a required test case and a potential bug surface. Nesting reaching level 7 means a developer reasoning about the deepest conditional must mentally track seven layers of context simultaneously — well past the ND 4 threshold that reliably signals comprehension difficulty.

The god-function and long-function patterns compound the branching problem: recalc calls into 16 distinct functions (fan-out of 16) while also inlining what are likely several discrete logical stages of recalculation. Exit-heavy behavior — multiple return or exception paths scattered across 51 branches — makes exhaustive test coverage genuinely difficult to achieve and verify. The function was touched once in the last 30 days, just three days ago, confirming it is under active development. The file has no historical bug-linked commits or reverts recorded, which is useful context: the risk here is structural and forward-looking, not a record of past failures. The single author active in the last 90 days means there is concentrated ownership — a bus-factor concern if this module needs urgent attention from others.

Recommendation: Apply extract-method refactoring to decompose recalc into named sub-functions that each handle one recalculation stage. Targeting the deepest nesting clusters first — those contributing most to the ND 7 score — will yield the fastest comprehension improvement. Aim to bring CC below 20 across the resulting functions, which would also make each branch testable in isolation.

HalftoneCanvaspackages/twenty-website/src/lib/halftone/components/HalftoneCanvas.tsx

HalftoneCanvas is the most structurally coupled function in this analysis. It calls into 140 distinct functions — a fan-out figure that is not a typo — making it the structural centre of gravity for the halftone rendering subsystem in Twenty’s marketing website. A change anywhere in those 140 callees can have an unexpected effect on this component, and a change inside HalftoneCanvas itself ripples outward just as broadly. Its cyclomatic complexity of 43 and nesting depth of 6 indicate that the component has accumulated significant conditional rendering logic, likely handling canvas API calls, animation frame management, device pixel ratio calculations, and responsive layout decisions all within one function body.

Like recalc, it was touched once in the last 30 days — three days ago — and sits firmly in the “fire” quadrant with an activity-weighted risk score of 19.0. The exit-heavy pattern suggests multiple early-return guards (perhaps for null canvas refs, missing browser APIs, or SSR environments), each of which is a path that must be independently exercised by tests. With a single author active in the last 90 days and no prior bug or revert history on file, the concern is purely structural: a component this large and this broadly coupled becomes increasingly fragile with each iteration.

Recommendation: Introduce a facade or decompose HalftoneCanvas into focused sub-components or custom hooks — for example, separating canvas initialization, the render loop, and event handling into distinct units. Reducing fan-out from 140 to something closer to 20–30 per sub-unit would make individual behaviors testable without instantiating the entire rendering pipeline.

HalftoneStudiopackages/twenty-website/src/app/[locale]/halftone/_components/HalftoneStudio.tsx

HalftoneStudio is the companion hotspot to HalftoneCanvas: lower on raw branching than the renderer, but still broad enough to make UI changes expensive. Its activity-weighted risk score of 17.4 comes from CC 24, nesting depth 5, and fan-out 81, which points to a component coordinating many behaviours rather than only presenting state. Because it lives in the app-level halftone route, it likely owns configuration, preview state, and wiring into the canvas component.

The right move is to split orchestration from presentation. Extract custom hooks for studio state and controls, then leave the component to compose smaller pieces. That would reduce the god-function and long-function pressure while giving tests stable seams around the most change-prone UI decisions.

validate_all_relationship_idspackages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/docx/validation/base.py

The DOCX validator shows the same sandbox-script pattern as recalc, but in validation rather than spreadsheet recalculation. CC 40 and nesting depth 7 are enough to make invalid-document edge cases hard to audit, and the risk score of 17.4 keeps it close behind the halftone UI functions. Fan-out is a more contained 21, so the main issue is not call breadth; it is deeply nested decision logic.

Start by flattening guard clauses and extracting validators for each relationship category. A validation pipeline with named checks would make the exit-heavy paths explicit and would let tests target one document relationship rule at a time instead of exercising the whole validator.

apply_replacementspackages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/pptx/replace.py

apply_replacements has the highest CC in the top five at 54, but its lower nesting depth of 4 keeps it just below the other sandbox functions with a 17.3 risk score. That shape suggests many replacement cases or type-specific branches arranged relatively flatly. The fan-out of 32 also indicates a function doing substantial orchestration across the PPTX replacement pipeline.

Prioritise a dispatch-table or strategy-style split by replacement type. That would turn the broad branch set into named handlers, reduce the parent function’s CC, and make regressions easier to isolate when presentation replacement behaviour changes.

Key Takeaways

  • recalc needs decomposition now. CC 51 with nesting depth 7 in an actively-changing sandbox script is the highest-priority refactoring target in this analysis. Extract discrete recalculation stages into named functions before the next development push adds more branching.
  • HalftoneCanvas’s fan-out of 140 is the broadest coupling in the dataset. Even incremental decomposition — extracting the render loop or initialization logic into a custom hook — would meaningfully reduce the blast radius of future changes.
  • The sandbox scripts repeat the same shape across formats. validate_all_relationship_ids and apply_replacements should be split into named validators or replacement handlers so edge cases can be tested independently.

Patterns Found

Antipatterns detected across the top functions in this snapshot:

PatternOccurrences
complex_branching5
god_function5
long_function5
deeply_nested4
exit_heavy4

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/twentyhq/twenty
cd twenty
git checkout be39702fd2fbbd303af5d85ddc8624228ae4cf9c
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.

Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →

Run this on your own codebase

Hotspots runs locally in under a minute — no account, no data leaves your machine.

macOS
$ brew install Stephen-Collins-tech/tap/hotspots
Linux / cargo
$ cargo install hotspots-cli
Run in any repo
$ hotspots analyze .
★ Star on GitHub

Related Analyses