truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.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 (205) hide show
  1. truthound_dashboard/api/alerts.py +75 -86
  2. truthound_dashboard/api/anomaly.py +7 -13
  3. truthound_dashboard/api/cross_alerts.py +38 -52
  4. truthound_dashboard/api/drift.py +49 -59
  5. truthound_dashboard/api/drift_monitor.py +234 -79
  6. truthound_dashboard/api/enterprise_sampling.py +498 -0
  7. truthound_dashboard/api/history.py +57 -5
  8. truthound_dashboard/api/lineage.py +3 -48
  9. truthound_dashboard/api/maintenance.py +104 -49
  10. truthound_dashboard/api/mask.py +1 -2
  11. truthound_dashboard/api/middleware.py +2 -1
  12. truthound_dashboard/api/model_monitoring.py +435 -311
  13. truthound_dashboard/api/notifications.py +227 -191
  14. truthound_dashboard/api/notifications_advanced.py +21 -20
  15. truthound_dashboard/api/observability.py +586 -0
  16. truthound_dashboard/api/plugins.py +2 -433
  17. truthound_dashboard/api/profile.py +199 -37
  18. truthound_dashboard/api/quality_reporter.py +701 -0
  19. truthound_dashboard/api/reports.py +7 -16
  20. truthound_dashboard/api/router.py +66 -0
  21. truthound_dashboard/api/rule_suggestions.py +5 -5
  22. truthound_dashboard/api/scan.py +17 -19
  23. truthound_dashboard/api/schedules.py +85 -50
  24. truthound_dashboard/api/schema_evolution.py +6 -6
  25. truthound_dashboard/api/schema_watcher.py +667 -0
  26. truthound_dashboard/api/sources.py +98 -27
  27. truthound_dashboard/api/tiering.py +1323 -0
  28. truthound_dashboard/api/triggers.py +14 -11
  29. truthound_dashboard/api/validations.py +12 -11
  30. truthound_dashboard/api/versioning.py +1 -6
  31. truthound_dashboard/core/__init__.py +129 -3
  32. truthound_dashboard/core/actions/__init__.py +62 -0
  33. truthound_dashboard/core/actions/custom.py +426 -0
  34. truthound_dashboard/core/actions/notifications.py +910 -0
  35. truthound_dashboard/core/actions/storage.py +472 -0
  36. truthound_dashboard/core/actions/webhook.py +281 -0
  37. truthound_dashboard/core/anomaly.py +262 -67
  38. truthound_dashboard/core/anomaly_explainer.py +4 -3
  39. truthound_dashboard/core/backends/__init__.py +67 -0
  40. truthound_dashboard/core/backends/base.py +299 -0
  41. truthound_dashboard/core/backends/errors.py +191 -0
  42. truthound_dashboard/core/backends/factory.py +423 -0
  43. truthound_dashboard/core/backends/mock_backend.py +451 -0
  44. truthound_dashboard/core/backends/truthound_backend.py +718 -0
  45. truthound_dashboard/core/checkpoint/__init__.py +87 -0
  46. truthound_dashboard/core/checkpoint/adapters.py +814 -0
  47. truthound_dashboard/core/checkpoint/checkpoint.py +491 -0
  48. truthound_dashboard/core/checkpoint/runner.py +270 -0
  49. truthound_dashboard/core/connections.py +437 -10
  50. truthound_dashboard/core/converters/__init__.py +14 -0
  51. truthound_dashboard/core/converters/truthound.py +620 -0
  52. truthound_dashboard/core/cross_alerts.py +540 -320
  53. truthound_dashboard/core/datasource_factory.py +1672 -0
  54. truthound_dashboard/core/drift_monitor.py +216 -20
  55. truthound_dashboard/core/enterprise_sampling.py +1291 -0
  56. truthound_dashboard/core/interfaces/__init__.py +225 -0
  57. truthound_dashboard/core/interfaces/actions.py +652 -0
  58. truthound_dashboard/core/interfaces/base.py +247 -0
  59. truthound_dashboard/core/interfaces/checkpoint.py +676 -0
  60. truthound_dashboard/core/interfaces/protocols.py +664 -0
  61. truthound_dashboard/core/interfaces/reporters.py +650 -0
  62. truthound_dashboard/core/interfaces/routing.py +646 -0
  63. truthound_dashboard/core/interfaces/triggers.py +619 -0
  64. truthound_dashboard/core/lineage.py +407 -71
  65. truthound_dashboard/core/model_monitoring.py +431 -3
  66. truthound_dashboard/core/notifications/base.py +4 -0
  67. truthound_dashboard/core/notifications/channels.py +501 -1203
  68. truthound_dashboard/core/notifications/deduplication/__init__.py +81 -115
  69. truthound_dashboard/core/notifications/deduplication/service.py +131 -348
  70. truthound_dashboard/core/notifications/dispatcher.py +202 -11
  71. truthound_dashboard/core/notifications/escalation/__init__.py +119 -106
  72. truthound_dashboard/core/notifications/escalation/engine.py +168 -358
  73. truthound_dashboard/core/notifications/routing/__init__.py +88 -128
  74. truthound_dashboard/core/notifications/routing/engine.py +90 -317
  75. truthound_dashboard/core/notifications/stats_aggregator.py +246 -1
  76. truthound_dashboard/core/notifications/throttling/__init__.py +67 -50
  77. truthound_dashboard/core/notifications/throttling/builder.py +117 -255
  78. truthound_dashboard/core/notifications/truthound_adapter.py +842 -0
  79. truthound_dashboard/core/phase5/collaboration.py +1 -1
  80. truthound_dashboard/core/plugins/lifecycle/__init__.py +0 -13
  81. truthound_dashboard/core/quality_reporter.py +1359 -0
  82. truthound_dashboard/core/report_history.py +0 -6
  83. truthound_dashboard/core/reporters/__init__.py +175 -14
  84. truthound_dashboard/core/reporters/adapters.py +943 -0
  85. truthound_dashboard/core/reporters/base.py +0 -3
  86. truthound_dashboard/core/reporters/builtin/__init__.py +18 -0
  87. truthound_dashboard/core/reporters/builtin/csv_reporter.py +111 -0
  88. truthound_dashboard/core/reporters/builtin/html_reporter.py +270 -0
  89. truthound_dashboard/core/reporters/builtin/json_reporter.py +127 -0
  90. truthound_dashboard/core/reporters/compat.py +266 -0
  91. truthound_dashboard/core/reporters/csv_reporter.py +2 -35
  92. truthound_dashboard/core/reporters/factory.py +526 -0
  93. truthound_dashboard/core/reporters/interfaces.py +745 -0
  94. truthound_dashboard/core/reporters/registry.py +1 -10
  95. truthound_dashboard/core/scheduler.py +165 -0
  96. truthound_dashboard/core/schema_evolution.py +3 -3
  97. truthound_dashboard/core/schema_watcher.py +1528 -0
  98. truthound_dashboard/core/services.py +595 -76
  99. truthound_dashboard/core/store_manager.py +810 -0
  100. truthound_dashboard/core/streaming_anomaly.py +169 -4
  101. truthound_dashboard/core/tiering.py +1309 -0
  102. truthound_dashboard/core/triggers/evaluators.py +178 -8
  103. truthound_dashboard/core/truthound_adapter.py +2620 -197
  104. truthound_dashboard/core/unified_alerts.py +23 -20
  105. truthound_dashboard/db/__init__.py +8 -0
  106. truthound_dashboard/db/database.py +8 -2
  107. truthound_dashboard/db/models.py +944 -25
  108. truthound_dashboard/db/repository.py +2 -0
  109. truthound_dashboard/main.py +11 -0
  110. truthound_dashboard/schemas/__init__.py +177 -16
  111. truthound_dashboard/schemas/base.py +44 -23
  112. truthound_dashboard/schemas/collaboration.py +19 -6
  113. truthound_dashboard/schemas/cross_alerts.py +19 -3
  114. truthound_dashboard/schemas/drift.py +61 -55
  115. truthound_dashboard/schemas/drift_monitor.py +67 -23
  116. truthound_dashboard/schemas/enterprise_sampling.py +653 -0
  117. truthound_dashboard/schemas/lineage.py +0 -33
  118. truthound_dashboard/schemas/mask.py +10 -8
  119. truthound_dashboard/schemas/model_monitoring.py +89 -10
  120. truthound_dashboard/schemas/notifications_advanced.py +13 -0
  121. truthound_dashboard/schemas/observability.py +453 -0
  122. truthound_dashboard/schemas/plugins.py +0 -280
  123. truthound_dashboard/schemas/profile.py +154 -247
  124. truthound_dashboard/schemas/quality_reporter.py +403 -0
  125. truthound_dashboard/schemas/reports.py +2 -2
  126. truthound_dashboard/schemas/rule_suggestion.py +8 -1
  127. truthound_dashboard/schemas/scan.py +4 -24
  128. truthound_dashboard/schemas/schedule.py +11 -3
  129. truthound_dashboard/schemas/schema_watcher.py +727 -0
  130. truthound_dashboard/schemas/source.py +17 -2
  131. truthound_dashboard/schemas/tiering.py +822 -0
  132. truthound_dashboard/schemas/triggers.py +16 -0
  133. truthound_dashboard/schemas/unified_alerts.py +7 -0
  134. truthound_dashboard/schemas/validation.py +0 -13
  135. truthound_dashboard/schemas/validators/base.py +41 -21
  136. truthound_dashboard/schemas/validators/business_rule_validators.py +244 -0
  137. truthound_dashboard/schemas/validators/localization_validators.py +273 -0
  138. truthound_dashboard/schemas/validators/ml_feature_validators.py +308 -0
  139. truthound_dashboard/schemas/validators/profiling_validators.py +275 -0
  140. truthound_dashboard/schemas/validators/referential_validators.py +312 -0
  141. truthound_dashboard/schemas/validators/registry.py +93 -8
  142. truthound_dashboard/schemas/validators/timeseries_validators.py +389 -0
  143. truthound_dashboard/schemas/versioning.py +1 -6
  144. truthound_dashboard/static/index.html +2 -2
  145. truthound_dashboard-1.5.0.dist-info/METADATA +309 -0
  146. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/RECORD +149 -148
  147. truthound_dashboard/core/plugins/hooks/__init__.py +0 -63
  148. truthound_dashboard/core/plugins/hooks/decorators.py +0 -367
  149. truthound_dashboard/core/plugins/hooks/manager.py +0 -403
  150. truthound_dashboard/core/plugins/hooks/protocols.py +0 -265
  151. truthound_dashboard/core/plugins/lifecycle/hot_reload.py +0 -584
  152. truthound_dashboard/core/reporters/junit_reporter.py +0 -233
  153. truthound_dashboard/core/reporters/markdown_reporter.py +0 -207
  154. truthound_dashboard/core/reporters/pdf_reporter.py +0 -209
  155. truthound_dashboard/static/assets/_baseUniq-BcrSP13d.js +0 -1
  156. truthound_dashboard/static/assets/arc-DlYjKwIL.js +0 -1
  157. truthound_dashboard/static/assets/architectureDiagram-VXUJARFQ-Bb2drbQM.js +0 -36
  158. truthound_dashboard/static/assets/blockDiagram-VD42YOAC-BlsPG1CH.js +0 -122
  159. truthound_dashboard/static/assets/c4Diagram-YG6GDRKO-B9JdUoaC.js +0 -10
  160. truthound_dashboard/static/assets/channel-Q6mHF1Hd.js +0 -1
  161. truthound_dashboard/static/assets/chunk-4BX2VUAB-DmyoPVuJ.js +0 -1
  162. truthound_dashboard/static/assets/chunk-55IACEB6-Bcz6Siv8.js +0 -1
  163. truthound_dashboard/static/assets/chunk-B4BG7PRW-Br3G5Rum.js +0 -165
  164. truthound_dashboard/static/assets/chunk-DI55MBZ5-DuM9c23u.js +0 -220
  165. truthound_dashboard/static/assets/chunk-FMBD7UC4-DNU-5mvT.js +0 -15
  166. truthound_dashboard/static/assets/chunk-QN33PNHL-Im2yNcmS.js +0 -1
  167. truthound_dashboard/static/assets/chunk-QZHKN3VN-kZr8XFm1.js +0 -1
  168. truthound_dashboard/static/assets/chunk-TZMSLE5B-Q__360q_.js +0 -1
  169. truthound_dashboard/static/assets/classDiagram-2ON5EDUG-vtixxUyK.js +0 -1
  170. truthound_dashboard/static/assets/classDiagram-v2-WZHVMYZB-vtixxUyK.js +0 -1
  171. truthound_dashboard/static/assets/clone-BOt2LwD0.js +0 -1
  172. truthound_dashboard/static/assets/cose-bilkent-S5V4N54A-CBDw6iac.js +0 -1
  173. truthound_dashboard/static/assets/dagre-6UL2VRFP-XdKqmmY9.js +0 -4
  174. truthound_dashboard/static/assets/diagram-PSM6KHXK-DAZ8nx9V.js +0 -24
  175. truthound_dashboard/static/assets/diagram-QEK2KX5R-BRvDTbGD.js +0 -43
  176. truthound_dashboard/static/assets/diagram-S2PKOQOG-bQcczUkl.js +0 -24
  177. truthound_dashboard/static/assets/erDiagram-Q2GNP2WA-DPje7VMN.js +0 -60
  178. truthound_dashboard/static/assets/flowDiagram-NV44I4VS-B7BVtFVS.js +0 -162
  179. truthound_dashboard/static/assets/ganttDiagram-JELNMOA3-D6WKSS7U.js +0 -267
  180. truthound_dashboard/static/assets/gitGraphDiagram-NY62KEGX-D3vtVd3y.js +0 -65
  181. truthound_dashboard/static/assets/graph-BKgNKZVp.js +0 -1
  182. truthound_dashboard/static/assets/index-C6JSrkHo.css +0 -1
  183. truthound_dashboard/static/assets/index-DkU82VsU.js +0 -1800
  184. truthound_dashboard/static/assets/infoDiagram-WHAUD3N6-DnNCT429.js +0 -2
  185. truthound_dashboard/static/assets/journeyDiagram-XKPGCS4Q-DGiMozqS.js +0 -139
  186. truthound_dashboard/static/assets/kanban-definition-3W4ZIXB7-BV2gUgli.js +0 -89
  187. truthound_dashboard/static/assets/katex-Cu_Erd72.js +0 -261
  188. truthound_dashboard/static/assets/layout-DI2MfQ5G.js +0 -1
  189. truthound_dashboard/static/assets/min-DYdgXVcT.js +0 -1
  190. truthound_dashboard/static/assets/mindmap-definition-VGOIOE7T-C7x4ruxz.js +0 -68
  191. truthound_dashboard/static/assets/pieDiagram-ADFJNKIX-CAJaAB9f.js +0 -30
  192. truthound_dashboard/static/assets/quadrantDiagram-AYHSOK5B-DeqwDI46.js +0 -7
  193. truthound_dashboard/static/assets/requirementDiagram-UZGBJVZJ-e3XDpZIM.js +0 -64
  194. truthound_dashboard/static/assets/sankeyDiagram-TZEHDZUN-CNnAv5Ux.js +0 -10
  195. truthound_dashboard/static/assets/sequenceDiagram-WL72ISMW-Dsne-Of3.js +0 -145
  196. truthound_dashboard/static/assets/stateDiagram-FKZM4ZOC-Ee0sQXyb.js +0 -1
  197. truthound_dashboard/static/assets/stateDiagram-v2-4FDKWEC3-B26KqW_W.js +0 -1
  198. truthound_dashboard/static/assets/timeline-definition-IT6M3QCI-DZYi2yl3.js +0 -61
  199. truthound_dashboard/static/assets/treemap-KMMF4GRG-CY3f8In2.js +0 -128
  200. truthound_dashboard/static/assets/unmerged_dictionaries-Dd7xcPWG.js +0 -1
  201. truthound_dashboard/static/assets/xychartDiagram-PRI3JC2R-CS7fydZZ.js +0 -7
  202. truthound_dashboard-1.4.4.dist-info/METADATA +0 -507
  203. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/WHEEL +0 -0
  204. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/entry_points.txt +0 -0
  205. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,12 +1,20 @@
