dakheel commited on
Commit
5f2bcd5
·
verified ·
1 Parent(s): a549e25

Update hudanet_core/evidence_selection.py

Browse files
Files changed (1) hide show
  1. hudanet_core/evidence_selection.py +164 -36
hudanet_core/evidence_selection.py CHANGED
@@ -302,14 +302,19 @@ class UnifiedEvidenceSelector:
302
  return ""
303
 
304
  def _explicit_condition_member_bridge(self, query: QueryFrame, item: ScoredEvidence) -> bool:
305
- """Recognize an explicit positive condition-of-the-requested-facet record.
306
-
307
- A distributed set member may be stored under a linked question phrased as a
308
- ruling or definition even though the record's own ruling explicitly says it
309
- is a condition of the requested facet. That local ruling is stronger than
310
- the surface form of the linked dataset question. This bridge is deliberately
311
- narrow: it is used only for conditions questions, rejects negative condition
312
- labels, and requires the ruling itself to bind the requested facet.
 
 
 
 
 
313
  """
314
  if query.primary_request_type != "conditions" or self.text is None:
315
  return False
@@ -317,43 +322,130 @@ class UnifiedEvidenceSelector:
317
  ruling = self._localized_source_value(item, "ruling", query.language)
318
  if not ruling:
319
  return False
320
- normalized = self.text.normalize(ruling, query.language)
321
- if not normalized:
 
322
  return False
323
 
 
 
 
 
324
  if query.language == "ar":
325
- # Reject statements such as "ليس شرط وجوب" before testing the
326
- # positive condition phrase.
327
- if re.search(r"(?:ليس|ليست|غير|لا)\s+.{0,24}(?:شرط|شروط)", normalized):
 
328
  return False
329
- condition_marker = bool(re.search(r"(?:^|\s)(?:شرط|شروط)(?:\s|$)", normalized))
 
 
 
 
 
 
 
 
 
 
 
330
  if query.facet_dimension == "obligation":
331
- facet_marker = bool(re.search(r"(?:وجوب|واجب|يجب|يلزم|فرض)", normalized))
 
 
 
 
 
332
  else:
333
- facet_marker = self._term_overlap(query.facet_terms, ruling, query.language) >= 0.44
 
 
 
 
 
 
 
334
  else:
335
- if re.search(r"\b(?:not|isn't|isnt)\b.{0,32}\bconditions?\b", normalized, re.I):
 
 
 
 
336
  return False
337
- condition_marker = bool(re.search(r"\bconditions?\b", normalized, re.I))
 
 
 
 
 
 
 
 
 
 
 
338
  if query.facet_dimension == "obligation":
339
- facet_marker = bool(re.search(r"\b(?:obligation|obligatory|required|must)\b", normalized, re.I))
 
 
 
 
 
 
340
  else:
341
- facet_marker = self._term_overlap(query.facet_terms, ruling, query.language) >= 0.44
 
 
 
 
 
 
 
342
 
343
- if not condition_marker or (query.facet_locked and not facet_marker):
 
 
344
  return False
345
 
346
- # The record still needs usable text and some connection to the central
347
- # query subject. The exact thresholds are intentionally lower than the
348
- # final direct gate because this helper only repairs linked-question form.
349
- target_terms = tuple(dict.fromkeys((*query.subject_terms, *query.anchor_terms)))
350
- frame = " ".join(filter(None, (
351
- self._localized_source_value(item, "title", query.language),
352
- self._localized_source_value(item, "question", query.language),
353
- item.evidence.answer_text,
354
- )))
355
- target_overlap = self._term_overlap(target_terms, frame, query.language) if target_terms else 1.0
356
- return bool(target_overlap >= 0.34 or not target_terms)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
  @staticmethod
359
  def _clip(value: object, default: float = 0.0) -> float:
@@ -454,6 +546,8 @@ class UnifiedEvidenceSelector:
454
  facet_conflict = self._clip(m.get("facet_conflicting_support", 0.0))
455
  if query.facet_locked:
456
  facet = self._clip(m.get("facet_alignment", 0.0)) * (1.0 - 0.72 * facet_conflict)
 
 
457
 
458
  # The requested operation, subject, constraints and text integrity are
459
  # bottleneck features. Neural retrieval is deliberately only a tie-breaker.
@@ -643,10 +737,20 @@ class UnifiedEvidenceSelector:
643
  all_rules = tuple(item.evidence.semantic_slots.get("condition_rule", ()))
