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
2.1.0a1 (reproduced on release/2.1.0a2, commit 932d4b73)
Affected area
Quality metrics / health
What happened?
Relative imports written inside a package __init__.py are resolved incorrectly or silently dropped, corrupting the dependency graph, coupling/cohesion inputs, and relationship facts. This is independent of the src-layout defect (#53) and reproduces in flat layouts too.
Root cause: _resolve_import_target (codeclone/analysis/_module_walk.py:78-90) has no package context. It strips level segments from the raw module_name string, assuming the last dotted segment is always "the module itself". For pkg/__init__.py, module_name_from_path already collapses the name to pkg (the package itself), so the arithmetic over-strips by one level. There is no is_package concept anywhere in the codebase (rg "is_package" → 0 hits).
Proof by executing the unmodified production function:
in pkg/__init__.py (module_name = "pkg"):
from . import x -> "" (falsy target; edge silently dropped
at _module_walk.py:385,410)
from .sibling import y -> "sibling" WRONG — missing "pkg." prefix; edge
points at nonexistent top-level module
in pkg/mod.py (module_name = "pkg.mod"):
from . import x -> "pkg" correct
from .sibling import y -> "pkg.sibling" correct
Downstream: _collect_import_from_node (_module_walk.py:377-419) only records a ModuleDep/import name when the target is truthy, so from . import x in any __init__.py produces no dependency edge, no import_names entry, no relationship binding — invisible to build_dep_graph, fan-in/out, cycles, coupling, and MCP implementation context. from .sibling import y records an edge to a module that does not exist.
What did you expect instead?
Relative imports must resolve from package context (package, is_package), not from arithmetic over the raw module string:
from . import x in pkg/__init__.py → target pkg (plus proven submodule pkg.x when it exists in the module inventory);
from .sibling import y in pkg/__init__.py → pkg.sibling;
over-stripped levels (from ... beyond the top) → explicit unresolved_relative observation, never a silently dropped edge.
Minimal reproduction
# repo/pkg/__init__.pyfrom . importa# edge pkg -> pkg.a: MISSING todayfrom .aimporthelper# edge should be pkg -> pkg.a; today points at top-level "a"# repo/pkg/a.pydefhelper(): ...
Observed: dependency graph has no pkg -> pkg.a edge from __init__.py; the from .a import helper edge targets a, which is classified external and dropped by _is_internal_target.
Additional context
Fix contract: Phase 39 spec specs/phase-39-baseline-container-lanes.md §10.2.1 (normative decision table; mandatory package + is_package + node_kind on every module identity).
Metadata
release/2.1.0a2, commit932d4b73)What happened?
Relative imports written inside a package
__init__.pyare resolved incorrectly or silently dropped, corrupting the dependency graph, coupling/cohesion inputs, and relationship facts. This is independent of the src-layout defect (#53) and reproduces in flat layouts too.Root cause:
_resolve_import_target(codeclone/analysis/_module_walk.py:78-90) has no package context. It stripslevelsegments from the rawmodule_namestring, assuming the last dotted segment is always "the module itself". Forpkg/__init__.py,module_name_from_pathalready collapses the name topkg(the package itself), so the arithmetic over-strips by one level. There is nois_packageconcept anywhere in the codebase (rg "is_package"→ 0 hits).Proof by executing the unmodified production function:
Downstream:
_collect_import_from_node(_module_walk.py:377-419) only records aModuleDep/import name when the target is truthy, sofrom . import xin any__init__.pyproduces no dependency edge, no import_names entry, no relationship binding — invisible tobuild_dep_graph, fan-in/out, cycles, coupling, and MCP implementation context.from .sibling import yrecords an edge to a module that does not exist.What did you expect instead?
Relative imports must resolve from package context (
package,is_package), not from arithmetic over the raw module string:from . import xinpkg/__init__.py→ targetpkg(plus proven submodulepkg.xwhen it exists in the module inventory);from .sibling import yinpkg/__init__.py→pkg.sibling;from ...beyond the top) → explicitunresolved_relativeobservation, never a silently dropped edge.Minimal reproduction
Observed: dependency graph has no
pkg -> pkg.aedge from__init__.py; thefrom .a import helperedge targetsa, which is classified external and dropped by_is_internal_target.Additional context
specs/phase-39-baseline-container-lanes.md§10.2.1 (normative decision table; mandatorypackage+is_package+node_kindon every module identity).