1
1
  """Trigger evaluator implementations.
2
2
 
3
- Provides concrete implementations for all trigger types:
3
+ Provides concrete implementations for all trigger types using truthound.checkpoint.triggers
4
+ when available, with fallback to APScheduler-based implementation:
4
5
  - CronTrigger: Cron expression based scheduling
5
6
  - IntervalTrigger: Fixed time interval scheduling
6
- - DataChangeTrigger: Profile-based change detection
7
+ - DataChangeTrigger: Profile-based change detection (FileWatchTrigger in truthound)
7
8
  - CompositeTrigger: Combine multiple triggers
8
9
  - EventTrigger: Respond to system events
9
10
  - ManualTrigger: API-only execution
11
+ - WebhookTrigger: External webhook triggers
12
+
13
+ truthound.checkpoint.triggers provides:
14
+ - ScheduleTrigger: Time-based scheduling
15
+ - CronTrigger: Cron expression scheduling
16
+ - EventTrigger: Event-driven triggers
17
+ - FileWatchTrigger: File/data change monitoring
10
18
  """
11
19
 
12
20
  from __future__ import annotations
@@ -27,11 +35,28 @@ from .base import (
27
35
 
28
36
  logger = logging.getLogger(__name__)
29
37
 
38
+ # Try to import truthound triggers
39
+ _TRUTHOUND_TRIGGERS_AVAILABLE = False
40
+ try:
41
+ from truthound.checkpoint.triggers import (
42
+ ScheduleTrigger as TruthoundScheduleTrigger,
43
+ CronTrigger as TruthoundCronTrigger,
44
+ EventTrigger as TruthoundEventTrigger,
45
+ FileWatchTrigger as TruthoundFileWatchTrigger,
46
+ )
47
+ _TRUTHOUND_TRIGGERS_AVAILABLE = True
48
+ logger.info("truthound.checkpoint.triggers available")
49
+ except ImportError:
50
+ logger.debug("truthound.checkpoint.triggers not available, using APScheduler fallback")
51
+
30
52
 
31
53
  @TriggerRegistry.register("cron")
32
54
  class CronTrigger(BaseTrigger):
33
55
  """Cron expression based trigger.
34
56
 
57
+ Uses truthound.checkpoint.triggers.CronTrigger when available,
58
+ falls back to APScheduler's CronTrigger.
59
+
35
60
  Uses standard cron format: minute hour day month weekday
36
61
 
37
62
  Config:
@@ -39,13 +64,35 @@ class CronTrigger(BaseTrigger):
39
64
  timezone: Optional timezone (default: UTC)
40
65
  """
41
66
 
67
+ def __init__(self, config: dict[str, Any]) -> None:
68
+ """Initialize cron trigger."""
69
+ super().__init__(config)
70
+ self._truthound_trigger = None
71
+ self._init_truthound_trigger()
72
+
73
+ def _init_truthound_trigger(self) -> None:
74
+ """Initialize truthound trigger if available."""
75
+ if _TRUTHOUND_TRIGGERS_AVAILABLE:
76
+ try:
77
+ expression = self.config.get("expression", "0 * * * *")
78
+ self._truthound_trigger = TruthoundCronTrigger(expression=expression)
79
+ logger.debug(f"Using truthound CronTrigger: {expression}")
80
+ except Exception as e:
81
+ logger.warning(f"Failed to create truthound CronTrigger: {e}")
82
+ self._truthound_trigger = None
83
+
42
84
  def _validate_config(self) -> None:
43
85
  """Validate cron configuration."""
44
86
  expression = self.config.get("expression")
45
87
  if not expression:
46
88
  raise ValueError("Cron trigger requires 'expression' field")
47
89
 
48
- # Validate by attempting to parse
90
+ # Validate using truthound or APScheduler
91
+ if self._truthound_trigger is not None:
92
+ # truthound already validated in _init_truthound_trigger
93
+ return
94
+
95
+ # Fallback validation with APScheduler
49
96
  try:
50
97
  APCronTrigger.from_crontab(expression)
51
98
  except Exception as e:
@@ -54,10 +101,37 @@ class CronTrigger(BaseTrigger):
54
101
  async def evaluate(self, context: TriggerContext) -> TriggerEvaluation:
55
102
  """Evaluate if cron trigger should fire.
56
103
 
57
- For cron triggers, we check if we're past the scheduled time
58
- since the last run.
104
+ Uses truthound trigger evaluation when available.
59
105
  """
60
106
  expression = self.config.get("expression")
107
+
108
+ # Try truthound evaluation first
109
+ if self._truthound_trigger is not None:
110
+ try:
111
+ should_fire = self._truthound_trigger.should_fire(
112
+ current_time=context.current_time,
113
+ last_run_at=context.last_run_at,
114
+ )
115
+ next_fire = self._truthound_trigger.get_next_fire_time(context.current_time)
116
+
117
+ return TriggerEvaluation(
118
+ should_trigger=should_fire,
119
+ reason=(
120
+ f"Scheduled time reached (truthound)"
121
+ if should_fire
122
+ else f"Waiting for scheduled time ({next_fire.isoformat() if next_fire else 'unknown'})"
123
+ ),
124
+ next_evaluation_at=next_fire if not should_fire else None,
125
+ details={
126
+ "expression": expression,
127
+ "next_fire_time": next_fire.isoformat() if next_fire else None,
128
+ "provider": "truthound",
129
+ },
130
+ )
131
+ except Exception as e:
132
+ logger.warning(f"truthound CronTrigger evaluation failed: {e}")
133
+
134
+ # Fallback to APScheduler
61
135
  trigger = APCronTrigger.from_crontab(expression)
62
136
 
63
137
  # Get next fire time from last run (or from epoch if never run)
@@ -83,6 +157,7 @@ class CronTrigger(BaseTrigger):
83
157
  details={
84
158
  "expression": expression,
85
159
  "next_fire_time": next_fire.isoformat(),
160
+ "provider": "apscheduler",
86
161
  },
87
162
  )