644
  valid_rules = tuple(item.source.get("generic_valid_condition_rules", ()))
645
  if all_rules and not valid_rules:
646
- reasons.append("condition_rule_not_locally_bound_to_query_contract")
647
- if f["subject"] >= self.cfg["adjacent_subject_floor"] or f["neural"] >= 0.76:
648
- return "adjacent", reasons
649
- return "irrelevant", reasons
 
 
 
 
 
 
 
 
 
 
650
 
651
  direct = bool(
652
  f["direct_score"] >= direct_floor
@@ -744,6 +848,26 @@ class UnifiedEvidenceSelector:
744
  return "exception", reasons
745
  return "direct", reasons
746
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
747
  supporting = bool(
748
  (f["support_score"] >= self.cfg["support_floor"] or f["entailment_operator"] >= self.cfg["entailment_support_floor"])
749
  and f["subject"] >= self.cfg["minimum_subject"]
@@ -935,6 +1059,10 @@ class UnifiedEvidenceSelector:
935
  "generic_explicit_condition_member_bridge": bool(
936
  self._explicit_condition_member_bridge(query, item)
937
  ),
 
 
 
 
938
  "generic_training_candidate": bool(
939
  shadow_disagreement
940
  or (role in {"adjacent", "irrelevant"} and f["neural"] >= self.cfg["hard_negative_neural_floor"])
 
302
  return ""
303
 
304
  def _explicit_condition_member_bridge(self, query: QueryFrame, item: ScoredEvidence) -> bool:
305
+ """Recognize one explicit positive member of a requested conditions set.
306
+
307
+ Distributed condition sets are often stored as sibling records whose linked
308
+ questions are phrased as rulings, definitions, or edge cases. A record may
309
+ still contribute when its own source framing explicitly marks it as a
310
+ positive condition of the requested facet.
311
+
312
+ Safety rules:
313
+ - negative labels such as "not a condition" are rejected;
314
+ - the condition marker must come from the ruling itself;
315
+ - the requested facet must be locally expressed in ruling/question/answer;
316
+ - the central subject must be bound structurally, unless retrieval already
317
+ marked the record as a bounded source-local sibling of a qualified set seed.
318
  """
319
  if query.primary_request_type != "conditions" or self.text is None:
320
  return False
 
322
  ruling = self._localized_source_value(item, "ruling", query.language)
323
  if not ruling:
324
  return False
325
+
326
+ normalized_ruling = self.text.normalize(ruling, query.language)
327
+ if not normalized_ruling:
328
  return False
329
 
330
+ question = self._localized_source_value(item, "question", query.language)
331
+ title = self._localized_source_value(item, "title", query.language)
332
+ answer_text = str(item.evidence.answer_text or "").strip()
333
+
334
  if query.language == "ar":
335
+ if re.search(
336
+ r"(?:ليس|ليست|غير|لا)\s+.{0,24}(?:شرط|شروط)",
337
+ normalized_ruling,
338
+ ):
339
  return False
340
+
341
+ condition_marker = bool(
342
+ re.search(
343
+ r"(?:^|\s)(?:شرط|شروط)(?:\s|$|\s*\()",
344
+ normalized_ruling,
345
+ )
346
+ )
347
+
348
+ facet_frame = self.text.normalize(
349
+ " ".join(filter(None, (ruling, question, answer_text))),
350
+ query.language,
351
+ )
352
  if query.facet_dimension == "obligation":
353
+ facet_marker = bool(
354
+ re.search(
355
+ r"(?:وجوب|واجب|يجب|يلزم|فرض)",
356
+ facet_frame,
357
+ )
358
+ )
359
  else:
360
+ facet_marker = (
361
+ self._term_overlap(
362
+ query.facet_terms,
363
+ facet_frame,
364
+ query.language,
365
+ )
366
+ >= 0.44
367
+ )
368
  else:
369
+ if re.search(
370
+ r"\b(?:not|isn't|isnt)\b.{0,32}\bconditions?\b",
371
+ normalized_ruling,
372
+ re.I,
373
+ ):
374
  return False
375
+
376
+ condition_marker = bool(
377
+ re.search(
378
+ r"\bconditions?\b",
379
+ normalized_ruling,
380
+ re.I,
381
+ )
382
+ )
383
+
384
+ facet_frame = " ".join(
385
+ filter(None, (ruling, question, answer_text))
386
+ )
387
  if query.facet_dimension == "obligation":
388
+ facet_marker = bool(
389
+ re.search(
390
+ r"\b(?:obligation|obligatory|required|must)\b",
391
+ facet_frame,
392
+ re.I,
393
+ )
394
+ )
395
  else:
396
+ facet_marker = (
397
+ self._term_overlap(
398
+ query.facet_terms,
399
+ facet_frame,
400
+ query.language,
401
+ )
402
+ >= 0.44
403
+ )
404
 
405
+ if not condition_marker:
406
+ return False
407
+ if query.facet_locked and not facet_marker:
408
  return False
409
 
410
+ target_terms = tuple(
411
+ dict.fromkeys(
412
+ (
413
+ *query.subject_terms,
414
+ *query.anchor_terms,
415
+ )
416
+ )
417
+ )
418
+
419
+ structural_frame = " ".join(
420
+ filter(
421
+ None,
422
+ (
423
+ title,
424
+ question,
425
+ ruling,
426
+ ),
427
+ )
428
+ )
429
+
430
+ target_overlap = (
431
+ self._term_overlap(
432
+ target_terms,
433
+ structural_frame,
434
+ query.language,
435
+ )
436
+ if target_terms
437
+ else 1.0
438
+ )
439
+
440
+ source_local_sibling = bool(
441
+ item.source.get("set_local_sibling", False)
442
+ or item.source.get("generic_set_local_sibling", False)
443
+ )
444
+
445
+ if target_terms and target_overlap < 0.34 and not source_local_sibling:
446
+ return False
447
+
448
+ return True
449
 
450
  @staticmethod
451
  def _clip(value: object, default: float = 0.0) -> float:
 
546
  facet_conflict = self._clip(m.get("facet_conflicting_support", 0.0))
547
  if query.facet_locked:
548
  facet = self._clip(m.get("facet_alignment", 0.0)) * (1.0 - 0.72 * facet_conflict)
549
+ if explicit_condition_bridge:
550
+ facet = max(facet, 0.78)
551
 
552
  # The requested operation, subject, constraints and text integrity are
553
  # bottleneck features. Neural retrieval is deliberately only a tie-breaker.
 
737
  all_rules = tuple(item.evidence.semantic_slots.get("condition_rule", ()))
738
  valid_rules = tuple(item.source.get("generic_valid_condition_rules", ()))
739
  if all_rules and not valid_rules:
740
+ if explicit_condition_bridge:
741
+ reasons.append(
742
+ "explicit_condition_member_overrides_rule_locality"
743
+ )
744
+ else:
745
+ reasons.append(
746
+ "condition_rule_not_locally_bound_to_query_contract"
747
+ )
748
+ if (
749
+ f["subject"] >= self.cfg["adjacent_subject_floor"]
750
+ or f["neural"] >= 0.76
751
+ ):
752
+ return "adjacent", reasons
753
+ return "irrelevant", reasons
754
 
755
  direct = bool(
756
  f["direct_score"] >= direct_floor
 
848
  return "exception", reasons
849
  return "direct", reasons
850
 
851
+ explicit_condition_member_support = bool(
852
+ query.primary_request_type == "conditions"
853
+ and explicit_condition_bridge
854
+ and f["integrity"] >= self.cfg["minimum_integrity"]
855
+ and f["facet"] >= self.cfg["minimum_facet"]
856
+ and f["operator"] >= 0.70
857
+ and (
858
+ f["subject"] >= 0.34
859
+ or bool(
860
+ item.source.get("set_local_sibling", False)
861
+ or item.source.get("generic_set_local_sibling", False)
862
+ )
863
+ )
864
+ )
865
+ if explicit_condition_member_support:
866
+ reasons.append(
867
+ "explicit_condition_member_supporting_anchor"
868
+ )
869
+ return "supporting", reasons
870
+
871
  supporting = bool(
872
  (f["support_score"] >= self.cfg["support_floor"] or f["entailment_operator"] >= self.cfg["entailment_support_floor"])
873
  and f["subject"] >= self.cfg["minimum_subject"]
 
1059
  "generic_explicit_condition_member_bridge": bool(
1060
  self._explicit_condition_member_bridge(query, item)
1061
  ),
1062
+ "generic_set_local_sibling": bool(
1063
+ item.source.get("set_local_sibling", False)
1064
+ or item.source.get("generic_set_local_sibling", False)
1065
+ ),
1066
  "generic_training_candidate": bool(
1067
  shadow_disagreement
1068
  or (role in {"adjacent", "irrelevant"} and f["neural"] >= self.cfg["hard_negative_neural_floor"])