You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
get_architecture hotspots report inflated fan_in that contradicts actual graph in-degree (same-name collision across languages) #725
get_architecture reports a hotspot fan_in that does not match the node's real in-degree in the graph. For short identifiers shared across languages (e.g. commit, parse, add), the reported fan_in appears to aggregate by bare name rather than by resolved node — producing large over-counts, and attributing the count to a node that actually has in-degree 0.
Environment
Mixed Python + TypeScript/JavaScript monorepo, indexed with mode: full.
Two distinct symbols named commit: a JS arrow function commit (defined in a React page component) and a Python method Store.commit.
But that JS commit has one local call-site, and querying the graph directly shows it has zero inbound edges:
query_graph: MATCH (n {name:'commit'})<-[r]-(c)
RETURN n.qualified_name, count(r)
→ only the Python Store.commit, in_degree 20.
The JS Editor.commit node returns nothing (in_degree 0).
So fan_in: 234 is not reproducible from CALLS/USAGE edges.
Hotspots whose names are class-qualified Python methods matched their real in-degree correctly (a function reported with fan_in: 46 had graph in_degree 46), so the inflation is specific to short bare names shared across the Python/JS boundary.
Expected
Hotspot fan_in should equal the node's resolved inbound CALLS/USAGE in-degree (the value query_graph / search_code already report per node), not a count aggregated by bare name.
Impact
get_architecture is the first-call "understand this codebase" tool; an inflated headline metric on the wrong node is misleading. The qualitative structure (clusters, layers, routes, languages) is accurate — only the hotspot fan_in figures are affected.
Possibly related to #558 (Class in_degree/out_degree = 0) — both are node-level degree-metric correctness issues.
Thanks, this is a useful correctness report. The expected invariant is right: get_architecture hotspots should be node/resolved-symbol based, not bare-name aggregates. I’m tracking it under graph query/reporting correctness; the fix should start with a regression fixture containing same-named Python and JS symbols and assert fan_in matches graph in-degree.
Additional public repro — willow-2.0 (Python monorepo)
We maintain a fleet structural audit that treats CBM as a discovery instrument and verifies every measurement against source (addendum). Re-checked on v0.8.1, project home-sean-campbell-github-willow-2.0 (~17.8k nodes).
Case A — get_architecture fan_in matches graph in_degree, but both are inflated by bare-name collapse
MATCH (m:Method) WHEREm.qualified_nameCONTAINS'JsonStore.get'RETURNm.qualified_name, m.in_degree-- → 789 (matchesfan_inexactly)
So the hotspot metric is internally consistent with node-levelin_degree — but that in_degree itself aggregates every .get() / .append()-shaped call in the repo onto one resolved symbol (F-007 in our ledger). Qualitative architecture (clusters, packages) looks fine; hotspot ranking is misleading for common method names.
Case B — trace_path on bare execute lists cursor.execute callers as inbound to nuke.execute
Only one Function named execute exists (willow.nuke.execute, in_degree: 66). trace_path(function_name="execute", direction="inbound") returns grove_msg.cmd_send and dozens of scripts as callers.
Source for cmd_send — calls cur.execute(...) (Postgres cursor), not nuke.execute:
cur.execute(
"INSERT INTO grove.messages ...",
(channel_id, sender, content),
)
This is the same bare-name / receiver-blind resolver class as inflated fan-in, seen from the traversal side.
Links
Our F-007 write-up + cbm_verify_callers guardrail: sap/cbm_facade.py in willow-2.0
Another reproduction of this, cross-language but Bash↔Python this time rather than JS↔Python.
Version: v0.10.2
Setup: repo mixes Bash and Python. Two distinct mains:
.codex/setup-codex-cloud.sh — a Bash script's top-level main
py_packages/validate_agent_files/validate_agent_files/main.py:main — a Python CLI entry point, called from ~45 pytest test functions (test_cli_*, test_issue310_*, etc.)
But trace_path(function_name=".codex.setup-codex-cloud.main", direction="inbound", depth=1) shows real callers_total: 1 (just the file itself invoking its own script).
Querying inbound edges directly onto that qualified node:
MATCH (a)-[r]->(b:Function{qualified_name:"workspaces-agent-devcontainer-wortree-2.codex.setup-codex-cloud.main"})
RETURNtype(r), a.qualified_nameLIMIT50
returns the ~45 pytest test_cli_*/test_issue310_* CALLS+TESTS edges that actually target the Pythonmain, not the Bash one — confirming the bare-name aggregation described in this issue, just across a different language pair (Bash/Python instead of JS/Python).
Same workaround as the OP: trace_path/direct query_graph on the exact qualified name gives the correct in-degree; only the hotspots aspect of get_architecture is affected.
Thank you @anton-matosov. The v0.10.2 Bash/Python reproduction confirms that this resolver class persists beyond the original JavaScript/Python case. Current unique_name resolution is project-wide and language-agnostic, so wrong CALLS edges can inflate a node's in-degree before get_architecture ranks hotspots.
#1572 now provides a small Python-to-TypeScript instance of the same root behavior, while #1555 covers the multi-candidate receiver case. They are related rather than exact duplicates, so all remain linked under #594.
@rudi193-cmd, thank you for volunteering to take this on. That would be welcome. I have raised #725 to priority/high: the fresh v0.10.2 Bash/Python reproduction confirms that the cross-language, bare-name resolver can still attach real edges to the wrong node and then inflate architecture hotspots.
Please keep #725 and #876 as separate PRs, with one reproducer and one claim per change. Before starting the resolver change, compare with #1572 and #1555 so the fixes do not compete or encode different ambiguity rules. A focused red case that distinguishes two same-named symbols across languages is the most useful first slice.
Thank you again for offering to give back on a path you use regularly.
Fixed by #1647 (89f0cd4), landing in the next release: suffix_match CALLS edges are no longer created across language-family boundaries (JS/TS/TSX counting as one family), so same-named symbols in different languages stop inflating hotspot fan_in. unique_name cross-language bleed is tracked separately in #1572.
Activity
DeusData commentedon Jun 30, 2026
Thanks, this is a useful correctness report. The expected invariant is right:
get_architecturehotspots should be node/resolved-symbol based, not bare-name aggregates. I’m tracking it under graph query/reporting correctness; the fix should start with a regression fixture containing same-named Python and JS symbols and assertfan_inmatches graph in-degree.rudi193-cmd commentedon Jul 5, 2026
Additional public repro — willow-2.0 (Python monorepo)
We maintain a fleet structural audit that treats CBM as a discovery instrument and verifies every measurement against source (addendum). Re-checked on v0.8.1, project
home-sean-campbell-github-willow-2.0(~17.8k nodes).Case A —
get_architecturefan_in matches graphin_degree, but both are inflated by bare-name collapseget_architecturehotspot:query_graph:So the hotspot metric is internally consistent with node-level
in_degree— but thatin_degreeitself aggregates every.get()/.append()-shaped call in the repo onto one resolved symbol (F-007 in our ledger). Qualitative architecture (clusters, packages) looks fine; hotspot ranking is misleading for common method names.Case B —
trace_pathon bareexecutelistscursor.executecallers as inbound tonuke.executeOnly one
Functionnamedexecuteexists (willow.nuke.execute,in_degree: 66).trace_path(function_name="execute", direction="inbound")returnsgrove_msg.cmd_sendand dozens of scripts as callers.Source for
cmd_send— callscur.execute(...)(Postgres cursor), notnuke.execute:This is the same bare-name / receiver-blind resolver class as inflated fan-in, seen from the traversal side.
Links
cbm_verify_callersguardrail:sap/cbm_facade.pyin willow-2.0Happy to attach a minimal query script if useful for a regression fixture.
anton-matosov commentedon Aug 12, 2026
Another reproduction of this, cross-language but Bash↔Python this time rather than JS↔Python.
Version: v0.10.2
Setup: repo mixes Bash and Python. Two distinct
mains:.codex/setup-codex-cloud.sh— a Bash script's top-levelmainpy_packages/validate_agent_files/validate_agent_files/main.py:main— a Python CLI entry point, called from ~45 pytest test functions (test_cli_*,test_issue310_*, etc.)Observed:
get_architecture→hotspotsreported:But
trace_path(function_name=".codex.setup-codex-cloud.main", direction="inbound", depth=1)shows realcallers_total: 1(just the file itself invoking its own script).Querying inbound edges directly onto that qualified node:
returns the ~45 pytest
test_cli_*/test_issue310_*CALLS+TESTS edges that actually target the Pythonmain, not the Bash one — confirming the bare-name aggregation described in this issue, just across a different language pair (Bash/Python instead of JS/Python).Same workaround as the OP:
trace_path/directquery_graphon the exact qualified name gives the correct in-degree; only thehotspotsaspect ofget_architectureis affected.DeusData commentedon Aug 12, 2026
Thank you @anton-matosov. The v0.10.2 Bash/Python reproduction confirms that this resolver class persists beyond the original JavaScript/Python case. Current
unique_nameresolution is project-wide and language-agnostic, so wrongCALLSedges can inflate a node's in-degree beforeget_architectureranks hotspots.#1572 now provides a small Python-to-TypeScript instance of the same root behavior, while #1555 covers the multi-candidate receiver case. They are related rather than exact duplicates, so all remain linked under #594.
rudi193-cmd commentedon Aug 13, 2026
@DeusData I can pick this up, and finish up #876 , which has been on my list for too long.
I use this all the time, and would like to give more back.
DeusData commentedon Aug 13, 2026
@rudi193-cmd, thank you for volunteering to take this on. That would be welcome. I have raised #725 to
priority/high: the fresh v0.10.2 Bash/Python reproduction confirms that the cross-language, bare-name resolver can still attach real edges to the wrong node and then inflate architecture hotspots.Please keep #725 and #876 as separate PRs, with one reproducer and one claim per change. Before starting the resolver change, compare with #1572 and #1555 so the fixes do not compete or encode different ambiguity rules. A focused red case that distinguishes two same-named symbols across languages is the most useful first slice.
Thank you again for offering to give back on a path you use regularly.
DeusData commentedon Aug 17, 2026
Fixed by #1647 (89f0cd4), landing in the next release: suffix_match CALLS edges are no longer created across language-family boundaries (JS/TS/TSX counting as one family), so same-named symbols in different languages stop inflating hotspot fan_in. unique_name cross-language bleed is tracked separately in #1572.
fix(registry): drop suffix_match CALLS across language boundaries
fix(pipeline): guard USAGE/WRITES/READS against cross-language binds
fix(pipeline): route registrations survive the cross-language guard
fix(resolve): a bare C call never weighs struct members or methods