Coverage for src/qdrant_loader_mcp_server/search/enhanced/cdi/legacy_adapters.py: 67%
69 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-08 06:06 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-08 06:06 +0000
1from __future__ import annotations
3import re
4from typing import Any
6from ....utils.logging import LoggingConfig
8logger = LoggingConfig.get_logger(__name__)
11class LegacyConflictDetectorAdapter:
12 """Adapter that hosts legacy/test-specific compatibility methods.
14 This wraps a current `ConflictDetector` instance and provides
15 the old compatibility helpers used by tests without bloating
16 the main detector implementation.
17 """
19 def __init__(self, detector: Any):
20 self.detector = detector
21 self.logger = LoggingConfig.get_logger(__name__)
23 def _find_contradiction_patterns(self, doc1, doc2):
24 try:
25 text1 = getattr(doc1, "text", getattr(doc1, "content", ""))
26 text2 = getattr(doc2, "text", getattr(doc2, "content", ""))
28 patterns = []
30 # Version conflicts
31 version_pattern = r"version\s+(\d+\.\d+\.\d+)"
32 versions1 = re.findall(version_pattern, text1.lower())
33 versions2 = re.findall(version_pattern, text2.lower())
35 if versions1 and versions2 and versions1 != versions2:
36 patterns.append(
37 {
38 "type": "version_conflict",
39 "reason": f"Version mismatch: {versions1[0]} vs {versions2[0]}",
40 "confidence": 0.8,
41 }
42 )
44 # Procedural conflicts
45 conflict_indicators = [
46 ("should not", "should"),
47 ("avoid", "use"),
48 ("deprecated", "recommended"),
49 ("wrong", "correct"),
50 ("never", "always"),
51 ("must not", "must"),
52 ("don't", "do"),
53 ]
55 for negative, positive in conflict_indicators:
56 if (negative in text1.lower() and positive in text2.lower()) or (
57 negative in text2.lower() and positive in text1.lower()
58 ):
59 patterns.append(
60 {
61 "type": "procedural_conflict",
62 "reason": f"Conflicting advice: '{negative}' vs '{positive}'",
63 "confidence": 0.8,
64 }
65 )
67 return patterns
68 except Exception as e:
69 self.logger.warning(
70 f"Error in compatibility method _find_contradiction_patterns: {e}"
71 )
72 return []
74 def _detect_version_conflicts(self, doc1, doc2):
75 try:
76 text1 = getattr(doc1, "text", getattr(doc1, "content", ""))
77 text2 = getattr(doc2, "text", getattr(doc2, "content", ""))
79 import re
81 version_pattern = r"(?:python|node|java|version)\s*(\d+\.\d+(?:\.\d+)?)"
82 versions1 = re.findall(version_pattern, text1.lower())
83 versions2 = re.findall(version_pattern, text2.lower())
85 if versions1 and versions2:
86 for v1 in versions1:
87 for v2 in versions2:
88 if v1 != v2:
89 return [
90 {
91 "type": "version_conflict",
92 "reason": f"Version mismatch: {v1} vs {v2}",
93 "summary": f"Version mismatch: {v1} vs {v2}",
94 "confidence": 0.8,
95 }
96 ]
98 # Fallback to metadata analysis from detector
99 try:
100 has_conflict, reason, confidence = (
101 self.detector._analyze_metadata_conflicts(doc1, doc2)
102 )
103 if (
104 has_conflict
105 and isinstance(reason, str)
106 and "version" in reason.lower()
107 ):
108 return [
109 {
110 "type": "version_conflict",
111 "reason": reason,
112 "confidence": confidence,
113 }
114 ]
115 except Exception as exc:
116 self.logger.exception(
117 "Metadata conflict analysis failed during version conflict detection",
118 exc_info=exc,
119 )
120 return []
121 except Exception as e:
122 self.logger.warning(f"Error in version conflict detection: {e}")
123 return []
125 def _detect_procedural_conflicts(self, doc1, doc2):
126 try:
127 text1 = getattr(doc1, "text", getattr(doc1, "content", ""))
128 text2 = getattr(doc2, "text", getattr(doc2, "content", ""))
130 procedural_conflicts = [
131 ("should", "should not"),
132 ("must", "must not"),
133 ("manually", "automated"),
134 ("always", "never"),
135 ]
137 for positive, negative in procedural_conflicts:
138 if (positive in text1.lower() and negative in text2.lower()) or (
139 negative in text1.lower() and positive in text2.lower()
140 ):
141 return [
142 {
143 "type": "procedural_conflict",
144 "reason": f"Conflicting procedures: '{positive}' vs '{negative}'",
145 "confidence": 0.8,
146 }
147 ]
149 # Fallback to text analysis if available
150 try:
151 has_conflict, reason, confidence = (
152 self.detector._analyze_text_conflicts(doc1, doc2)
153 )
154 if has_conflict and any(
155 k in str(reason).lower()
156 for k in ["procedure", "process", "steps", "workflow"]
157 ):
158 return [
159 {
160 "type": "procedural_conflict",
161 "reason": reason,
162 "confidence": confidence,
163 }
164 ]
165 except Exception as exc:
166 self.logger.exception(
167 "Text conflict analysis failed during procedural conflict detection",
168 exc_info=exc,
169 )
171 return []
172 except Exception as e:
173 self.logger.warning(f"Error in procedural conflict detection: {e}")
174 return []
177__all__ = [
178 "LegacyConflictDetectorAdapter",
179]