Skip to content
Arxo Arxo

Function-Level Cycles

Arxo can detect cycles not only between modules (imports) but also between functions (calls). Function-level cycles show where runtime call chains form loops, useful when module-level analysis is clean but control flow is still tightly coupled.

For an overview of circular dependencies, see Circular Dependencies.

LevelWhat it detectsUse when
ModuleImport cycles (A imports B, B imports A)You want to fix dependency structure, tree-shaking, and build boundaries
FunctionCall cycles (f1 calls f2, f2 calls f1)You want to find circular call chains and runtime coupling

Function-level analysis requires a call graph. If the call graph is unavailable for a run, only module-level SCC metrics are reported.

MetricWhat it tells youIdeal
scc.function.component_countNumber of independent call-graph componentsHigh (= function count)
scc.function.cycle_countNumber of function-level cycles0
scc.function.max_cycle_sizeSize of the largest function-level cycle0
scc.function.total_nodes_in_cyclesFunctions stuck in call cycles0
scc.function.call_massTotal call volume (call_count) inside cycles0
scc.function.cycle_cut_candidates_countNumber of suggested edges to break call cycles

When call graph data is available, Arxo emits:

  • scc.function.cycle_cut_candidates_count (numeric count)
  • scc.function.cycle_cut_candidates (table in metric data)
  • ui_schemas.scc.issues.categories.cycle_cut_candidates (UI issue category)

Each candidate includes:

  • from and to: caller and callee IDs
  • call_count: how often the edge appears (lower is usually cheaper to cut)
{
"ui_schemas": {
"scc": {
"issues": {
"categories": {
"cycle_cut_candidates": {
"critical": [
{
"from": "src/document/builders/join.js::buildJoin",
"to": "src/document/utilities/assert-doc.js::assertDoc",
"call_count": 2,
"note": "Cheapest edge to cut in this call-graph cycle"
}
]
}
}
}
}
}
}
  • Module-level is clean: no import cycles, but code still feels tangled.
  • Refactoring inside a module: you need to break circular calls between functions/classes.
  • Runtime coupling is high: high call_mass means much execution still flows through cycles.

Function-level metrics appear when scc is enabled and a call graph is available in the run.

To inspect call-cycle cut candidates:

Terminal window
arxo analyze --format json | jq '.ui_schemas.scc.issues.categories.cycle_cut_candidates.critical'

To inspect function-level numeric keys:

Terminal window
arxo analyze --format json | jq '.results[] | select(.id=="scc") | .data[] | select(.key|startswith("scc.function."))'