truthound-dashboard 1.3.1__py3-none-any.whl → 1.4.0__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.
Files changed (169) hide show
  1. truthound_dashboard/api/alerts.py +258 -0
  2. truthound_dashboard/api/anomaly.py +1302 -0
  3. truthound_dashboard/api/cross_alerts.py +352 -0
  4. truthound_dashboard/api/deps.py +143 -0
  5. truthound_dashboard/api/drift_monitor.py +540 -0
  6. truthound_dashboard/api/lineage.py +1151 -0
  7. truthound_dashboard/api/maintenance.py +363 -0
  8. truthound_dashboard/api/middleware.py +373 -1
  9. truthound_dashboard/api/model_monitoring.py +805 -0
  10. truthound_dashboard/api/notifications_advanced.py +2452 -0
  11. truthound_dashboard/api/plugins.py +2096 -0
  12. truthound_dashboard/api/profile.py +211 -14
  13. truthound_dashboard/api/reports.py +853 -0
  14. truthound_dashboard/api/router.py +147 -0
  15. truthound_dashboard/api/rule_suggestions.py +310 -0
  16. truthound_dashboard/api/schema_evolution.py +231 -0
  17. truthound_dashboard/api/sources.py +47 -3
  18. truthound_dashboard/api/triggers.py +190 -0
  19. truthound_dashboard/api/validations.py +13 -0
  20. truthound_dashboard/api/validators.py +333 -4
  21. truthound_dashboard/api/versioning.py +309 -0
  22. truthound_dashboard/api/websocket.py +301 -0
  23. truthound_dashboard/core/__init__.py +27 -0
  24. truthound_dashboard/core/anomaly.py +1395 -0
  25. truthound_dashboard/core/anomaly_explainer.py +633 -0
  26. truthound_dashboard/core/cache.py +206 -0
  27. truthound_dashboard/core/cached_services.py +422 -0
  28. truthound_dashboard/core/charts.py +352 -0
  29. truthound_dashboard/core/connections.py +1069 -42
  30. truthound_dashboard/core/cross_alerts.py +837 -0
  31. truthound_dashboard/core/drift_monitor.py +1477 -0
  32. truthound_dashboard/core/drift_sampling.py +669 -0
  33. truthound_dashboard/core/i18n/__init__.py +42 -0
  34. truthound_dashboard/core/i18n/detector.py +173 -0
  35. truthound_dashboard/core/i18n/messages.py +564 -0
  36. truthound_dashboard/core/lineage.py +971 -0
  37. truthound_dashboard/core/maintenance.py +443 -5
  38. truthound_dashboard/core/model_monitoring.py +1043 -0
  39. truthound_dashboard/core/notifications/channels.py +1020 -1
  40. truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
  41. truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
  42. truthound_dashboard/core/notifications/deduplication/service.py +400 -0
  43. truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
  44. truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
  45. truthound_dashboard/core/notifications/dispatcher.py +43 -0
  46. truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
  47. truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
  48. truthound_dashboard/core/notifications/escalation/engine.py +429 -0
  49. truthound_dashboard/core/notifications/escalation/models.py +336 -0
  50. truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
  51. truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
  52. truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
  53. truthound_dashboard/core/notifications/events.py +49 -0
  54. truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
  55. truthound_dashboard/core/notifications/metrics/base.py +528 -0
  56. truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
  57. truthound_dashboard/core/notifications/routing/__init__.py +169 -0
  58. truthound_dashboard/core/notifications/routing/combinators.py +184 -0
  59. truthound_dashboard/core/notifications/routing/config.py +375 -0
  60. truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
  61. truthound_dashboard/core/notifications/routing/engine.py +382 -0
  62. truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
  63. truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
  64. truthound_dashboard/core/notifications/routing/rules.py +625 -0
  65. truthound_dashboard/core/notifications/routing/validator.py +678 -0
  66. truthound_dashboard/core/notifications/service.py +2 -0
  67. truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
  68. truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
  69. truthound_dashboard/core/notifications/throttling/builder.py +311 -0
  70. truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
  71. truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
  72. truthound_dashboard/core/openlineage.py +1028 -0
  73. truthound_dashboard/core/plugins/__init__.py +39 -0
  74. truthound_dashboard/core/plugins/docs/__init__.py +39 -0
  75. truthound_dashboard/core/plugins/docs/extractor.py +703 -0
  76. truthound_dashboard/core/plugins/docs/renderers.py +804 -0
  77. truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
  78. truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
  79. truthound_dashboard/core/plugins/hooks/manager.py +403 -0
  80. truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
  81. truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
  82. truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
  83. truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
  84. truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
  85. truthound_dashboard/core/plugins/loader.py +504 -0
  86. truthound_dashboard/core/plugins/registry.py +810 -0
  87. truthound_dashboard/core/plugins/reporter_executor.py +588 -0
  88. truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
  89. truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
  90. truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
  91. truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
  92. truthound_dashboard/core/plugins/sandbox.py +617 -0
  93. truthound_dashboard/core/plugins/security/__init__.py +68 -0
  94. truthound_dashboard/core/plugins/security/analyzer.py +535 -0
  95. truthound_dashboard/core/plugins/security/policies.py +311 -0
  96. truthound_dashboard/core/plugins/security/protocols.py +296 -0
  97. truthound_dashboard/core/plugins/security/signing.py +842 -0
  98. truthound_dashboard/core/plugins/security.py +446 -0
  99. truthound_dashboard/core/plugins/validator_executor.py +401 -0
  100. truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
  101. truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
  102. truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
  103. truthound_dashboard/core/plugins/versioning/semver.py +266 -0
  104. truthound_dashboard/core/profile_comparison.py +601 -0
  105. truthound_dashboard/core/report_history.py +570 -0
  106. truthound_dashboard/core/reporters/__init__.py +57 -0
  107. truthound_dashboard/core/reporters/base.py +296 -0
  108. truthound_dashboard/core/reporters/csv_reporter.py +155 -0
  109. truthound_dashboard/core/reporters/html_reporter.py +598 -0
  110. truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
  111. truthound_dashboard/core/reporters/i18n/base.py +494 -0
  112. truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
  113. truthound_dashboard/core/reporters/json_reporter.py +160 -0
  114. truthound_dashboard/core/reporters/junit_reporter.py +233 -0
  115. truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
  116. truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
  117. truthound_dashboard/core/reporters/registry.py +272 -0
  118. truthound_dashboard/core/rule_generator.py +2088 -0
  119. truthound_dashboard/core/scheduler.py +822 -12
  120. truthound_dashboard/core/schema_evolution.py +858 -0
  121. truthound_dashboard/core/services.py +152 -9
  122. truthound_dashboard/core/statistics.py +718 -0
  123. truthound_dashboard/core/streaming_anomaly.py +883 -0
  124. truthound_dashboard/core/triggers/__init__.py +45 -0
  125. truthound_dashboard/core/triggers/base.py +226 -0
  126. truthound_dashboard/core/triggers/evaluators.py +609 -0
  127. truthound_dashboard/core/triggers/factory.py +363 -0
  128. truthound_dashboard/core/unified_alerts.py +870 -0
  129. truthound_dashboard/core/validation_limits.py +509 -0
  130. truthound_dashboard/core/versioning.py +709 -0
  131. truthound_dashboard/core/websocket/__init__.py +59 -0
  132. truthound_dashboard/core/websocket/manager.py +512 -0
  133. truthound_dashboard/core/websocket/messages.py +130 -0
  134. truthound_dashboard/db/__init__.py +30 -0
  135. truthound_dashboard/db/models.py +3375 -3
  136. truthound_dashboard/main.py +22 -0
  137. truthound_dashboard/schemas/__init__.py +396 -1
  138. truthound_dashboard/schemas/anomaly.py +1258 -0
  139. truthound_dashboard/schemas/base.py +4 -0
  140. truthound_dashboard/schemas/cross_alerts.py +334 -0
  141. truthound_dashboard/schemas/drift_monitor.py +890 -0
  142. truthound_dashboard/schemas/lineage.py +428 -0
  143. truthound_dashboard/schemas/maintenance.py +154 -0
  144. truthound_dashboard/schemas/model_monitoring.py +374 -0
  145. truthound_dashboard/schemas/notifications_advanced.py +1363 -0
  146. truthound_dashboard/schemas/openlineage.py +704 -0
  147. truthound_dashboard/schemas/plugins.py +1293 -0
  148. truthound_dashboard/schemas/profile.py +420 -34
  149. truthound_dashboard/schemas/profile_comparison.py +242 -0
  150. truthound_dashboard/schemas/reports.py +285 -0
  151. truthound_dashboard/schemas/rule_suggestion.py +434 -0
  152. truthound_dashboard/schemas/schema_evolution.py +164 -0
  153. truthound_dashboard/schemas/source.py +117 -2
  154. truthound_dashboard/schemas/triggers.py +511 -0
  155. truthound_dashboard/schemas/unified_alerts.py +223 -0
  156. truthound_dashboard/schemas/validation.py +25 -1
  157. truthound_dashboard/schemas/validators/__init__.py +11 -0
  158. truthound_dashboard/schemas/validators/base.py +151 -0
  159. truthound_dashboard/schemas/versioning.py +152 -0
  160. truthound_dashboard/static/index.html +2 -2
  161. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
  162. truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
  163. truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
  164. truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
  165. truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
  166. truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
  167. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
  168. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
  169. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,352 @@
