Analyze Change Impact
Before refactoring a function, use impact to understand the blast radius.
Basic Usage
Output:
๐ฅ Impact analysis for 'my_function' โ HIGH
๐ Defined in: core.utils (L42)
๐ Direct callers (5): cli, core.engine, core.validator
๐ Affected modules (3): cli, core.engine, core.validator
๐งช Tests to rerun (4): test_utils, test_engine, test_cli, test_validator
๐ฆ Re-exported in (2): mylib, core
Understanding the Score
| Score | Criteria |
|---|---|
| LOW | 0-1 callers, no re-exports, no coupled files |
| MEDIUM | 2-4 callers or 1+ affected modules or coupled files |
| HIGH | 5+ callers, re-exported, many affected modules, or many coupled files |
Find Callers First
For just the call-site list without full impact analysis:
๐ 5 caller(s) of 'my_function':
cli:89 in main()
my_function(args)
core.engine:42 in process()
my_function(data)
Exclude Test Modules
Use --exclude-tests to focus the analysis on production code only, filtering out test modules from callers and affected modules:
This is useful when you want a clean view of production blast radius without test files inflating the caller count or affected module list. Test files are still listed under test_files โ they are only removed from the callers/affected-modules sections.
JSON for CI
{
"symbol": "my_function",
"score": "HIGH",
"definition": {"module": "core.utils", "line": 42, "kind": "function"},
"callers": [{"module": "cli", "line": 89, "context": "main"}],
"affected_modules": ["cli", "core.engine", "core.validator"],
"test_files": ["test_utils.py", "test_engine.py"],
"reexports": ["mylib", "core"],
"git_coupled": [
{"file": "src/mylib/config.py", "strength": 0.75, "co_changes": 6},
{"file": "src/mylib/schema.py", "strength": 0.45, "co_changes": 4}
]
}
Git Change Coupling
impact enriches its analysis with git change coupling โ files that historically co-change with the symbol's file. This reveals hidden dependencies invisible to static analysis (e.g., config files, schemas, docs that always change together).
Formula: coupling(A, B) = co_changes(A, B) / max(changes(A), changes(B)) over the last 6 months of git history.
Only files with coupling strength โฅ 0.3 and โฅ 3 co-changes are included.
Graceful degradation
If the project is not in a git repo or uses a shallow clone, git_coupled is simply an empty list โ no error is raised.
Import-Based Test Heuristic
When no test files reference a symbol by name (common for dataclasses, config models, or newly added symbols), impact falls back to an import-based heuristic: it scans tests/ for files that import the module containing the symbol.
Results appear in a separate key to distinguish them from direct matches:
When does the heuristic run?
Only when test_files is empty and the symbol has a known definition. If direct test matches exist, the heuristic is skipped to avoid noise.
Workspace: Cross-Package Impact
For uv workspaces with multiple packages, impact automatically performs cross-package analysis:
๐ฅ Impact analysis for 'ToolResult' โ HIGH (workspace)
๐ Defined in: axm::tools.base (L15) [package: axm]
๐ Direct callers (12): axm_mcp::server, axm_ast::tools.context, ...
๐งช Tests to rerun (5): test_tools, test_server, ...
๐ฆ Re-exported in (3): axm, axm_ast, axm_mcp
Automatic detection
No flag needed โ if the path contains a pyproject.toml with [tool.uv.workspace], workspace mode activates automatically.
Workflow: Safe Refactoring
-
Check impact before changing a symbol:
-
Run only affected tests after your change:
-
Verify no callers remain if removing a symbol: