@@ -116,9 +116,10 @@ class ViaEdge:
116116 in the same chain (e.g. `INJECTS` vs `IMPLEMENTS` vs `CALLS`) and at what hop
117117 from the frontier they were reached.
118118 """
119- edge_type : str # INJECTS | EXTENDS | IMPLEMENTS | CALLS
119+ edge_type : str # INJECTS | EXTENDS | IMPLEMENTS | CALLS | HTTP_CALLS | ASYNC_CALLS
120120 from_fqn : str
121121 hop : int # 1 = direct neighbour of previous-stage frontier
122+ caller_node_id : str = "" # Client id when edge_type is HTTP_CALLS (SCHEMA v2)
122123
123124
124125@dataclass
@@ -1281,6 +1282,7 @@ def _ingest_flow_row(
12811282 edge_type = str (row .get ("edge_type" ) or "" ),
12821283 from_fqn = str (row .get ("from_fqn" ) or "" ),
12831284 hop = hop ,
1285+ caller_node_id = str (row .get ("caller_client_id" ) or "" ),
12841286 )
12851287 existing = stage_results .get (sym .fqn )
12861288 if existing is None :
@@ -1342,7 +1344,8 @@ def _ingest_flow_row(
13421344 "AND n.resolved AND n.kind IN ['class','interface','enum','record','annotation'] "
13431345 "AND e.confidence >= $mc AND root.microservice <> n.microservice "
13441346 f"{ scrf } "
1345- f"RETURN { _symbol_return_for ('n' )} , 'HTTP_CALLS' AS edge_type, root.fqn AS from_fqn "
1347+ f"RETURN { _symbol_return_for ('n' )} , 'HTTP_CALLS' AS edge_type, "
1348+ f"root.fqn AS from_fqn, c.id AS caller_client_id "
13461349 f"LIMIT { max (1 , remaining * 4 )} "
13471350 )
13481351 for row in self ._rows (qrf , params_rf ):
@@ -1352,14 +1355,14 @@ def _ingest_flow_row(
13521355 if len (stage_results ) < stage_limit :
13531356 remaining = stage_limit - len (stage_results )
13541357 qrf_async = (
1355- "MATCH (root:Symbol)-[:DECLARES]->(m1:Symbol)-[e:ASYNC_CALLS]->(rt:Route)"
1356- "<-[:EXPOSES]-(handler:Symbol)<-[:DECLARES]-(n:Symbol) "
1357- "WHERE root.fqn IN $fqns AND n.role IN $roles "
1358- "AND n.resolved AND n.kind IN ['class','interface','enum','record','annotation'] "
1359- "AND e.confidence >= $mc AND root.microservice <> n.microservice "
1360- f"{ scrf } "
1361- f"RETURN { _symbol_return_for ('n' )} , 'ASYNC_CALLS' AS edge_type, root.fqn AS from_fqn "
1362- f"LIMIT { max (1 , remaining * 4 )} "
1358+ "MATCH (root:Symbol)-[:DECLARES]->(m1:Symbol)-[e:ASYNC_CALLS]->(rt:Route)"
1359+ "<-[:EXPOSES]-(handler:Symbol)<-[:DECLARES]-(n:Symbol) "
1360+ "WHERE root.fqn IN $fqns AND n.role IN $roles "
1361+ "AND n.resolved AND n.kind IN ['class','interface','enum','record','annotation'] "
1362+ "AND e.confidence >= $mc AND root.microservice <> n.microservice "
1363+ f"{ scrf } "
1364+ f"RETURN { _symbol_return_for ('n' )} , 'ASYNC_CALLS' AS edge_type, root.fqn AS from_fqn "
1365+ f"LIMIT { max (1 , remaining * 4 )} "
13631366 )
13641367 for row in self ._rows (qrf_async , params_rf ):
13651368 _ingest_flow_row (row , filter_external_fqn = True )
@@ -1488,6 +1491,7 @@ def find_route_callers(
14881491 path_template : str = "" ,
14891492 method : str = "" ,
14901493 ) -> list [RouteCaller ]:
1494+ """HTTP callers via Client (two-hop). Async callers omitted until PR-C (Producer)."""
14911495 rid = route_id or ""
14921496 if not rid :
14931497 params : dict [str , Any ] = {
@@ -1514,12 +1518,6 @@ def find_route_callers(
15141518 "ORDER BY e.confidence DESC, c.id" ,
15151519 {"rid" : rid },
15161520 )
1517- async_rows = self ._rows (
1518- "MATCH (s:Symbol)-[e:ASYNC_CALLS]->(r:Route {id: $rid}) "
1519- "RETURN s.id AS caller_node_id, s.microservice AS caller_microservice, "
1520- "s.id AS declaring_symbol_id, e.confidence AS confidence, e.match AS match" ,
1521- {"rid" : rid },
1522- )
15231521 out : list [RouteCaller ] = []
15241522 for row in http_rows :
15251523 out .append (
@@ -1534,22 +1532,10 @@ def find_route_callers(
15341532 raw_uri = str (row .get ("raw_uri" ) or "" ),
15351533 ),
15361534 )
1537- for row in async_rows :
1538- sym_id = str (row .get ("caller_node_id" ) or "" )
1539- out .append (
1540- RouteCaller (
1541- caller_node_id = sym_id ,
1542- caller_node_kind = "client" ,
1543- caller_microservice = str (row .get ("caller_microservice" ) or "" ),
1544- declaring_symbol_id = str (row .get ("declaring_symbol_id" ) or "" ),
1545- confidence = float (row .get ("confidence" ) or 0.0 ),
1546- match = str (row .get ("match" ) or "" ),
1547- ),
1548- )
1549- out .sort (key = lambda c : (- c .confidence , c .caller_node_id ))
15501535 return out
15511536
15521537 def trace_request_flow (self , entry_route_id : str , max_hops : int = 5 ) -> dict [str , Any ]:
1538+ """Inbound HTTP via Client two-hop. Async inbound omitted until PR-C (Producer)."""
15531539 hops = max (1 , min (int (max_hops ), 8 ))
15541540 inbound_http = self ._rows (
15551541 f"MATCH (entry:Route {{id: $rid}})<-[e:HTTP_CALLS]-(caller:Client)"
@@ -1562,17 +1548,7 @@ def trace_request_flow(self, entry_route_id: str, max_hops: int = 5) -> dict[str
15621548 "ORDER BY confidence DESC, caller_node_id" ,
15631549 {"rid" : entry_route_id },
15641550 )
1565- inbound_async = self ._rows (
1566- f"MATCH (entry:Route {{id: $rid}})<-[e:ASYNC_CALLS]-(caller:Symbol) "
1567- f"OPTIONAL MATCH (origin:Symbol)-[:CALLS*0..{ hops } ]->(caller) "
1568- "RETURN DISTINCT caller.id AS caller_node_id, 'client' AS caller_node_kind, "
1569- "caller.id AS declaring_symbol_id, caller.fqn AS declaring_symbol_fqn, "
1570- "caller.microservice AS microservice, e.confidence AS confidence, "
1571- "e.match AS match, origin.id AS origin_symbol_id, origin.fqn AS origin_fqn "
1572- "ORDER BY confidence DESC, caller_node_id" ,
1573- {"rid" : entry_route_id },
1574- )
1575- inbound = inbound_http + inbound_async
1551+ inbound = inbound_http
15761552 outbound = self ._rows (
15771553 f"MATCH (handler:Symbol)-[:EXPOSES]->(entry:Route {{id: $rid}}) "
15781554 f"OPTIONAL MATCH (handler)-[:CALLS*0..{ hops } ]->(next:Symbol) "
0 commit comments