1
+ """Cross-alert correlation API endpoints.
2
+
3
+ This module provides REST API endpoints for cross-feature integration
4
+ between Anomaly Detection and Drift Monitoring alerts.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Annotated
10
+
11
+ from fastapi import APIRouter, Depends, HTTPException, Query
12
+
13
+ from truthound_dashboard.core.cross_alerts import CrossAlertService
14
+ from truthound_dashboard.schemas.cross_alerts import (
15
+ CrossAlertCorrelation,
16
+ CrossAlertCorrelationListResponse,
17
+ AutoTriggerConfig,
18
+ AutoTriggerConfigCreate,
19
+ AutoTriggerConfigUpdate,
20
+ AutoTriggerEvent,
21
+ AutoTriggerEventListResponse,
22
+ CrossAlertSummary,
23
+ )
24
+ from .deps import SessionDep
25
+
26
+ router = APIRouter()
27
+
28
+
29
+ # Dependency
30
+ async def get_cross_alert_service(session: SessionDep) -> CrossAlertService:
31
+ """Get cross-alert service dependency."""
32
+ return CrossAlertService(session)
33
+
34
+
35
+ CrossAlertServiceDep = Annotated[CrossAlertService, Depends(get_cross_alert_service)]
36
+
37
+
38
+ # =============================================================================
39
+ # Correlation Endpoints
40
+ # =============================================================================
41
+
42
+
43
+ @router.get(
44
+ "/cross-alerts/correlations",
45
+ response_model=CrossAlertCorrelationListResponse,
46
+ summary="Get correlated alerts",
47
+ description="Get correlations between anomaly and drift alerts.",
48
+ )
49
+ async def get_correlations(
50
+ service: CrossAlertServiceDep,
51
+ source_id: str | None = Query(None, description="Filter by source ID"),
52
+ limit: int = Query(50, ge=1, le=100, description="Maximum items to return"),
53
+ offset: int = Query(0, ge=0, description="Number of items to skip"),
54
+ ) -> CrossAlertCorrelationListResponse:
55
+ """Get correlated alerts.
56
+
57
+ Args:
58
+ service: Injected cross-alert service.
59
+ source_id: Optional source ID filter.
60
+ limit: Maximum items to return.
61
+ offset: Number of items to skip.
62
+
63
+ Returns:
64
+ Paginated list of correlations.
65
+ """
66
+ correlations, total = await service.get_correlations(
67
+ source_id=source_id,
68
+ limit=limit,
69
+ offset=offset,
70
+ )
71
+
72
+ return CrossAlertCorrelationListResponse(
73
+ success=True,
74
+ data=[CrossAlertCorrelation(**c) for c in correlations],
75
+ total=total,
76
+ offset=offset,
77
+ limit=limit,
78
+ )
79
+
80
+
81
+ @router.get(
82
+ "/cross-alerts/correlations/{source_id}",
83
+ response_model=dict,
84
+ summary="Find correlations for source",
85
+ description="Find correlated anomaly and drift alerts for a specific source.",
86
+ )
87
+ async def find_correlations_for_source(
88
+ source_id: str,
89
+ service: CrossAlertServiceDep,
90
+ time_window_hours: int = Query(24, ge=1, le=168, description="Time window in hours"),
91
+ limit: int = Query(50, ge=1, le=100, description="Maximum items to return"),
92
+ ) -> dict:
93
+ """Find correlations for a specific source.
94
+
95
+ This actively searches for correlations between recent anomaly
96
+ detections and drift alerts for the given source.
97
+
98
+ Args:
99
+ source_id: Source ID to analyze.
100
+ service: Injected cross-alert service.
101
+ time_window_hours: Time window to search (1-168 hours).
102
+ limit: Maximum correlations to return.
103
+
104
+ Returns:
105
+ Dictionary with correlations found.
106
+ """
107
+ correlations = await service.correlate_anomaly_drift(
108
+ source_id=source_id,
109
+ time_window_hours=time_window_hours,
110
+ limit=limit,
111
+ )
112
+
113
+ return {
114
+ "success": True,
115
+ "data": correlations,
116
+ "total": len(correlations),
117
+ }
118
+
119
+
120
+ # =============================================================================
121
+ # Auto-Trigger Configuration Endpoints
122
+ # =============================================================================
123
+
124
+
125
+ @router.get(
126
+ "/cross-alerts/config",
127
+ response_model=dict,
128
+ summary="Get auto-trigger config",
129
+ description="Get auto-trigger configuration (global or source-specific).",
130
+ )
131
+ async def get_config(
132
+ service: CrossAlertServiceDep,
133
+ source_id: str | None = Query(None, description="Source ID for source-specific config"),
134
+ ) -> dict:
135
+ """Get auto-trigger configuration.
136
+
137
+ Args:
138
+ service: Injected cross-alert service.
139
+ source_id: Optional source ID for source-specific config.
140
+
141
+ Returns:
142
+ Configuration dictionary.
143
+ """
144
+ config = service.get_config(source_id)
145
+ return {
146
+ "success": True,
147
+ "data": config,
148
+ }
149
+
150
+
151
+ @router.post(
152
+ "/cross-alerts/config",
153
+ response_model=dict,
154
+ status_code=201,
155
+ summary="Create/update auto-trigger config",
156
+ description="Create or update auto-trigger configuration.",
157
+ )
158
+ async def update_config(
159
+ request: AutoTriggerConfigCreate,
160
+ service: CrossAlertServiceDep,
161
+ ) -> dict:
162
+ """Create or update auto-trigger configuration.
163
+
164
+ Args:
165
+ request: Configuration data.
166
+ service: Injected cross-alert service.
167
+
168
+ Returns:
169
+ Updated configuration.
170
+ """
171
+ update_data = request.model_dump(exclude_unset=True)
172
+ source_id = update_data.pop("source_id", None)
173
+
174
+ config = service.update_config(source_id, **update_data)
175
+
176
+ return {
177
+ "success": True,
178
+ "data": config,
179
+ }
180
+
181
+
182
+ @router.put(
183
+ "/cross-alerts/config",
184
+ response_model=dict,
185
+ summary="Update auto-trigger config",
186
+ description="Update existing auto-trigger configuration.",
187
+ )
188
+ async def patch_config(
189
+ request: AutoTriggerConfigUpdate,
190
+ service: CrossAlertServiceDep,
191
+ source_id: str | None = Query(None, description="Source ID for source-specific config"),
192
+ ) -> dict:
193
+ """Update auto-trigger configuration.
194
+
195
+ Args:
196
+ request: Configuration update data.
197
+ service: Injected cross-alert service.
198
+ source_id: Optional source ID for source-specific config.
199
+
200
+ Returns:
201
+ Updated configuration.
202
+ """
203
+ update_data = request.model_dump(exclude_unset=True)
204
+ config = service.update_config(source_id, **update_data)
205
+
206
+ return {
207
+ "success": True,
208
+ "data": config,
209
+ }
210
+
211
+
212
+ # =============================================================================
213
+ # Auto-Trigger Event Endpoints
214
+ # =============================================================================
215
+
216
+
217
+ @router.get(
218
+ "/cross-alerts/events",
219
+ response_model=AutoTriggerEventListResponse,
220
+ summary="List auto-trigger events",
221
+ description="Get history of auto-triggered checks.",
222
+ )
223
+ async def list_events(
224
+ service: CrossAlertServiceDep,
225
+ source_id: str | None = Query(None, description="Filter by source ID"),
226
+ limit: int = Query(50, ge=1, le=100, description="Maximum items to return"),
227
+ offset: int = Query(0, ge=0, description="Number of items to skip"),
228
+ ) -> AutoTriggerEventListResponse:
229
+ """List auto-trigger events.
230
+
231
+ Args:
232
+ service: Injected cross-alert service.
233
+ source_id: Optional source ID filter.
234
+ limit: Maximum items to return.
235
+ offset: Number of items to skip.
236
+
237
+ Returns:
238
+ Paginated list of events.
239
+ """
240
+ events, total = await service.get_auto_trigger_events(
241
+ source_id=source_id,
242
+ limit=limit,
243
+ offset=offset,
244
+ )
245
+
246
+ return AutoTriggerEventListResponse(
247
+ success=True,
248
+ data=[AutoTriggerEvent(**e) for e in events],
249
+ total=total,
250
+ offset=offset,
251
+ limit=limit,
252
+ )
253
+
254
+
255
+ # =============================================================================
256
+ # Manual Trigger Endpoints
257
+ # =============================================================================
258
+
259
+
260
+ @router.post(
261
+ "/cross-alerts/trigger/drift-on-anomaly/{detection_id}",
262
+ response_model=dict,
263
+ summary="Trigger drift check on anomaly",
264
+ description="Manually trigger a drift check based on an anomaly detection result.",
265
+ )
266
+ async def trigger_drift_on_anomaly(
267
+ detection_id: str,
268
+ service: CrossAlertServiceDep,
269
+ ) -> dict:
270
+ """Manually trigger drift check after anomaly detection.
271
+
272
+ Args:
273
+ detection_id: Anomaly detection ID.
274
+ service: Injected cross-alert service.
275
+
276
+ Returns:
277
+ Trigger event result.
278
+
279
+ Raises:
280
+ HTTPException: 404 if detection not found.
281
+ """
282
+ event = await service.auto_trigger_drift_on_anomaly(detection_id)
283
+
284
+ if not event:
285
+ raise HTTPException(status_code=404, detail="Detection not found")
286
+
287
+ return {
288
+ "success": True,
289
+ "data": event,
290
+ }
291
+
292
+
293
+ @router.post(
294
+ "/cross-alerts/trigger/anomaly-on-drift/{monitor_id}",
295
+ response_model=dict,
296
+ summary="Trigger anomaly check on drift",
297
+ description="Manually trigger an anomaly check based on drift detection.",
298
+ )
299
+ async def trigger_anomaly_on_drift(
300
+ monitor_id: str,
301
+ service: CrossAlertServiceDep,
302
+ ) -> dict:
303
+ """Manually trigger anomaly check after drift detection.
304
+
305
+ Args:
306
+ monitor_id: Drift monitor ID.
307
+ service: Injected cross-alert service.
308
+
309
+ Returns:
310
+ Trigger event result.
311
+
312
+ Raises:
313
+ HTTPException: 404 if monitor not found.
314
+ """
315
+ event = await service.auto_trigger_anomaly_on_drift(monitor_id)
316
+
317
+ if not event:
318
+ raise HTTPException(status_code=404, detail="Monitor not found")
319
+
320
+ return {
321
+ "success": True,
322
+ "data": event,
323
+ }
324
+
325
+
326
+ # =============================================================================
327
+ # Summary Endpoint
328
+ # =============================================================================
329
+
330
+
331
+ @router.get(
332
+ "/cross-alerts/summary",
333
+ response_model=dict,
334
+ summary="Get cross-alert summary",
335
+ description="Get summary statistics for cross-alert correlations.",
336
+ )
337
+ async def get_summary(
338
+ service: CrossAlertServiceDep,
339
+ ) -> dict:
340
+ """Get cross-alert summary statistics.
341
+
342
+ Args:
343
+ service: Injected cross-alert service.
344
+
345
+ Returns:
346
+ Summary statistics dictionary.
347
+ """
348
+ summary = await service.get_summary()
349
+ return {
350
+ "success": True,
351
+ "data": summary,
352
+ }
@@ -31,6 +31,14 @@ from truthound_dashboard.core import (
31
31
  SourceService,
32
32
  ValidationService,
33
33
  )
34
+ from truthound_dashboard.core.schema_evolution import SchemaEvolutionService
35
+ from truthound_dashboard.core.rule_generator import RuleGeneratorService
36
+ from truthound_dashboard.core.profile_comparison import ProfileComparisonService
37
+ from truthound_dashboard.core.lineage import LineageService
38
+ from truthound_dashboard.core.anomaly import AnomalyDetectionService
39
+ from truthound_dashboard.core.anomaly_explainer import AnomalyExplainerService
40
+ from truthound_dashboard.core.openlineage import OpenLineageEmitterService, OpenLineageWebhookService
41
+ from truthound_dashboard.core.report_history import ReportHistoryService
34
42
  from truthound_dashboard.db import get_db_session
35
43
 
36
44
 
@@ -168,6 +176,102 @@ async def get_mask_service(session: SessionDep) -> MaskService:
168
176
  return MaskService(session)
169
177
 
170
178
 
179
+ async def get_schema_evolution_service(session: SessionDep) -> SchemaEvolutionService:
180
+ """Get schema evolution service dependency.
181
+
182
+ Args:
183
+ session: Database session.
184
+
185
+ Returns:
186
+ SchemaEvolutionService instance.
187
+ """
188
+ return SchemaEvolutionService(session)
189
+
190
+
191
+ async def get_rule_generator_service(session: SessionDep) -> RuleGeneratorService:
192
+ """Get rule generator service dependency.
193
+
194
+ Args:
195
+ session: Database session.
196
+
197
+ Returns:
198
+ RuleGeneratorService instance.
199
+ """
200
+ return RuleGeneratorService(session)
201
+
202
+
203
+ async def get_profile_comparison_service(session: SessionDep) -> ProfileComparisonService:
204
+ """Get profile comparison service dependency.
205
+
206
+ Args:
207
+ session: Database session.
208
+
209
+ Returns:
210
+ ProfileComparisonService instance.
211
+ """
212
+ return ProfileComparisonService(session)
213
+
214
+
215
+ async def get_lineage_service(session: SessionDep) -> LineageService:
216
+ """Get lineage service dependency.
217
+
218
+ Args:
219
+ session: Database session.
220
+
221
+ Returns:
222
+ LineageService instance.
223
+ """
224
+ return LineageService(session)
225
+
226
+
227
+ async def get_anomaly_detection_service(session: SessionDep) -> AnomalyDetectionService:
228
+ """Get anomaly detection service dependency.
229
+
230
+ Args:
231
+ session: Database session.
232
+
233
+ Returns:
234
+ AnomalyDetectionService instance.
235
+ """
236
+ return AnomalyDetectionService(session)
237
+
238
+
239
+ async def get_anomaly_explainer_service(session: SessionDep) -> AnomalyExplainerService:
240
+ """Get anomaly explainer service dependency.
241
+
242
+ Args:
243
+ session: Database session.
244
+
245
+ Returns:
246
+ AnomalyExplainerService instance for SHAP/LIME explanations.
247
+ """
248
+ return AnomalyExplainerService(session)
249
+
250
+
251
+ async def get_openlineage_emitter_service(session: SessionDep) -> OpenLineageEmitterService:
252
+ """Get OpenLineage emitter service dependency.
253
+
254
+ Args:
255
+ session: Database session.
256
+
257
+ Returns:
258
+ OpenLineageEmitterService instance.
259
+ """
260
+ return OpenLineageEmitterService(session)
261
+
262
+
263
+ async def get_openlineage_webhook_service(session: SessionDep) -> OpenLineageWebhookService:
264
+ """Get OpenLineage webhook service dependency.
265
+
266
+ Args:
267
+ session: Database session.
268
+
269
+ Returns:
270
+ OpenLineageWebhookService instance.
271
+ """
272
+ return OpenLineageWebhookService(session)
273
+
274
+
171
275
  # Type aliases for service dependencies
172
276
  SourceServiceDep = Annotated[SourceService, Depends(get_source_service)]
173
277
  ValidationServiceDep = Annotated[ValidationService, Depends(get_validation_service)]
@@ -179,3 +283,42 @@ DriftServiceDep = Annotated[DriftService, Depends(get_drift_service)]
179
283
  ScheduleServiceDep = Annotated[ScheduleService, Depends(get_schedule_service)]
180
284
  PIIScanServiceDep = Annotated[PIIScanService, Depends(get_pii_scan_service)]
181
285
  MaskServiceDep = Annotated[MaskService, Depends(get_mask_service)]
286
+ SchemaEvolutionServiceDep = Annotated[
287
+ SchemaEvolutionService, Depends(get_schema_evolution_service)
288
+ ]
289
+ RuleGeneratorServiceDep = Annotated[
290
+ RuleGeneratorService, Depends(get_rule_generator_service)
291
+ ]
292
+ ProfileComparisonServiceDep = Annotated[
293
+ ProfileComparisonService, Depends(get_profile_comparison_service)
294
+ ]
295
+ LineageServiceDep = Annotated[LineageService, Depends(get_lineage_service)]
296
+ AnomalyDetectionServiceDep = Annotated[
297
+ AnomalyDetectionService, Depends(get_anomaly_detection_service)
298
+ ]
299
+ AnomalyExplainerServiceDep = Annotated[
300
+ AnomalyExplainerService, Depends(get_anomaly_explainer_service)
301
+ ]
302
+ OpenLineageEmitterServiceDep = Annotated[
303
+ OpenLineageEmitterService, Depends(get_openlineage_emitter_service)
304
+ ]
305
+ OpenLineageWebhookServiceDep = Annotated[
306
+ OpenLineageWebhookService, Depends(get_openlineage_webhook_service)
307
+ ]
308
+
309
+
310
+ async def get_report_history_service(session: SessionDep) -> ReportHistoryService:
311
+ """Get report history service dependency.
312
+
313
+ Args:
314
+ session: Database session.
315
+
316
+ Returns:
317
+ ReportHistoryService instance.
318
+ """
319
+ return ReportHistoryService(session)
320
+
321
+
322
+ ReportHistoryServiceDep = Annotated[
323
+ ReportHistoryService, Depends(get_report_history_service)
324
+ ]