java-codebase-rag 0.6.3__py3-none-any.whl → 0.6.5__py3-none-any.whl
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.
- ast_java.py +28 -57
- build_ast_graph.py +486 -262
- graph_enrich.py +13 -35
- java_codebase_rag/cli.py +10 -10
- java_codebase_rag/install_data/agents/explorer-rag-enhanced.md +3 -3
- java_codebase_rag/install_data/skills/explore-codebase/SKILL.md +5 -5
- {java_codebase_rag-0.6.3.dist-info → java_codebase_rag-0.6.5.dist-info}/METADATA +10 -10
- {java_codebase_rag-0.6.3.dist-info → java_codebase_rag-0.6.5.dist-info}/RECORD +18 -18
- java_index_flow_lancedb.py +95 -21
- ladybug_queries.py +45 -51
- mcp_v2.py +9 -17
- path_filtering.py +24 -19
- pr_analysis.py +3 -4
- search_lancedb.py +2 -2
- {java_codebase_rag-0.6.3.dist-info → java_codebase_rag-0.6.5.dist-info}/WHEEL +0 -0
- {java_codebase_rag-0.6.3.dist-info → java_codebase_rag-0.6.5.dist-info}/entry_points.txt +0 -0
- {java_codebase_rag-0.6.3.dist-info → java_codebase_rag-0.6.5.dist-info}/licenses/LICENSE +0 -0
- {java_codebase_rag-0.6.3.dist-info → java_codebase_rag-0.6.5.dist-info}/top_level.txt +0 -0
ladybug_queries.py
CHANGED
|
@@ -1161,8 +1161,11 @@ class LadybugGraph:
|
|
|
1161
1161
|
)
|
|
1162
1162
|
return [str(r["id"]) for r in rows2 if r.get("id")]
|
|
1163
1163
|
|
|
1164
|
-
def
|
|
1165
|
-
self,
|
|
1164
|
+
def _walk_calls(
|
|
1165
|
+
self,
|
|
1166
|
+
needle: str,
|
|
1167
|
+
*,
|
|
1168
|
+
side: str,
|
|
1166
1169
|
depth: int = 1,
|
|
1167
1170
|
limit: int = 100,
|
|
1168
1171
|
min_confidence: float = 0.0,
|
|
@@ -1170,6 +1173,17 @@ class LadybugGraph:
|
|
|
1170
1173
|
module: str | None = None,
|
|
1171
1174
|
microservice: str | None = None,
|
|
1172
1175
|
) -> list[CallEdge]:
|
|
1176
|
+
"""BFS the CALLS graph outward from ``needle`` along one relationship end.
|
|
1177
|
+
|
|
1178
|
+
``side="callers"`` treats the needle as the callee: the frontier matches
|
|
1179
|
+
the ``callee`` end and discovered/expanded/external-filtered nodes are the
|
|
1180
|
+
``caller`` (src) end. ``side="callees"`` is the mirror. The two public
|
|
1181
|
+
methods differ only in that orientation, so the BFS body is shared here.
|
|
1182
|
+
"""
|
|
1183
|
+
if side == "callers":
|
|
1184
|
+
scope_alias, frontier_end, discovered = "caller", "callee", "src"
|
|
1185
|
+
else:
|
|
1186
|
+
scope_alias, frontier_end, discovered = "callee", "caller", "dst"
|
|
1173
1187
|
frontier = self._method_ids_for_call_graph_needle(needle, limit=max(limit, 50))
|
|
1174
1188
|
if not frontier:
|
|
1175
1189
|
return []
|
|
@@ -1182,8 +1196,8 @@ class LadybugGraph:
|
|
|
1182
1196
|
"frontier": list(frontier),
|
|
1183
1197
|
"minc": float(min_confidence),
|
|
1184
1198
|
}
|
|
1185
|
-
sc = _scope_filters(
|
|
1186
|
-
wh_parts = ["
|
|
1199
|
+
sc = _scope_filters(scope_alias, module=module, microservice=microservice, params=params)
|
|
1200
|
+
wh_parts = [f"{frontier_end}.id IN $frontier", "c.confidence >= $minc"]
|
|
1187
1201
|
wh_parts.extend(sc)
|
|
1188
1202
|
wh = " AND ".join(wh_parts)
|
|
1189
1203
|
q = (
|
|
@@ -1197,16 +1211,19 @@ class LadybugGraph:
|
|
|
1197
1211
|
next_frontier: list[str] = []
|
|
1198
1212
|
for row in self._rows(q, params):
|
|
1199
1213
|
ce = _row_to_call_edge(row)
|
|
1200
|
-
#
|
|
1201
|
-
#
|
|
1202
|
-
|
|
1214
|
+
# The needle itself may be external (e.g. java.util.List#add);
|
|
1215
|
+
# filter only the discovered end so internal callers/callees
|
|
1216
|
+
# that touch it are still surfaced.
|
|
1217
|
+
disc_fqn = ce.src.fqn if discovered == "src" else ce.dst.fqn
|
|
1218
|
+
disc_id = ce.src.id if discovered == "src" else ce.dst.id
|
|
1219
|
+
if exclude_external and _is_external_fqn(disc_fqn):
|
|
1203
1220
|
continue
|
|
1204
1221
|
key = (ce.src.id, ce.dst.id, ce.call_site_line, ce.call_site_byte)
|
|
1205
1222
|
if key in seen:
|
|
1206
1223
|
continue
|
|
1207
1224
|
seen.add(key)
|
|
1208
1225
|
out.append(ce)
|
|
1209
|
-
next_frontier.append(
|
|
1226
|
+
next_frontier.append(disc_id)
|
|
1210
1227
|
if len(out) >= limit:
|
|
1211
1228
|
return out
|
|
1212
1229
|
frontier = list(dict.fromkeys(next_frontier))
|
|
@@ -1214,6 +1231,21 @@ class LadybugGraph:
|
|
|
1214
1231
|
break
|
|
1215
1232
|
return out
|
|
1216
1233
|
|
|
1234
|
+
def find_callers(
|
|
1235
|
+
self, needle: str, *,
|
|
1236
|
+
depth: int = 1,
|
|
1237
|
+
limit: int = 100,
|
|
1238
|
+
min_confidence: float = 0.0,
|
|
1239
|
+
exclude_external: bool = True,
|
|
1240
|
+
module: str | None = None,
|
|
1241
|
+
microservice: str | None = None,
|
|
1242
|
+
) -> list[CallEdge]:
|
|
1243
|
+
return self._walk_calls(
|
|
1244
|
+
needle, side="callers", depth=depth, limit=limit,
|
|
1245
|
+
min_confidence=min_confidence, exclude_external=exclude_external,
|
|
1246
|
+
module=module, microservice=microservice,
|
|
1247
|
+
)
|
|
1248
|
+
|
|
1217
1249
|
def find_callees(
|
|
1218
1250
|
self, needle: str, *,
|
|
1219
1251
|
depth: int = 1,
|
|
@@ -1223,49 +1255,11 @@ class LadybugGraph:
|
|
|
1223
1255
|
module: str | None = None,
|
|
1224
1256
|
microservice: str | None = None,
|
|
1225
1257
|
) -> list[CallEdge]:
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
out: list[CallEdge] = []
|
|
1232
|
-
seen: set[tuple[str, str, int, int]] = set()
|
|
1233
|
-
for _ in range(max(1, int(depth))):
|
|
1234
|
-
params: dict[str, Any] = {
|
|
1235
|
-
"frontier": list(frontier),
|
|
1236
|
-
"minc": float(min_confidence),
|
|
1237
|
-
}
|
|
1238
|
-
sc = _scope_filters("callee", module=module, microservice=microservice, params=params)
|
|
1239
|
-
wh_parts = ["caller.id IN $frontier", "c.confidence >= $minc"]
|
|
1240
|
-
wh_parts.extend(sc)
|
|
1241
|
-
wh = " AND ".join(wh_parts)
|
|
1242
|
-
q = (
|
|
1243
|
-
f"MATCH (caller:Symbol)-[c:CALLS]->(callee:Symbol) WHERE {wh} "
|
|
1244
|
-
f"RETURN {caller_proj}, {callee_proj}, "
|
|
1245
|
-
f"c.call_site_line AS call_site_line, c.call_site_byte AS call_site_byte, "
|
|
1246
|
-
f"c.arg_count AS arg_count, c.confidence AS confidence, c.strategy AS strategy, "
|
|
1247
|
-
f"c.source AS source, c.resolved AS resolved "
|
|
1248
|
-
f"LIMIT {int(limit) * 8}"
|
|
1249
|
-
)
|
|
1250
|
-
next_frontier: list[str] = []
|
|
1251
|
-
for row in self._rows(q, params):
|
|
1252
|
-
ce = _row_to_call_edge(row)
|
|
1253
|
-
# Filter only discovered callees (dst). Needle may be external while
|
|
1254
|
-
# still listing non-external outbound calls when any exist.
|
|
1255
|
-
if exclude_external and _is_external_fqn(ce.dst.fqn):
|
|
1256
|
-
continue
|
|
1257
|
-
key = (ce.src.id, ce.dst.id, ce.call_site_line, ce.call_site_byte)
|
|
1258
|
-
if key in seen:
|
|
1259
|
-
continue
|
|
1260
|
-
seen.add(key)
|
|
1261
|
-
out.append(ce)
|
|
1262
|
-
next_frontier.append(ce.dst.id)
|
|
1263
|
-
if len(out) >= limit:
|
|
1264
|
-
return out
|
|
1265
|
-
frontier = list(dict.fromkeys(next_frontier))
|
|
1266
|
-
if not frontier:
|
|
1267
|
-
break
|
|
1268
|
-
return out
|
|
1258
|
+
return self._walk_calls(
|
|
1259
|
+
needle, side="callees", depth=depth, limit=limit,
|
|
1260
|
+
min_confidence=min_confidence, exclude_external=exclude_external,
|
|
1261
|
+
module=module, microservice=microservice,
|
|
1262
|
+
)
|
|
1269
1263
|
|
|
1270
1264
|
def expand_methods(
|
|
1271
1265
|
self, fqns: list[str], *, depth: int = 1,
|
mcp_v2.py
CHANGED
|
@@ -817,7 +817,7 @@ def _merge_overrides_edge_summary(
|
|
|
817
817
|
"""Reconcile `OVERRIDES` with `override_axis_rollup_for` without clobbering stored `in`.
|
|
818
818
|
|
|
819
819
|
Rollup rows reuse the ``OVERRIDES`` key for dispatch-up counts only (``in`` is always
|
|
820
|
-
zero there). Stored ``[:OVERRIDES]`` edges contribute real ``in``/``out`` from
|
|
820
|
+
zero there). Stored ``[:OVERRIDES]`` edges contribute real ``in``/``out`` from LadybugDB;
|
|
821
821
|
merge per direction with ``max`` so inbound override edges stay visible.
|
|
822
822
|
"""
|
|
823
823
|
roll = _incident_counts(summary_after_rollups.get("OVERRIDES"))
|
|
@@ -1095,9 +1095,9 @@ def describe_v2(
|
|
|
1095
1095
|
has_id = bool(id and str(id).strip())
|
|
1096
1096
|
has_fqn = bool(fqn and str(fqn).strip())
|
|
1097
1097
|
if not has_id and not has_fqn:
|
|
1098
|
-
return DescribeOutput(success=False, message="id or fqn required"
|
|
1098
|
+
return DescribeOutput(success=False, message="id or fqn required")
|
|
1099
1099
|
if has_id and str(id).strip().startswith("ucs:"):
|
|
1100
|
-
return DescribeOutput(success=False, message=_DESCRIBE_UCS_ID_MESSAGE
|
|
1100
|
+
return DescribeOutput(success=False, message=_DESCRIBE_UCS_ID_MESSAGE)
|
|
1101
1101
|
hint_message: str | None = None
|
|
1102
1102
|
node_id: str
|
|
1103
1103
|
if has_id:
|
|
@@ -1109,7 +1109,7 @@ def describe_v2(
|
|
|
1109
1109
|
{"fqn": fqn_val},
|
|
1110
1110
|
)
|
|
1111
1111
|
if not rows:
|
|
1112
|
-
return DescribeOutput(success=False, message=f"No Symbol found for fqn='{fqn_val}'"
|
|
1112
|
+
return DescribeOutput(success=False, message=f"No Symbol found for fqn='{fqn_val}'")
|
|
1113
1113
|
node_id = str(rows[0]["id"] or "")
|
|
1114
1114
|
if len(rows) > 1:
|
|
1115
1115
|
hint_message = (
|
|
@@ -1784,7 +1784,7 @@ def neighbors_v2(
|
|
|
1784
1784
|
)
|
|
1785
1785
|
except ValueError as exc:
|
|
1786
1786
|
_log_fail_loud("edge_filter")
|
|
1787
|
-
return NeighborsOutput(success=False, message=str(exc),
|
|
1787
|
+
return NeighborsOutput(success=False, message=str(exc), requested_edge_types=[])
|
|
1788
1788
|
if include_unresolved and ef is not None:
|
|
1789
1789
|
return NeighborsOutput(
|
|
1790
1790
|
success=False,
|
|
@@ -1792,21 +1792,18 @@ def neighbors_v2(
|
|
|
1792
1792
|
"include_unresolved=True is incompatible with edge_filter; "
|
|
1793
1793
|
"UnresolvedCallSite rows have no edge attributes to filter on"
|
|
1794
1794
|
),
|
|
1795
|
-
hints=[],
|
|
1796
1795
|
requested_edge_types=requested_edge_types,
|
|
1797
1796
|
)
|
|
1798
1797
|
if include_unresolved and requested_edge_types != ["CALLS"]:
|
|
1799
1798
|
return NeighborsOutput(
|
|
1800
1799
|
success=False,
|
|
1801
1800
|
message="include_unresolved requires edge_types=['CALLS']",
|
|
1802
|
-
hints=[],
|
|
1803
1801
|
requested_edge_types=requested_edge_types,
|
|
1804
1802
|
)
|
|
1805
1803
|
if include_unresolved and direction != "out":
|
|
1806
1804
|
return NeighborsOutput(
|
|
1807
1805
|
success=False,
|
|
1808
1806
|
message='include_unresolved requires direction="out"',
|
|
1809
|
-
hints=[],
|
|
1810
1807
|
requested_edge_types=requested_edge_types,
|
|
1811
1808
|
)
|
|
1812
1809
|
if ef and (err := _edgefilter_applicability_error(requested_edge_types, ef)):
|
|
@@ -1814,17 +1811,15 @@ def neighbors_v2(
|
|
|
1814
1811
|
return NeighborsOutput(
|
|
1815
1812
|
success=False,
|
|
1816
1813
|
message=err,
|
|
1817
|
-
hints=[],
|
|
1818
1814
|
requested_edge_types=requested_edge_types,
|
|
1819
1815
|
)
|
|
1820
1816
|
if nf and (err := _validate_no_wildcards(nf)):
|
|
1821
1817
|
_log_fail_loud("wildcard")
|
|
1822
|
-
return NeighborsOutput(success=False, message=err,
|
|
1818
|
+
return NeighborsOutput(success=False, message=err, requested_edge_types=[])
|
|
1823
1819
|
if composed_keys and direction != "out":
|
|
1824
1820
|
return NeighborsOutput(
|
|
1825
1821
|
success=False,
|
|
1826
1822
|
message='Composed edge types require direction="out"',
|
|
1827
|
-
hints=[],
|
|
1828
1823
|
requested_edge_types=requested_edge_types,
|
|
1829
1824
|
)
|
|
1830
1825
|
use_calls_path = flat_labels == ["CALLS"] and not composed_keys
|
|
@@ -1849,7 +1844,6 @@ def neighbors_v2(
|
|
|
1849
1844
|
return NeighborsOutput(
|
|
1850
1845
|
success=False,
|
|
1851
1846
|
message=axis_msg,
|
|
1852
|
-
hints=[],
|
|
1853
1847
|
requested_edge_types=requested_edge_types,
|
|
1854
1848
|
)
|
|
1855
1849
|
origin_row = _load_node_record(g, origin_id, "symbol")
|
|
@@ -1865,7 +1859,6 @@ def neighbors_v2(
|
|
|
1865
1859
|
return NeighborsOutput(
|
|
1866
1860
|
success=False,
|
|
1867
1861
|
message=err,
|
|
1868
|
-
hints=[],
|
|
1869
1862
|
requested_edge_types=requested_edge_types,
|
|
1870
1863
|
)
|
|
1871
1864
|
if use_calls_path:
|
|
@@ -1891,7 +1884,6 @@ def neighbors_v2(
|
|
|
1891
1884
|
return NeighborsOutput(
|
|
1892
1885
|
success=False,
|
|
1893
1886
|
message=str(exc),
|
|
1894
|
-
hints=[],
|
|
1895
1887
|
requested_edge_types=requested_edge_types,
|
|
1896
1888
|
)
|
|
1897
1889
|
if (
|
|
@@ -1904,7 +1896,7 @@ def neighbors_v2(
|
|
|
1904
1896
|
results.extend(origin_edges)
|
|
1905
1897
|
continue
|
|
1906
1898
|
if flat_labels:
|
|
1907
|
-
#
|
|
1899
|
+
# Some Cypher binders can drop `label(e) IN $list` in WHERE; use OR of scalar equalities.
|
|
1908
1900
|
label_params = [f"l{i}" for i in range(len(flat_labels))]
|
|
1909
1901
|
label_predicate = "(" + " OR ".join(f"label(e) = ${name}" for name in label_params) + ")"
|
|
1910
1902
|
q_params = {"id": origin_id, **dict(zip(label_params, flat_labels, strict=True))}
|
|
@@ -1941,7 +1933,7 @@ def neighbors_v2(
|
|
|
1941
1933
|
if nf and (err := _nodefilter_applicability_error(other_kind, nf)):
|
|
1942
1934
|
_log_fail_loud("applicability")
|
|
1943
1935
|
return NeighborsOutput(
|
|
1944
|
-
success=False, message=err,
|
|
1936
|
+
success=False, message=err, requested_edge_types=[]
|
|
1945
1937
|
)
|
|
1946
1938
|
if not _node_matches_filter(other_kind, other_rec, nf):
|
|
1947
1939
|
continue
|
|
@@ -1968,7 +1960,7 @@ def neighbors_v2(
|
|
|
1968
1960
|
if nf and (err := _nodefilter_applicability_error(other_kind, nf)):
|
|
1969
1961
|
_log_fail_loud("applicability")
|
|
1970
1962
|
return NeighborsOutput(
|
|
1971
|
-
success=False, message=err,
|
|
1963
|
+
success=False, message=err, requested_edge_types=[]
|
|
1972
1964
|
)
|
|
1973
1965
|
if not _node_matches_filter(other_kind, other_rec, nf):
|
|
1974
1966
|
continue
|
path_filtering.py
CHANGED
|
@@ -300,6 +300,7 @@ class LayeredIgnore:
|
|
|
300
300
|
_scan_negation_any_bundle_ignore(self.project_root)
|
|
301
301
|
or (use_gitignore and _scan_negation_any_gitignore(self.project_root))
|
|
302
302
|
)
|
|
303
|
+
self._mega_cache: dict[str, tuple[list[str], GitIgnoreSpec, list[tuple[str, Path | None, int, str]]]] = {}
|
|
303
304
|
|
|
304
305
|
def cocoindex_excluded_patterns(self) -> list[str]:
|
|
305
306
|
"""Patterns for CocoIndex ``PatternFilePathMatcher.excluded_patterns``.
|
|
@@ -332,6 +333,11 @@ class LayeredIgnore:
|
|
|
332
333
|
return path.as_posix()
|
|
333
334
|
|
|
334
335
|
def _mega(self, rel_project: str) -> tuple[list[str], GitIgnoreSpec, list[tuple[str, Path | None, int, str]]]:
|
|
336
|
+
# Cache by directory (parent of rel_project). _mega_build_for_rel reads only dir_parts,
|
|
337
|
+
# so files in the same directory share the same mega/spec/meta tuple.
|
|
338
|
+
cache_key = Path(rel_project).parent.as_posix()
|
|
339
|
+
if cache_key in self._mega_cache:
|
|
340
|
+
return self._mega_cache[cache_key]
|
|
335
341
|
mega, meta = _mega_build_for_rel(
|
|
336
342
|
self.project_root,
|
|
337
343
|
rel_project,
|
|
@@ -340,26 +346,26 @@ class LayeredIgnore:
|
|
|
340
346
|
project_ignore_path=self._project_ignore_path,
|
|
341
347
|
project_lines=self._project_lines,
|
|
342
348
|
)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
349
|
+
result = (mega, GitIgnoreSpec.from_lines(mega), meta)
|
|
350
|
+
self._mega_cache[cache_key] = result
|
|
351
|
+
return result
|
|
352
|
+
|
|
353
|
+
def is_ignored(self, path: Path) -> bool:
|
|
354
|
+
"""Return whether ``path`` is ignored by any configured layer.
|
|
355
|
+
|
|
356
|
+
Boolean-only fast path for the per-file index walk. It deliberately does
|
|
357
|
+
not compute *which* layer/source last matched: that attribution is
|
|
358
|
+
O(rules²) via :func:`_winning_row` (one ``GitIgnoreSpec`` rebuild per
|
|
359
|
+
rule prefix) and is only needed for ``diagnose-ignore``, so it lives in
|
|
360
|
+
:meth:`diagnose_dict` and is never paid on the hot path.
|
|
361
|
+
"""
|
|
347
362
|
rel = self._rel_project(path)
|
|
348
363
|
if rel is None:
|
|
349
|
-
return False
|
|
350
|
-
mega, spec,
|
|
364
|
+
return False
|
|
365
|
+
mega, spec, _ = self._mega(rel)
|
|
351
366
|
if not mega:
|
|
352
|
-
return False
|
|
353
|
-
|
|
354
|
-
if not ignored:
|
|
355
|
-
return False, None
|
|
356
|
-
src, fp, ln, _pat = _winning_row(rel, mega, meta)
|
|
357
|
-
return True, IgnoreLayer(
|
|
358
|
-
root=self.project_root,
|
|
359
|
-
spec=spec,
|
|
360
|
-
source=src,
|
|
361
|
-
ignore_file=fp,
|
|
362
|
-
)
|
|
367
|
+
return False
|
|
368
|
+
return spec.match_file(rel)
|
|
363
369
|
|
|
364
370
|
def diagnose(self, path: Path) -> str:
|
|
365
371
|
"""Human-readable, multi-line explanation of the ignore decision."""
|
|
@@ -466,7 +472,6 @@ def iter_java_source_files(
|
|
|
466
472
|
if not fn.endswith(".java"):
|
|
467
473
|
continue
|
|
468
474
|
p = Path(dirpath) / fn
|
|
469
|
-
|
|
470
|
-
if ign:
|
|
475
|
+
if ignore_ctx.is_ignored(p):
|
|
471
476
|
continue
|
|
472
477
|
yield p
|
pr_analysis.py
CHANGED
|
@@ -152,7 +152,7 @@ def _resolve_graph_filename(
|
|
|
152
152
|
*,
|
|
153
153
|
ambiguity_notes: list[str] | None = None,
|
|
154
154
|
) -> str | None:
|
|
155
|
-
"""Map a diff path to `Symbol.filename` values stored in
|
|
155
|
+
"""Map a diff path to `Symbol.filename` values stored in LadybugDB."""
|
|
156
156
|
variants = {_strip_ab_prefix(path)}
|
|
157
157
|
for v in list(variants):
|
|
158
158
|
if v.startswith("./"):
|
|
@@ -362,7 +362,7 @@ def _is_public_interface_method(graph: Any, sym: SymbolHit) -> bool:
|
|
|
362
362
|
|
|
363
363
|
|
|
364
364
|
def _route_ids_for_symbol(graph: Any, symbol_id: str) -> list[str]:
|
|
365
|
-
# Note:
|
|
365
|
+
# Note: LadybugDB rejects `ORDER BY r.id` together with `RETURN DISTINCT r.id` (binder loses `r`).
|
|
366
366
|
q = (
|
|
367
367
|
"MATCH (s:Symbol)-[e:EXPOSES]->(r:Route) WHERE s.id = $sid "
|
|
368
368
|
"RETURN r.id AS id ORDER BY id"
|
|
@@ -384,7 +384,6 @@ def compute_risk(graph: Any, changed: list[ChangedSymbol]) -> PrRiskReport:
|
|
|
384
384
|
bump (up to +1.0) after normalization so they influence rank while
|
|
385
385
|
preserving the public scalar contract.
|
|
386
386
|
"""
|
|
387
|
-
notes: list[str] = []
|
|
388
387
|
blast_by: dict[str, int] = {}
|
|
389
388
|
blast_total = 0
|
|
390
389
|
routes: list[str] = []
|
|
@@ -495,7 +494,7 @@ def compute_risk(graph: Any, changed: list[ChangedSymbol]) -> PrRiskReport:
|
|
|
495
494
|
routes_touched=routes,
|
|
496
495
|
risk_score=score,
|
|
497
496
|
risk_band=band,
|
|
498
|
-
notes=
|
|
497
|
+
notes=[],
|
|
499
498
|
)
|
|
500
499
|
|
|
501
500
|
|
search_lancedb.py
CHANGED
|
@@ -677,8 +677,8 @@ def _graph_expand_merge(
|
|
|
677
677
|
expand_depth: int,
|
|
678
678
|
ladybug_path: str | None,
|
|
679
679
|
) -> list[dict]:
|
|
680
|
-
"""Expand vector top-k through the
|
|
681
|
-
# Lazy import so the module works without
|
|
680
|
+
"""Expand vector top-k through the LadybugDB graph and fuse (RRF) with the original list."""
|
|
681
|
+
# Lazy import so the module works without ladybug installed when graph_expand=False.
|
|
682
682
|
try:
|
|
683
683
|
from ladybug_queries import LadybugGraph
|
|
684
684
|
except Exception:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|