truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.1__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 +75 -86
- truthound_dashboard/api/anomaly.py +7 -13
- truthound_dashboard/api/cross_alerts.py +38 -52
- truthound_dashboard/api/drift.py +49 -59
- truthound_dashboard/api/drift_monitor.py +234 -79
- truthound_dashboard/api/enterprise_sampling.py +498 -0
- truthound_dashboard/api/history.py +57 -5
- truthound_dashboard/api/lineage.py +3 -48
- truthound_dashboard/api/maintenance.py +104 -49
- truthound_dashboard/api/mask.py +1 -2
- truthound_dashboard/api/middleware.py +2 -1
- truthound_dashboard/api/model_monitoring.py +435 -311
- truthound_dashboard/api/notifications.py +227 -191
- truthound_dashboard/api/notifications_advanced.py +21 -20
- truthound_dashboard/api/observability.py +586 -0
- truthound_dashboard/api/plugins.py +2 -433
- truthound_dashboard/api/profile.py +199 -37
- truthound_dashboard/api/quality_reporter.py +701 -0
- truthound_dashboard/api/reports.py +7 -16
- truthound_dashboard/api/router.py +66 -0
- truthound_dashboard/api/rule_suggestions.py +5 -5
- truthound_dashboard/api/scan.py +17 -19
- truthound_dashboard/api/schedules.py +85 -50
- truthound_dashboard/api/schema_evolution.py +6 -6
- truthound_dashboard/api/schema_watcher.py +667 -0
- truthound_dashboard/api/sources.py +98 -27
- truthound_dashboard/api/tiering.py +1323 -0
- truthound_dashboard/api/triggers.py +14 -11
- truthound_dashboard/api/validations.py +12 -11
- truthound_dashboard/api/versioning.py +1 -6
- truthound_dashboard/core/__init__.py +129 -3
- truthound_dashboard/core/actions/__init__.py +62 -0
- truthound_dashboard/core/actions/custom.py +426 -0
- truthound_dashboard/core/actions/notifications.py +910 -0
- truthound_dashboard/core/actions/storage.py +472 -0
- truthound_dashboard/core/actions/webhook.py +281 -0
- truthound_dashboard/core/anomaly.py +262 -67
- truthound_dashboard/core/anomaly_explainer.py +4 -3
- truthound_dashboard/core/backends/__init__.py +67 -0
- truthound_dashboard/core/backends/base.py +299 -0
- truthound_dashboard/core/backends/errors.py +191 -0
- truthound_dashboard/core/backends/factory.py +423 -0
- truthound_dashboard/core/backends/mock_backend.py +451 -0
- truthound_dashboard/core/backends/truthound_backend.py +718 -0
- truthound_dashboard/core/checkpoint/__init__.py +87 -0
- truthound_dashboard/core/checkpoint/adapters.py +814 -0
- truthound_dashboard/core/checkpoint/checkpoint.py +491 -0
- truthound_dashboard/core/checkpoint/runner.py +270 -0
- truthound_dashboard/core/connections.py +645 -23
- truthound_dashboard/core/converters/__init__.py +14 -0
- truthound_dashboard/core/converters/truthound.py +620 -0
- truthound_dashboard/core/cross_alerts.py +540 -320
- truthound_dashboard/core/datasource_factory.py +1672 -0
- truthound_dashboard/core/drift_monitor.py +216 -20
- truthound_dashboard/core/enterprise_sampling.py +1291 -0
- truthound_dashboard/core/interfaces/__init__.py +225 -0
- truthound_dashboard/core/interfaces/actions.py +652 -0
- truthound_dashboard/core/interfaces/base.py +247 -0
- truthound_dashboard/core/interfaces/checkpoint.py +676 -0
- truthound_dashboard/core/interfaces/protocols.py +664 -0
- truthound_dashboard/core/interfaces/reporters.py +650 -0
- truthound_dashboard/core/interfaces/routing.py +646 -0
- truthound_dashboard/core/interfaces/triggers.py +619 -0
- truthound_dashboard/core/lineage.py +407 -71
- truthound_dashboard/core/model_monitoring.py +431 -3
- truthound_dashboard/core/notifications/base.py +4 -0
- truthound_dashboard/core/notifications/channels.py +501 -1203
- truthound_dashboard/core/notifications/deduplication/__init__.py +81 -115
- truthound_dashboard/core/notifications/deduplication/service.py +131 -348
- truthound_dashboard/core/notifications/dispatcher.py +202 -11
- truthound_dashboard/core/notifications/escalation/__init__.py +119 -106
- truthound_dashboard/core/notifications/escalation/engine.py +168 -358
- truthound_dashboard/core/notifications/routing/__init__.py +88 -128
- truthound_dashboard/core/notifications/routing/engine.py +90 -317
- truthound_dashboard/core/notifications/stats_aggregator.py +246 -1
- truthound_dashboard/core/notifications/throttling/__init__.py +67 -50
- truthound_dashboard/core/notifications/throttling/builder.py +117 -255
- truthound_dashboard/core/notifications/truthound_adapter.py +842 -0
- truthound_dashboard/core/phase5/collaboration.py +1 -1
- truthound_dashboard/core/plugins/lifecycle/__init__.py +0 -13
- truthound_dashboard/core/quality_reporter.py +1359 -0
- truthound_dashboard/core/report_history.py +0 -6
- truthound_dashboard/core/reporters/__init__.py +175 -14
- truthound_dashboard/core/reporters/adapters.py +943 -0
- truthound_dashboard/core/reporters/base.py +0 -3
- truthound_dashboard/core/reporters/builtin/__init__.py +18 -0
- truthound_dashboard/core/reporters/builtin/csv_reporter.py +111 -0
- truthound_dashboard/core/reporters/builtin/html_reporter.py +270 -0
- truthound_dashboard/core/reporters/builtin/json_reporter.py +127 -0
- truthound_dashboard/core/reporters/compat.py +266 -0
- truthound_dashboard/core/reporters/csv_reporter.py +2 -35
- truthound_dashboard/core/reporters/factory.py +526 -0
- truthound_dashboard/core/reporters/interfaces.py +745 -0
- truthound_dashboard/core/reporters/registry.py +1 -10
- truthound_dashboard/core/scheduler.py +165 -0
- truthound_dashboard/core/schema_evolution.py +3 -3
- truthound_dashboard/core/schema_watcher.py +1528 -0
- truthound_dashboard/core/services.py +595 -76
- truthound_dashboard/core/store_manager.py +810 -0
- truthound_dashboard/core/streaming_anomaly.py +169 -4
- truthound_dashboard/core/tiering.py +1309 -0
- truthound_dashboard/core/triggers/evaluators.py +178 -8
- truthound_dashboard/core/truthound_adapter.py +2620 -197
- truthound_dashboard/core/unified_alerts.py +23 -20
- truthound_dashboard/db/__init__.py +8 -0
- truthound_dashboard/db/database.py +8 -2
- truthound_dashboard/db/models.py +944 -25
- truthound_dashboard/db/repository.py +2 -0
- truthound_dashboard/main.py +15 -0
- truthound_dashboard/schemas/__init__.py +177 -16
- truthound_dashboard/schemas/base.py +44 -23
- truthound_dashboard/schemas/collaboration.py +19 -6
- truthound_dashboard/schemas/cross_alerts.py +19 -3
- truthound_dashboard/schemas/drift.py +61 -55
- truthound_dashboard/schemas/drift_monitor.py +67 -23
- truthound_dashboard/schemas/enterprise_sampling.py +653 -0
- truthound_dashboard/schemas/lineage.py +0 -33
- truthound_dashboard/schemas/mask.py +10 -8
- truthound_dashboard/schemas/model_monitoring.py +89 -10
- truthound_dashboard/schemas/notifications_advanced.py +13 -0
- truthound_dashboard/schemas/observability.py +453 -0
- truthound_dashboard/schemas/plugins.py +0 -280
- truthound_dashboard/schemas/profile.py +154 -247
- truthound_dashboard/schemas/quality_reporter.py +403 -0
- truthound_dashboard/schemas/reports.py +2 -2
- truthound_dashboard/schemas/rule_suggestion.py +8 -1
- truthound_dashboard/schemas/scan.py +4 -24
- truthound_dashboard/schemas/schedule.py +11 -3
- truthound_dashboard/schemas/schema_watcher.py +727 -0
- truthound_dashboard/schemas/source.py +17 -2
- truthound_dashboard/schemas/tiering.py +822 -0
- truthound_dashboard/schemas/triggers.py +16 -0
- truthound_dashboard/schemas/unified_alerts.py +7 -0
- truthound_dashboard/schemas/validation.py +0 -13
- truthound_dashboard/schemas/validators/base.py +41 -21
- truthound_dashboard/schemas/validators/business_rule_validators.py +244 -0
- truthound_dashboard/schemas/validators/localization_validators.py +273 -0
- truthound_dashboard/schemas/validators/ml_feature_validators.py +308 -0
- truthound_dashboard/schemas/validators/profiling_validators.py +275 -0
- truthound_dashboard/schemas/validators/referential_validators.py +312 -0
- truthound_dashboard/schemas/validators/registry.py +93 -8
- truthound_dashboard/schemas/validators/timeseries_validators.py +389 -0
- truthound_dashboard/schemas/versioning.py +1 -6
- truthound_dashboard/static/index.html +2 -2
- truthound_dashboard-1.5.1.dist-info/METADATA +312 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/RECORD +149 -148
- truthound_dashboard/core/plugins/hooks/__init__.py +0 -63
- truthound_dashboard/core/plugins/hooks/decorators.py +0 -367
- truthound_dashboard/core/plugins/hooks/manager.py +0 -403
- truthound_dashboard/core/plugins/hooks/protocols.py +0 -265
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +0 -584
- truthound_dashboard/core/reporters/junit_reporter.py +0 -233
- truthound_dashboard/core/reporters/markdown_reporter.py +0 -207
- truthound_dashboard/core/reporters/pdf_reporter.py +0 -209
- truthound_dashboard/static/assets/_baseUniq-BcrSP13d.js +0 -1
- truthound_dashboard/static/assets/arc-DlYjKwIL.js +0 -1
- truthound_dashboard/static/assets/architectureDiagram-VXUJARFQ-Bb2drbQM.js +0 -36
- truthound_dashboard/static/assets/blockDiagram-VD42YOAC-BlsPG1CH.js +0 -122
- truthound_dashboard/static/assets/c4Diagram-YG6GDRKO-B9JdUoaC.js +0 -10
- truthound_dashboard/static/assets/channel-Q6mHF1Hd.js +0 -1
- truthound_dashboard/static/assets/chunk-4BX2VUAB-DmyoPVuJ.js +0 -1
- truthound_dashboard/static/assets/chunk-55IACEB6-Bcz6Siv8.js +0 -1
- truthound_dashboard/static/assets/chunk-B4BG7PRW-Br3G5Rum.js +0 -165
- truthound_dashboard/static/assets/chunk-DI55MBZ5-DuM9c23u.js +0 -220
- truthound_dashboard/static/assets/chunk-FMBD7UC4-DNU-5mvT.js +0 -15
- truthound_dashboard/static/assets/chunk-QN33PNHL-Im2yNcmS.js +0 -1
- truthound_dashboard/static/assets/chunk-QZHKN3VN-kZr8XFm1.js +0 -1
- truthound_dashboard/static/assets/chunk-TZMSLE5B-Q__360q_.js +0 -1
- truthound_dashboard/static/assets/classDiagram-2ON5EDUG-vtixxUyK.js +0 -1
- truthound_dashboard/static/assets/classDiagram-v2-WZHVMYZB-vtixxUyK.js +0 -1
- truthound_dashboard/static/assets/clone-BOt2LwD0.js +0 -1
- truthound_dashboard/static/assets/cose-bilkent-S5V4N54A-CBDw6iac.js +0 -1
- truthound_dashboard/static/assets/dagre-6UL2VRFP-XdKqmmY9.js +0 -4
- truthound_dashboard/static/assets/diagram-PSM6KHXK-DAZ8nx9V.js +0 -24
- truthound_dashboard/static/assets/diagram-QEK2KX5R-BRvDTbGD.js +0 -43
- truthound_dashboard/static/assets/diagram-S2PKOQOG-bQcczUkl.js +0 -24
- truthound_dashboard/static/assets/erDiagram-Q2GNP2WA-DPje7VMN.js +0 -60
- truthound_dashboard/static/assets/flowDiagram-NV44I4VS-B7BVtFVS.js +0 -162
- truthound_dashboard/static/assets/ganttDiagram-JELNMOA3-D6WKSS7U.js +0 -267
- truthound_dashboard/static/assets/gitGraphDiagram-NY62KEGX-D3vtVd3y.js +0 -65
- truthound_dashboard/static/assets/graph-BKgNKZVp.js +0 -1
- truthound_dashboard/static/assets/index-C6JSrkHo.css +0 -1
- truthound_dashboard/static/assets/index-DkU82VsU.js +0 -1800
- truthound_dashboard/static/assets/infoDiagram-WHAUD3N6-DnNCT429.js +0 -2
- truthound_dashboard/static/assets/journeyDiagram-XKPGCS4Q-DGiMozqS.js +0 -139
- truthound_dashboard/static/assets/kanban-definition-3W4ZIXB7-BV2gUgli.js +0 -89
- truthound_dashboard/static/assets/katex-Cu_Erd72.js +0 -261
- truthound_dashboard/static/assets/layout-DI2MfQ5G.js +0 -1
- truthound_dashboard/static/assets/min-DYdgXVcT.js +0 -1
- truthound_dashboard/static/assets/mindmap-definition-VGOIOE7T-C7x4ruxz.js +0 -68
- truthound_dashboard/static/assets/pieDiagram-ADFJNKIX-CAJaAB9f.js +0 -30
- truthound_dashboard/static/assets/quadrantDiagram-AYHSOK5B-DeqwDI46.js +0 -7
- truthound_dashboard/static/assets/requirementDiagram-UZGBJVZJ-e3XDpZIM.js +0 -64
- truthound_dashboard/static/assets/sankeyDiagram-TZEHDZUN-CNnAv5Ux.js +0 -10
- truthound_dashboard/static/assets/sequenceDiagram-WL72ISMW-Dsne-Of3.js +0 -145
- truthound_dashboard/static/assets/stateDiagram-FKZM4ZOC-Ee0sQXyb.js +0 -1
- truthound_dashboard/static/assets/stateDiagram-v2-4FDKWEC3-B26KqW_W.js +0 -1
- truthound_dashboard/static/assets/timeline-definition-IT6M3QCI-DZYi2yl3.js +0 -61
- truthound_dashboard/static/assets/treemap-KMMF4GRG-CY3f8In2.js +0 -128
- truthound_dashboard/static/assets/unmerged_dictionaries-Dd7xcPWG.js +0 -1
- truthound_dashboard/static/assets/xychartDiagram-PRI3JC2R-CS7fydZZ.js +0 -7
- truthound_dashboard-1.4.4.dist-info/METADATA +0 -507
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"""Quality Reporter schemas for API request/response validation.
|
|
2
|
+
|
|
3
|
+
This module provides Pydantic schemas for the Quality Reporter feature,
|
|
4
|
+
enabling comprehensive quality assessment and reporting of validation rules.
|
|
5
|
+
|
|
6
|
+
Based on truthound's QualityReporter module:
|
|
7
|
+
- Quality scoring (F1, precision, recall, accuracy)
|
|
8
|
+
- Quality levels (excellent, good, acceptable, poor, unacceptable)
|
|
9
|
+
- Filtering and comparison capabilities
|
|
10
|
+
- Multiple report formats (console, json, html, markdown, junit)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from enum import Enum
|
|
17
|
+
from typing import Any, Literal
|
|
18
|
+
|
|
19
|
+
from pydantic import Field
|
|
20
|
+
|
|
21
|
+
from .base import BaseSchema, IDMixin, PaginatedResponse, TimestampMixin
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# =============================================================================
|
|
25
|
+
# Enums
|
|
26
|
+
# =============================================================================
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class QualityLevel(str, Enum):
|
|
30
|
+
"""Quality levels for rules based on F1 score."""
|
|
31
|
+
|
|
32
|
+
EXCELLENT = "excellent" # 0.9 - 1.0
|
|
33
|
+
GOOD = "good" # 0.7 - 0.9
|
|
34
|
+
ACCEPTABLE = "acceptable" # 0.5 - 0.7
|
|
35
|
+
POOR = "poor" # 0.3 - 0.5
|
|
36
|
+
UNACCEPTABLE = "unacceptable" # 0.0 - 0.3
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class QualityReportFormat(str, Enum):
|
|
40
|
+
"""Available quality report formats."""
|
|
41
|
+
|
|
42
|
+
CONSOLE = "console"
|
|
43
|
+
JSON = "json"
|
|
44
|
+
HTML = "html"
|
|
45
|
+
MARKDOWN = "markdown"
|
|
46
|
+
JUNIT = "junit"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class QualityReportStatus(str, Enum):
|
|
50
|
+
"""Status of quality report generation."""
|
|
51
|
+
|
|
52
|
+
PENDING = "pending"
|
|
53
|
+
GENERATING = "generating"
|
|
54
|
+
COMPLETED = "completed"
|
|
55
|
+
FAILED = "failed"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ReportSortOrder(str, Enum):
|
|
59
|
+
"""Sort order for quality scores."""
|
|
60
|
+
|
|
61
|
+
F1_DESC = "f1_desc"
|
|
62
|
+
F1_ASC = "f1_asc"
|
|
63
|
+
PRECISION_DESC = "precision_desc"
|
|
64
|
+
PRECISION_ASC = "precision_asc"
|
|
65
|
+
RECALL_DESC = "recall_desc"
|
|
66
|
+
RECALL_ASC = "recall_asc"
|
|
67
|
+
LEVEL_DESC = "level_desc"
|
|
68
|
+
LEVEL_ASC = "level_asc"
|
|
69
|
+
NAME_ASC = "name_asc"
|
|
70
|
+
NAME_DESC = "name_desc"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class QualityDisplayMode(str, Enum):
|
|
74
|
+
"""Display mode for quality reports."""
|
|
75
|
+
|
|
76
|
+
SUMMARY = "summary"
|
|
77
|
+
DETAILED = "detailed"
|
|
78
|
+
COMPARISON = "comparison"
|
|
79
|
+
TREND = "trend"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ChartType(str, Enum):
|
|
83
|
+
"""Chart types for quality visualizations."""
|
|
84
|
+
|
|
85
|
+
BAR = "bar"
|
|
86
|
+
LINE = "line"
|
|
87
|
+
PIE = "pie"
|
|
88
|
+
RADAR = "radar"
|
|
89
|
+
HEATMAP = "heatmap"
|
|
90
|
+
SCATTER = "scatter"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# =============================================================================
|
|
94
|
+
# Confusion Matrix
|
|
95
|
+
# =============================================================================
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class ConfusionMatrixSchema(BaseSchema):
|
|
99
|
+
"""Confusion matrix for rule evaluation."""
|
|
100
|
+
|
|
101
|
+
true_positive: int = Field(default=0, ge=0, description="Correct violation detections")
|
|
102
|
+
true_negative: int = Field(default=0, ge=0, description="Correct passes")
|
|
103
|
+
false_positive: int = Field(default=0, ge=0, description="Incorrect violation detections (false alarms)")
|
|
104
|
+
false_negative: int = Field(default=0, ge=0, description="Missed violations")
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def precision(self) -> float:
|
|
108
|
+
"""Precision: TP / (TP + FP)."""
|
|
109
|
+
total = self.true_positive + self.false_positive
|
|
110
|
+
return self.true_positive / total if total > 0 else 0.0
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def recall(self) -> float:
|
|
114
|
+
"""Recall: TP / (TP + FN)."""
|
|
115
|
+
total = self.true_positive + self.false_negative
|
|
116
|
+
return self.true_positive / total if total > 0 else 0.0
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def f1_score(self) -> float:
|
|
120
|
+
"""F1 score: harmonic mean of precision and recall."""
|
|
121
|
+
p, r = self.precision, self.recall
|
|
122
|
+
return 2 * (p * r) / (p + r) if (p + r) > 0 else 0.0
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def accuracy(self) -> float:
|
|
126
|
+
"""Accuracy: (TP + TN) / Total."""
|
|
127
|
+
total = (
|
|
128
|
+
self.true_positive
|
|
129
|
+
+ self.true_negative
|
|
130
|
+
+ self.false_positive
|
|
131
|
+
+ self.false_negative
|
|
132
|
+
)
|
|
133
|
+
return (self.true_positive + self.true_negative) / total if total > 0 else 0.0
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# =============================================================================
|
|
137
|
+
# Quality Metrics
|
|
138
|
+
# =============================================================================
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class QualityMetricsSchema(BaseSchema):
|
|
142
|
+
"""Quality metrics for a validation rule."""
|
|
143
|
+
|
|
144
|
+
f1_score: float = Field(..., ge=0.0, le=1.0, description="F1 score (0-1)")
|
|
145
|
+
precision: float = Field(..., ge=0.0, le=1.0, description="Precision (0-1)")
|
|
146
|
+
recall: float = Field(..., ge=0.0, le=1.0, description="Recall (0-1)")
|
|
147
|
+
accuracy: float = Field(..., ge=0.0, le=1.0, description="Accuracy (0-1)")
|
|
148
|
+
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="Confidence score (0-1)")
|
|
149
|
+
quality_level: QualityLevel = Field(..., description="Computed quality level")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class QualityThresholdsSchema(BaseSchema):
|
|
153
|
+
"""Configurable thresholds for quality levels."""
|
|
154
|
+
|
|
155
|
+
excellent: float = Field(default=0.9, ge=0.0, le=1.0, description="Minimum for excellent")
|
|
156
|
+
good: float = Field(default=0.7, ge=0.0, le=1.0, description="Minimum for good")
|
|
157
|
+
acceptable: float = Field(default=0.5, ge=0.0, le=1.0, description="Minimum for acceptable")
|
|
158
|
+
poor: float = Field(default=0.3, ge=0.0, le=1.0, description="Minimum for poor")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# =============================================================================
|
|
162
|
+
# Quality Score
|
|
163
|
+
# =============================================================================
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class QualityScoreSchema(BaseSchema):
|
|
167
|
+
"""Quality score result for a single rule."""
|
|
168
|
+
|
|
169
|
+
rule_name: str = Field(..., description="Name of the validation rule")
|
|
170
|
+
rule_type: str | None = Field(default=None, description="Type of rule (pattern, range, etc.)")
|
|
171
|
+
column: str | None = Field(default=None, description="Target column name")
|
|
172
|
+
metrics: QualityMetricsSchema = Field(..., description="Quality metrics")
|
|
173
|
+
confusion_matrix: ConfusionMatrixSchema | None = Field(default=None, description="Confusion matrix details")
|
|
174
|
+
test_sample_size: int = Field(default=0, ge=0, description="Number of samples tested")
|
|
175
|
+
evaluation_time_ms: float = Field(default=0.0, ge=0.0, description="Evaluation time in milliseconds")
|
|
176
|
+
recommendation: str | None = Field(default=None, description="Recommendation message")
|
|
177
|
+
should_use: bool = Field(default=True, description="Whether the rule should be used")
|
|
178
|
+
issues: list[dict[str, Any]] = Field(default_factory=list, description="List of identified issues")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# =============================================================================
|
|
182
|
+
# Quality Statistics
|
|
183
|
+
# =============================================================================
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class QualityStatisticsSchema(BaseSchema):
|
|
187
|
+
"""Aggregate statistics for quality scores."""
|
|
188
|
+
|
|
189
|
+
total_count: int = Field(default=0, ge=0, description="Total number of rules")
|
|
190
|
+
excellent_count: int = Field(default=0, ge=0, description="Count of excellent rules")
|
|
191
|
+
good_count: int = Field(default=0, ge=0, description="Count of good rules")
|
|
192
|
+
acceptable_count: int = Field(default=0, ge=0, description="Count of acceptable rules")
|
|
193
|
+
poor_count: int = Field(default=0, ge=0, description="Count of poor rules")
|
|
194
|
+
unacceptable_count: int = Field(default=0, ge=0, description="Count of unacceptable rules")
|
|
195
|
+
should_use_count: int = Field(default=0, ge=0, description="Count of recommended rules")
|
|
196
|
+
avg_f1: float = Field(default=0.0, ge=0.0, le=1.0, description="Average F1 score")
|
|
197
|
+
min_f1: float = Field(default=0.0, ge=0.0, le=1.0, description="Minimum F1 score")
|
|
198
|
+
max_f1: float = Field(default=0.0, ge=0.0, le=1.0, description="Maximum F1 score")
|
|
199
|
+
avg_precision: float = Field(default=0.0, ge=0.0, le=1.0, description="Average precision")
|
|
200
|
+
avg_recall: float = Field(default=0.0, ge=0.0, le=1.0, description="Average recall")
|
|
201
|
+
avg_confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="Average confidence")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class QualityLevelDistribution(BaseSchema):
|
|
205
|
+
"""Distribution of quality levels."""
|
|
206
|
+
|
|
207
|
+
level: QualityLevel = Field(..., description="Quality level")
|
|
208
|
+
count: int = Field(..., ge=0, description="Number of rules at this level")
|
|
209
|
+
percentage: float = Field(..., ge=0.0, le=100.0, description="Percentage of total")
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# =============================================================================
|
|
213
|
+
# Request Schemas
|
|
214
|
+
# =============================================================================
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class QualityScoreRequest(BaseSchema):
|
|
218
|
+
"""Request to score validation rules."""
|
|
219
|
+
|
|
220
|
+
source_id: str | None = Field(default=None, description="Source ID to score rules for")
|
|
221
|
+
validation_id: str | None = Field(default=None, description="Validation ID to score")
|
|
222
|
+
rule_names: list[str] | None = Field(default=None, description="Specific rules to score (optional)")
|
|
223
|
+
sample_size: int = Field(default=10000, ge=100, le=1000000, description="Sample size for scoring")
|
|
224
|
+
thresholds: QualityThresholdsSchema | None = Field(default=None, description="Custom quality thresholds")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class QualityFilterRequest(BaseSchema):
|
|
228
|
+
"""Request to filter quality scores."""
|
|
229
|
+
|
|
230
|
+
min_level: QualityLevel | None = Field(default=None, description="Minimum quality level")
|
|
231
|
+
max_level: QualityLevel | None = Field(default=None, description="Maximum quality level")
|
|
232
|
+
min_f1: float | None = Field(default=None, ge=0.0, le=1.0, description="Minimum F1 score")
|
|
233
|
+
max_f1: float | None = Field(default=None, ge=0.0, le=1.0, description="Maximum F1 score")
|
|
234
|
+
min_confidence: float | None = Field(default=None, ge=0.0, le=1.0, description="Minimum confidence")
|
|
235
|
+
should_use_only: bool = Field(default=False, description="Only include recommended rules")
|
|
236
|
+
include_columns: list[str] | None = Field(default=None, description="Filter by specific columns")
|
|
237
|
+
exclude_columns: list[str] | None = Field(default=None, description="Exclude specific columns")
|
|
238
|
+
rule_types: list[str] | None = Field(default=None, description="Filter by rule types")
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class QualityReportConfigSchema(BaseSchema):
|
|
242
|
+
"""Configuration for quality report generation."""
|
|
243
|
+
|
|
244
|
+
title: str | None = Field(default=None, description="Report title")
|
|
245
|
+
description: str | None = Field(default=None, description="Report description")
|
|
246
|
+
|
|
247
|
+
# Content settings
|
|
248
|
+
include_metrics: bool = Field(default=True, description="Include detailed metrics")
|
|
249
|
+
include_confusion_matrix: bool = Field(default=False, description="Include confusion matrices")
|
|
250
|
+
include_recommendations: bool = Field(default=True, description="Include recommendations")
|
|
251
|
+
include_statistics: bool = Field(default=True, description="Include aggregate statistics")
|
|
252
|
+
include_summary: bool = Field(default=True, description="Include summary section")
|
|
253
|
+
include_charts: bool = Field(default=True, description="Include visual charts (HTML only)")
|
|
254
|
+
|
|
255
|
+
# Formatting
|
|
256
|
+
metric_precision: int = Field(default=2, ge=0, le=6, description="Decimal places for metrics")
|
|
257
|
+
percentage_format: bool = Field(default=True, description="Display as percentages")
|
|
258
|
+
|
|
259
|
+
# Display
|
|
260
|
+
sort_order: ReportSortOrder = Field(
|
|
261
|
+
default=ReportSortOrder.F1_DESC, description="Sort order for scores"
|
|
262
|
+
)
|
|
263
|
+
max_scores: int | None = Field(default=None, ge=1, description="Maximum scores to include")
|
|
264
|
+
|
|
265
|
+
# HTML-specific
|
|
266
|
+
theme: Literal["light", "dark", "professional"] = Field(
|
|
267
|
+
default="professional", description="Theme for HTML reports"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class QualityReportGenerateRequest(BaseSchema):
|
|
272
|
+
"""Request to generate a quality report."""
|
|
273
|
+
|
|
274
|
+
source_id: str | None = Field(default=None, description="Source ID for the report")
|
|
275
|
+
validation_id: str | None = Field(default=None, description="Validation ID for the report")
|
|
276
|
+
format: QualityReportFormat = Field(
|
|
277
|
+
default=QualityReportFormat.HTML, description="Report format"
|
|
278
|
+
)
|
|
279
|
+
config: QualityReportConfigSchema | None = Field(default=None, description="Report configuration")
|
|
280
|
+
filter: QualityFilterRequest | None = Field(default=None, description="Score filter")
|
|
281
|
+
score_rules: bool = Field(
|
|
282
|
+
default=True, description="Score rules before generating report"
|
|
283
|
+
)
|
|
284
|
+
sample_size: int = Field(default=10000, ge=100, le=1000000, description="Sample size for scoring")
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class QualityCompareRequest(BaseSchema):
|
|
288
|
+
"""Request to compare quality scores."""
|
|
289
|
+
|
|
290
|
+
score_ids: list[str] | None = Field(default=None, description="Score IDs to compare")
|
|
291
|
+
source_ids: list[str] | None = Field(default=None, description="Source IDs to compare")
|
|
292
|
+
sort_by: Literal["f1_score", "precision", "recall", "confidence"] = Field(
|
|
293
|
+
default="f1_score", description="Metric to sort by"
|
|
294
|
+
)
|
|
295
|
+
descending: bool = Field(default=True, description="Sort in descending order")
|
|
296
|
+
group_by: Literal["column", "level", "rule_type"] | None = Field(
|
|
297
|
+
default=None, description="Group results by"
|
|
298
|
+
)
|
|
299
|
+
max_results: int = Field(default=50, ge=1, le=500, description="Maximum results")
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
# =============================================================================
|
|
303
|
+
# Response Schemas
|
|
304
|
+
# =============================================================================
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class QualityScoreResponse(BaseSchema, IDMixin, TimestampMixin):
|
|
308
|
+
"""Response for a quality score."""
|
|
309
|
+
|
|
310
|
+
source_id: str = Field(..., description="Source ID")
|
|
311
|
+
source_name: str | None = Field(default=None, description="Source name")
|
|
312
|
+
validation_id: str | None = Field(default=None, description="Associated validation ID")
|
|
313
|
+
status: QualityReportStatus = Field(..., description="Score status")
|
|
314
|
+
scores: list[QualityScoreSchema] = Field(default_factory=list, description="Individual rule scores")
|
|
315
|
+
statistics: QualityStatisticsSchema | None = Field(default=None, description="Aggregate statistics")
|
|
316
|
+
level_distribution: list[QualityLevelDistribution] | None = Field(
|
|
317
|
+
default=None, description="Quality level distribution"
|
|
318
|
+
)
|
|
319
|
+
sample_size: int = Field(default=0, ge=0, description="Sample size used")
|
|
320
|
+
evaluation_time_ms: float = Field(default=0.0, ge=0.0, description="Total evaluation time")
|
|
321
|
+
error_message: str | None = Field(default=None, description="Error message if failed")
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class QualityReportResponse(BaseSchema, IDMixin, TimestampMixin):
|
|
325
|
+
"""Response for a generated quality report."""
|
|
326
|
+
|
|
327
|
+
source_id: str | None = Field(default=None, description="Source ID")
|
|
328
|
+
source_name: str | None = Field(default=None, description="Source name")
|
|
329
|
+
validation_id: str | None = Field(default=None, description="Validation ID")
|
|
330
|
+
format: QualityReportFormat = Field(..., description="Report format")
|
|
331
|
+
status: QualityReportStatus = Field(..., description="Report status")
|
|
332
|
+
filename: str | None = Field(default=None, description="Generated filename")
|
|
333
|
+
file_path: str | None = Field(default=None, description="File path")
|
|
334
|
+
file_size_bytes: int | None = Field(default=None, ge=0, description="File size in bytes")
|
|
335
|
+
content_type: str | None = Field(default=None, description="Content type")
|
|
336
|
+
generation_time_ms: float | None = Field(default=None, ge=0.0, description="Generation time")
|
|
337
|
+
scores_count: int = Field(default=0, ge=0, description="Number of scores in report")
|
|
338
|
+
statistics: QualityStatisticsSchema | None = Field(default=None, description="Report statistics")
|
|
339
|
+
error_message: str | None = Field(default=None, description="Error message if failed")
|
|
340
|
+
download_count: int = Field(default=0, ge=0, description="Number of downloads")
|
|
341
|
+
expires_at: datetime | None = Field(default=None, description="Expiration timestamp")
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class QualityCompareResponse(BaseSchema):
|
|
345
|
+
"""Response for quality comparison."""
|
|
346
|
+
|
|
347
|
+
scores: list[QualityScoreSchema] = Field(..., description="Compared scores")
|
|
348
|
+
ranked_by: str = Field(..., description="Metric used for ranking")
|
|
349
|
+
best_rule: QualityScoreSchema | None = Field(default=None, description="Best performing rule")
|
|
350
|
+
worst_rule: QualityScoreSchema | None = Field(default=None, description="Worst performing rule")
|
|
351
|
+
groups: dict[str, list[QualityScoreSchema]] | None = Field(
|
|
352
|
+
default=None, description="Grouped scores"
|
|
353
|
+
)
|
|
354
|
+
statistics: QualityStatisticsSchema | None = Field(default=None, description="Comparison statistics")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class QualitySummaryResponse(BaseSchema):
|
|
358
|
+
"""Summary response for quality scores."""
|
|
359
|
+
|
|
360
|
+
total_rules: int = Field(..., ge=0, description="Total rules scored")
|
|
361
|
+
statistics: QualityStatisticsSchema = Field(..., description="Quality statistics")
|
|
362
|
+
level_distribution: list[QualityLevelDistribution] = Field(
|
|
363
|
+
..., description="Level distribution"
|
|
364
|
+
)
|
|
365
|
+
recommendations: dict[str, int] = Field(
|
|
366
|
+
..., description="Recommendation counts (should_use, should_not_use)"
|
|
367
|
+
)
|
|
368
|
+
metric_averages: dict[str, dict[str, float]] = Field(
|
|
369
|
+
..., description="Metric averages (avg, min, max)"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
# =============================================================================
|
|
374
|
+
# List Response Types
|
|
375
|
+
# =============================================================================
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class QualityScoreListResponse(PaginatedResponse[QualityScoreResponse]):
|
|
379
|
+
"""Paginated list of quality scores."""
|
|
380
|
+
|
|
381
|
+
pass
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class QualityReportListResponse(PaginatedResponse[QualityReportResponse]):
|
|
385
|
+
"""Paginated list of quality reports."""
|
|
386
|
+
|
|
387
|
+
pass
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
# =============================================================================
|
|
391
|
+
# Available Formats Response
|
|
392
|
+
# =============================================================================
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class QualityFormatsResponse(BaseSchema):
|
|
396
|
+
"""Available quality report formats and options."""
|
|
397
|
+
|
|
398
|
+
formats: list[str] = Field(..., description="Available report formats")
|
|
399
|
+
sort_orders: list[str] = Field(..., description="Available sort orders")
|
|
400
|
+
themes: list[str] = Field(..., description="Available themes")
|
|
401
|
+
default_thresholds: QualityThresholdsSchema = Field(
|
|
402
|
+
..., description="Default quality thresholds"
|
|
403
|
+
)
|
|
@@ -14,7 +14,7 @@ from pydantic import Field
|
|
|
14
14
|
from .base import BaseSchema, IDMixin, ListResponseWrapper, TimestampMixin
|
|
15
15
|
|
|
16
16
|
# Report format types
|
|
17
|
-
ReportFormatType = Literal["html", "csv", "json", "
|
|
17
|
+
ReportFormatType = Literal["html", "csv", "json", "custom"]
|
|
18
18
|
|
|
19
19
|
# Report theme types
|
|
20
20
|
ReportThemeType = Literal["light", "dark", "professional", "minimal", "high_contrast"]
|
|
@@ -96,7 +96,7 @@ class AvailableFormatsResponse(BaseSchema):
|
|
|
96
96
|
formats: list[str] = Field(
|
|
97
97
|
...,
|
|
98
98
|
description="List of available format names",
|
|
99
|
-
examples=[["html", "csv", "json"
|
|
99
|
+
examples=[["html", "csv", "json"]],
|
|
100
100
|
)
|
|
101
101
|
themes: list[str] = Field(
|
|
102
102
|
...,
|
|
@@ -115,6 +115,10 @@ class CrossColumnRuleType(str, Enum):
|
|
|
115
115
|
class SuggestedRule(BaseSchema):
|
|
116
116
|
"""A single suggested validation rule."""
|
|
117
117
|
|
|
118
|
+
id: str = Field(
|
|
119
|
+
default_factory=lambda: str(__import__("uuid").uuid4()),
|
|
120
|
+
description="Unique identifier for the suggestion",
|
|
121
|
+
)
|
|
118
122
|
column: str = Field(..., description="Target column name (or primary column for multi-column rules)")
|
|
119
123
|
validator_name: str = Field(..., description="Validator to apply")
|
|
120
124
|
params: dict[str, Any] = Field(
|
|
@@ -153,7 +157,10 @@ class SuggestedRule(BaseSchema):
|
|
|
153
157
|
class CrossColumnRuleSuggestion(BaseSchema):
|
|
154
158
|
"""A suggested cross-column validation rule with detailed relationship info."""
|
|
155
159
|
|
|
156
|
-
id: str = Field(
|
|
160
|
+
id: str = Field(
|
|
161
|
+
default_factory=lambda: str(__import__("uuid").uuid4()),
|
|
162
|
+
description="Unique suggestion ID",
|
|
163
|
+
)
|
|
157
164
|
rule_type: CrossColumnRuleType = Field(..., description="Type of cross-column rule")
|
|
158
165
|
columns: list[str] = Field(..., description="Columns involved in the relationship")
|
|
159
166
|
validator_name: str = Field(..., description="Validator to apply")
|
|
@@ -50,32 +50,12 @@ PII_TYPES = [
|
|
|
50
50
|
class PIIScanRequest(BaseSchema):
|
|
51
51
|
"""Request to run PII scan on a data source.
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
Note: truthound's th.scan() does not support any configuration parameters.
|
|
54
|
+
The scan runs on all columns with default settings.
|
|
55
|
+
This schema is kept for API compatibility but options are not used.
|
|
55
56
|
"""
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
columns: list[str] | None = Field(
|
|
59
|
-
default=None,
|
|
60
|
-
description="Columns to scan. If None, all columns are scanned.",
|
|
61
|
-
examples=[["email", "phone", "ssn"]],
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
# Regulation compliance checking
|
|
65
|
-
regulations: list[RegulationLiteral] | None = Field(
|
|
66
|
-
default=None,
|
|
67
|
-
description="Privacy regulations to check compliance: gdpr, ccpa, lgpd",
|
|
68
|
-
examples=[["gdpr", "ccpa"]],
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
# Confidence threshold
|
|
72
|
-
min_confidence: float = Field(
|
|
73
|
-
default=0.8,
|
|
74
|
-
ge=0.0,
|
|
75
|
-
le=1.0,
|
|
76
|
-
description="Minimum confidence threshold for PII detection (0.0-1.0)",
|
|
77
|
-
examples=[0.8, 0.9],
|
|
78
|
-
)
|
|
58
|
+
pass
|
|
79
59
|
|
|
80
60
|
|
|
81
61
|
class PIIFinding(BaseSchema):
|
|
@@ -28,6 +28,8 @@ class ScheduleCreate(ScheduleBase):
|
|
|
28
28
|
"""Request body for creating a schedule."""
|
|
29
29
|
|
|
30
30
|
source_id: str = Field(..., description="Source ID to schedule")
|
|
31
|
+
trigger_type: str = Field("cron", description="Trigger type (cron, interval, data_change, composite, event, webhook, manual)")
|
|
32
|
+
trigger_config: dict[str, Any] | None = Field(None, description="Trigger-specific configuration")
|
|
31
33
|
config: dict[str, Any] | None = Field(
|
|
32
34
|
None,
|
|
33
35
|
description="Additional configuration (validators, schema_path, etc.)",
|
|
@@ -39,6 +41,8 @@ class ScheduleUpdate(BaseModel):
|
|
|
39
41
|
|
|
40
42
|
name: str | None = Field(None, min_length=1, max_length=255)
|
|
41
43
|
cron_expression: str | None = Field(None)
|
|
44
|
+
trigger_type: str | None = Field(None, description="Trigger type")
|
|
45
|
+
trigger_config: dict[str, Any] | None = Field(None, description="Trigger-specific configuration")
|
|
42
46
|
notify_on_failure: bool | None = Field(None)
|
|
43
47
|
config: dict[str, Any] | None = Field(None)
|
|
44
48
|
|
|
@@ -49,6 +53,8 @@ class ScheduleResponse(BaseModel, IDMixin, TimestampMixin):
|
|
|
49
53
|
name: str = Field(..., description="Schedule name")
|
|
50
54
|
source_id: str = Field(..., description="Source ID")
|
|
51
55
|
cron_expression: str = Field(..., description="Cron expression")
|
|
56
|
+
trigger_type: str = Field("cron", description="Trigger type")
|
|
57
|
+
trigger_config: dict[str, Any] | None = Field(None, description="Trigger-specific configuration")
|
|
52
58
|
is_active: bool = Field(..., description="Whether schedule is active")
|
|
53
59
|
notify_on_failure: bool = Field(..., description="Notify on failure")
|
|
54
60
|
last_run_at: str | None = Field(None, description="Last run timestamp (ISO)")
|
|
@@ -65,6 +71,8 @@ class ScheduleListItem(BaseModel, IDMixin, TimestampMixin):
|
|
|
65
71
|
name: str
|
|
66
72
|
source_id: str
|
|
67
73
|
cron_expression: str
|
|
74
|
+
trigger_type: str = "cron"
|
|
75
|
+
trigger_config: dict[str, Any] | None = None
|
|
68
76
|
is_active: bool
|
|
69
77
|
notify_on_failure: bool
|
|
70
78
|
last_run_at: str | None = None
|
|
@@ -73,16 +81,16 @@ class ScheduleListItem(BaseModel, IDMixin, TimestampMixin):
|
|
|
73
81
|
|
|
74
82
|
|
|
75
83
|
class ScheduleListResponse(BaseModel):
|
|
76
|
-
"""
|
|
84
|
+
"""Paginated list response for schedules."""
|
|
77
85
|
|
|
78
|
-
success: bool = True
|
|
79
86
|
data: list[ScheduleListItem] = Field(default_factory=list)
|
|
80
87
|
total: int = 0
|
|
88
|
+
offset: int = 0
|
|
89
|
+
limit: int = 100
|
|
81
90
|
|
|
82
91
|
|
|
83
92
|
class ScheduleActionResponse(BaseModel):
|
|
84
93
|
"""Response for schedule actions (pause, resume, run)."""
|
|
85
94
|
|
|
86
|
-
success: bool = True
|
|
87
95
|
message: str = Field(..., description="Action result message")
|
|
88
96
|
schedule: ScheduleResponse | None = Field(None, description="Updated schedule")
|