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
@@ -3,13 +3,19 @@
3
3
  The dispatcher coordinates between events, rules, and channels to
4
4
  deliver notifications based on configured triggers.
5
5
 
6
- Architecture:
7
- Event -> Dispatcher -> Rules -> Channels -> Delivery
6
+ Architecture (with truthound integration):
7
+ Event -> Dispatcher -> Truthound Adapter (Routing/Dedup/Throttle) -> Channels -> Delivery -> Escalation
8
+
9
+ The dispatcher now integrates with truthound library for:
10
+ - Routing: ActionRouter with 11+ rule types
11
+ - Deduplication: NotificationDeduplicator with time windows
12
+ - Throttling: NotificationThrottler with rate limits
13
+ - Escalation: EscalationEngine with multi-level policies
8
14
 
9
15
  Example:
10
16
  dispatcher = get_dispatcher()
11
17
 
12
- # Notify about validation failure
18
+ # Notify about validation failure (with truthound processing)
13
19
  await dispatcher.notify_validation_failed(
14
20
  source_id="source-123",
15
21
  source_name="My Source",
@@ -24,7 +30,7 @@ from __future__ import annotations
24
30
 
25
31
  import logging
26
32
  from collections.abc import Sequence
27
- from typing import Any
33
+ from typing import TYPE_CHECKING, Any
28
34
 
29
35
  from sqlalchemy import select
30
36
  from sqlalchemy.ext.asyncio import AsyncSession
@@ -50,6 +56,9 @@ from .events import (
50
56
  ValidationFailedEvent,
51
57
  )
52
58
 
59
+ if TYPE_CHECKING:
60
+ from .truthound_adapter import TruthoundNotificationAdapter
61
+
53
62
  logger = logging.getLogger(__name__)
54
63
 
55
64
 
@@ -58,10 +67,12 @@ class NotificationDispatcher:
58
67
 
59
68
  The dispatcher:
60
69
  1. Receives notification events
61
- 2. Matches events against active rules
62
- 3. Resolves target channels from matching rules
63
- 4. Delivers notifications through channels
64
- 5. Logs delivery results
70
+ 2. Routes through truthound ActionRouter (if enabled)
71
+ 3. Checks deduplication via truthound NotificationDeduplicator
72
+ 4. Checks throttling via truthound NotificationThrottler
73
+ 5. Delivers notifications through channels
74
+ 6. Logs delivery results
75
+ 7. Triggers escalation via truthound EscalationEngine (for critical events)
65
76
 
66
77
  Usage:
67
78
  dispatcher = NotificationDispatcher(session)
@@ -69,17 +80,37 @@ class NotificationDispatcher:
69
80
  # Send test notification
70
81
  results = await dispatcher.test_channel(channel_id)
71
82
 
72
- # Notify about events
83
+ # Notify about events (with truthound processing)
73
84
  await dispatcher.notify_validation_failed(...)
85
+
86
+ # Disable truthound for direct sending
87
+ dispatcher = NotificationDispatcher(session, use_truthound=False)
74
88
  """
75
89
 
76
- def __init__(self, session: AsyncSession) -> None:
90
+ def __init__(
91
+ self,
92
+ session: AsyncSession,
93
+ use_truthound: bool = True,
94
+ ) -> None:
77
95
  """Initialize the dispatcher.
78
96
 
79
97
  Args:
80
98
  session: Database session for accessing rules and channels.
99
+ use_truthound: Whether to use truthound library for routing,
100
+ deduplication, throttling, and escalation. Default True.
81
101
  """
82
102
  self.session = session
103
+ self.use_truthound = use_truthound
104
+ self._truthound_adapter: TruthoundNotificationAdapter | None = None
105
+
106
+ async def _get_truthound_adapter(self) -> TruthoundNotificationAdapter:
107
+ """Get or create the truthound adapter lazily."""
108
+ if self._truthound_adapter is None:
109
+ from .truthound_adapter import TruthoundNotificationAdapter
110
+
111
+ self._truthound_adapter = TruthoundNotificationAdapter(self.session)
112
+ await self._truthound_adapter.initialize()
113
+ return self._truthound_adapter
83
114
 
84
115
  async def dispatch(
85
116
  self,
@@ -91,7 +122,15 @@ class NotificationDispatcher:
91
122
  """Dispatch a notification event to matching channels.
92
123
 
93
124
  If channel_ids is provided, sends directly to those channels.
94
- Otherwise, matches event against rules to find target channels.
125
+ Otherwise, matches event against rules (or truthound routes) to find
126
+ target channels.
127
+
128
+ When truthound is enabled:
129
+ 1. Routes through ActionRouter to get matched channels
130
+ 2. Checks deduplication to suppress duplicate notifications
131
+ 3. Checks throttling to enforce rate limits
132
+ 4. Sends to channels that pass all checks
133
+ 5. Triggers escalation for high severity unacknowledged events
95
134
 
96
135
  Args:
97
136
  event: The notification event to dispatch.
@@ -101,6 +140,18 @@ class NotificationDispatcher:
101
140
  Returns:
102
141
  List of delivery results for each channel.
103
142
  """
143
+ if self.use_truthound and not channel_ids:
144
+ return await self._dispatch_via_truthound(event, rule_id)
145
+
146
+ return await self._dispatch_legacy(event, channel_ids, rule_id)
147
+
148
+ async def _dispatch_legacy(
149
+ self,
150
+ event: NotificationEvent,
151
+ channel_ids: list[str] | None = None,
152
+ rule_id: str | None = None,
153
+ ) -> list[NotificationResult]:
154
+ """Legacy dispatch without truthound integration."""
104
155
  # Get target channels
105
156
  if channel_ids:
106
157
  channels = await self._get_channels_by_ids(channel_ids)
@@ -119,6 +170,146 @@ class NotificationDispatcher:
119
170
 
120
171
  return results
121
172
 
173
+ async def _dispatch_via_truthound(
174
+ self,
175
+ event: NotificationEvent,
176
+ rule_id: str | None = None,
177
+ ) -> list[NotificationResult]:
178
+ """Dispatch using truthound library for routing, dedup, throttle, escalation.
179
+
180
+ This method integrates with truthound's checkpoint modules:
181
+ - ActionRouter: Matches events to channels via configurable rules
182
+ - NotificationDeduplicator: Suppresses duplicate notifications
183
+ - NotificationThrottler: Enforces rate limits per channel
184
+ - EscalationEngine: Escalates unacknowledged critical events
185
+ """
186
+ adapter = await self._get_truthound_adapter()
187
+
188
+ # Step 1: Route event to channels via truthound ActionRouter
189
+ matched_channel_ids = await adapter.match_routes(event)
190
+
191
+ # Fall back to legacy rule matching if no routes configured
192
+ if not matched_channel_ids:
193
+ channels = await self._get_channels_for_event(event)
194
+ matched_channel_ids = [ch.id for ch in channels]
195
+
196
+ if not matched_channel_ids:
197
+ logger.debug(f"No channels matched for event: {event.event_type}")
198
+ return []
199
+
200
+ # Get channel models
201
+ channels = await self._get_channels_by_ids(matched_channel_ids)
202
+ if not channels:
203
+ return []
204
+
205
+ results: list[NotificationResult] = []
206
+
207
+ for channel_model in channels:
208
+ channel_id = channel_model.id
209
+
210
+ # Step 2: Check deduplication via truthound NotificationDeduplicator
211
+ if await adapter.is_duplicate(event, channel_id):
212
+ logger.debug(
213
+ f"Notification deduplicated for channel {channel_id}: {event.event_type}"
214
+ )
215
+ results.append(
216
+ NotificationResult(
217
+ success=True,
218
+ channel_id=channel_id,
219
+ channel_type=channel_model.type,
220
+ message="",
221
+ error=None,
222
+ suppressed=True,
223
+ suppression_reason="duplicate",
224
+ )
225
+ )
226
+ continue
227
+
228
+ # Step 3: Check throttling via truthound NotificationThrottler
229
+ if await adapter.is_throttled(channel_id):
230
+ logger.debug(
231
+ f"Notification throttled for channel {channel_id}: {event.event_type}"
232
+ )
233
+ results.append(
234
+ NotificationResult(
235
+ success=True,
236
+ channel_id=channel_id,
237
+ channel_type=channel_model.type,
238
+ message="",
239
+ error=None,
240
+ suppressed=True,
241
+ suppression_reason="throttled",
242
+ )
243
+ )
244
+ continue
245
+
246
+ # Step 4: Send notification
247
+ result = await self._send_to_channel(channel_model, event, rule_id)
248
+ results.append(result)
249
+
250
+ # Step 5: Mark as sent for deduplication tracking
251
+ if result.success:
252
+ await adapter.mark_notification_sent(event, channel_id)
253
+
254
+ # Step 6: Check escalation for high severity events
255
+ await self._check_escalation(event, adapter)
256
+
257
+ return results
258
+
259
+ async def _check_escalation(
260
+ self,
261
+ event: NotificationEvent,
262
+ adapter: TruthoundNotificationAdapter,
263
+ ) -> None:
264
+ """Check and trigger escalation for high severity events.
265
+
266
+ Escalation is triggered for:
267
+ - Critical validation failures
268
+ - High severity drift detection
269
+ - Schedule failures
270
+
271
+ The escalation engine will notify secondary/tertiary channels
272
+ if the primary notification is not acknowledged within timeout.
273
+ """
274
+ severity = self._get_event_severity(event)
275
+
276
+ if severity in ("critical", "high"):
277
+ try:
278
+ escalation_id = await adapter.trigger_escalation(
279
+ event,
280
+ policy_name=f"{severity}_alert",
281
+ )
282
+ if escalation_id:
283
+ logger.info(
284
+ f"Escalation triggered for {event.event_type}: {escalation_id}"
285
+ )
286
+ except Exception as e:
287
+ logger.warning(f"Failed to trigger escalation: {e}")
288
+
289
+ def _get_event_severity(self, event: NotificationEvent) -> str:
290
+ """Determine severity level of an event."""
291
+ if isinstance(event, ValidationFailedEvent):
292
+ if event.has_critical:
293
+ return "critical"
294
+ if event.has_high:
295
+ return "high"
296
+ return "medium"
297
+
298
+ if isinstance(event, DriftDetectedEvent):
299
+ if event.has_high_drift:
300
+ return "high"
301
+ return "medium"
302
+
303
+ if isinstance(event, ScheduleFailedEvent):
304
+ return "high"
305
+
306
+ if isinstance(event, SchemaChangedEvent):
307
+ if event.has_breaking_changes:
308
+ return "high"
309
+ return "low"
310
+
311
+ return "low"
312
+
122
313
  async def _get_channels_by_ids(
123
314
  self, channel_ids: list[str]
124
315
  ) -> Sequence[NotificationChannel]:
@@ -1,149 +1,162 @@
1
- """Escalation engine for notification management.
1
+ """Escalation engine using truthound.checkpoint.escalation.
2
2
 
3
3
  This module provides a multi-level escalation system for managing
4
- alerts that require attention at different organizational levels.
4
+ alerts using truthound's escalation infrastructure.
5
5
 
6
- Features:
7
- - Multi-level escalation policies
8
- - State machine for incident tracking
9
- - Configurable delay between escalation levels
10
- - Support for user, group, and on-call targets
11
- - Auto-resolution on success
6
+ Key Components from truthound.checkpoint.escalation:
7
+ - EscalationEngine: Main escalation engine
8
+ - EscalationEngineConfig: Engine configuration
9
+ - EscalationPolicy: Policy definition
10
+ - EscalationLevel: Level definition
11
+ - EscalationTarget: Target definition
12
+ - EscalationRecord: Escalation state record
12
13
 
13
- State Machine:
14
- PENDING -> TRIGGERED -> ESCALATED -> RESOLVED
15
- | ^
16
- v |
17
- ACKNOWLEDGED ------+
14
+ Target Types from truthound:
15
+ - USER: Individual user
16
+ - TEAM: Team
17
+ - CHANNEL: Channel (Slack, etc.)
18
+ - SCHEDULE: On-call schedule
19
+ - WEBHOOK: Webhook URL
20
+ - EMAIL: Email
21
+ - PHONE: Phone
22
+ - CUSTOM: Custom
23
+
24
+ Escalation States from truthound:
25
+ - PENDING: Initial state, waiting to start
26
+ - ACTIVE: Currently notifying at level
27
+ - ESCALATING: Escalating to next level
28
+ - ACKNOWLEDGED: Responder acknowledged
29
+ - RESOLVED: Issue resolved
30
+ - CANCELLED: Manually cancelled
31
+ - TIMED_OUT: Max escalation reached
32
+ - FAILED: System error
33
+
34
+ Storage Backends from truthound:
35
+ - InMemoryEscalationStore: Single-process storage
36
+ - RedisEscalationStore: Distributed storage
37
+ - SQLiteEscalationStore: Persistent storage
18
38
 
19
39
  Example:
20
- from truthound_dashboard.core.notifications.escalation import (
40
+ from truthound.checkpoint.escalation import (
21
41
  EscalationEngine,
42
+ EscalationEngineConfig,
22
43
  EscalationPolicy,
23
44
  EscalationLevel,
24
45
  EscalationTarget,
25
- TargetType,
46
+ EscalationTrigger,
26
47
  )
27
48
 
49
+ # Define policy
28
50
  policy = EscalationPolicy(
29
51
  name="critical_alerts",
30
52
  levels=[
31
53
  EscalationLevel(
32
54
  level=1,
33
55
  delay_minutes=0,
34
- targets=[
35
- EscalationTarget(type=TargetType.USER, identifier="team-lead", channel="slack")
36
- ],
56
+ targets=[EscalationTarget.user("team-lead", "Team Lead")],
57
+ repeat_count=2,
58
+ repeat_interval_minutes=5,
37
59
  ),
38
60
  EscalationLevel(
39
61
  level=2,
40
62
  delay_minutes=15,
41
- targets=[
42
- EscalationTarget(type=TargetType.GROUP, identifier="managers", channel="pagerduty")
43
- ],
63
+ targets=[EscalationTarget.user("manager", "Manager")],
44
64
  ),
45
65
  ],
66
+ triggers=[EscalationTrigger.UNACKNOWLEDGED],
67
+ severity_filter=["critical", "high"],
46
68
  )
47
69
 
48
- engine = EscalationEngine(policy=policy)
49
- await engine.trigger("incident-123", context={"severity": "critical"})
70
+ # Create engine
71
+ config = EscalationEngineConfig(store_type="memory")
72
+ engine = EscalationEngine(config)
73
+ engine.register_policy(policy)
74
+
75
+ # Trigger escalation
76
+ await engine.start()
77
+ result = await engine.trigger(
78
+ incident_id="incident-123",
79
+ context={"severity": "critical"},
80
+ policy_name="critical_alerts",
81
+ )
50
82
  """
51
83
 
52
- from .engine import EscalationEngine, EscalationEngineConfig
53
- from .models import (
54
- EscalationEvent,
55
- EscalationIncident,
56
- EscalationLevel,
84
+ # Re-export from truthound.checkpoint.escalation
85
+ from truthound.checkpoint.escalation import (
86
+ EscalationEngine,
87
+ EscalationEngineConfig,
57
88
  EscalationPolicy,
58
- EscalationState,
89
+ EscalationLevel,
59
90
  EscalationTarget,
60
- StateTransition,
91
+ EscalationRecord,
92
+ EscalationTrigger,
93
+ EscalationState,
61
94
  TargetType,
95
+ EscalationPolicyManager,
96
+ EscalationPolicyConfig,
62
97
  )
63
- from .backends import (
64
- BackendType,
65
- InMemorySchedulerBackend,
66
- JobData,
67
- JobExecutionResult,
68
- JobState,
69
- MisfirePolicy,
70
- SchedulerBackend,
71
- SchedulerBackendConfig,
72
- SQLAlchemySchedulerBackend,
73
- create_scheduler_backend,
98
+
99
+ # Storage backends
100
+ from truthound.checkpoint.escalation import (
101
+ InMemoryEscalationStore,
102
+ create_store,
74
103
  )
75
- from .scheduler import (
76
- DefaultEscalationHandler,
77
- EscalationHandler,
78
- EscalationResult,
79
- EscalationSchedulerConfig,
80
- EscalationSchedulerService,
81
- EscalationStrategy,
82
- ImmediateEscalationStrategy,
83
- LoggingEscalationHandler,
84
- TimeBasedEscalationStrategy,
85
- get_escalation_scheduler,
86
- reset_escalation_scheduler,
87
- start_escalation_scheduler,
88
- stop_escalation_scheduler,
104
+
105
+ # Redis/SQLite stores (optional)
106
+ try:
107
+ from truthound.checkpoint.escalation import RedisEscalationStore
108
+ REDIS_AVAILABLE = True
109
+ except ImportError:
110
+ RedisEscalationStore = None # type: ignore
111
+ REDIS_AVAILABLE = False
112
+
113
+ try:
114
+ from truthound.checkpoint.escalation import SQLiteEscalationStore
115
+ SQLITE_AVAILABLE = True
116
+ except ImportError:
117
+ SQLiteEscalationStore = None # type: ignore
118
+ SQLITE_AVAILABLE = False
119
+
120
+ # Routing integration
121
+ from truthound.checkpoint.escalation import (
122
+ EscalationRule,
123
+ EscalationRuleConfig,
124
+ EscalationAction,
125
+ create_escalation_route,
89
126
  )
90
- from .state_machine import EscalationStateMachine
91
- from .stores import (
92
- BaseEscalationStore,
93
- EscalationMetrics,
94
- EscalationStoreType,
95
- InMemoryEscalationStore,
96
- RedisEscalationStore,
97
- SQLiteEscalationStore,
98
- create_escalation_store,
127
+
128
+ # Dashboard-specific adapters
129
+ from .engine import (
130
+ DashboardEscalationService,
131
+ create_policy_from_db,
99
132
  )
100
133
 
101
134
  __all__ = [
102
- # Models
135
+ # truthound core
136
+ "EscalationEngine",
137
+ "EscalationEngineConfig",
138
+ "EscalationPolicy",
139
+ "EscalationLevel",
140
+ "EscalationTarget",
141
+ "EscalationRecord",
142
+ "EscalationTrigger",
103
143
  "EscalationState",
104
144
  "TargetType",
105
- "EscalationTarget",
106
- "EscalationLevel",
107
- "EscalationPolicy",
108
- "EscalationIncident",
109
- "EscalationEvent",
110
- "StateTransition",
111
- # State Machine
112
- "EscalationStateMachine",
113
- # Stores
114
- "BaseEscalationStore",
115
- "EscalationMetrics",
116
- "EscalationStoreType",
145
+ "EscalationPolicyManager",
146
+ "EscalationPolicyConfig",
147
+ # Storage
117
148
  "InMemoryEscalationStore",
149
+ "create_store",
118
150
  "RedisEscalationStore",
119
151
  "SQLiteEscalationStore",
120
- "create_escalation_store",
121
- # Engine
122
- "EscalationEngine",
123
- "EscalationEngineConfig",
124
- # Scheduler Backends
125
- "BackendType",
126
- "JobState",
127
- "MisfirePolicy",
128
- "SchedulerBackendConfig",
129
- "JobData",
130
- "JobExecutionResult",
131
- "SchedulerBackend",
132
- "InMemorySchedulerBackend",
133
- "SQLAlchemySchedulerBackend",
134
- "create_scheduler_backend",
135
- # Scheduler
136
- "EscalationSchedulerService",
137
- "EscalationSchedulerConfig",
138
- "EscalationHandler",
139
- "EscalationResult",
140
- "EscalationStrategy",
141
- "DefaultEscalationHandler",
142
- "LoggingEscalationHandler",
143
- "TimeBasedEscalationStrategy",
144
- "ImmediateEscalationStrategy",
145
- "get_escalation_scheduler",
146
- "reset_escalation_scheduler",
147
- "start_escalation_scheduler",
148
- "stop_escalation_scheduler",
152
+ "REDIS_AVAILABLE",
153
+ "SQLITE_AVAILABLE",
154
+ # Routing integration
155
+ "EscalationRule",
156
+ "EscalationRuleConfig",
157
+ "EscalationAction",
158
+ "create_escalation_route",
159
+ # Dashboard adapters
160
+ "DashboardEscalationService",
161
+ "create_policy_from_db",
149
162
  ]