88
163
 
@@ -90,6 +165,14 @@ class CronTrigger(BaseTrigger):
90
165
  self, context: TriggerContext
91
166
  ) -> datetime | None:
92
167
  """Get next cron fire time."""
168
+ # Try truthound first
169
+ if self._truthound_trigger is not None:
170
+ try:
171
+ return self._truthound_trigger.get_next_fire_time(context.current_time)
172
+ except Exception:
173
+ pass
174
+
175
+ # Fallback to APScheduler
93
176
  expression = self.config.get("expression")
94
177
  try:
95
178
  trigger = APCronTrigger.from_crontab(expression)
@@ -189,6 +272,9 @@ class IntervalTrigger(BaseTrigger):
189
272
  class DataChangeTrigger(BaseTrigger):
190
273
  """Data change detection trigger.
191
274
 
275
+ Uses truthound.checkpoint.triggers.FileWatchTrigger when available
276
+ for enhanced file/data monitoring with change detection.
277
+
192
278
  Triggers when profile metrics change by more than a threshold.
193
279
 
194
280
  Config:
@@ -199,6 +285,25 @@ class DataChangeTrigger(BaseTrigger):
199
285
 
200
286
  DEFAULT_METRICS = ["row_count", "null_percentage", "distinct_count"]
201
287
 
288
+ def __init__(self, config: dict[str, Any]) -> None:
289
+ """Initialize data change trigger."""
290
+ super().__init__(config)
291
+ self._truthound_trigger = None
292
+ self._init_truthound_trigger()
293
+
294
+ def _init_truthound_trigger(self) -> None:
295
+ """Initialize truthound FileWatchTrigger if available."""
296
+ if _TRUTHOUND_TRIGGERS_AVAILABLE:
297
+ try:
298
+ self._truthound_trigger = TruthoundFileWatchTrigger(
299
+ change_threshold=self.config.get("change_threshold", 0.05),
300
+ metrics=self.config.get("metrics", self.DEFAULT_METRICS),
301
+ )
302
+ logger.debug("Using truthound FileWatchTrigger for data change detection")
303
+ except Exception as e:
304
+ logger.warning(f"Failed to create truthound FileWatchTrigger: {e}")
305
+ self._truthound_trigger = None
306
+
202
307
  def _validate_config(self) -> None:
203
308
  """Validate data change configuration."""
204
309
  threshold = self.config.get("change_threshold", 0.05)
@@ -208,12 +313,34 @@ class DataChangeTrigger(BaseTrigger):
208
313
  async def evaluate(self, context: TriggerContext) -> TriggerEvaluation:
209
314
  """Evaluate if data has changed enough to trigger.
