Function-Level Cycles
Function-Level Cycles
Section titled “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.
Module vs Function Level
Section titled “Module vs Function Level”| Level | What it detects | Use when |
|---|---|---|
| Module | Import cycles (A imports B, B imports A) | You want to fix dependency structure, tree-shaking, and build boundaries |
| Function | Call 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.
What It Measures
Section titled “What It Measures”| Metric | What it tells you | Ideal |
|---|---|---|
scc.function.component_count | Number of independent call-graph components | High (= function count) |
scc.function.cycle_count | Number of function-level cycles | 0 |
scc.function.max_cycle_size | Size of the largest function-level cycle | 0 |
scc.function.total_nodes_in_cycles | Functions stuck in call cycles | 0 |
scc.function.call_mass | Total call volume (call_count) inside cycles | 0 |
scc.function.cycle_cut_candidates_count | Number of suggested edges to break call cycles | — |
Cycle-Cut Candidates (Function Level)
Section titled “Cycle-Cut Candidates (Function Level)”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" } ] } } } } }}When to Use Function-Level Analysis
Section titled “When to Use Function-Level Analysis”- 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_massmeans much execution still flows through cycles.
Enabling and Output
Section titled “Enabling and Output”Function-level metrics appear when scc is enabled and a call graph is available in the run.
To inspect call-cycle cut candidates:
arxo analyze --format json | jq '.ui_schemas.scc.issues.categories.cycle_cut_candidates.critical'To inspect function-level numeric keys:
arxo analyze --format json | jq '.results[] | select(.id=="scc") | .data[] | select(.key|startswith("scc.function."))'Next Steps
Section titled “Next Steps”- Interpretation: how to read cycle results and thresholds
- Fixing Cycles: step-by-step process
- Refactoring Patterns: patterns that break cycles
- Keys and Output Contract: full key list
- Circular Dependencies: back to overview