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
@@ -188,6 +188,8 @@ class BaseRepository(Generic[ModelT]):
188
188
  if instance is None:
189
189
  return False
190
190
 
191
+ # Refresh to load all relationships for proper cascade delete
192
+ await self.session.refresh(instance)
191
193
  await self.session.delete(instance)
192
194
  await self.session.flush()
193
195
  return True
@@ -108,6 +108,13 @@ async def lifespan(_app: FastAPI) -> AsyncGenerator[None, None]:
108
108
  await ws_manager.start()
109
109
  logger.info("WebSocket manager started")
110
110
 
111
+ # Start streaming session cleanup
112
+ from truthound_dashboard.core.streaming_anomaly import get_streaming_detector
113
+
114
+ streaming_detector = get_streaming_detector()
115
+ await streaming_detector.start()
116
+ logger.info("Streaming session cleanup started")
117
+
111
118
  # Register maintenance tasks with scheduler
112
119
  _register_maintenance_tasks()
113
120
 
@@ -116,6 +123,10 @@ async def lifespan(_app: FastAPI) -> AsyncGenerator[None, None]:
116
123
  # Shutdown
117
124
  logger.info("Shutting down Truthound Dashboard")
118
125
 
126
+ # Stop streaming session cleanup
127
+ await streaming_detector.stop()
128
+ logger.info("Streaming session cleanup stopped")
129
+
119
130
  # Stop WebSocket manager
120
131
  await ws_manager.stop()
121
132
  logger.info("WebSocket manager stopped")
@@ -20,8 +20,6 @@ from .base import (
20
20
  )