210
315
 
316
+ Uses truthound FileWatchTrigger when available for enhanced detection.
211
317
  Compares current profile against baseline and checks if
212
318
  any monitored metrics have changed beyond the threshold.
213
319
  """
214
320
  threshold = self.config.get("change_threshold", 0.05)
215
321
  metrics = self.config.get("metrics", self.DEFAULT_METRICS)
216
322
 
323
+ # Try truthound evaluation first
324
+ if self._truthound_trigger is not None and context.profile_data and context.baseline_profile:
325
+ try:
326
+ result = self._truthound_trigger.evaluate_change(
327
+ current_profile=context.profile_data,
328
+ baseline_profile=context.baseline_profile,
329
+ )
330
+
331
+ return TriggerEvaluation(
332
+ should_trigger=result.should_trigger,
333
+ reason=result.reason,
334
+ details={
335
+ **result.details,
336
+ "provider": "truthound",
337
+ },
338
+ confidence=result.confidence,
339
+ )
340
+ except Exception as e:
341
+ logger.warning(f"truthound FileWatchTrigger evaluation failed: {e}")
342
+
343
+ # Fallback to manual implementation
217
344
  # Need both profiles to compare
218
345
  if context.profile_data is None:
219
346
  return TriggerEvaluation(
@@ -272,6 +399,7 @@ class DataChangeTrigger(BaseTrigger):
272
399
  "max_change": max_change,
273
400
  "changes": changes,
274
401
  "triggered_metrics": triggered_metrics,
402
+ "provider": "manual",
275
403
  },
276
404
  confidence=max_change if should_trigger else 1.0 - max_change,
277
405
  )
@@ -384,6 +512,9 @@ class CompositeTrigger(BaseTrigger):
384
512
  class EventTrigger(BaseTrigger):
385
513
  """Event-based trigger.
