victor-codegraph 0.10.1__tar.gz → 0.10.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/PKG-INFO +7 -3
  2. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/README.md +6 -2
  3. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/pyproject.toml +1 -1
  4. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_relations_v2.py +36 -0
  5. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/__init__.py +1 -1
  6. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/python_parser.py +39 -17
  7. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/repository_index.py +16 -8
  8. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/resolution.py +9 -1
  9. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph.egg-info/PKG-INFO +7 -3
  10. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/setup.cfg +0 -0
  11. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_adapter.py +0 -0
  12. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_adapter_validation_v2.py +0 -0
  13. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_chunk_contract_v2.py +0 -0
  14. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_diagnostics_v2.py +0 -0
  15. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_embedding_contract.py +0 -0
  16. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_identity_v2.py +0 -0
  17. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_line_base_contract.py +0 -0
  18. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_manifest.py +0 -0
  19. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_python_parser.py +0 -0
  20. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_repo.py +0 -0
  21. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_repository_delta_v2.py +0 -0
  22. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_sizing_and_chunk.py +0 -0
  23. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_sizing_overlap.py +0 -0
  24. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_symbol_oid_contract.py +0 -0
  25. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_symbol_oid_parity.py +0 -0
  26. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_treesitter_jsts.py +0 -0
  27. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_treesitter_languages.py +0 -0
  28. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/tests/test_treesitter_relations.py +0 -0
  29. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/adapter.py +0 -0
  30. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/config.py +0 -0
  31. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/embeddings.py +0 -0
  32. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/javascript_repository.py +0 -0
  33. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/languages.py +0 -0
  34. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/manifest.py +0 -0
  35. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/model.py +0 -0
  36. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/parser.py +0 -0
  37. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/py.typed +0 -0
  38. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/repo.py +0 -0
  39. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/rust_repository.py +0 -0
  40. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/sizing.py +0 -0
  41. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/treesitter_parser.py +0 -0
  42. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph/treesitter_tables.py +0 -0
  43. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph.egg-info/SOURCES.txt +0 -0
  44. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph.egg-info/dependency_links.txt +0 -0
  45. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph.egg-info/requires.txt +0 -0
  46. {victor_codegraph-0.10.1 → victor_codegraph-0.10.2}/victor_codegraph.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: victor-codegraph
3
- Version: 0.10.1
3
+ Version: 0.10.2
4
4
  Summary: Repository-to-Code-Semantic-Graph compiler with stable identity, bounded chunks, incremental deltas, and ProximaRecord projection.
5
5
  Author-email: Vijaykumar Singh <vijay@anvaiops.com>
6
6
  License: Apache-2.0
@@ -56,7 +56,11 @@ gaps:
56
56
  ## Install
57
57
 