21
21
  from .drift import (
22
22
  ColumnDriftResult,
23
- CorrectionMethod,
24
- CorrectionMethodLiteral,
25
23
  DEFAULT_THRESHOLDS,
26
24
  DriftCompareRequest,
27
25
  DriftComparisonListItem,
@@ -45,14 +43,9 @@ from .profile import (
45
43
  ColumnProfile,
46
44
  DetectedPattern,
47
45
  HistogramBucket,
48
- PatternDetectionConfig,
49
- PatternType,
46
+ ProfileAdvancedRequest,
50
47
  ProfileRequest,
51
48
  ProfileResponse,
52
- SamplingConfig,
53
- SamplingMetadata,
54
- SamplingStrategy,
55
- SamplingStrategyType,
56
49
  )
57
50
  from .rule import (
58
51
  RuleBase,
@@ -375,6 +368,97 @@ from .plugins import (
375
368
  ValidatorTestRequest,
376
369
  ValidatorTestResponse,
377
370
  )
371
+ # Storage Tiering (truthound 1.2.10+)
372
+ from .tiering import (
373
+ AccessBasedPolicyConfig,
374
+ AgeBasedPolicyConfig,
375
+ CompositePolicyConfig,
376
+ CustomPolicyConfig,
377
+ MigrationDirection,
378
+ MigrationHistoryCreate,
379
+ MigrationHistoryListResponse,
380
+ MigrationHistoryResponse,
381
+ MigrationStatus,
382
+ PolicyConfigBase,
383
+ PolicyTypeInfo,
384
+ PolicyTypesResponse,
385
+ ScheduledPolicyConfig,
386
+ SizeBasedPolicyConfig,
387
+ StorageTierBase,
388
+ StorageTierCreate,
389
+ StorageTierListResponse,
390
+ StorageTierResponse,
391
+ StorageTierUpdate,
392
+ TierPolicyBase,
393
+ TierPolicyCreate,
394
+ TierPolicyListResponse,
395
+ TierPolicyResponse,
396
+ TierPolicyType,
397
+ TierPolicyUpdate,
398
+ TierPolicyWithChildren,
399
+ TierStatistics,
400
+ TierType,
401
+ TieringConfigBase,
402
+ TieringConfigCreate,
403
+ TieringConfigListResponse,
404
+ TieringConfigResponse,
405
+ TieringConfigUpdate,
406
+ TieringStatistics,
407
+ )
408
+ # Quality Reporter
409
+ from .quality_reporter import (
410
+ ChartType,
411
+ ConfusionMatrixSchema,
412
+ QualityCompareRequest,
413
+ QualityCompareResponse,
414
+ QualityDisplayMode,
415
+ QualityFilterRequest,
416
+ QualityFormatsResponse,
417
+ QualityLevel,
418
+ QualityLevelDistribution,
419
+ QualityMetricsSchema,
420
+ QualityReportConfigSchema,
421
+ QualityReportFormat,
422
+ QualityReportGenerateRequest,
423
+ QualityReportListResponse,
424
+ QualityReportResponse,
425
+ QualityReportStatus,
426
+ QualityScoreListResponse,
427
+ QualityScoreRequest,
428
+ QualityScoreResponse,
429
+ QualityScoreSchema,
430
+ QualityStatisticsSchema,
431
+ QualitySummaryResponse,
432
+ QualityThresholdsSchema,
433
+ ReportSortOrder,
434
+ )
435
+ # Observability (truthound store observability)
436
+ from .observability import (
437
+ AuditEventListResponse,
438
+ AuditEventResponse,
439
+ AuditEventTypeEnum,
440
+ AuditQueryRequest,
441
+ AuditStatsResponse,
442
+ AuditStatusEnum,
443
+ HistogramValue,
444
+ MetricsResponse,
445
+ MetricTypeEnum,
446
+ MetricValue,
447
+ ObservabilityConfigRequest,
448
+ ObservabilityConfigResponse,
449
+ ObservabilityStatsResponse,
450
+ SpanContext,
451
+ SpanEvent,
452
+ SpanKindEnum,
453
+ SpanListResponse,
454
+ SpanResponse,
455
+ SpanStatusEnum,
456
+ StoreMetricsResponse,
457
+ SummaryQuantile,
458
+ SummaryValue,
459
+ TraceResponse,
460
+ TracingStatsResponse,
461
+ )
378
462
 
379
463
  __all__ = [
380
464
  # Base
@@ -432,12 +516,6 @@ __all__ = [
432
516
  "ProfileResponse",
433
517
  "DetectedPattern",
434
518
  "HistogramBucket",
435
- "PatternDetectionConfig",
436
- "PatternType",
437
- "SamplingConfig",
438
- "SamplingMetadata",
439
- "SamplingStrategy",
440
- "SamplingStrategyType",
441
519
  # Data Masking
442
520
  "MaskingStrategy",
443
521
  "MaskingStrategyLiteral",
@@ -466,8 +544,6 @@ __all__ = [
466
544
  # Drift
467
545
  "DriftMethod",
468
546
  "DriftMethodLiteral",
469
- "CorrectionMethod",
470
- "CorrectionMethodLiteral",
471
547
  "DEFAULT_THRESHOLDS",
472
548
  "get_default_threshold",
473
549
  "DriftCompareRequest",
@@ -707,4 +783,89 @@ __all__ = [
707
783
  "ReporterGenerateResponse",
708
784
  "MarketplaceSearchRequest",
709
785
  "MarketplaceStats",
786
+ # Storage Tiering (truthound 1.2.10+)
787
+ "TierType",
788
+ "MigrationDirection",
789
+ "TierPolicyType",
790
+ "MigrationStatus",
791
+ "StorageTierBase",
792
+ "StorageTierCreate",
793
+ "StorageTierUpdate",
794
+ "StorageTierResponse",
795
+ "StorageTierListResponse",
796
+ "PolicyConfigBase",
797
+ "AgeBasedPolicyConfig",
798
+ "AccessBasedPolicyConfig",
799
+ "SizeBasedPolicyConfig",
800
+ "ScheduledPolicyConfig",
801
+ "CompositePolicyConfig",
802
+ "CustomPolicyConfig",
803
+ "TierPolicyBase",
804
+ "TierPolicyCreate",
805
+ "TierPolicyUpdate",
806
+ "TierPolicyResponse",
807
+ "TierPolicyListResponse",
808
+ "TierPolicyWithChildren",
809
+ "TieringConfigBase",
810
+ "TieringConfigCreate",
811
+ "TieringConfigUpdate",
812
+ "TieringConfigResponse",
813
+ "TieringConfigListResponse",
814
+ "MigrationHistoryCreate",
815
+ "MigrationHistoryResponse",
816
+ "MigrationHistoryListResponse",
817
+ "TierStatistics",
818
+ "TieringStatistics",
819
+ "PolicyTypeInfo",
820
+ "PolicyTypesResponse",
821
+ # Quality Reporter
822
+ "QualityLevel",
823
+ "QualityReportFormat",
824
+ "QualityReportStatus",
825
+ "QualityDisplayMode",
826
+ "ReportSortOrder",
827
+ "ChartType",
828
+ "ConfusionMatrixSchema",
829
+ "QualityMetricsSchema",
830
+ "QualityThresholdsSchema",
831
+ "QualityScoreSchema",
832
+ "QualityStatisticsSchema",
833
+ "QualityLevelDistribution",
834
+ "QualityScoreRequest",
835
+ "QualityFilterRequest",
836
+ "QualityReportConfigSchema",
837
+ "QualityReportGenerateRequest",
838
+ "QualityCompareRequest",
839
+ "QualityScoreResponse",
840
+ "QualityReportResponse",
841
+ "QualityCompareResponse",
842
+ "QualitySummaryResponse",
843
+ "QualityScoreListResponse",
844
+ "QualityReportListResponse",
845
+ "QualityFormatsResponse",
846
+ # Observability (truthound store observability)
847
+ "AuditEventTypeEnum",
848
+ "AuditStatusEnum",
849
+ "MetricTypeEnum",
850
+ "SpanKindEnum",
851
+ "SpanStatusEnum",
852
+ "ObservabilityConfigRequest",
853
+ "ObservabilityConfigResponse",
854
+ "AuditEventResponse",
855
+ "AuditEventListResponse",
856
+ "AuditQueryRequest",
857
+ "AuditStatsResponse",
858
+ "MetricValue",
859
+ "HistogramValue",
860
+ "SummaryQuantile",
861
+ "SummaryValue",
862
+ "MetricsResponse",
863
+ "StoreMetricsResponse",
864
+ "SpanContext",
865
+ "SpanEvent",
866
+ "SpanResponse",
867
+ "SpanListResponse",
868
+ "TraceResponse",
869
+ "TracingStatsResponse",
870
+ "ObservabilityStatsResponse",
710
871
  ]
@@ -3,12 +3,18 @@
3
3
  This module provides reusable base classes and mixins for Pydantic schemas,
4
4
  enabling consistent patterns across all API schemas.
5
5
 
6
+ Design Philosophy - Direct Response Style:
7
+ - Single resources return the resource directly (no wrapper)
8
+ - List endpoints return PaginatedResponse[T] with data, total, offset, limit
9
+ - Errors are handled via HTTPException (FastAPI converts to proper JSON)
10
+ - Success is indicated by HTTP status codes (200, 201, 204), not response fields
11
+
6
12
  The schema classes follow a consistent naming convention:
7
13
  - *Base: Common fields shared by create/update/response
8
14
  - *Create: Fields for creation (POST)
9
15
  - *Update: Fields for updates (PUT/PATCH)
10
16
  - *Response: Fields returned in responses
11
- - *ListResponse: Paginated list response wrapper
17
+ - *ListResponse: Alias for PaginatedResponse[*Response]
12
18
  """
13
19
 
14
20
  from __future__ import annotations
@@ -49,28 +55,20 @@ class IDMixin:
49
55
  id: str = Field(..., description="Unique identifier")
50
56
 
51
57
 
52
- class ResponseWrapper(BaseSchema, Generic[T]):
53
- """Generic wrapper for single item responses.
54
-
55
- Provides consistent structure for API responses.
56
- """
57
-
58
- success: bool = Field(default=True, description="Whether request succeeded")
59
- data: T = Field(..., description="Response data")
60
- message: str | None = Field(default=None, description="Optional message")
58
+ class PaginatedResponse(BaseSchema, Generic[T]):
59
+ """Generic paginated list response.
61
60
 
61
+ RESTful design - no 'success' field. HTTP status codes indicate success/failure.
62
62
 
63
- # Alias for backward compatibility with newer code
64
- DataResponse = ResponseWrapper
65
-
66
-
67
- class ListResponseWrapper(BaseSchema, Generic[T]):
68
- """Generic wrapper for list responses with pagination.
69
-
70
- Provides consistent structure for paginated API responses.
63
+ Example response:
64
+ {
65
+ "data": [...],
66
+ "total": 100,
67
+ "offset": 0,
68
+ "limit": 20
69
+ }
71
70
  """
72
71
 
73
- success: bool = Field(default=True, description="Whether request succeeded")
74
72
  data: list[T] = Field(default_factory=list, description="List of items")
75
73
  total: int = Field(default=0, description="Total count of items")
76
74
  offset: int = Field(default=0, description="Offset for pagination")
@@ -82,10 +80,34 @@ class ListResponseWrapper(BaseSchema, Generic[T]):
82
80
  return self.offset + len(self.data) < self.total
83
81
 
84
82
 
83
+ # Backward compatibility aliases
84
+ ListResponseWrapper = PaginatedResponse
85
+ """@deprecated Use PaginatedResponse instead."""
86
+
87
+
88
+ class ResponseWrapper(BaseSchema, Generic[T]):
89
+ """@deprecated - For backward compatibility only.
90
+
91
+ New code should return resources directly without wrapper.
92
+ """
93
+
94
+ success: bool = Field(default=True, description="Whether request succeeded")
95
+ data: T = Field(..., description="Response data")
96
+ message: str | None = Field(default=None, description="Optional message")
97
+
98
+
99
+ # Alias for backward compatibility
100
+ DataResponse = ResponseWrapper
101
+ """@deprecated Use direct response instead."""
102
+
103
+
85
104
  class ErrorResponse(BaseSchema):
86
- """Standard error response schema."""
105
+ """Standard error response schema.
106
+
107
+ Note: In most cases, use HTTPException instead. This schema is for
108
+ documentation purposes and complex error responses.
109
+ """
87
110
 
88
- success: bool = Field(default=False)
89
111
  detail: str = Field(..., description="Error description")
90
112
  code: str | None = Field(default=None, description="Error code")
91
113
  errors: list[dict[str, Any]] | None = Field(
@@ -94,7 +116,6 @@ class ErrorResponse(BaseSchema):
94
116
 
95
117
 
96
118
  class MessageResponse(BaseSchema):
97
- """Simple message response schema."""
119
+ """Simple message response schema for delete/action endpoints."""
98
120
 
99
- success: bool = Field(default=True)
100
121
  message: str = Field(..., description="Response message")
@@ -89,11 +89,24 @@ class CommentResponse(BaseSchema, IDMixin, TimestampMixin):
89
89
  def from_model(cls, comment: any, include_replies: bool = True) -> CommentResponse:
90
90
  """Create response from model."""
91
91
  replies = []
92
- if include_replies and comment.replies:
93
- replies = [
94
- CommentResponse.from_model(r, include_replies=False)
95
- for r in comment.replies
96
- ]
92
+ reply_count = 0
93
+
94
+ if include_replies:
95
+ # Access replies if loaded (include_replies=True means we're a parent)
96
+ try:
97
+ loaded_replies = comment.replies
98
+ replies = [
99
+ CommentResponse.from_model(r, include_replies=False)
100
+ for r in loaded_replies
101
+ ]
102
+ reply_count = len(loaded_replies)
103
+ except Exception:
104
+ # If replies not loaded, use 0
105
+ reply_count = 0
106
+ else:
107
+ # For nested replies, avoid lazy loading - just use 0
108
+ # Nested reply counts aren't typically needed in UI
109
+ reply_count = 0
97
110
 
98
111
  return cls(
99
112
  id=comment.id,
@@ -103,7 +116,7 @@ class CommentResponse(BaseSchema, IDMixin, TimestampMixin):
103
116
  author_id=comment.author_id,
104
117
  parent_id=comment.parent_id,
105
118
  is_reply=comment.is_reply,
106
- reply_count=comment.reply_count,
119
+ reply_count=reply_count,
107
120
  replies=replies,
108
121
  created_at=comment.created_at,
109
122
  updated_at=comment.updated_at,
@@ -2,6 +2,12 @@
2
2
 
3
3
  This module defines schemas for cross-feature integration between
4
4
  Anomaly Detection and Drift Monitoring alerts.
5
+
6
+ API Design: Direct Response Style
7
+ - Single resources return the resource directly
8
+ - List endpoints return PaginatedResponse with data, total, offset, limit
9
+ - Errors are handled via HTTPException
10
+ - Success is indicated by HTTP status codes (200, 201, 204)
5
11
  """
6
12
 
7
13
  from __future__ import annotations
@@ -11,7 +17,7 @@ from typing import Literal
11
17
 
12
18
  from pydantic import Field
13
19
 
14
- from .base import BaseSchema, IDMixin, TimestampMixin, ListResponseWrapper
20
+ from .base import BaseSchema, IDMixin, TimestampMixin, PaginatedResponse
15
21
 
16
22
 
17
23
  # =============================================================================
@@ -105,12 +111,22 @@ class CrossAlertCorrelation(IDMixin, TimestampMixin, BaseSchema):
105
111
  )
106
112
 
107
113
 
108
- class CrossAlertCorrelationListResponse(ListResponseWrapper[CrossAlertCorrelation]):
114
+ class CrossAlertCorrelationListResponse(PaginatedResponse[CrossAlertCorrelation]):
109
115
  """Paginated list of cross-alert correlations."""
110
116
 
111
117
  pass
112
118
 
113
119
 
120
+ class CorrelationSearchResult(BaseSchema):
121
+ """Result of a correlation search for a specific source."""
122
+
123
+ correlations: list[CrossAlertCorrelation] = Field(
124
+ default_factory=list,
125
+ description="Found correlations",
126
+ )
127
+ total: int = Field(default=0, description="Total correlations found")
128
+
129
+
114
130
  # =============================================================================
115
131
  # Auto-Trigger Configuration Schemas
116
132
  # =============================================================================
@@ -272,7 +288,7 @@ class AutoTriggerEvent(IDMixin, TimestampMixin, BaseSchema):
272
288
  )
273
289
 
274
290
 
275
- class AutoTriggerEventListResponse(ListResponseWrapper[AutoTriggerEvent]):
291
+ class AutoTriggerEventListResponse(PaginatedResponse[AutoTriggerEvent]):
276
292
  """Paginated list of auto-trigger events."""
277
293
 
278
294
  pass
@@ -2,20 +2,27 @@
2
2
 
3
3
  Schemas for drift comparison request/response.
4
4
 
5
- Drift Methods (from truthound):
6
- - ks: Kolmogorov-Smirnov test (continuous distributions)
7
- - psi: Population Stability Index (any distribution, industry standard)
8
- - chi2: Chi-Square test (categorical data)
9
- - js: Jensen-Shannon divergence (probability distributions)
10
- - kl: Kullback-Leibler divergence (distribution difference)
11
- - wasserstein: Wasserstein/Earth Mover's Distance (distribution transport)
12
- - cvm: Cramér-von Mises test (more sensitive to tails than KS)
13
- - anderson: Anderson-Darling test (weighted for tail sensitivity)
14
-
15
- Multiple Testing Correction:
16
- - bonferroni: Conservative, independent tests
17
- - holm: Sequential adjustment, less conservative
18
- - bh: Benjamini-Hochberg (FDR control, default for multiple columns)
5
+ Drift Methods (14 supported by th.compare() in truthound v1.2.9+):
6
+
7
+ General purpose (any column type):
8
+ - auto: Smart selection (numeric → PSI, categorical → chi2) [RECOMMENDED]
9
+ - js: Jensen-Shannon divergence (symmetric, bounded 0-1)
10
+ - hellinger: Hellinger distance (bounded metric, 0-1)
11
+ - bhattacharyya: Bhattacharyya distance (classification error bounds)
12
+ - tv: Total Variation distance (max probability difference)
13
+
14
+ Numeric columns only:
15
+ - ks: Kolmogorov-Smirnov test
16
+ - psi: Population Stability Index (industry standard)
17
+ - kl: Kullback-Leibler divergence (asymmetric)
18
+ - wasserstein: Wasserstein/Earth Mover's Distance
19
+ - cvm: Cramér-von Mises test (tail sensitive)
20
+ - anderson: Anderson-Darling test (most tail sensitive)
21
+ - energy: Energy distance (location/scale sensitive)
22
+ - mmd: Maximum Mean Discrepancy (kernel-based, high-dimensional)
23
+
24
+ Categorical columns:
25
+ - chi2: Chi-Square test
19
26
  """
20
27
 
21
28
  from __future__ import annotations
@@ -29,18 +36,29 @@ from .base import IDMixin, TimestampMixin
29
36
 
30
37
 
31
38
  class DriftMethod(str, Enum):
32
- """Drift detection methods supported by truthound.
39
+ """Drift detection methods supported by truthound v1.2.9+.
33
40
 
34
- Each method has different characteristics and use cases:
41
+ All 14 methods are fully supported by th.compare():
42
+
43
+ General purpose (any column type):
35
44
  - auto: Smart selection based on data type (numeric → PSI, categorical → chi2)
36
- - ks: Kolmogorov-Smirnov test - best for continuous distributions
37
- - psi: Population Stability Index - industry standard, any distribution
38
- - chi2: Chi-Square test - best for categorical data
39
45
  - js: Jensen-Shannon divergence - symmetric, bounded (0-1)
40
- - kl: Kullback-Leibler divergence - information loss measure
41
- - wasserstein: Earth Mover's Distance - metric, meaningful for non-overlapping
42
- - cvm: Cramér-von Mises - more sensitive to tail differences than KS
43
- - anderson: Anderson-Darling - weighted for tail sensitivity
46
+ - hellinger: Hellinger distance - bounded metric (0-1), triangle inequality
47
+ - bhattacharyya: Bhattacharyya distance - classification error bounds
48
+ - tv: Total Variation distance - max probability difference
49
+
50
+ Numeric columns only:
51
+ - ks: Kolmogorov-Smirnov test - detects any distribution shape difference
52
+ - psi: Population Stability Index - industry standard for model monitoring
53
+ - kl: Kullback-Leibler divergence - measures information loss (asymmetric)
54
+ - wasserstein: Earth Mover's Distance - intuitive physical interpretation
55
+ - cvm: Cramér-von Mises - more sensitive to tails than KS
56
+ - anderson: Anderson-Darling - most sensitive to tail differences
57
+ - energy: Energy distance - location/scale sensitive
58
+ - mmd: Maximum Mean Discrepancy - kernel-based, high-dimensional
59
+
60
+ Categorical columns:
61
+ - chi2: Chi-Square test - best for categorical data
44
62
  """
45
63
 
46
64
  AUTO = "auto"
@@ -52,23 +70,12 @@ class DriftMethod(str, Enum):
52
70
  WASSERSTEIN = "wasserstein"
53
71
  CVM = "cvm"
54
72
  ANDERSON = "anderson"
55
-
56
-
57
- class CorrectionMethod(str, Enum):
58
- """Multiple testing correction methods.
59
-
60
- When comparing multiple columns, correction adjusts p-values to control
61
- false discovery rate:
62
- - none: No correction (use with caution)
63
- - bonferroni: Conservative, suitable for independent tests
64
- - holm: Sequential adjustment, less conservative than Bonferroni
65
- - bh: Benjamini-Hochberg (FDR control), default for multiple columns
66
- """
67
-
68
- NONE = "none"
69
- BONFERRONI = "bonferroni"
70
- HOLM = "holm"
71
- BH = "bh"
73
+ # New in v1.2.9
74
+ HELLINGER = "hellinger"
75
+ BHATTACHARYYA = "bhattacharyya"
76
+ TV = "tv"
77
+ ENERGY = "energy"
78
+ MMD = "mmd"
72
79
 
73
80
 
74
81
  # Default thresholds for each detection method
@@ -82,6 +89,12 @@ DEFAULT_THRESHOLDS: dict[DriftMethod, float] = {
82
89
  DriftMethod.WASSERSTEIN: 0.1, # Scale-dependent, adjust based on data
83
90
  DriftMethod.CVM: 0.05,
84
91
  DriftMethod.ANDERSON: 0.05,
92
+ # New in v1.2.9
93
+ DriftMethod.HELLINGER: 0.1,
94
+ DriftMethod.BHATTACHARYYA: 0.1,
95
+ DriftMethod.TV: 0.1,
96
+ DriftMethod.ENERGY: 0.1,
97
+ DriftMethod.MMD: 0.1,
85
98
  }
86
99
 
87
100
 
@@ -104,9 +117,9 @@ def get_default_threshold(method: DriftMethod | str) -> float:
104
117
 
105
118
  # Type alias for method values (for Literal type hints)
106
119
  DriftMethodLiteral = Literal[
107
- "auto", "ks", "psi", "chi2", "js", "kl", "wasserstein", "cvm", "anderson"
120
+ "auto", "ks", "psi", "chi2", "js", "kl", "wasserstein", "cvm", "anderson",
121
+ "hellinger", "bhattacharyya", "tv", "energy", "mmd"
108
122
  ]
109
- CorrectionMethodLiteral = Literal["none", "bonferroni", "holm", "bh"]
110
123
 
111
124
 
112
125
  class DriftCompareRequest(BaseModel):
@@ -120,10 +133,9 @@ class DriftCompareRequest(BaseModel):
120
133
  method: DriftMethodLiteral = Field(
121
134
  "auto",
122
135
  description=(
123
- "Drift detection method: "
124
- "auto (smart selection), ks (Kolmogorov-Smirnov), psi (Population Stability Index), "
125
- "chi2 (Chi-Square), js (Jensen-Shannon), kl (Kullback-Leibler), "
126
- "wasserstein (Earth Mover's), cvm (Cramér-von Mises), anderson (Anderson-Darling)"
136
+ "Drift detection method (14 available): "
137
+ "auto (smart selection), ks, psi, chi2, js, kl, wasserstein, cvm, anderson, "
138
+ "hellinger, bhattacharyya, tv, energy, mmd"
127
139
  ),
128
140
  )
129
141
  threshold: float | None = Field(
@@ -132,13 +144,6 @@ class DriftCompareRequest(BaseModel):
132
144
  le=1,
133
145
  description="Custom threshold (default varies by method: KS/chi2/cvm/anderson=0.05, PSI/JS/KL/wasserstein=0.1)",
134
146
  )
135
- correction: CorrectionMethodLiteral | None = Field(
136
- None,
137
- description=(
138
- "Multiple testing correction: none, bonferroni (conservative), "
139
- "holm (sequential), bh (Benjamini-Hochberg FDR, default for multiple columns)"
140
- ),
141
- )
142
147
  sample_size: int | None = Field(
143
148
  None, ge=100, description="Sample size for large datasets"
144
149
  )
@@ -226,8 +231,9 @@ class DriftComparisonListItem(BaseModel, IDMixin, TimestampMixin):
226
231
 
227
232
 
228
233
  class DriftComparisonListResponse(BaseModel):
229
- """List response for drift comparisons."""
234
+ """Paginated list response for drift comparisons."""
230
235
 
231
- success: bool = True
232
236
  data: list[DriftComparisonListItem] = Field(default_factory=list)
233
237
  total: int = 0
238
+ offset: int = 0
239
+ limit: int = 100