386
514
 
515
+ Uses truthound.checkpoint.triggers.EventTrigger when available
516
+ for enhanced event matching and filtering.
517
+
387
518
  Triggers in response to specific system events.
388
519
 
389
520
  Config:
@@ -401,6 +532,25 @@ class EventTrigger(BaseTrigger):
401
532
  "source_updated",
402
533
  }
403
534
 
535
+ def __init__(self, config: dict[str, Any]) -> None:
536
+ """Initialize event trigger."""
537
+ super().__init__(config)
538
+ self._truthound_trigger = None
539
+ self._init_truthound_trigger()
540
+
541
+ def _init_truthound_trigger(self) -> None:
542
+ """Initialize truthound EventTrigger if available."""
543
+ if _TRUTHOUND_TRIGGERS_AVAILABLE:
544
+ try:
545
+ self._truthound_trigger = TruthoundEventTrigger(
546
+ event_types=self.config.get("event_types", []),
547
+ source_filter=self.config.get("source_filter"),
548
+ )
549
+ logger.debug("Using truthound EventTrigger")
550
+ except Exception as e:
551
+ logger.warning(f"Failed to create truthound EventTrigger: {e}")
552
+ self._truthound_trigger = None
553
+
404
554
  def _validate_config(self) -> None:
405
555
  """Validate event configuration."""
