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.
- truthound_dashboard/api/alerts.py +258 -0
- truthound_dashboard/api/anomaly.py +1302 -0
- truthound_dashboard/api/cross_alerts.py +352 -0
- truthound_dashboard/api/deps.py +143 -0
- truthound_dashboard/api/drift_monitor.py +540 -0
- truthound_dashboard/api/lineage.py +1151 -0
- truthound_dashboard/api/maintenance.py +363 -0
- truthound_dashboard/api/middleware.py +373 -1
- truthound_dashboard/api/model_monitoring.py +805 -0
- truthound_dashboard/api/notifications_advanced.py +2452 -0
- truthound_dashboard/api/plugins.py +2096 -0
- truthound_dashboard/api/profile.py +211 -14
- truthound_dashboard/api/reports.py +853 -0
- truthound_dashboard/api/router.py +147 -0
- truthound_dashboard/api/rule_suggestions.py +310 -0
- truthound_dashboard/api/schema_evolution.py +231 -0
- truthound_dashboard/api/sources.py +47 -3
- truthound_dashboard/api/triggers.py +190 -0
- truthound_dashboard/api/validations.py +13 -0
- truthound_dashboard/api/validators.py +333 -4
- truthound_dashboard/api/versioning.py +309 -0
- truthound_dashboard/api/websocket.py +301 -0
- truthound_dashboard/core/__init__.py +27 -0
- truthound_dashboard/core/anomaly.py +1395 -0
- truthound_dashboard/core/anomaly_explainer.py +633 -0
- truthound_dashboard/core/cache.py +206 -0
- truthound_dashboard/core/cached_services.py +422 -0
- truthound_dashboard/core/charts.py +352 -0
- truthound_dashboard/core/connections.py +1069 -42
- truthound_dashboard/core/cross_alerts.py +837 -0
- truthound_dashboard/core/drift_monitor.py +1477 -0
- truthound_dashboard/core/drift_sampling.py +669 -0
- truthound_dashboard/core/i18n/__init__.py +42 -0
- truthound_dashboard/core/i18n/detector.py +173 -0
- truthound_dashboard/core/i18n/messages.py +564 -0
- truthound_dashboard/core/lineage.py +971 -0
- truthound_dashboard/core/maintenance.py +443 -5
- truthound_dashboard/core/model_monitoring.py +1043 -0
- truthound_dashboard/core/notifications/channels.py +1020 -1
- truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
- truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
- truthound_dashboard/core/notifications/deduplication/service.py +400 -0
- truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
- truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
- truthound_dashboard/core/notifications/dispatcher.py +43 -0
- truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
- truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
- truthound_dashboard/core/notifications/escalation/engine.py +429 -0
- truthound_dashboard/core/notifications/escalation/models.py +336 -0
- truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
- truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
- truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
- truthound_dashboard/core/notifications/events.py +49 -0
- truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
- truthound_dashboard/core/notifications/metrics/base.py +528 -0
- truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
- truthound_dashboard/core/notifications/routing/__init__.py +169 -0
- truthound_dashboard/core/notifications/routing/combinators.py +184 -0
- truthound_dashboard/core/notifications/routing/config.py +375 -0
- truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
- truthound_dashboard/core/notifications/routing/engine.py +382 -0
- truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
- truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
- truthound_dashboard/core/notifications/routing/rules.py +625 -0
- truthound_dashboard/core/notifications/routing/validator.py +678 -0
- truthound_dashboard/core/notifications/service.py +2 -0
- truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
- truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
- truthound_dashboard/core/notifications/throttling/builder.py +311 -0
- truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
- truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
- truthound_dashboard/core/openlineage.py +1028 -0
- truthound_dashboard/core/plugins/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/extractor.py +703 -0
- truthound_dashboard/core/plugins/docs/renderers.py +804 -0
- truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
- truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
- truthound_dashboard/core/plugins/hooks/manager.py +403 -0
- truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
- truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
- truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
- truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
- truthound_dashboard/core/plugins/loader.py +504 -0
- truthound_dashboard/core/plugins/registry.py +810 -0
- truthound_dashboard/core/plugins/reporter_executor.py +588 -0
- truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
- truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
- truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
- truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
- truthound_dashboard/core/plugins/sandbox.py +617 -0
- truthound_dashboard/core/plugins/security/__init__.py +68 -0
- truthound_dashboard/core/plugins/security/analyzer.py +535 -0
- truthound_dashboard/core/plugins/security/policies.py +311 -0
- truthound_dashboard/core/plugins/security/protocols.py +296 -0
- truthound_dashboard/core/plugins/security/signing.py +842 -0
- truthound_dashboard/core/plugins/security.py +446 -0
- truthound_dashboard/core/plugins/validator_executor.py +401 -0
- truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
- truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
- truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
- truthound_dashboard/core/plugins/versioning/semver.py +266 -0
- truthound_dashboard/core/profile_comparison.py +601 -0
- truthound_dashboard/core/report_history.py +570 -0
- truthound_dashboard/core/reporters/__init__.py +57 -0
- truthound_dashboard/core/reporters/base.py +296 -0
- truthound_dashboard/core/reporters/csv_reporter.py +155 -0
- truthound_dashboard/core/reporters/html_reporter.py +598 -0
- truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
- truthound_dashboard/core/reporters/i18n/base.py +494 -0
- truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
- truthound_dashboard/core/reporters/json_reporter.py +160 -0
- truthound_dashboard/core/reporters/junit_reporter.py +233 -0
- truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
- truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
- truthound_dashboard/core/reporters/registry.py +272 -0
- truthound_dashboard/core/rule_generator.py +2088 -0
- truthound_dashboard/core/scheduler.py +822 -12
- truthound_dashboard/core/schema_evolution.py +858 -0
- truthound_dashboard/core/services.py +152 -9
- truthound_dashboard/core/statistics.py +718 -0
- truthound_dashboard/core/streaming_anomaly.py +883 -0
- truthound_dashboard/core/triggers/__init__.py +45 -0
- truthound_dashboard/core/triggers/base.py +226 -0
- truthound_dashboard/core/triggers/evaluators.py +609 -0
- truthound_dashboard/core/triggers/factory.py +363 -0
- truthound_dashboard/core/unified_alerts.py +870 -0
- truthound_dashboard/core/validation_limits.py +509 -0
- truthound_dashboard/core/versioning.py +709 -0
- truthound_dashboard/core/websocket/__init__.py +59 -0
- truthound_dashboard/core/websocket/manager.py +512 -0
- truthound_dashboard/core/websocket/messages.py +130 -0
- truthound_dashboard/db/__init__.py +30 -0
- truthound_dashboard/db/models.py +3375 -3
- truthound_dashboard/main.py +22 -0
- truthound_dashboard/schemas/__init__.py +396 -1
- truthound_dashboard/schemas/anomaly.py +1258 -0
- truthound_dashboard/schemas/base.py +4 -0
- truthound_dashboard/schemas/cross_alerts.py +334 -0
- truthound_dashboard/schemas/drift_monitor.py +890 -0
- truthound_dashboard/schemas/lineage.py +428 -0
- truthound_dashboard/schemas/maintenance.py +154 -0
- truthound_dashboard/schemas/model_monitoring.py +374 -0
- truthound_dashboard/schemas/notifications_advanced.py +1363 -0
- truthound_dashboard/schemas/openlineage.py +704 -0
- truthound_dashboard/schemas/plugins.py +1293 -0
- truthound_dashboard/schemas/profile.py +420 -34
- truthound_dashboard/schemas/profile_comparison.py +242 -0
- truthound_dashboard/schemas/reports.py +285 -0
- truthound_dashboard/schemas/rule_suggestion.py +434 -0
- truthound_dashboard/schemas/schema_evolution.py +164 -0
- truthound_dashboard/schemas/source.py +117 -2
- truthound_dashboard/schemas/triggers.py +511 -0
- truthound_dashboard/schemas/unified_alerts.py +223 -0
- truthound_dashboard/schemas/validation.py +25 -1
- truthound_dashboard/schemas/validators/__init__.py +11 -0
- truthound_dashboard/schemas/validators/base.py +151 -0
- truthound_dashboard/schemas/versioning.py +152 -0
- truthound_dashboard/static/index.html +2 -2
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
- truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
- truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
- truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
- truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
- truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"""Trigger factory for creating and managing triggers.
|
|
2
|
+
|
|
3
|
+
Provides a high-level API for creating triggers from configuration
|
|
4
|
+
and integrating with the scheduler.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from truthound_dashboard.db import Schedule
|
|
14
|
+
from truthound_dashboard.schemas.triggers import (
|
|
15
|
+
TriggerType,
|
|
16
|
+
parse_trigger_config,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from .base import (
|
|
20
|
+
BaseTrigger,
|
|
21
|
+
TriggerContext,
|
|
22
|
+
TriggerEvaluation,
|
|
23
|
+
TriggerRegistry,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Import evaluators to register them
|
|
27
|
+
from . import evaluators # noqa: F401
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TriggerFactory:
|
|
33
|
+
"""Factory for creating and managing trigger instances.
|
|
34
|
+
|
|
35
|
+
Provides methods to:
|
|
36
|
+
- Create triggers from Schedule models
|
|
37
|
+
- Create triggers from raw configuration
|
|
38
|
+
- Evaluate triggers with proper context
|
|
39
|
+
- Get trigger metadata and descriptions
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_schedule(cls, schedule: Schedule) -> BaseTrigger | None:
|
|
44
|
+
"""Create a trigger from a Schedule model.
|
|
45
|
+
|
|
46
|
+
Handles both new trigger_config and legacy cron_expression fields.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
schedule: Schedule model instance.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
BaseTrigger instance or None if creation fails.
|
|
53
|
+
"""
|
|
54
|
+
trigger_type = schedule.trigger_type or TriggerType.CRON.value
|
|
55
|
+
|
|
56
|
+
# Build config from schedule
|
|
57
|
+
if schedule.trigger_config:
|
|
58
|
+
config = schedule.trigger_config.copy()
|
|
59
|
+
else:
|
|
60
|
+
config = {}
|
|
61
|
+
|
|
62
|
+
# Handle legacy cron_expression field
|
|
63
|
+
if trigger_type == TriggerType.CRON.value:
|
|
64
|
+
if "expression" not in config and schedule.cron_expression:
|
|
65
|
+
config["expression"] = schedule.cron_expression
|
|
66
|
+
|
|
67
|
+
return cls.create(trigger_type, config)
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def create(
|
|
71
|
+
cls, trigger_type: str, config: dict[str, Any]
|
|
72
|
+
) -> BaseTrigger | None:
|
|
73
|
+
"""Create a trigger from type and configuration.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
trigger_type: Type identifier string.
|
|
77
|
+
config: Trigger-specific configuration.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
BaseTrigger instance or None if creation fails.
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
# Normalize type to lowercase
|
|
84
|
+
trigger_type = trigger_type.lower()
|
|
85
|
+
|
|
86
|
+
trigger = TriggerRegistry.create(trigger_type, config)
|
|
87
|
+
if trigger is None:
|
|
88
|
+
logger.warning(f"Unknown trigger type: {trigger_type}")
|
|
89
|
+
return trigger
|
|
90
|
+
|
|
91
|
+
except ValueError as e:
|
|
92
|
+
logger.error(f"Invalid trigger config for {trigger_type}: {e}")
|
|
93
|
+
return None
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.error(f"Failed to create trigger {trigger_type}: {e}")
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def create_from_dict(cls, data: dict[str, Any]) -> BaseTrigger | None:
|
|
100
|
+
"""Create a trigger from a dictionary with type and config.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
data: Dictionary with 'type' and optional config fields.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
BaseTrigger instance or None if creation fails.
|
|
107
|
+
"""
|
|
108
|
+
trigger_type = data.get("type")
|
|
109
|
+
if not trigger_type:
|
|
110
|
+
logger.error("Trigger data missing 'type' field")
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
# Extract config (all fields except 'type')
|
|
114
|
+
config = {k: v for k, v in data.items() if k != "type"}
|
|
115
|
+
|
|
116
|
+
return cls.create(trigger_type, config)
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
async def evaluate_schedule(
|
|
120
|
+
cls,
|
|
121
|
+
schedule: Schedule,
|
|
122
|
+
*,
|
|
123
|
+
profile_data: dict[str, Any] | None = None,
|
|
124
|
+
baseline_profile: dict[str, Any] | None = None,
|
|
125
|
+
event_data: dict[str, Any] | None = None,
|
|
126
|
+
force_trigger: bool = False,
|
|
127
|
+
) -> TriggerEvaluation:
|
|
128
|
+
"""Evaluate a schedule's trigger.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
schedule: Schedule to evaluate.
|
|
132
|
+
profile_data: Current profile data (for data change triggers).
|
|
133
|
+
baseline_profile: Baseline profile for comparison.
|
|
134
|
+
event_data: Event data (for event triggers).
|
|
135
|
+
force_trigger: Force trigger regardless of conditions.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
TriggerEvaluation with result.
|
|
139
|
+
"""
|
|
140
|
+
trigger = cls.from_schedule(schedule)
|
|
141
|
+
|
|
142
|
+
if trigger is None:
|
|
143
|
+
return TriggerEvaluation(
|
|
144
|
+
should_trigger=False,
|
|
145
|
+
reason=f"Failed to create trigger: {schedule.trigger_type}",
|
|
146
|
+
details={"error": "trigger_creation_failed"},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
context = TriggerContext(
|
|
150
|
+
schedule_id=schedule.id,
|
|
151
|
+
source_id=schedule.source_id,
|
|
152
|
+
last_run_at=schedule.last_run_at,
|
|
153
|
+
trigger_count=schedule.trigger_count,
|
|
154
|
+
profile_data=profile_data,
|
|
155
|
+
baseline_profile=baseline_profile,
|
|
156
|
+
event_data=event_data,
|
|
157
|
+
custom_data={"force_trigger": force_trigger},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
return await trigger.evaluate(context)
|
|
162
|
+
except Exception as e:
|
|
163
|
+
logger.error(f"Trigger evaluation failed for schedule {schedule.id}: {e}")
|
|
164
|
+
return TriggerEvaluation(
|
|
165
|
+
should_trigger=False,
|
|
166
|
+
reason=f"Evaluation error: {str(e)}",
|
|
167
|
+
details={"error": str(e)},
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def get_trigger_types(cls) -> list[dict[str, Any]]:
|
|
172
|
+
"""Get information about all registered trigger types.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of trigger type information dictionaries.
|
|
176
|
+
"""
|
|
177
|
+
types = []
|
|
178
|
+
for trigger_type in TriggerRegistry.list_types():
|
|
179
|
+
trigger_class = TriggerRegistry.get(trigger_type)
|
|
180
|
+
if trigger_class:
|
|
181
|
+
types.append({
|
|
182
|
+
"type": trigger_type,
|
|
183
|
+
"name": trigger_type.replace("_", " ").title(),
|
|
184
|
+
"description": _get_type_description(trigger_type),
|
|
185
|
+
"config_schema": _get_config_schema(trigger_type),
|
|
186
|
+
})
|
|
187
|
+
return types
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def validate_config(
|
|
191
|
+
cls, trigger_type: str, config: dict[str, Any]
|
|
192
|
+
) -> tuple[bool, str | None]:
|
|
193
|
+
"""Validate trigger configuration without creating the trigger.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
trigger_type: Type identifier.
|
|
197
|
+
config: Configuration to validate.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Tuple of (is_valid, error_message).
|
|
201
|
+
"""
|
|
202
|
+
try:
|
|
203
|
+
trigger = cls.create(trigger_type, config)
|
|
204
|
+
if trigger is None:
|
|
205
|
+
return False, f"Unknown trigger type: {trigger_type}"
|
|
206
|
+
return True, None
|
|
207
|
+
except ValueError as e:
|
|
208
|
+
return False, str(e)
|
|
209
|
+
except Exception as e:
|
|
210
|
+
return False, f"Validation error: {str(e)}"
|
|
211
|
+
|
|
212
|
+
@classmethod
|
|
213
|
+
def get_next_run_time(
|
|
214
|
+
cls,
|
|
215
|
+
schedule: Schedule,
|
|
216
|
+
from_time: datetime | None = None,
|
|
217
|
+
) -> datetime | None:
|
|
218
|
+
"""Calculate the next run time for a schedule.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
schedule: Schedule to check.
|
|
222
|
+
from_time: Base time for calculation (defaults to now).
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Next run datetime or None.
|
|
226
|
+
"""
|
|
227
|
+
trigger = cls.from_schedule(schedule)
|
|
228
|
+
if trigger is None:
|
|
229
|
+
return None
|
|
230
|
+
|
|
231
|
+
context = TriggerContext(
|
|
232
|
+
schedule_id=schedule.id,
|
|
233
|
+
source_id=schedule.source_id,
|
|
234
|
+
last_run_at=schedule.last_run_at,
|
|
235
|
+
trigger_count=schedule.trigger_count,
|
|
236
|
+
current_time=from_time or datetime.utcnow(),
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
return trigger.get_next_evaluation_time(context)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _get_type_description(trigger_type: str) -> str:
|
|
243
|
+
"""Get description for a trigger type."""
|
|
244
|
+
descriptions = {
|
|
245
|
+
"cron": "Schedule using cron expressions (e.g., '0 0 * * *' for daily at midnight)",
|
|
246
|
+
"interval": "Run at fixed time intervals (e.g., every 6 hours)",
|
|
247
|
+
"data_change": "Trigger when data profile changes by a threshold percentage",
|
|
248
|
+
"composite": "Combine multiple triggers with AND/OR logic",
|
|
249
|
+
"event": "Trigger in response to system events (e.g., schema changes)",
|
|
250
|
+
"manual": "Only run when manually triggered via API",
|
|
251
|
+
}
|
|
252
|
+
return descriptions.get(trigger_type, "Unknown trigger type")
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _get_config_schema(trigger_type: str) -> dict[str, Any]:
|
|
256
|
+
"""Get configuration schema for a trigger type."""
|
|
257
|
+
schemas = {
|
|
258
|
+
"cron": {
|
|
259
|
+
"expression": {
|
|
260
|
+
"type": "string",
|
|
261
|
+
"required": True,
|
|
262
|
+
"description": "Cron expression (minute hour day month weekday)",
|
|
263
|
+
"examples": ["0 0 * * *", "0 */6 * * *", "0 8 * * 1-5"],
|
|
264
|
+
},
|
|
265
|
+
"timezone": {
|
|
266
|
+
"type": "string",
|
|
267
|
+
"required": False,
|
|
268
|
+
"default": "UTC",
|
|
269
|
+
"description": "Timezone for scheduling",
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
"interval": {
|
|
273
|
+
"seconds": {
|
|
274
|
+
"type": "integer",
|
|
275
|
+
"required": False,
|
|
276
|
+
"min": 1,
|
|
277
|
+
"description": "Interval in seconds",
|
|
278
|
+
},
|
|
279
|
+
"minutes": {
|
|
280
|
+
"type": "integer",
|
|
281
|
+
"required": False,
|
|
282
|
+
"min": 1,
|
|
283
|
+
"description": "Interval in minutes",
|
|
284
|
+
},
|
|
285
|
+
"hours": {
|
|
286
|
+
"type": "integer",
|
|
287
|
+
"required": False,
|
|
288
|
+
"min": 1,
|
|
289
|
+
"description": "Interval in hours",
|
|
290
|
+
},
|
|
291
|
+
"days": {
|
|
292
|
+
"type": "integer",
|
|
293
|
+
"required": False,
|
|
294
|
+
"min": 1,
|
|
295
|
+
"description": "Interval in days",
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
"data_change": {
|
|
299
|
+
"change_threshold": {
|
|
300
|
+
"type": "number",
|
|
301
|
+
"required": False,
|
|
302
|
+
"default": 0.05,
|
|
303
|
+
"min": 0.0,
|
|
304
|
+
"max": 1.0,
|
|
305
|
+
"description": "Minimum change percentage to trigger (0.0-1.0)",
|
|
306
|
+
},
|
|
307
|
+
"metrics": {
|
|
308
|
+
"type": "array",
|
|
309
|
+
"items": "string",
|
|
310
|
+
"required": False,
|
|
311
|
+
"default": ["row_count", "null_percentage", "distinct_count"],
|
|
312
|
+
"description": "Metrics to monitor for changes",
|
|
313
|
+
},
|
|
314
|
+
"check_interval_minutes": {
|
|
315
|
+
"type": "integer",
|
|
316
|
+
"required": False,
|
|
317
|
+
"default": 60,
|
|
318
|
+
"min": 1,
|
|
319
|
+
"description": "How often to check for changes",
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
"composite": {
|
|
323
|
+
"operator": {
|
|
324
|
+
"type": "string",
|
|
325
|
+
"required": False,
|
|
326
|
+
"default": "and",
|
|
327
|
+
"enum": ["and", "or"],
|
|
328
|
+
"description": "How to combine triggers",
|
|
329
|
+
},
|
|
330
|
+
"triggers": {
|
|
331
|
+
"type": "array",
|
|
332
|
+
"items": "object",
|
|
333
|
+
"required": True,
|
|
334
|
+
"min_items": 2,
|
|
335
|
+
"description": "List of trigger configurations to combine",
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
"event": {
|
|
339
|
+
"event_types": {
|
|
340
|
+
"type": "array",
|
|
341
|
+
"items": "string",
|
|
342
|
+
"required": True,
|
|
343
|
+
"description": "Event types that trigger execution",
|
|
344
|
+
"enum": [
|
|
345
|
+
"validation_completed",
|
|
346
|
+
"validation_failed",
|
|
347
|
+
"schema_changed",
|
|
348
|
+
"drift_detected",
|
|
349
|
+
"profile_updated",
|
|
350
|
+
"source_created",
|
|
351
|
+
"source_updated",
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
"source_filter": {
|
|
355
|
+
"type": "array",
|
|
356
|
+
"items": "string",
|
|
357
|
+
"required": False,
|
|
358
|
+
"description": "Optional source IDs to filter events",
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
"manual": {},
|
|
362
|
+
}
|
|
363
|
+
return schemas.get(trigger_type, {})
|