Summary
#578 (module-attribute call sites after from pkg import module) was fixed by #715 and the plain form now resolves correctly. But the aliased forms still produce no calls edges on 1.6.0 (latest, npm). The call lands in unresolved_refs with status='failed' and the caller is silently absent from codegraph_callers and from the MCP codegraph_explore blast-radius summary.
Repro (1.6.0, win32-x64, Python project)
# services/kit.py
def sync_subscribers(get_db):
...
# routes/email.py
from services import kit as kit_service # <-- aliased from-import
def handler():
kit_service.sync_subscribers(get_db) # no calls edge
# hook.py
import build_api_contract as builder # <-- aliased plain import
builder.source_fingerprint() # no calls edge
Observed on a real repo (side-by-side in the same index, same session):
| Import form |
calls edge created? |
from services import email_send -> email_send.log_sent() |
yes (fixed by #715) |
from services import leads as leads_svc -> leads_svc.convert_lead_to_buyer() |
no |
import build_api_contract as builder -> builder.source_fingerprint() |
no |
Module-level vs function-scoped import makes no difference — both aliased forms miss.
unresolved_refs rows for the failing sites look like:
('builder.source_fingerprint', 'calls', 'failed')
('kit_service.sync_subscribers', 'calls', 'failed')
Why it bites
Same consequence as #578: codegraph_callers reports a function as having one caller (a script) when a live route handler also calls it through the alias — "is this dead code?" gets the wrong answer. The MCP codegraph_explore output is also self-inconsistent in this case: the blast-radius header says "1 caller in scripts/kit_sync.py" while the verbatim source it prints below shows the aliased call site.
Suggested fix
Wherever #715 taught the Python resolver that a bare imported-module name qualifies attribute calls, the alias table needs to participate: import x as y / from p import x as y should register y as a binding for module x in the same scope map.
Summary
#578 (module-attribute call sites after
from pkg import module) was fixed by #715 and the plain form now resolves correctly. But the aliased forms still produce nocallsedges on 1.6.0 (latest, npm). The call lands inunresolved_refswithstatus='failed'and the caller is silently absent fromcodegraph_callersand from the MCPcodegraph_exploreblast-radius summary.Repro (1.6.0, win32-x64, Python project)
Observed on a real repo (side-by-side in the same index, same session):
callsedge created?from services import email_send->email_send.log_sent()from services import leads as leads_svc->leads_svc.convert_lead_to_buyer()import build_api_contract as builder->builder.source_fingerprint()Module-level vs function-scoped import makes no difference — both aliased forms miss.
unresolved_refsrows for the failing sites look like:Why it bites
Same consequence as #578:
codegraph_callersreports a function as having one caller (a script) when a live route handler also calls it through the alias — "is this dead code?" gets the wrong answer. The MCPcodegraph_exploreoutput is also self-inconsistent in this case: the blast-radius header says "1 caller in scripts/kit_sync.py" while the verbatim source it prints below shows the aliased call site.Suggested fix
Wherever #715 taught the Python resolver that a bare imported-module name qualifies attribute calls, the alias table needs to participate:
import x as y/from p import x as yshould registeryas a binding for modulexin the same scope map.