406
556
  event_types = self.config.get("event_types", [])
@@ -412,7 +562,10 @@ class EventTrigger(BaseTrigger):
412
562
  raise ValueError(f"Invalid event types: {invalid_events}")
413
563
 
414
564
  async def evaluate(self, context: TriggerContext) -> TriggerEvaluation:
415
- """Evaluate if event matches configured types."""
565
+ """Evaluate if event matches configured types.
566
+
567
+ Uses truthound EventTrigger when available.
568
+ """
416
569
  event_types = set(self.config.get("event_types", []))
417
570
  source_filter = self.config.get("source_filter")
418
571
 
@@ -423,6 +576,22 @@ class EventTrigger(BaseTrigger):
423
576
  reason="No event data in context",
424
577
  )
425
578
 
579
+ # Try truthound evaluation first
580
+ if self._truthound_trigger is not None:
581
+ try:
582
+ result = self._truthound_trigger.evaluate(context.event_data)
583
+ return TriggerEvaluation(
584
+ should_trigger=result.should_trigger,
585
+ reason=result.reason,
586
+ details={
587
+ **result.details,
588
+ "provider": "truthound",
589
+ },
590
+ )
591
+ except Exception as e:
592
+ logger.warning(f"truthound EventTrigger evaluation failed: {e}")
593
+
594
+ # Fallback to manual implementation
426
595
  event_type = context.event_data.get("type")
427
596
  event_source = context.event_data.get("source_id")
428
597
 
@@ -431,7 +600,7 @@ class EventTrigger(BaseTrigger):
431
600
  return TriggerEvaluation(
432
601
  should_trigger=False,
433
602
  reason=f"Event type '{event_type}' not in configured types",
434
- details={"event_type": event_type, "configured_types": list(event_types)},
603
+ details={"event_type": event_type, "configured_types": list(event_types), "provider": "manual"},
435
604
  )
436
605
 
437
606
  # Check source filter if configured
@@ -439,7 +608,7 @@ class EventTrigger(BaseTrigger):
439
608
  return TriggerEvaluation(
440
609
  should_trigger=False,
441
610
  reason=f"Event source '{event_source}' not in filter",
442
- details={"event_source": event_source, "filter": source_filter},
611
+ details={"event_source": event_source, "filter": source_filter, "provider": "manual"},
443
612
  )
444
613
 
445
614
  return TriggerEvaluation(
@@ -449,6 +618,7 @@ class EventTrigger(BaseTrigger):
449
618
  "event_type": event_type,
450
619
  "event_source": event_source,
451
620
  "event_data": context.event_data,
621
+ "provider": "manual",
452
622
  },
453
623
  )
454
624