abinazebinoy commited on
Commit
fa85dbd
·
unverified ·
2 Parent(s): f37a0aff064888

Merge pull request #105 from abinaze/fix/r5-wire-cache-ttl

Browse files

Wire get_graph_depth() into 5 internal investigator queries

ai/deep_investigator.py CHANGED
@@ -3,6 +3,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
3
 
4
  from datetime import datetime
5
  from loguru import logger
 
6
 
7
 
8
  LAYER_NAMES = [
@@ -204,6 +205,15 @@ class DeepInvestigator:
204
 
205
  def _layer_3_patterns(self, entity_id: str, session) -> dict:
206
  findings = []
 
 
 
 
 
 
 
 
 
207
 
208
  # Pattern 1: Company with multiple directors that won contracts
209
  rows = session.run(
@@ -223,8 +233,8 @@ class DeepInvestigator:
223
 
224
  # Pattern 2: Audit flags on connected schemes
225
  rows = session.run(
226
- """
227
- MATCH (n {id:$id})-[*1..2]-(a:AuditReport)
228
  RETURN a.title AS title, a.year AS year, a.amount_crore AS amount LIMIT 5
229
  """, id=entity_id
230
  ).data()
@@ -237,8 +247,8 @@ class DeepInvestigator:
237
 
238
  # Pattern 3: Electoral bond connections
239
  rows = session.run(
240
- """
241
- MATCH (n {id:$id})-[*1..2]-(e:ElectoralBond)
242
  RETURN e.donor_name AS donor, e.amount AS amount, e.party AS party LIMIT 5
243
  """, id=entity_id
244
  ).data()
@@ -258,11 +268,12 @@ class DeepInvestigator:
258
 
259
  def _layer_4_timeline(self, entity_id: str, session) -> dict:
260
  events = []
 
261
 
262
  # Timeline events from multiple sources
263
  rows = session.run(
264
- """
265
- MATCH (n {id:$id})-[:DIRECTOR_OF|WON_CONTRACT|FLAGS|MENTIONED_IN|AUDITS*1..2]-(m)
266
  WHERE m.order_date IS NOT NULL OR m.year IS NOT NULL OR m.scraped_at IS NOT NULL
267
  RETURN coalesce(m.name,m.title,m.id) AS name,
268
  labels(m)[0] AS type,
 
3
 
4
  from datetime import datetime
5
  from loguru import logger
6
+ from config.model_selector import get_graph_depth
7
 
8
 
9
  LAYER_NAMES = [
 
205
 
206
  def _layer_3_patterns(self, entity_id: str, session) -> dict:
207
  findings = []
208
+ # R-5 fix: was a hardcoded *1..2 in both queries below. Safe to wire
209
+ # tier-aware here specifically because 2 IS the current hardcoded
210
+ # value AND PROFILE["low"]'s value -- so a low-tier/desktop install
211
+ # sees zero change, while medium/high tiers get a deeper (more
212
+ # thorough, not less) traversal than today's shared baseline. This
213
+ # is NOT true of every graph_depth call site in this codebase (see
214
+ # this commit's message), which is why each one was checked
215
+ # individually rather than assuming they all behave the same way.
216
+ depth = int(get_graph_depth())
217
 
218
  # Pattern 1: Company with multiple directors that won contracts
219
  rows = session.run(
 
233
 
234
  # Pattern 2: Audit flags on connected schemes
235
  rows = session.run(
236
+ f"""
237
+ MATCH (n {{id:$id}})-[*1..{depth}]-(a:AuditReport)
238
  RETURN a.title AS title, a.year AS year, a.amount_crore AS amount LIMIT 5
239
  """, id=entity_id
240
  ).data()
 
247
 
248
  # Pattern 3: Electoral bond connections
249
  rows = session.run(
250
+ f"""
251
+ MATCH (n {{id:$id}})-[*1..{depth}]-(e:ElectoralBond)
252
  RETURN e.donor_name AS donor, e.amount AS amount, e.party AS party LIMIT 5
253
  """, id=entity_id
254
  ).data()
 
268
 
269
  def _layer_4_timeline(self, entity_id: str, session) -> dict:
270
  events = []
271
+ depth = int(get_graph_depth()) # R-5 fix -- see _layer_3_patterns
272
 
273
  # Timeline events from multiple sources
274
  rows = session.run(
275
+ f"""
276
+ MATCH (n {{id:$id}})-[:DIRECTOR_OF|WON_CONTRACT|FLAGS|MENTIONED_IN|AUDITS*1..{depth}]-(m)
277
  WHERE m.order_date IS NOT NULL OR m.year IS NOT NULL OR m.scraped_at IS NOT NULL
278
  RETURN coalesce(m.name,m.title,m.id) AS name,
279
  labels(m)[0] AS type,
ai/investigators/historical_investigator.py CHANGED
@@ -3,6 +3,7 @@ import sys
3
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
4
  from datetime import datetime
5
  from loguru import logger
 
6
 
7
 
8
  class HistoricalInvestigator:
@@ -28,9 +29,13 @@ class HistoricalInvestigator:
28
 
29
  entity_type = node_row["type"] if node_row else "Unknown"
30
 
 
 
 
 
31
  contract_rows = session.run(
32
- """
33
- MATCH (n {id: $id})-[:DIRECTOR_OF|WON_CONTRACT*1..2]->(ct:Contract)
34
  RETURN ct.order_date AS date, ct.amount_crore AS amount,
35
  ct.buyer_org AS buyer
36
  ORDER BY ct.order_date
 
3
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
4
  from datetime import datetime
5
  from loguru import logger
6
+ from config.model_selector import get_graph_depth
7
 
8
 
9
  class HistoricalInvestigator:
 
29
 
30
  entity_type = node_row["type"] if node_row else "Unknown"
31
 
32
+ # R-5 fix: was a hardcoded *1..2, which is exactly PROFILE["low"]'s
33
+ # value -- zero change for a low-tier/desktop install, deeper
34
+ # (not shallower) traversal for medium/high.
35
+ depth = int(get_graph_depth())
36
  contract_rows = session.run(
37
+ f"""
38
+ MATCH (n {{id: $id}})-[:DIRECTOR_OF|WON_CONTRACT*1..{depth}]->(ct:Contract)
39
  RETURN ct.order_date AS date, ct.amount_crore AS amount,
40
  ct.buyer_org AS buyer
41
  ORDER BY ct.order_date
api/routes/risk.py CHANGED
@@ -11,6 +11,7 @@ from ai.benfords_analyzer import BenfordsAnalyzer
11
  from ai.ghost_company import GhostCompanyDetector
12
  from ai.shadow_director import ShadowDirectorDetector
13
  from ai.explainer import generate_explanation
 
14
 
15
  router = APIRouter()
16
 
@@ -204,8 +205,13 @@ def get_risk(entity_id: str, driver=Depends(get_db)):
204
 
205
  # Phase 34: ghost company detection
206
  try:
 
 
 
 
 
207
  co_rows = session.run(
208
- "MATCH (co:Company)-[:DIRECTOR_OF|:LINKED_TO*1..2]-(n {id: $id})"
209
  " OPTIONAL MATCH (co)-[:WON_CONTRACT]->(ct:Contract)"
210
  " WITH co, min(ct.order_date) AS first_contract,"
211
  " count(ct) AS contract_count,"
 
11
  from ai.ghost_company import GhostCompanyDetector
12
  from ai.shadow_director import ShadowDirectorDetector
13
  from ai.explainer import generate_explanation
14
+ from config.model_selector import get_graph_depth
15
 
16
  router = APIRouter()
17
 
 
205
 
206
  # Phase 34: ghost company detection
207
  try:
208
+ # R-5 fix: was a hardcoded *1..2, matching PROFILE["low"]'s value
209
+ # exactly -- zero change for low tier, deeper traversal for
210
+ # medium/high (see ai/deep_investigator.py's _layer_3_patterns
211
+ # for the full reasoning, identical here).
212
+ depth = int(get_graph_depth())
213
  co_rows = session.run(
214
+ f"MATCH (co:Company)-[:DIRECTOR_OF|:LINKED_TO*1..{depth}]-(n {{id: $id}})"
215
  " OPTIONAL MATCH (co)-[:WON_CONTRACT]->(ct:Contract)"
216
  " WITH co, min(ct.order_date) AS first_contract,"
217
  " count(ct) AS contract_count,"