58
58
  Published on PyPI as [`victor-codegraph`](https://pypi.org/project/victor-codegraph/).
59
- This source tree is version **0.10.1**; consumers should use a compatible `<1.0` pin.
59
+ This source tree is version **0.10.2**; consumers should use a compatible `<1.0` pin.
60
+ It repairs nested Python definition/import shadowing: proven local definitions
61
+ retain their targets, while unmodeled conditional bindings stay unresolved.
62
+ Rebuild derived graphs when adopting the new parser; unchanged source hashes do
63
+ not invalidate old semantic results automatically. Publication is a separate gate.
60
64
 
61
65
  ```bash
62
66
  # from PyPI
@@ -128,7 +132,7 @@ records = to_proxima_records(repository, repo_graph_id="myrepo")
128
132
 
129
133
  ## Status
130
134
 
131
- `0.10.1` source version. Python (`ast`) is the full, offline frontend. JS/TS, Go, Rust,
135
+ `0.10.2` source version. Python (`ast`) is the full, offline frontend. JS/TS, Go, Rust,
132
136
  Java, C, and C++ have conformance fixtures; other mapped tree-sitter languages report
133
137
  symbols-tier or fallback status rather than implying full fidelity.
134
138
 
@@ -25,7 +25,11 @@ gaps:
25
25
  ## Install
26
26
 
27
27
  Published on PyPI as [`victor-codegraph`](https://pypi.org/project/victor-codegraph/).
28
- This source tree is version **0.10.1**; consumers should use a compatible `<1.0` pin.
28
+ This source tree is version **0.10.2**; consumers should use a compatible `<1.0` pin.
29
+ It repairs nested Python definition/import shadowing: proven local definitions
30
+ retain their targets, while unmodeled conditional bindings stay unresolved.
31
+ Rebuild derived graphs when adopting the new parser; unchanged source hashes do
32
+ not invalidate old semantic results automatically. Publication is a separate gate.
29
33
 
30
34
  ```bash
31
35
  # from PyPI
@@ -97,7 +101,7 @@ records = to_proxima_records(repository, repo_graph_id="myrepo")
97
101
 
98
102
  ## Status
99
103
 
100
- `0.10.1` source version. Python (`ast`) is the full, offline frontend. JS/TS, Go, Rust,
104
+ `0.10.2` source version. Python (`ast`) is the full, offline frontend. JS/TS, Go, Rust,
101
105
  Java, C, and C++ have conformance fixtures; other mapped tree-sitter languages report
102
106
  symbols-tier or fallback status rather than implying full fidelity.
103
107
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "victor-codegraph"
7
- version = "0.10.1"
7
+ version = "0.10.2"
8
8
  description = "Repository-to-Code-Semantic-Graph compiler with stable identity, bounded chunks, incremental deltas, and ProximaRecord projection."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from pathlib import Path
4
+
3
5
  import pytest
4
6
 
5
7
  from victor_codegraph import CodeRelationType, parse, parse_repo, to_proxima_records
@@ -319,6 +321,40 @@ def test_python_enclosing_and_capture_bindings_block_import_guess(tmp_path, body
319
321
  assert calls and all(r.target_ref for r in calls)
320
322
 
321
323
 
324
+ @pytest.mark.parametrize(
325
+ ("body", "target_scope"),
326
+ [
327
+ ("def caller():\n def target(): return 2\n return target()", ["caller"]),
328
+ ("async def caller():\n async def target(): return 2\n return await target()", ["caller"]),
329
+ ("def caller():\n class target: pass\n return target()", ["caller"]),
330
+ ("def outer():\n def target(): return 2\n def caller(): return target()", ["outer"]),
331
+ ("def caller(flag):\n if flag:\n def target(): return 2\n return target()", None),
332
+ (
333
+ "def outer():\n def target(): return 2\n def caller(flag):\n if flag:\n def target(): return 3\n return target()",
334
+ None,
335
+ ),
336
+ ("def caller(): return target()", []),
337
+ ],
338
+ )
339
+ def test_python_nearest_definition_precedes_import(
340
+ tmp_path: Path, body: str, target_scope: list[str] | None
341
+ ) -> None:
342
+ (tmp_path / "a.py").write_text("def target(): return 1\n")
343
+ (tmp_path / "b.py").write_text("from a import target\n" + body)
344
+ graph = parse_repo(tmp_path)
345
+ calls = [r for r in graph.relations if r.relation_type == CodeRelationType.CALLS]
346
+ assert len(calls) == 1
347
+ call = calls[0]
348
+ if target_scope is None:
349
+ assert call.target_ref is not None
350
+ assert call.confidence < 1.0
351
+ else:
352
+ target = next(s for s in graph.symbols if s.id == call.to_symbol_id)
353
+ assert call.target_ref is None
354
+ assert target.scope_chain == target_scope
355
+ assert target.location.file_path == ("b.py" if target_scope else "a.py")
356
+
357
+
322
358
  def test_python_reassigned_self_is_not_a_proven_receiver():
323
359
  parsed = parse(
324
360
  "class A:\n def target(self): pass\n def caller(self):\n self = external\n self.target()\n",
@@ -54,7 +54,7 @@ from .repository_index import (
54
54
  relation_key,
55
55
  )
56
56
 
57
- __version__ = "0.10.1"
57
+ __version__ = "0.10.2"
58
58
 
59
59
  __all__ = [
60
60
  "__version__",
@@ -8,6 +8,8 @@ signatures, docstrings, decorators, parameters, cyclomatic complexity, and CALLS
8
8
  from __future__ import annotations
9
9
 
10
10
  import ast
11
+ from collections.abc import Iterator, Sequence
12
+ from typing import NotRequired, TypedDict
11
13
 
12
14
  from .model import (
13
15
  CodeRelation,
@@ -47,13 +49,20 @@ def _cyclomatic(node: ast.AST) -> dict[str, int]:
47
49
  return {"cyclomatic": count, "lines": end - lineno + 1}
48
50
 
49
51
 
50
- def _params(args: ast.arguments) -> list[dict]:
51
- out: list[dict] = []
52
+ class _Parameter(TypedDict):
53
+ name: str
54
+ type: NotRequired[str]
55
+ is_variadic: NotRequired[bool]
56
+ is_kwonly: NotRequired[bool]
57
+
58
+
59
+ def _params(args: ast.arguments) -> list[_Parameter]:
60
+ out: list[_Parameter] = []
52
61
  posonly = getattr(args, "posonlyargs", [])
53
62
  for a in [*posonly, *args.args]:
54
63
  if a.arg in ("self", "cls"):
55
64
  continue
56
- p: dict = {"name": a.arg}
65
+ p: _Parameter = {"name": a.arg}
57
66
  if a.annotation is not None:
58
67
  p["type"] = ast.unparse(a.annotation)
59
68
  out.append(p)
@@ -109,7 +118,7 @@ def _callee_ref(call: ast.Call) -> SymbolReference | None:
109
118
  return None
110
119
 
111
120
 
112
- def _calls_owned_by(node: ast.AST):
121
+ def _calls_owned_by(node: ast.AST) -> Iterator[ast.Call]:
113
122
  """Yield calls owned by ``node`` without stealing calls from nested definitions."""
114
123
 
115
124
  stack = list(ast.iter_child_nodes(node))
@@ -122,13 +131,15 @@ def _calls_owned_by(node: ast.AST):
122
131
  stack.extend(ast.iter_child_nodes(child))
123
132
 
124
133
 
125
- def _bound_names(nodes: list[ast.AST]) -> set[str]:
126
- """Conservative lexical writes, including captures and deletion bindings."""
134
+ def _lexical_bindings(nodes: Sequence[ast.AST]) -> tuple[set[str], set[str]]:
135
+ """Collect writes and definition bindings without entering nested namespaces."""
127
136
  names: set[str] = set()
137
+ definitions: set[str] = set()
128
138
  stack = list(nodes)
129
139
  while stack:
130
140
  node = stack.pop()
131
141
  if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
142
+ definitions.add(node.name)
132
143
  continue
133
144
  if isinstance(node, ast.arg):
134
145
  names.add(node.arg)
@@ -141,7 +152,7 @@ def _bound_names(nodes: list[ast.AST]) -> set[str]:
141
152
  if isinstance(node, (ast.Import, ast.ImportFrom)):
142
153
  names.update(a.asname or a.name.split(".")[0] for a in node.names)
143
154
  stack.extend(ast.iter_child_nodes(node))
144
- return names
155
+ return names, definitions
145
156
 
146
157
 
147
158
  class _Visitor:
@@ -152,6 +163,7 @@ class _Visitor:
152
163
  self.relations: list[CodeRelation] = []
153
164
  self.imports: list[str] = []
154
165
  self._enclosing_bindings: list[set[str]] = []
166
+ self._definition_scopes: list[dict[str, list[str]]] = [{}]
155
167
  self._import_names: set[str] = set()
156
168
  self._wildcard_import = False
157
169
  self._fqn_prefix = file_path.replace("/", ".").replace("\\", ".")
@@ -190,7 +202,7 @@ class _Visitor:
190
202
  symbol_type: CodeSymbolType,
191
203
  scope: list[str],
192
204
  signature: str | None = None,
193
- params: list[dict] | None = None,
205
+ params: list[_Parameter] | None = None,
194
206
  return_type: str | None = None,
195
207
  modifiers: list[str] | None = None,
196
208
  ) -> CodeSymbol:
@@ -220,7 +232,7 @@ class _Visitor:
220
232
  signature=signature,
221
233
  modifiers=modifiers or [],
222
234
  scope_chain=list(scope),
223
- parameters=params or [],
235
+ parameters=[dict(parameter) for parameter in params or []],
224
236
  return_type=return_type,
225
237
  complexity=_cyclomatic(node),
226
238
  )
@@ -254,10 +266,16 @@ class _Visitor:
254
266
  bound.add(node.args.vararg.arg)
255
267
  if node.args.kwarg:
256
268
  bound.add(node.args.kwarg.arg)
257
- writes = _bound_names(node.body)
269
+ writes, definitions = _lexical_bindings(node.body)
270
+ inner = [*scope, name]
271
+ definition_scopes = {
272
+ **self._definition_scopes[-1],
273
+ **{definition: inner for definition in definitions},
274
+ }
258
275
  enclosing = set().union(*self._enclosing_bindings)
259
276
  sym.metadata["python_bound_names"] = sorted(bound | writes | enclosing)
260
277
  sym.metadata["python_rebound_names"] = sorted(writes | enclosing)
278
+ sym.metadata["python_definition_scopes"] = definition_scopes
261
279
  sym.metadata["python_import_names"] = sorted(self._import_names)
262
280
  sym.metadata["python_wildcard_import"] = self._wildcard_import
263
281
  sym.metadata["python_receiver"] = (
@@ -275,10 +293,10 @@ class _Visitor:
275
293
  # and otherwise keeps it as a bare name (so cross-file/external calls — e.g.
276
294
  # a CPG's blast radius — are not silently dropped). ``call_site`` records the
277
295
  # call line for consumers that need it.
278
- for child in _calls_owned_by(node):
279
- ref = _callee_ref(child)
296
+ for call in _calls_owned_by(node):
297
+ ref = _callee_ref(call)
280
298
  if ref:
281
- line, col, end_line, end_col, offset, length = self._span(child)
299
+ line, col, end_line, end_col, offset, length = self._span(call)
282
300
  self.relations.append(
283
301
  CodeRelation(
284
302
  from_symbol_id=sym.id,
@@ -297,8 +315,8 @@ class _Visitor:
297
315
  ),
298
316
  )
299
317
  )
300
- inner = [*scope, name]
301
318
  self._enclosing_bindings.append(bound | writes)
319
+ self._definition_scopes.append(definition_scopes)
302
320
  for child in node.body:
303
321
  nested: CodeSymbol | None = None
304
322
  if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
@@ -314,6 +332,7 @@ class _Visitor:
314
332
  )
315
333
  )
316
334
  self._enclosing_bindings.pop()
335
+ self._definition_scopes.pop()
317
336
  return sym
318
337
 
319
338
  def visit_class(self, node: ast.ClassDef, scope: list[str]) -> CodeSymbol:
@@ -322,6 +341,7 @@ class _Visitor:
322
341
  if bases:
323
342
  mods.append(f"extends({','.join(bases)})")
324
343
  cls = self._make_symbol(node, node.name, CodeSymbolType.CLASS, scope, modifiers=mods)
344
+ cls.metadata["python_definition_scopes"] = self._definition_scopes[-1]
325
345
  cls.metadata["python_rebound_names"] = sorted(set().union(*self._enclosing_bindings))
326
346
  self.symbols.append(cls)
327
347
  for base in bases:
@@ -356,9 +376,11 @@ class _Visitor:
356
376
  return cls
357
377
 
358
378
  def run(self, tree: ast.Module) -> None:
359
- self._enclosing_bindings = [
360
- _bound_names([n for n in tree.body if not isinstance(n, (ast.Import, ast.ImportFrom))])
361
- ]
379
+ module_writes, _ = _lexical_bindings(
380
+ [n for n in tree.body if not isinstance(n, (ast.Import, ast.ImportFrom))]
381
+ )
382
+ self._enclosing_bindings = [module_writes]
383
+ self._definition_scopes = [{}]
362
384
  self._import_names = set()
363
385
  for declaration in tree.body:
364
386
  if isinstance(declaration, (ast.Import, ast.ImportFrom)):
@@ -7,6 +7,10 @@ import hashlib
7
7
  import os
8
8
  from dataclasses import asdict, dataclass, field, replace
9
9
  from pathlib import Path
10
+ from typing import TYPE_CHECKING
11
+
12
+ if TYPE_CHECKING:
13
+ from .rust_repository import RustBinding
10
14
 
11
15
  from .model import (
12
16
  CodeRelation,
@@ -67,7 +71,7 @@ def _resolve_across_files(
67
71
  symbols: list[CodeSymbol],
68
72
  relations: list[CodeRelation],
69
73
  files: dict[str, ParsedCode],
70
- rust_bindings: dict[str, list] | None = None,
74
+ rust_bindings: dict[str, list[RustBinding]] | None = None,
71
75
  javascript: JavaScriptRepository | None = None,
72
76
  ) -> list[CodeRelation]:
73
77
  """Resolve only unambiguous repository targets; ambiguity remains explicit."""
@@ -147,11 +151,15 @@ def _resolve_across_files(
147
151
  if source.language == "python":
148
152
  text = ref.text or ref.name
149
153
  root, *tail = text.split(".")
150
- if not source.metadata.get(
151
- "python_wildcard_import"
152
- ) and root not in source.metadata.get("python_bound_names", []):
153
- for binding, targets in python_bindings.get(source.location.file_path, {}).items():
154
- prefix = binding.split(".")
154
+ if (
155
+ not source.metadata.get("python_wildcard_import")
156
+ and root not in source.metadata.get("python_bound_names", [])
157
+ and root not in source.metadata.get("python_definition_scopes", {})
158
+ ):
159
+ for import_name, targets in python_bindings.get(
160
+ source.location.file_path, {}
161
+ ).items():
162
+ prefix = import_name.split(".")
155
163
  parts = text.split(".")
156
164
  if parts[: len(prefix)] != prefix:
157
165
  continue
@@ -198,7 +206,7 @@ def _python_bindings(
198
206
  if isinstance(node, ast.ImportFrom):
199
207
  module = "." * node.level + (node.module or "")
200
208
  name = alias.asname or alias.name
201
- target = (alias.name,)
209
+ target: tuple[str, ...] = (alias.name,)
202
210
  options = [
203
211
  (module, target),
204
212
  (module + ("." if node.module else "") + alias.name, ()),
@@ -347,7 +355,7 @@ def parse_repo(
347
355
 
348
356
  rust = RustRepository(root_path, resolution_files)
349
357
  javascript = JavaScriptRepository(resolution_files)
350
- rust_bindings: dict[str, list] = {}
358
+ rust_bindings: dict[str, list[RustBinding]] = {}
351
359
  for relative, parsed in resolution_files.items():
352
360
  owner = file_symbols[relative]
353
361
  for symbol in parsed.symbols:
@@ -72,6 +72,7 @@ def resolve_relations(
72
72
  if source is not None and source.language == "rust":
73
73
  candidates = _rust_candidates(source, ref, candidates, symbols)
74
74
  elif source is not None and source.language == "python":
75
+ definition_scope = source.metadata.get("python_definition_scopes", {}).get(ref.name)
75
76
  if source.metadata.get("python_wildcard_import"):
76
77
  candidates = []
77
78
  elif ref.qualifier in {"self", "cls"}:
@@ -87,7 +88,10 @@ def resolve_relations(
87
88
  elif (
88
89
  ref.qualifier
89
90
  or ref.name in source.metadata.get("python_bound_names", [])
90
- or ref.name in source.metadata.get("python_import_names", [])
91
+ or (
92
+ ref.name in source.metadata.get("python_import_names", [])
93
+ and definition_scope is None
94
+ )
91
95
  ):
92
96
  candidates = []
93
97
  else:
@@ -104,6 +108,10 @@ def resolve_relations(
104
108
  and [*source.scope_chain, source.simple_name][: len(c.scope_chain)]
105
109
  == c.scope_chain
106
110
  ]
111
+ # A lexical definition shadows imports and outer definitions even
112
+ # when its conditional body is not represented by this parser.
113
+ if definition_scope is not None:
114
+ candidates = [c for c in candidates if c.scope_chain == definition_scope]
107
115
  nearest = max((len(c.scope_chain) for c in candidates), default=-1)
108
116
  candidates = [c for c in candidates if len(c.scope_chain) == nearest]
109
117
  elif source is not None and source.language in {"javascript", "typescript", "tsx"}:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: victor-codegraph
3
- Version: 0.10.1
3
+ Version: 0.10.2
4
4
  Summary: Repository-to-Code-Semantic-Graph compiler with stable identity, bounded chunks, incremental deltas, and ProximaRecord projection.
5
5
  Author-email: Vijaykumar Singh <vijay@anvaiops.com>
6
6
  License: Apache-2.0
@@ -56,7 +56,11 @@ gaps:
56
56
  ## Install
57
57
 
58
58
  Published on PyPI as [`victor-codegraph`](https://pypi.org/project/victor-codegraph/).
59
- This source tree is version **0.10.1**; consumers should use a compatible `<1.0` pin.
59
+ This source tree is version **0.10.2**; consumers should use a compatible `<1.0` pin.
60
+ It repairs nested Python definition/import shadowing: proven local definitions
61
+ retain their targets, while unmodeled conditional bindings stay unresolved.
62
+ Rebuild derived graphs when adopting the new parser; unchanged source hashes do
63
+ not invalidate old semantic results automatically. Publication is a separate gate.
60
64
 
61
65
  ```bash
62
66
  # from PyPI
@@ -128,7 +132,7 @@ records = to_proxima_records(repository, repo_graph_id="myrepo")
128
132
 
129
133
  ## Status
130
134
 
131
- `0.10.1` source version. Python (`ast`) is the full, offline frontend. JS/TS, Go, Rust,
135
+ `0.10.2` source version. Python (`ast`) is the full, offline frontend. JS/TS, Go, Rust,
132
136
  Java, C, and C++ have conformance fixtures; other mapped tree-sitter languages report
133
137
  symbols-tier or fallback status rather than implying full fidelity.
134
138