Before changing a file, your agent should know what it's walking
into. get_risk rolls up churn, complexity, dependents, hidden
coupling (co-changes), ownership, test coverage, and security signals
into a single per-file profile, plus an optional PR-style blast-radius
analysis when you pass a changed_files list.
When to call
- Before editing any file the agent doesn't already understand.
- PR review: pass
changed_filesto get the transitive impact surface, missing co-change partners, and recommended reviewers. - Architectural planning: surface bus-factor risks and coupling hotspots ahead of time.
Parameters
| Parameter | Type | Description |
|---|---|---|
targetsrequired | string[] | File paths to assess. |
repo | string | Repository alias. Usually omitted. |
changed_files | string[] | When provided, switches the response into PR mode: it leads with a directive, and adds transitive affected files, co-change warnings, recommended reviewers, and a structural_impact_score of 0 to 10. |
include | string[] | Opt-in blocks. "graph" adds dependents, consumers, cross_repo_links, impact_surface, relationship_analysis, and (in PR mode) direct_risks. "churn" adds change_magnitude, risk_type, and change_pattern. "scales" adds the per-field units and calibration, which never vary between calls, so ask for them once per session. |
Returns
targets is keyed by file path. Each entry contains:
| Field | Meaning |
|---|---|
hotspot_score | 0 to 1 churn percentile (higher = changed more often) |
health_score | The stored code-health score, 0 to 10. Absent when the file has no stored health row |
trend | "increasing", "decreasing", or "stable" (30d vs 60d rate) |
dependents_count | Direct directed dependents: files the graph records as depending on this one. A floor over the indexed graph, not a proof of completeness |
co_change_partners | Top 5 historical co-changers (see below) |
primary_owner, owner_pct | Historical owner |
recent_owner, recent_owner_pct | Active maintainer if different |
bus_factor | How many people could disappear before the file becomes unowned |
contributor_count | Total contributors |
coverage_pct, branch_coverage_pct | From ingested coverage data. Absent when none was ingested |
top_biomarkers | Up to 3 open health findings, highest impact first |
defect_profile | (only on files with counted bug fixes) fix_count, last_fix_days_ago, bug_magnet flag, and up to 3 top_symbols most often touched by those fixes |
test_gap | true if coverage data doesn't prove a test exercises this file, and no test file matches its basename |
security_signals | kind, severity, snippet from static analysis |
episodes | (only when at least one exists) count of dated episode records bound to this target; get_why serves the bodies. A directory target aggregates everything beneath it |
risk_summary | One-line human summary |
These fields ship only when include asks for them:
| Field | Gated behind |
|---|---|
dependents, consumers, cross_repo_links, impact_surface, relationship_analysis | include=["graph"] |
direct_risks (inside pr_blast_radius) | include=["graph"] |
risk_type, change_pattern, change_magnitude | include=["churn"] |
All of them are computed either way and all of them feed risk_summary.
include decides whether they ship, not whether they run. The gating is
deliberate: impact_surface and direct_risks are pagerank floats an
agent cannot rank against anything, and risk_type, change_pattern and
change_magnitude restate numbers already printed beside them.
Top-level extras:
global_hotspots: top 5 hotspot files in the repo, excluding the targets. It accompanies a multi-target call only. A single named file does not need ambient orientation.pr_blast_radius(only ifchanged_filesprovided):transitive_affected,cochange_warnings,recommended_reviewers,test_gaps,structural_impact_score, anddirect_risksunderinclude=["graph"].
Co-change partners
Each partner row carries:
| Field | Meaning |
|---|---|
weight | A recency-decayed sum over shared commits, not a count. Fractional by construction |
direction | a_to_b, b_to_a, or undirected, where a is the assessed file and b the partner |
conf_ab, conf_ba | The share of each file's own commits that touched the other |
has_structural_link, has_import_link | Whether the graph also connects them |
last_co_change | Date of the most recent shared commit |
direction is decided by comparing the two confidences: the side that
seldom changes without the other leads. Equal confidences stay
undirected, and so does an index written before the per-file commit
totals were recorded, which omits conf_ab and conf_ba entirely.
Co-change is historical correlation. It is not a dependency.
structural_impact_score is a deterministic, uncalibrated 0 to 10
structural-exposure heuristic: localized below 4, moderate from 4 to
below 7, broad at 7 or above. It is not a runtime-breakage
probability, and it is not comparable to get_change_risk's score.
overall_risk_score remains an exact alias for the compatibility
window, carrying its own migration metadata.
PR mode: read directive first
When changed_files is passed, the response leads with a directive
block. This is the block a PR-reviewing agent is told to read before
anything else in the response:
| Field | Meaning |
|---|---|
may_break | Production files the diff structurally reaches, by a reverse-import walk. Candidates for review, not proven breakage, which is why it says may |
may_break_tests | Test files reached the same way, kept separate so a burst of broken tests doesn't crowd out production impact |
missing_cochanges | Historical co-changers absent from the diff |
missing_tests | Changed files without test coverage |
tests_to_run | Runnable test ids for the changed files, measured first and falling back to inferred. tests_to_run_basis says which: measured, inferred, or none |
test_recommendations | The typed form of the same evidence. Each row keeps its basis (measured means the per-test coverage map found the test; inferred means structural reachability named a candidate and is not coverage proof), its source files, and its repository identity |
Unavailable coverage with tests_to_run: [] never means no tests are
needed. coverage_analysis, test_inference_analysis and
test_analysis separate available-but-empty evidence from unavailable,
stale, partial and degraded analysis.
get_risk is handed a file list and never a diff, so may_break and
may_break_tests cannot know whether the symbol an importer actually
uses changed. Read both as reach worth reviewing rather than predicted
breakage.
In workspace mode, the same directive also carries the changed repo's
cross-repo fallout: will_break_consumers (services in other repos that
structurally depend on this one), missing_cross_repo_cochanges,
breaking_changes (incompatible provider-contract changes and the
consumers they endanger), conformance_violations (declared
dependency-rule breaches) and dependency_cycles.
Despite its name, will_break_consumers is structural reach and not a
runtime claim: its rows carry claim: structural_reach and
runtime_breakage_claim: false. Only breaking_changes comes from
contract diffing.
directive is the block to act on. Everything else in the response
ranks and describes; directive recommends. Read it before
pr_blast_radius or any of the per-target fields.
Example
get_risk(["src/auth/service.py"])
get_risk(
targets=["src/payments/api.py", "src/payments/db.py"],
changed_files=["src/payments/api.py", "src/payments/db.py"],
)
get_risk(targets=["src/auth/service.py"], include=["graph", "churn"])Things worth knowing
- Risk type classification (priority order), under
include=["churn"]:bug-proneif the file is flaggedbug_magnetor has 3+ counted bug fixes in the fix history (not a keyword scan over commit messages);churn-heavyif churn percentile is 0.7 or above;bus-factor-riskifbus_factor == 1, more than 20 commits, and the repo isn't a small team unless the file is itself a hotspot;high-couplingif there are 5 or more dependents. - Change pattern is the dominant commit category at 50% or more,
else
mixed-activity. - Test gap detection checks ingested coverage data first: if a
coverage report proves a test exercises the file, it's not a gap. Only
when there's no coverage proof does it fall back to a filename
heuristic, looking for
test_*.py,*_test.py, or*.spec.*matching the file's basename. Test files themselves are never reported as having a test gap. - PR blast radius walks the import graph up to depth 3.
Recommended reviewers are the top-5 owners of affected files.
cochange_warningsflag missing historical co-change partners not in the PR. - Cross-repo impact (workspace mode): co-change partners and
contract links from other repos contribute to
dependents_count. - Responses are bounded. A default call fits 24,000 serialized
characters and a call with a nonempty
includegets 32,000. Anything reduced carries counts plus a recovery ref in_meta.omitted. An include-gated block is a projection, not an omission, so it is not listed there.
A high hotspot_score plus bus_factor: 1 plus test_gap: true is
the danger triangle. Don't ship a refactor of that file without pulling
the primary owner into review.