truthound 1.0.8__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 (877) hide show
  1. truthound/__init__.py +162 -0
  2. truthound/adapters.py +100 -0
  3. truthound/api.py +365 -0
  4. truthound/audit/__init__.py +248 -0
  5. truthound/audit/core.py +967 -0
  6. truthound/audit/filters.py +620 -0
  7. truthound/audit/formatters.py +707 -0
  8. truthound/audit/logger.py +902 -0
  9. truthound/audit/middleware.py +571 -0
  10. truthound/audit/storage.py +1083 -0
  11. truthound/benchmark/__init__.py +123 -0
  12. truthound/benchmark/base.py +757 -0
  13. truthound/benchmark/comparison.py +635 -0
  14. truthound/benchmark/generators.py +706 -0
  15. truthound/benchmark/reporters.py +718 -0
  16. truthound/benchmark/runner.py +635 -0
  17. truthound/benchmark/scenarios.py +712 -0
  18. truthound/cache.py +252 -0
  19. truthound/checkpoint/__init__.py +136 -0
  20. truthound/checkpoint/actions/__init__.py +164 -0
  21. truthound/checkpoint/actions/base.py +324 -0
  22. truthound/checkpoint/actions/custom.py +234 -0
  23. truthound/checkpoint/actions/discord_notify.py +290 -0
  24. truthound/checkpoint/actions/email_notify.py +405 -0
  25. truthound/checkpoint/actions/github_action.py +406 -0
  26. truthound/checkpoint/actions/opsgenie.py +1499 -0
  27. truthound/checkpoint/actions/pagerduty.py +226 -0
  28. truthound/checkpoint/actions/slack_notify.py +233 -0
  29. truthound/checkpoint/actions/store_result.py +249 -0
  30. truthound/checkpoint/actions/teams_notify.py +1570 -0
  31. truthound/checkpoint/actions/telegram_notify.py +419 -0
  32. truthound/checkpoint/actions/update_docs.py +552 -0
  33. truthound/checkpoint/actions/webhook.py +293 -0
  34. truthound/checkpoint/analytics/__init__.py +147 -0
  35. truthound/checkpoint/analytics/aggregations/__init__.py +23 -0
  36. truthound/checkpoint/analytics/aggregations/rollup.py +481 -0
  37. truthound/checkpoint/analytics/aggregations/time_bucket.py +306 -0
  38. truthound/checkpoint/analytics/analyzers/__init__.py +17 -0
  39. truthound/checkpoint/analytics/analyzers/anomaly.py +386 -0
  40. truthound/checkpoint/analytics/analyzers/base.py +270 -0
  41. truthound/checkpoint/analytics/analyzers/forecast.py +421 -0
  42. truthound/checkpoint/analytics/analyzers/trend.py +314 -0
  43. truthound/checkpoint/analytics/models.py +292 -0
  44. truthound/checkpoint/analytics/protocols.py +549 -0
  45. truthound/checkpoint/analytics/service.py +718 -0
  46. truthound/checkpoint/analytics/stores/__init__.py +16 -0
  47. truthound/checkpoint/analytics/stores/base.py +306 -0
  48. truthound/checkpoint/analytics/stores/memory_store.py +353 -0
  49. truthound/checkpoint/analytics/stores/sqlite_store.py +557 -0
  50. truthound/checkpoint/analytics/stores/timescale_store.py +501 -0
  51. truthound/checkpoint/async_actions.py +794 -0
  52. truthound/checkpoint/async_base.py +708 -0
  53. truthound/checkpoint/async_checkpoint.py +617 -0
  54. truthound/checkpoint/async_runner.py +639 -0
  55. truthound/checkpoint/checkpoint.py +527 -0
  56. truthound/checkpoint/ci/__init__.py +61 -0
  57. truthound/checkpoint/ci/detector.py +355 -0
  58. truthound/checkpoint/ci/reporter.py +436 -0
  59. truthound/checkpoint/ci/templates.py +454 -0
  60. truthound/checkpoint/circuitbreaker/__init__.py +133 -0
  61. truthound/checkpoint/circuitbreaker/breaker.py +542 -0
  62. truthound/checkpoint/circuitbreaker/core.py +252 -0
  63. truthound/checkpoint/circuitbreaker/detection.py +459 -0
  64. truthound/checkpoint/circuitbreaker/middleware.py +389 -0
  65. truthound/checkpoint/circuitbreaker/registry.py +357 -0
  66. truthound/checkpoint/distributed/__init__.py +139 -0
  67. truthound/checkpoint/distributed/backends/__init__.py +35 -0
  68. truthound/checkpoint/distributed/backends/celery_backend.py +503 -0
  69. truthound/checkpoint/distributed/backends/kubernetes_backend.py +696 -0
  70. truthound/checkpoint/distributed/backends/local_backend.py +397 -0
  71. truthound/checkpoint/distributed/backends/ray_backend.py +625 -0
  72. truthound/checkpoint/distributed/base.py +774 -0
  73. truthound/checkpoint/distributed/orchestrator.py +765 -0
  74. truthound/checkpoint/distributed/protocols.py +842 -0
  75. truthound/checkpoint/distributed/registry.py +449 -0
  76. truthound/checkpoint/idempotency/__init__.py +120 -0
  77. truthound/checkpoint/idempotency/core.py +295 -0
  78. truthound/checkpoint/idempotency/fingerprint.py +454 -0
  79. truthound/checkpoint/idempotency/locking.py +604 -0
  80. truthound/checkpoint/idempotency/service.py +592 -0
  81. truthound/checkpoint/idempotency/stores.py +653 -0
  82. truthound/checkpoint/monitoring/__init__.py +134 -0
  83. truthound/checkpoint/monitoring/aggregators/__init__.py +15 -0
  84. truthound/checkpoint/monitoring/aggregators/base.py +372 -0
  85. truthound/checkpoint/monitoring/aggregators/realtime.py +300 -0
  86. truthound/checkpoint/monitoring/aggregators/window.py +493 -0
  87. truthound/checkpoint/monitoring/collectors/__init__.py +17 -0
  88. truthound/checkpoint/monitoring/collectors/base.py +257 -0
  89. truthound/checkpoint/monitoring/collectors/memory_collector.py +617 -0
  90. truthound/checkpoint/monitoring/collectors/prometheus_collector.py +451 -0
  91. truthound/checkpoint/monitoring/collectors/redis_collector.py +518 -0
  92. truthound/checkpoint/monitoring/events.py +410 -0
  93. truthound/checkpoint/monitoring/protocols.py +636 -0
  94. truthound/checkpoint/monitoring/service.py +578 -0
  95. truthound/checkpoint/monitoring/views/__init__.py +17 -0
  96. truthound/checkpoint/monitoring/views/base.py +172 -0
  97. truthound/checkpoint/monitoring/views/queue_view.py +220 -0
  98. truthound/checkpoint/monitoring/views/task_view.py +240 -0
  99. truthound/checkpoint/monitoring/views/worker_view.py +263 -0
  100. truthound/checkpoint/registry.py +337 -0
  101. truthound/checkpoint/runner.py +356 -0
  102. truthound/checkpoint/transaction/__init__.py +133 -0
  103. truthound/checkpoint/transaction/base.py +389 -0
  104. truthound/checkpoint/transaction/compensatable.py +537 -0
  105. truthound/checkpoint/transaction/coordinator.py +576 -0
  106. truthound/checkpoint/transaction/executor.py +622 -0
  107. truthound/checkpoint/transaction/idempotency.py +534 -0
  108. truthound/checkpoint/transaction/saga/__init__.py +143 -0
  109. truthound/checkpoint/transaction/saga/builder.py +584 -0
  110. truthound/checkpoint/transaction/saga/definition.py +515 -0
  111. truthound/checkpoint/transaction/saga/event_store.py +542 -0
  112. truthound/checkpoint/transaction/saga/patterns.py +833 -0
  113. truthound/checkpoint/transaction/saga/runner.py +718 -0
  114. truthound/checkpoint/transaction/saga/state_machine.py +793 -0
  115. truthound/checkpoint/transaction/saga/strategies.py +780 -0
  116. truthound/checkpoint/transaction/saga/testing.py +886 -0
  117. truthound/checkpoint/triggers/__init__.py +58 -0
  118. truthound/checkpoint/triggers/base.py +237 -0
  119. truthound/checkpoint/triggers/event.py +385 -0
  120. truthound/checkpoint/triggers/schedule.py +355 -0
  121. truthound/cli.py +2358 -0
  122. truthound/cli_modules/__init__.py +124 -0
  123. truthound/cli_modules/advanced/__init__.py +45 -0
  124. truthound/cli_modules/advanced/benchmark.py +343 -0
  125. truthound/cli_modules/advanced/docs.py +225 -0
  126. truthound/cli_modules/advanced/lineage.py +209 -0
  127. truthound/cli_modules/advanced/ml.py +320 -0
  128. truthound/cli_modules/advanced/realtime.py +196 -0
  129. truthound/cli_modules/checkpoint/__init__.py +46 -0
  130. truthound/cli_modules/checkpoint/init.py +114 -0
  131. truthound/cli_modules/checkpoint/list.py +71 -0
  132. truthound/cli_modules/checkpoint/run.py +159 -0
  133. truthound/cli_modules/checkpoint/validate.py +67 -0
  134. truthound/cli_modules/common/__init__.py +71 -0
  135. truthound/cli_modules/common/errors.py +414 -0
  136. truthound/cli_modules/common/options.py +419 -0
  137. truthound/cli_modules/common/output.py +507 -0
  138. truthound/cli_modules/common/protocol.py +552 -0
  139. truthound/cli_modules/core/__init__.py +48 -0
  140. truthound/cli_modules/core/check.py +123 -0
  141. truthound/cli_modules/core/compare.py +104 -0
  142. truthound/cli_modules/core/learn.py +57 -0
  143. truthound/cli_modules/core/mask.py +77 -0
  144. truthound/cli_modules/core/profile.py +65 -0
  145. truthound/cli_modules/core/scan.py +61 -0
  146. truthound/cli_modules/profiler/__init__.py +51 -0
  147. truthound/cli_modules/profiler/auto_profile.py +175 -0
  148. truthound/cli_modules/profiler/metadata.py +107 -0
  149. truthound/cli_modules/profiler/suite.py +283 -0
  150. truthound/cli_modules/registry.py +431 -0
  151. truthound/cli_modules/scaffolding/__init__.py +89 -0
  152. truthound/cli_modules/scaffolding/base.py +631 -0
  153. truthound/cli_modules/scaffolding/commands.py +545 -0
  154. truthound/cli_modules/scaffolding/plugins.py +1072 -0
  155. truthound/cli_modules/scaffolding/reporters.py +594 -0
  156. truthound/cli_modules/scaffolding/validators.py +1127 -0
  157. truthound/common/__init__.py +18 -0
  158. truthound/common/resilience/__init__.py +130 -0
  159. truthound/common/resilience/bulkhead.py +266 -0
  160. truthound/common/resilience/circuit_breaker.py +516 -0
  161. truthound/common/resilience/composite.py +332 -0
  162. truthound/common/resilience/config.py +292 -0
  163. truthound/common/resilience/protocols.py +217 -0
  164. truthound/common/resilience/rate_limiter.py +404 -0
  165. truthound/common/resilience/retry.py +341 -0
  166. truthound/datadocs/__init__.py +260 -0
  167. truthound/datadocs/base.py +571 -0
  168. truthound/datadocs/builder.py +761 -0
  169. truthound/datadocs/charts.py +764 -0
  170. truthound/datadocs/dashboard/__init__.py +63 -0
  171. truthound/datadocs/dashboard/app.py +576 -0
  172. truthound/datadocs/dashboard/components.py +584 -0
  173. truthound/datadocs/dashboard/state.py +240 -0
  174. truthound/datadocs/engine/__init__.py +46 -0
  175. truthound/datadocs/engine/context.py +376 -0
  176. truthound/datadocs/engine/pipeline.py +618 -0
  177. truthound/datadocs/engine/registry.py +469 -0
  178. truthound/datadocs/exporters/__init__.py +49 -0
  179. truthound/datadocs/exporters/base.py +198 -0
  180. truthound/datadocs/exporters/html.py +178 -0
  181. truthound/datadocs/exporters/json_exporter.py +253 -0
  182. truthound/datadocs/exporters/markdown.py +284 -0
  183. truthound/datadocs/exporters/pdf.py +392 -0
  184. truthound/datadocs/i18n/__init__.py +86 -0
  185. truthound/datadocs/i18n/catalog.py +960 -0
  186. truthound/datadocs/i18n/formatting.py +505 -0
  187. truthound/datadocs/i18n/loader.py +256 -0
  188. truthound/datadocs/i18n/plurals.py +378 -0
  189. truthound/datadocs/renderers/__init__.py +42 -0
  190. truthound/datadocs/renderers/base.py +401 -0
  191. truthound/datadocs/renderers/custom.py +342 -0
  192. truthound/datadocs/renderers/jinja.py +697 -0
  193. truthound/datadocs/sections.py +736 -0
  194. truthound/datadocs/styles.py +931 -0
  195. truthound/datadocs/themes/__init__.py +101 -0
  196. truthound/datadocs/themes/base.py +336 -0
  197. truthound/datadocs/themes/default.py +417 -0
  198. truthound/datadocs/themes/enterprise.py +419 -0
  199. truthound/datadocs/themes/loader.py +336 -0
  200. truthound/datadocs/themes.py +301 -0
  201. truthound/datadocs/transformers/__init__.py +57 -0
  202. truthound/datadocs/transformers/base.py +268 -0
  203. truthound/datadocs/transformers/enrichers.py +544 -0
  204. truthound/datadocs/transformers/filters.py +447 -0
  205. truthound/datadocs/transformers/i18n.py +468 -0
  206. truthound/datadocs/versioning/__init__.py +62 -0
  207. truthound/datadocs/versioning/diff.py +639 -0
  208. truthound/datadocs/versioning/storage.py +497 -0
  209. truthound/datadocs/versioning/version.py +358 -0
  210. truthound/datasources/__init__.py +223 -0
  211. truthound/datasources/_async_protocols.py +222 -0
  212. truthound/datasources/_protocols.py +159 -0
  213. truthound/datasources/adapters.py +428 -0
  214. truthound/datasources/async_base.py +599 -0
  215. truthound/datasources/async_factory.py +511 -0
  216. truthound/datasources/base.py +516 -0
  217. truthound/datasources/factory.py +433 -0
  218. truthound/datasources/nosql/__init__.py +47 -0
  219. truthound/datasources/nosql/base.py +487 -0
  220. truthound/datasources/nosql/elasticsearch.py +801 -0
  221. truthound/datasources/nosql/mongodb.py +636 -0
  222. truthound/datasources/pandas_optimized.py +582 -0
  223. truthound/datasources/pandas_source.py +216 -0
  224. truthound/datasources/polars_source.py +395 -0
  225. truthound/datasources/spark_source.py +479 -0
  226. truthound/datasources/sql/__init__.py +154 -0
  227. truthound/datasources/sql/base.py +710 -0
  228. truthound/datasources/sql/bigquery.py +410 -0
  229. truthound/datasources/sql/cloud_base.py +199 -0
  230. truthound/datasources/sql/databricks.py +471 -0
  231. truthound/datasources/sql/mysql.py +316 -0
  232. truthound/datasources/sql/oracle.py +427 -0
  233. truthound/datasources/sql/postgresql.py +321 -0
  234. truthound/datasources/sql/redshift.py +479 -0
  235. truthound/datasources/sql/snowflake.py +439 -0
  236. truthound/datasources/sql/sqlite.py +286 -0
  237. truthound/datasources/sql/sqlserver.py +437 -0
  238. truthound/datasources/streaming/__init__.py +47 -0
  239. truthound/datasources/streaming/base.py +350 -0
  240. truthound/datasources/streaming/kafka.py +670 -0
  241. truthound/decorators.py +98 -0
  242. truthound/docs/__init__.py +69 -0
  243. truthound/docs/extractor.py +971 -0
  244. truthound/docs/generator.py +601 -0
  245. truthound/docs/parser.py +1037 -0
  246. truthound/docs/renderer.py +999 -0
  247. truthound/drift/__init__.py +22 -0
  248. truthound/drift/compare.py +189 -0
  249. truthound/drift/detectors.py +464 -0
  250. truthound/drift/report.py +160 -0
  251. truthound/execution/__init__.py +65 -0
  252. truthound/execution/_protocols.py +324 -0
  253. truthound/execution/base.py +576 -0
  254. truthound/execution/distributed/__init__.py +179 -0
  255. truthound/execution/distributed/aggregations.py +731 -0
  256. truthound/execution/distributed/arrow_bridge.py +817 -0
  257. truthound/execution/distributed/base.py +550 -0
  258. truthound/execution/distributed/dask_engine.py +976 -0
  259. truthound/execution/distributed/mixins.py +766 -0
  260. truthound/execution/distributed/protocols.py +756 -0
  261. truthound/execution/distributed/ray_engine.py +1127 -0
  262. truthound/execution/distributed/registry.py +446 -0
  263. truthound/execution/distributed/spark_engine.py +1011 -0
  264. truthound/execution/distributed/validator_adapter.py +682 -0
  265. truthound/execution/pandas_engine.py +401 -0
  266. truthound/execution/polars_engine.py +497 -0
  267. truthound/execution/pushdown/__init__.py +230 -0
  268. truthound/execution/pushdown/ast.py +1550 -0
  269. truthound/execution/pushdown/builder.py +1550 -0
  270. truthound/execution/pushdown/dialects.py +1072 -0
  271. truthound/execution/pushdown/executor.py +829 -0
  272. truthound/execution/pushdown/optimizer.py +1041 -0
  273. truthound/execution/sql_engine.py +518 -0
  274. truthound/infrastructure/__init__.py +189 -0
  275. truthound/infrastructure/audit.py +1515 -0
  276. truthound/infrastructure/config.py +1133 -0
  277. truthound/infrastructure/encryption.py +1132 -0
  278. truthound/infrastructure/logging.py +1503 -0
  279. truthound/infrastructure/metrics.py +1220 -0
  280. truthound/lineage/__init__.py +89 -0
  281. truthound/lineage/base.py +746 -0
  282. truthound/lineage/impact_analysis.py +474 -0
  283. truthound/lineage/integrations/__init__.py +22 -0
  284. truthound/lineage/integrations/openlineage.py +548 -0
  285. truthound/lineage/tracker.py +512 -0
  286. truthound/lineage/visualization/__init__.py +33 -0
  287. truthound/lineage/visualization/protocols.py +145 -0
  288. truthound/lineage/visualization/renderers/__init__.py +20 -0
  289. truthound/lineage/visualization/renderers/cytoscape.py +329 -0
  290. truthound/lineage/visualization/renderers/d3.py +331 -0
  291. truthound/lineage/visualization/renderers/graphviz.py +276 -0
  292. truthound/lineage/visualization/renderers/mermaid.py +308 -0
  293. truthound/maskers.py +113 -0
  294. truthound/ml/__init__.py +124 -0
  295. truthound/ml/anomaly_models/__init__.py +31 -0
  296. truthound/ml/anomaly_models/ensemble.py +362 -0
  297. truthound/ml/anomaly_models/isolation_forest.py +444 -0
  298. truthound/ml/anomaly_models/statistical.py +392 -0
  299. truthound/ml/base.py +1178 -0
  300. truthound/ml/drift_detection/__init__.py +26 -0
  301. truthound/ml/drift_detection/concept.py +381 -0
  302. truthound/ml/drift_detection/distribution.py +361 -0
  303. truthound/ml/drift_detection/feature.py +442 -0
  304. truthound/ml/drift_detection/multivariate.py +495 -0
  305. truthound/ml/monitoring/__init__.py +88 -0
  306. truthound/ml/monitoring/alerting/__init__.py +33 -0
  307. truthound/ml/monitoring/alerting/handlers.py +427 -0
  308. truthound/ml/monitoring/alerting/rules.py +508 -0
  309. truthound/ml/monitoring/collectors/__init__.py +19 -0
  310. truthound/ml/monitoring/collectors/composite.py +105 -0
  311. truthound/ml/monitoring/collectors/drift.py +324 -0
  312. truthound/ml/monitoring/collectors/performance.py +179 -0
  313. truthound/ml/monitoring/collectors/quality.py +369 -0
  314. truthound/ml/monitoring/monitor.py +536 -0
  315. truthound/ml/monitoring/protocols.py +451 -0
  316. truthound/ml/monitoring/stores/__init__.py +15 -0
  317. truthound/ml/monitoring/stores/memory.py +201 -0
  318. truthound/ml/monitoring/stores/prometheus.py +296 -0
  319. truthound/ml/rule_learning/__init__.py +25 -0
  320. truthound/ml/rule_learning/constraint_miner.py +443 -0
  321. truthound/ml/rule_learning/pattern_learner.py +499 -0
  322. truthound/ml/rule_learning/profile_learner.py +462 -0
  323. truthound/multitenancy/__init__.py +326 -0
  324. truthound/multitenancy/core.py +852 -0
  325. truthound/multitenancy/integration.py +597 -0
  326. truthound/multitenancy/isolation.py +630 -0
  327. truthound/multitenancy/manager.py +770 -0
  328. truthound/multitenancy/middleware.py +765 -0
  329. truthound/multitenancy/quota.py +537 -0
  330. truthound/multitenancy/resolvers.py +603 -0
  331. truthound/multitenancy/storage.py +703 -0
  332. truthound/observability/__init__.py +307 -0
  333. truthound/observability/context.py +531 -0
  334. truthound/observability/instrumentation.py +611 -0
  335. truthound/observability/logging.py +887 -0
  336. truthound/observability/metrics.py +1157 -0
  337. truthound/observability/tracing/__init__.py +178 -0
  338. truthound/observability/tracing/baggage.py +310 -0
  339. truthound/observability/tracing/config.py +426 -0
  340. truthound/observability/tracing/exporter.py +787 -0
  341. truthound/observability/tracing/integration.py +1018 -0
  342. truthound/observability/tracing/otel/__init__.py +146 -0
  343. truthound/observability/tracing/otel/adapter.py +982 -0
  344. truthound/observability/tracing/otel/bridge.py +1177 -0
  345. truthound/observability/tracing/otel/compat.py +681 -0
  346. truthound/observability/tracing/otel/config.py +691 -0
  347. truthound/observability/tracing/otel/detection.py +327 -0
  348. truthound/observability/tracing/otel/protocols.py +426 -0
  349. truthound/observability/tracing/processor.py +561 -0
  350. truthound/observability/tracing/propagator.py +757 -0
  351. truthound/observability/tracing/provider.py +569 -0
  352. truthound/observability/tracing/resource.py +515 -0
  353. truthound/observability/tracing/sampler.py +487 -0
  354. truthound/observability/tracing/span.py +676 -0
  355. truthound/plugins/__init__.py +198 -0
  356. truthound/plugins/base.py +599 -0
  357. truthound/plugins/cli.py +680 -0
  358. truthound/plugins/dependencies/__init__.py +42 -0
  359. truthound/plugins/dependencies/graph.py +422 -0
  360. truthound/plugins/dependencies/resolver.py +417 -0
  361. truthound/plugins/discovery.py +379 -0
  362. truthound/plugins/docs/__init__.py +46 -0
  363. truthound/plugins/docs/extractor.py +444 -0
  364. truthound/plugins/docs/renderer.py +499 -0
  365. truthound/plugins/enterprise_manager.py +877 -0
  366. truthound/plugins/examples/__init__.py +19 -0
  367. truthound/plugins/examples/custom_validators.py +317 -0
  368. truthound/plugins/examples/slack_notifier.py +312 -0
  369. truthound/plugins/examples/xml_reporter.py +254 -0
  370. truthound/plugins/hooks.py +558 -0
  371. truthound/plugins/lifecycle/__init__.py +43 -0
  372. truthound/plugins/lifecycle/hot_reload.py +402 -0
  373. truthound/plugins/lifecycle/manager.py +371 -0
  374. truthound/plugins/manager.py +736 -0
  375. truthound/plugins/registry.py +338 -0
  376. truthound/plugins/security/__init__.py +93 -0
  377. truthound/plugins/security/exceptions.py +332 -0
  378. truthound/plugins/security/policies.py +348 -0
  379. truthound/plugins/security/protocols.py +643 -0
  380. truthound/plugins/security/sandbox/__init__.py +45 -0
  381. truthound/plugins/security/sandbox/context.py +158 -0
  382. truthound/plugins/security/sandbox/engines/__init__.py +19 -0
  383. truthound/plugins/security/sandbox/engines/container.py +379 -0
  384. truthound/plugins/security/sandbox/engines/noop.py +144 -0
  385. truthound/plugins/security/sandbox/engines/process.py +336 -0
  386. truthound/plugins/security/sandbox/factory.py +211 -0
  387. truthound/plugins/security/signing/__init__.py +57 -0
  388. truthound/plugins/security/signing/service.py +330 -0
  389. truthound/plugins/security/signing/trust_store.py +368 -0
  390. truthound/plugins/security/signing/verifier.py +459 -0
  391. truthound/plugins/versioning/__init__.py +41 -0
  392. truthound/plugins/versioning/constraints.py +297 -0
  393. truthound/plugins/versioning/resolver.py +329 -0
  394. truthound/profiler/__init__.py +1729 -0
  395. truthound/profiler/_lazy.py +452 -0
  396. truthound/profiler/ab_testing/__init__.py +80 -0
  397. truthound/profiler/ab_testing/analysis.py +449 -0
  398. truthound/profiler/ab_testing/base.py +257 -0
  399. truthound/profiler/ab_testing/experiment.py +395 -0
  400. truthound/profiler/ab_testing/tracking.py +368 -0
  401. truthound/profiler/auto_threshold.py +1170 -0
  402. truthound/profiler/base.py +579 -0
  403. truthound/profiler/cache_patterns.py +911 -0
  404. truthound/profiler/caching.py +1303 -0
  405. truthound/profiler/column_profiler.py +712 -0
  406. truthound/profiler/comparison.py +1007 -0
  407. truthound/profiler/custom_patterns.py +1170 -0
  408. truthound/profiler/dashboard/__init__.py +50 -0
  409. truthound/profiler/dashboard/app.py +476 -0
  410. truthound/profiler/dashboard/components.py +457 -0
  411. truthound/profiler/dashboard/config.py +72 -0
  412. truthound/profiler/distributed/__init__.py +83 -0
  413. truthound/profiler/distributed/base.py +281 -0
  414. truthound/profiler/distributed/dask_backend.py +498 -0
  415. truthound/profiler/distributed/local_backend.py +293 -0
  416. truthound/profiler/distributed/profiler.py +304 -0
  417. truthound/profiler/distributed/ray_backend.py +374 -0
  418. truthound/profiler/distributed/spark_backend.py +375 -0
  419. truthound/profiler/distributed.py +1366 -0
  420. truthound/profiler/enterprise_sampling.py +1065 -0
  421. truthound/profiler/errors.py +488 -0
  422. truthound/profiler/evolution/__init__.py +91 -0
  423. truthound/profiler/evolution/alerts.py +426 -0
  424. truthound/profiler/evolution/changes.py +206 -0
  425. truthound/profiler/evolution/compatibility.py +365 -0
  426. truthound/profiler/evolution/detector.py +372 -0
  427. truthound/profiler/evolution/protocols.py +121 -0
  428. truthound/profiler/generators/__init__.py +48 -0
  429. truthound/profiler/generators/base.py +384 -0
  430. truthound/profiler/generators/ml_rules.py +375 -0
  431. truthound/profiler/generators/pattern_rules.py +384 -0
  432. truthound/profiler/generators/schema_rules.py +267 -0
  433. truthound/profiler/generators/stats_rules.py +324 -0
  434. truthound/profiler/generators/suite_generator.py +857 -0
  435. truthound/profiler/i18n.py +1542 -0
  436. truthound/profiler/incremental.py +554 -0
  437. truthound/profiler/incremental_validation.py +1710 -0
  438. truthound/profiler/integration/__init__.py +73 -0
  439. truthound/profiler/integration/adapters.py +345 -0
  440. truthound/profiler/integration/context.py +371 -0
  441. truthound/profiler/integration/executor.py +527 -0
  442. truthound/profiler/integration/naming.py +75 -0
  443. truthound/profiler/integration/protocols.py +243 -0
  444. truthound/profiler/memory.py +1185 -0
  445. truthound/profiler/migration/__init__.py +60 -0
  446. truthound/profiler/migration/base.py +345 -0
  447. truthound/profiler/migration/manager.py +444 -0
  448. truthound/profiler/migration/v1_0_to_v1_1.py +484 -0
  449. truthound/profiler/ml/__init__.py +73 -0
  450. truthound/profiler/ml/base.py +244 -0
  451. truthound/profiler/ml/classifier.py +507 -0
  452. truthound/profiler/ml/feature_extraction.py +604 -0
  453. truthound/profiler/ml/pretrained.py +448 -0
  454. truthound/profiler/ml_inference.py +1276 -0
  455. truthound/profiler/native_patterns.py +815 -0
  456. truthound/profiler/observability.py +1184 -0
  457. truthound/profiler/process_timeout.py +1566 -0
  458. truthound/profiler/progress.py +568 -0
  459. truthound/profiler/progress_callbacks.py +1734 -0
  460. truthound/profiler/quality.py +1345 -0
  461. truthound/profiler/resilience.py +1180 -0
  462. truthound/profiler/sampled_matcher.py +794 -0
  463. truthound/profiler/sampling.py +1288 -0
  464. truthound/profiler/scheduling/__init__.py +82 -0
  465. truthound/profiler/scheduling/protocols.py +214 -0
  466. truthound/profiler/scheduling/scheduler.py +474 -0
  467. truthound/profiler/scheduling/storage.py +457 -0
  468. truthound/profiler/scheduling/triggers.py +449 -0
  469. truthound/profiler/schema.py +603 -0
  470. truthound/profiler/streaming.py +685 -0
  471. truthound/profiler/streaming_patterns.py +1354 -0
  472. truthound/profiler/suite_cli.py +625 -0
  473. truthound/profiler/suite_config.py +789 -0
  474. truthound/profiler/suite_export.py +1268 -0
  475. truthound/profiler/table_profiler.py +547 -0
  476. truthound/profiler/timeout.py +565 -0
  477. truthound/profiler/validation.py +1532 -0
  478. truthound/profiler/visualization/__init__.py +118 -0
  479. truthound/profiler/visualization/base.py +346 -0
  480. truthound/profiler/visualization/generator.py +1259 -0
  481. truthound/profiler/visualization/plotly_renderer.py +811 -0
  482. truthound/profiler/visualization/renderers.py +669 -0
  483. truthound/profiler/visualization/sections.py +540 -0
  484. truthound/profiler/visualization.py +2122 -0
  485. truthound/profiler/yaml_validation.py +1151 -0
  486. truthound/py.typed +0 -0
  487. truthound/ratelimit/__init__.py +248 -0
  488. truthound/ratelimit/algorithms.py +1108 -0
  489. truthound/ratelimit/core.py +573 -0
  490. truthound/ratelimit/integration.py +532 -0
  491. truthound/ratelimit/limiter.py +663 -0
  492. truthound/ratelimit/middleware.py +700 -0
  493. truthound/ratelimit/policy.py +792 -0
  494. truthound/ratelimit/storage.py +763 -0
  495. truthound/rbac/__init__.py +340 -0
  496. truthound/rbac/core.py +976 -0
  497. truthound/rbac/integration.py +760 -0
  498. truthound/rbac/manager.py +1052 -0
  499. truthound/rbac/middleware.py +842 -0
  500. truthound/rbac/policy.py +954 -0
  501. truthound/rbac/storage.py +878 -0
  502. truthound/realtime/__init__.py +141 -0
  503. truthound/realtime/adapters/__init__.py +43 -0
  504. truthound/realtime/adapters/base.py +533 -0
  505. truthound/realtime/adapters/kafka.py +487 -0
  506. truthound/realtime/adapters/kinesis.py +479 -0
  507. truthound/realtime/adapters/mock.py +243 -0
  508. truthound/realtime/base.py +553 -0
  509. truthound/realtime/factory.py +382 -0
  510. truthound/realtime/incremental.py +660 -0
  511. truthound/realtime/processing/__init__.py +67 -0
  512. truthound/realtime/processing/exactly_once.py +575 -0
  513. truthound/realtime/processing/state.py +547 -0
  514. truthound/realtime/processing/windows.py +647 -0
  515. truthound/realtime/protocols.py +569 -0
  516. truthound/realtime/streaming.py +605 -0
  517. truthound/realtime/testing/__init__.py +32 -0
  518. truthound/realtime/testing/containers.py +615 -0
  519. truthound/realtime/testing/fixtures.py +484 -0
  520. truthound/report.py +280 -0
  521. truthound/reporters/__init__.py +46 -0
  522. truthound/reporters/_protocols.py +30 -0
  523. truthound/reporters/base.py +324 -0
  524. truthound/reporters/ci/__init__.py +66 -0
  525. truthound/reporters/ci/azure.py +436 -0
  526. truthound/reporters/ci/base.py +509 -0
  527. truthound/reporters/ci/bitbucket.py +567 -0
  528. truthound/reporters/ci/circleci.py +547 -0
  529. truthound/reporters/ci/detection.py +364 -0
  530. truthound/reporters/ci/factory.py +182 -0
  531. truthound/reporters/ci/github.py +388 -0
  532. truthound/reporters/ci/gitlab.py +471 -0
  533. truthound/reporters/ci/jenkins.py +525 -0
  534. truthound/reporters/console_reporter.py +299 -0
  535. truthound/reporters/factory.py +211 -0
  536. truthound/reporters/html_reporter.py +524 -0
  537. truthound/reporters/json_reporter.py +256 -0
  538. truthound/reporters/markdown_reporter.py +280 -0
  539. truthound/reporters/sdk/__init__.py +174 -0
  540. truthound/reporters/sdk/builder.py +558 -0
  541. truthound/reporters/sdk/mixins.py +1150 -0
  542. truthound/reporters/sdk/schema.py +1493 -0
  543. truthound/reporters/sdk/templates.py +666 -0
  544. truthound/reporters/sdk/testing.py +968 -0
  545. truthound/scanners.py +170 -0
  546. truthound/scheduling/__init__.py +122 -0
  547. truthound/scheduling/cron.py +1136 -0
  548. truthound/scheduling/presets.py +212 -0
  549. truthound/schema.py +275 -0
  550. truthound/secrets/__init__.py +173 -0
  551. truthound/secrets/base.py +618 -0
  552. truthound/secrets/cloud.py +682 -0
  553. truthound/secrets/integration.py +507 -0
  554. truthound/secrets/manager.py +633 -0
  555. truthound/secrets/oidc/__init__.py +172 -0
  556. truthound/secrets/oidc/base.py +902 -0
  557. truthound/secrets/oidc/credential_provider.py +623 -0
  558. truthound/secrets/oidc/exchangers.py +1001 -0
  559. truthound/secrets/oidc/github/__init__.py +110 -0
  560. truthound/secrets/oidc/github/claims.py +718 -0
  561. truthound/secrets/oidc/github/enhanced_provider.py +693 -0
  562. truthound/secrets/oidc/github/trust_policy.py +742 -0
  563. truthound/secrets/oidc/github/verification.py +723 -0
  564. truthound/secrets/oidc/github/workflow.py +691 -0
  565. truthound/secrets/oidc/providers.py +825 -0
  566. truthound/secrets/providers.py +506 -0
  567. truthound/secrets/resolver.py +495 -0
  568. truthound/stores/__init__.py +177 -0
  569. truthound/stores/backends/__init__.py +18 -0
  570. truthound/stores/backends/_protocols.py +340 -0
  571. truthound/stores/backends/azure_blob.py +530 -0
  572. truthound/stores/backends/concurrent_filesystem.py +915 -0
  573. truthound/stores/backends/connection_pool.py +1365 -0
  574. truthound/stores/backends/database.py +743 -0
  575. truthound/stores/backends/filesystem.py +538 -0
  576. truthound/stores/backends/gcs.py +399 -0
  577. truthound/stores/backends/memory.py +354 -0
  578. truthound/stores/backends/s3.py +434 -0
  579. truthound/stores/backpressure/__init__.py +84 -0
  580. truthound/stores/backpressure/base.py +375 -0
  581. truthound/stores/backpressure/circuit_breaker.py +434 -0
  582. truthound/stores/backpressure/monitor.py +376 -0
  583. truthound/stores/backpressure/strategies.py +677 -0
  584. truthound/stores/base.py +551 -0
  585. truthound/stores/batching/__init__.py +65 -0
  586. truthound/stores/batching/base.py +305 -0
  587. truthound/stores/batching/buffer.py +370 -0
  588. truthound/stores/batching/store.py +248 -0
  589. truthound/stores/batching/writer.py +521 -0
  590. truthound/stores/caching/__init__.py +60 -0
  591. truthound/stores/caching/backends.py +684 -0
  592. truthound/stores/caching/base.py +356 -0
  593. truthound/stores/caching/store.py +305 -0
  594. truthound/stores/compression/__init__.py +193 -0
  595. truthound/stores/compression/adaptive.py +694 -0
  596. truthound/stores/compression/base.py +514 -0
  597. truthound/stores/compression/pipeline.py +868 -0
  598. truthound/stores/compression/providers.py +672 -0
  599. truthound/stores/compression/streaming.py +832 -0
  600. truthound/stores/concurrency/__init__.py +81 -0
  601. truthound/stores/concurrency/atomic.py +556 -0
  602. truthound/stores/concurrency/index.py +775 -0
  603. truthound/stores/concurrency/locks.py +576 -0
  604. truthound/stores/concurrency/manager.py +482 -0
  605. truthound/stores/encryption/__init__.py +297 -0
  606. truthound/stores/encryption/base.py +952 -0
  607. truthound/stores/encryption/keys.py +1191 -0
  608. truthound/stores/encryption/pipeline.py +903 -0
  609. truthound/stores/encryption/providers.py +953 -0
  610. truthound/stores/encryption/streaming.py +950 -0
  611. truthound/stores/expectations.py +227 -0
  612. truthound/stores/factory.py +246 -0
  613. truthound/stores/migration/__init__.py +75 -0
  614. truthound/stores/migration/base.py +480 -0
  615. truthound/stores/migration/manager.py +347 -0
  616. truthound/stores/migration/registry.py +382 -0
  617. truthound/stores/migration/store.py +559 -0
  618. truthound/stores/observability/__init__.py +106 -0
  619. truthound/stores/observability/audit.py +718 -0
  620. truthound/stores/observability/config.py +270 -0
  621. truthound/stores/observability/factory.py +208 -0
  622. truthound/stores/observability/metrics.py +636 -0
  623. truthound/stores/observability/protocols.py +410 -0
  624. truthound/stores/observability/store.py +570 -0
  625. truthound/stores/observability/tracing.py +784 -0
  626. truthound/stores/replication/__init__.py +76 -0
  627. truthound/stores/replication/base.py +260 -0
  628. truthound/stores/replication/monitor.py +269 -0
  629. truthound/stores/replication/store.py +439 -0
  630. truthound/stores/replication/syncer.py +391 -0
  631. truthound/stores/results.py +359 -0
  632. truthound/stores/retention/__init__.py +77 -0
  633. truthound/stores/retention/base.py +378 -0
  634. truthound/stores/retention/policies.py +621 -0
  635. truthound/stores/retention/scheduler.py +279 -0
  636. truthound/stores/retention/store.py +526 -0
  637. truthound/stores/streaming/__init__.py +138 -0
  638. truthound/stores/streaming/base.py +801 -0
  639. truthound/stores/streaming/database.py +984 -0
  640. truthound/stores/streaming/filesystem.py +719 -0
  641. truthound/stores/streaming/reader.py +629 -0
  642. truthound/stores/streaming/s3.py +843 -0
  643. truthound/stores/streaming/writer.py +790 -0
  644. truthound/stores/tiering/__init__.py +108 -0
  645. truthound/stores/tiering/base.py +462 -0
  646. truthound/stores/tiering/manager.py +249 -0
  647. truthound/stores/tiering/policies.py +692 -0
  648. truthound/stores/tiering/store.py +526 -0
  649. truthound/stores/versioning/__init__.py +56 -0
  650. truthound/stores/versioning/base.py +376 -0
  651. truthound/stores/versioning/store.py +660 -0
  652. truthound/stores/versioning/strategies.py +353 -0
  653. truthound/types.py +56 -0
  654. truthound/validators/__init__.py +774 -0
  655. truthound/validators/aggregate/__init__.py +27 -0
  656. truthound/validators/aggregate/central.py +116 -0
  657. truthound/validators/aggregate/extremes.py +116 -0
  658. truthound/validators/aggregate/spread.py +118 -0
  659. truthound/validators/aggregate/sum.py +64 -0
  660. truthound/validators/aggregate/type.py +78 -0
  661. truthound/validators/anomaly/__init__.py +93 -0
  662. truthound/validators/anomaly/base.py +431 -0
  663. truthound/validators/anomaly/ml_based.py +1190 -0
  664. truthound/validators/anomaly/multivariate.py +647 -0
  665. truthound/validators/anomaly/statistical.py +599 -0
  666. truthound/validators/base.py +1089 -0
  667. truthound/validators/business_rule/__init__.py +46 -0
  668. truthound/validators/business_rule/base.py +147 -0
  669. truthound/validators/business_rule/checksum.py +509 -0
  670. truthound/validators/business_rule/financial.py +526 -0
  671. truthound/validators/cache.py +733 -0
  672. truthound/validators/completeness/__init__.py +39 -0
  673. truthound/validators/completeness/conditional.py +73 -0
  674. truthound/validators/completeness/default.py +98 -0
  675. truthound/validators/completeness/empty.py +103 -0
  676. truthound/validators/completeness/nan.py +337 -0
  677. truthound/validators/completeness/null.py +152 -0
  678. truthound/validators/cross_table/__init__.py +17 -0
  679. truthound/validators/cross_table/aggregate.py +333 -0
  680. truthound/validators/cross_table/row_count.py +122 -0
  681. truthound/validators/datetime/__init__.py +29 -0
  682. truthound/validators/datetime/format.py +78 -0
  683. truthound/validators/datetime/freshness.py +269 -0
  684. truthound/validators/datetime/order.py +73 -0
  685. truthound/validators/datetime/parseable.py +185 -0
  686. truthound/validators/datetime/range.py +202 -0
  687. truthound/validators/datetime/timezone.py +69 -0
  688. truthound/validators/distribution/__init__.py +49 -0
  689. truthound/validators/distribution/distribution.py +128 -0
  690. truthound/validators/distribution/monotonic.py +119 -0
  691. truthound/validators/distribution/outlier.py +178 -0
  692. truthound/validators/distribution/quantile.py +80 -0
  693. truthound/validators/distribution/range.py +254 -0
  694. truthound/validators/distribution/set.py +125 -0
  695. truthound/validators/distribution/statistical.py +459 -0
  696. truthound/validators/drift/__init__.py +79 -0
  697. truthound/validators/drift/base.py +427 -0
  698. truthound/validators/drift/multi_feature.py +401 -0
  699. truthound/validators/drift/numeric.py +395 -0
  700. truthound/validators/drift/psi.py +446 -0
  701. truthound/validators/drift/statistical.py +510 -0
  702. truthound/validators/enterprise.py +1658 -0
  703. truthound/validators/geospatial/__init__.py +80 -0
  704. truthound/validators/geospatial/base.py +97 -0
  705. truthound/validators/geospatial/boundary.py +238 -0
  706. truthound/validators/geospatial/coordinate.py +351 -0
  707. truthound/validators/geospatial/distance.py +399 -0
  708. truthound/validators/geospatial/polygon.py +665 -0
  709. truthound/validators/i18n/__init__.py +308 -0
  710. truthound/validators/i18n/bidi.py +571 -0
  711. truthound/validators/i18n/catalogs.py +570 -0
  712. truthound/validators/i18n/dialects.py +763 -0
  713. truthound/validators/i18n/extended_catalogs.py +549 -0
  714. truthound/validators/i18n/formatting.py +1434 -0
  715. truthound/validators/i18n/loader.py +1020 -0
  716. truthound/validators/i18n/messages.py +521 -0
  717. truthound/validators/i18n/plural.py +683 -0
  718. truthound/validators/i18n/protocols.py +855 -0
  719. truthound/validators/i18n/tms.py +1162 -0
  720. truthound/validators/localization/__init__.py +53 -0
  721. truthound/validators/localization/base.py +122 -0
  722. truthound/validators/localization/chinese.py +362 -0
  723. truthound/validators/localization/japanese.py +275 -0
  724. truthound/validators/localization/korean.py +524 -0
  725. truthound/validators/memory/__init__.py +94 -0
  726. truthound/validators/memory/approximate_knn.py +506 -0
  727. truthound/validators/memory/base.py +547 -0
  728. truthound/validators/memory/sgd_online.py +719 -0
  729. truthound/validators/memory/streaming_ecdf.py +753 -0
  730. truthound/validators/ml_feature/__init__.py +54 -0
  731. truthound/validators/ml_feature/base.py +249 -0
  732. truthound/validators/ml_feature/correlation.py +299 -0
  733. truthound/validators/ml_feature/leakage.py +344 -0
  734. truthound/validators/ml_feature/null_impact.py +270 -0
  735. truthound/validators/ml_feature/scale.py +264 -0
  736. truthound/validators/multi_column/__init__.py +89 -0
  737. truthound/validators/multi_column/arithmetic.py +284 -0
  738. truthound/validators/multi_column/base.py +231 -0
  739. truthound/validators/multi_column/comparison.py +273 -0
  740. truthound/validators/multi_column/consistency.py +312 -0
  741. truthound/validators/multi_column/statistical.py +299 -0
  742. truthound/validators/optimization/__init__.py +164 -0
  743. truthound/validators/optimization/aggregation.py +563 -0
  744. truthound/validators/optimization/covariance.py +556 -0
  745. truthound/validators/optimization/geo.py +626 -0
  746. truthound/validators/optimization/graph.py +587 -0
  747. truthound/validators/optimization/orchestrator.py +970 -0
  748. truthound/validators/optimization/profiling.py +1312 -0
  749. truthound/validators/privacy/__init__.py +223 -0
  750. truthound/validators/privacy/base.py +635 -0
  751. truthound/validators/privacy/ccpa.py +670 -0
  752. truthound/validators/privacy/gdpr.py +728 -0
  753. truthound/validators/privacy/global_patterns.py +604 -0
  754. truthound/validators/privacy/plugins.py +867 -0
  755. truthound/validators/profiling/__init__.py +52 -0
  756. truthound/validators/profiling/base.py +175 -0
  757. truthound/validators/profiling/cardinality.py +312 -0
  758. truthound/validators/profiling/entropy.py +391 -0
  759. truthound/validators/profiling/frequency.py +455 -0
  760. truthound/validators/pushdown_support.py +660 -0
  761. truthound/validators/query/__init__.py +91 -0
  762. truthound/validators/query/aggregate.py +346 -0
  763. truthound/validators/query/base.py +246 -0
  764. truthound/validators/query/column.py +249 -0
  765. truthound/validators/query/expression.py +274 -0
  766. truthound/validators/query/result.py +323 -0
  767. truthound/validators/query/row_count.py +264 -0
  768. truthound/validators/referential/__init__.py +80 -0
  769. truthound/validators/referential/base.py +395 -0
  770. truthound/validators/referential/cascade.py +391 -0
  771. truthound/validators/referential/circular.py +563 -0
  772. truthound/validators/referential/foreign_key.py +624 -0
  773. truthound/validators/referential/orphan.py +485 -0
  774. truthound/validators/registry.py +112 -0
  775. truthound/validators/schema/__init__.py +41 -0
  776. truthound/validators/schema/column_count.py +142 -0
  777. truthound/validators/schema/column_exists.py +80 -0
  778. truthound/validators/schema/column_order.py +82 -0
  779. truthound/validators/schema/column_pair.py +85 -0
  780. truthound/validators/schema/column_pair_set.py +195 -0
  781. truthound/validators/schema/column_type.py +94 -0
  782. truthound/validators/schema/multi_column.py +53 -0
  783. truthound/validators/schema/multi_column_aggregate.py +175 -0
  784. truthound/validators/schema/referential.py +274 -0
  785. truthound/validators/schema/table_schema.py +91 -0
  786. truthound/validators/schema_validator.py +219 -0
  787. truthound/validators/sdk/__init__.py +250 -0
  788. truthound/validators/sdk/builder.py +680 -0
  789. truthound/validators/sdk/decorators.py +474 -0
  790. truthound/validators/sdk/enterprise/__init__.py +211 -0
  791. truthound/validators/sdk/enterprise/docs.py +725 -0
  792. truthound/validators/sdk/enterprise/fuzzing.py +659 -0
  793. truthound/validators/sdk/enterprise/licensing.py +709 -0
  794. truthound/validators/sdk/enterprise/manager.py +543 -0
  795. truthound/validators/sdk/enterprise/resources.py +628 -0
  796. truthound/validators/sdk/enterprise/sandbox.py +766 -0
  797. truthound/validators/sdk/enterprise/signing.py +603 -0
  798. truthound/validators/sdk/enterprise/templates.py +865 -0
  799. truthound/validators/sdk/enterprise/versioning.py +659 -0
  800. truthound/validators/sdk/templates.py +757 -0
  801. truthound/validators/sdk/testing.py +807 -0
  802. truthound/validators/security/__init__.py +181 -0
  803. truthound/validators/security/redos/__init__.py +182 -0
  804. truthound/validators/security/redos/core.py +861 -0
  805. truthound/validators/security/redos/cpu_monitor.py +593 -0
  806. truthound/validators/security/redos/cve_database.py +791 -0
  807. truthound/validators/security/redos/ml/__init__.py +155 -0
  808. truthound/validators/security/redos/ml/base.py +785 -0
  809. truthound/validators/security/redos/ml/datasets.py +618 -0
  810. truthound/validators/security/redos/ml/features.py +359 -0
  811. truthound/validators/security/redos/ml/models.py +1000 -0
  812. truthound/validators/security/redos/ml/predictor.py +507 -0
  813. truthound/validators/security/redos/ml/storage.py +632 -0
  814. truthound/validators/security/redos/ml/training.py +571 -0
  815. truthound/validators/security/redos/ml_analyzer.py +937 -0
  816. truthound/validators/security/redos/optimizer.py +674 -0
  817. truthound/validators/security/redos/profiler.py +682 -0
  818. truthound/validators/security/redos/re2_engine.py +709 -0
  819. truthound/validators/security/redos.py +886 -0
  820. truthound/validators/security/sql_security.py +1247 -0
  821. truthound/validators/streaming/__init__.py +126 -0
  822. truthound/validators/streaming/base.py +292 -0
  823. truthound/validators/streaming/completeness.py +210 -0
  824. truthound/validators/streaming/mixin.py +575 -0
  825. truthound/validators/streaming/range.py +308 -0
  826. truthound/validators/streaming/sources.py +846 -0
  827. truthound/validators/string/__init__.py +57 -0
  828. truthound/validators/string/casing.py +158 -0
  829. truthound/validators/string/charset.py +96 -0
  830. truthound/validators/string/format.py +501 -0
  831. truthound/validators/string/json.py +77 -0
  832. truthound/validators/string/json_schema.py +184 -0
  833. truthound/validators/string/length.py +104 -0
  834. truthound/validators/string/like_pattern.py +237 -0
  835. truthound/validators/string/regex.py +202 -0
  836. truthound/validators/string/regex_extended.py +435 -0
  837. truthound/validators/table/__init__.py +88 -0
  838. truthound/validators/table/base.py +78 -0
  839. truthound/validators/table/column_count.py +198 -0
  840. truthound/validators/table/freshness.py +362 -0
  841. truthound/validators/table/row_count.py +251 -0
  842. truthound/validators/table/schema.py +333 -0
  843. truthound/validators/table/size.py +285 -0
  844. truthound/validators/timeout/__init__.py +102 -0
  845. truthound/validators/timeout/advanced/__init__.py +247 -0
  846. truthound/validators/timeout/advanced/circuit_breaker.py +675 -0
  847. truthound/validators/timeout/advanced/prediction.py +773 -0
  848. truthound/validators/timeout/advanced/priority.py +618 -0
  849. truthound/validators/timeout/advanced/redis_backend.py +770 -0
  850. truthound/validators/timeout/advanced/retry.py +721 -0
  851. truthound/validators/timeout/advanced/sampling.py +788 -0
  852. truthound/validators/timeout/advanced/sla.py +661 -0
  853. truthound/validators/timeout/advanced/telemetry.py +804 -0
  854. truthound/validators/timeout/cascade.py +477 -0
  855. truthound/validators/timeout/deadline.py +657 -0
  856. truthound/validators/timeout/degradation.py +525 -0
  857. truthound/validators/timeout/distributed.py +597 -0
  858. truthound/validators/timeseries/__init__.py +89 -0
  859. truthound/validators/timeseries/base.py +326 -0
  860. truthound/validators/timeseries/completeness.py +617 -0
  861. truthound/validators/timeseries/gap.py +485 -0
  862. truthound/validators/timeseries/monotonic.py +310 -0
  863. truthound/validators/timeseries/seasonality.py +422 -0
  864. truthound/validators/timeseries/trend.py +510 -0
  865. truthound/validators/uniqueness/__init__.py +59 -0
  866. truthound/validators/uniqueness/approximate.py +475 -0
  867. truthound/validators/uniqueness/distinct_values.py +253 -0
  868. truthound/validators/uniqueness/duplicate.py +118 -0
  869. truthound/validators/uniqueness/primary_key.py +140 -0
  870. truthound/validators/uniqueness/unique.py +191 -0
  871. truthound/validators/uniqueness/within_record.py +599 -0
  872. truthound/validators/utils.py +756 -0
  873. truthound-1.0.8.dist-info/METADATA +474 -0
  874. truthound-1.0.8.dist-info/RECORD +877 -0
  875. truthound-1.0.8.dist-info/WHEEL +4 -0
  876. truthound-1.0.8.dist-info/entry_points.txt +2 -0
  877. truthound-1.0.8.dist-info/licenses/LICENSE +190 -0
@@ -0,0 +1,780 @@
1
+ """Advanced Compensation Strategies.
2
+
3
+ This module provides advanced compensation strategies for enterprise
4
+ saga patterns, including semantic compensation, pivot transactions,
5
+ and countermeasure strategies.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from abc import ABC, abstractmethod
12
+ from dataclasses import dataclass, field
13
+ from datetime import datetime
14
+ from enum import Enum, auto
15
+ from typing import TYPE_CHECKING, Any, Callable
16
+
17
+ if TYPE_CHECKING:
18
+ from truthound.checkpoint.actions.base import ActionResult, BaseAction
19
+ from truthound.checkpoint.checkpoint import CheckpointResult
20
+ from truthound.checkpoint.transaction.base import CompensationResult, TransactionContext
21
+ from truthound.checkpoint.transaction.saga.definition import SagaDefinition, SagaStepDefinition
22
+
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class CompensationPolicy(str, Enum):
28
+ """Compensation policy types."""
29
+
30
+ # Standard backward compensation (default Saga pattern)
31
+ BACKWARD = "backward"
32
+
33
+ # Forward recovery - try to complete remaining steps
34
+ FORWARD = "forward"
35
+
36
+ # Semantic compensation - compensate with semantically equivalent actions
37
+ SEMANTIC = "semantic"
38
+
39
+ # Pivot transaction - commit point after which no compensation
40
+ PIVOT = "pivot"
41
+
42
+ # Countermeasure - corrective actions instead of undo
43
+ COUNTERMEASURE = "countermeasure"
44
+
45
+ # Parallel compensation - compensate multiple steps in parallel
46
+ PARALLEL = "parallel"
47
+
48
+ # Selective compensation - only compensate specific steps
49
+ SELECTIVE = "selective"
50
+
51
+ # Best effort - try to compensate, continue on failure
52
+ BEST_EFFORT = "best_effort"
53
+
54
+ def __str__(self) -> str:
55
+ return self.value
56
+
57
+
58
+ class CompensationPriority(str, Enum):
59
+ """Priority for compensation execution."""
60
+
61
+ CRITICAL = "critical" # Must compensate, fail saga if not possible
62
+ HIGH = "high" # Highly important, retry multiple times
63
+ NORMAL = "normal" # Standard compensation
64
+ LOW = "low" # Can skip if necessary
65
+ OPTIONAL = "optional" # Best effort, ignore failures
66
+
67
+
68
+ @dataclass
69
+ class CompensationPlanStep:
70
+ """A single step in a compensation plan.
71
+
72
+ Attributes:
73
+ step_id: ID of the step to compensate.
74
+ step_name: Name of the step.
75
+ priority: Compensation priority.
76
+ strategy: Strategy for this step.
77
+ dependencies: Steps that must be compensated first.
78
+ action: Compensation action or function.
79
+ estimated_duration_ms: Estimated compensation duration.
80
+ can_parallel: Whether can run in parallel with others.
81
+ """
82
+
83
+ step_id: str
84
+ step_name: str
85
+ priority: CompensationPriority = CompensationPriority.NORMAL
86
+ strategy: str = "backward"
87
+ dependencies: list[str] = field(default_factory=list)
88
+ action: "BaseAction[Any] | Callable[..., Any]" | None = None
89
+ estimated_duration_ms: float = 0.0
90
+ can_parallel: bool = False
91
+ metadata: dict[str, Any] = field(default_factory=dict)
92
+
93
+
94
+ @dataclass
95
+ class CompensationPlan:
96
+ """Complete compensation plan for a saga.
97
+
98
+ Attributes:
99
+ saga_id: ID of the saga.
100
+ policy: Overall compensation policy.
101
+ steps: Ordered list of compensation steps.
102
+ created_at: When the plan was created.
103
+ pivot_step_id: ID of pivot step (if using pivot strategy).
104
+ metadata: Additional plan metadata.
105
+ """
106
+
107
+ saga_id: str
108
+ policy: CompensationPolicy
109
+ steps: list[CompensationPlanStep] = field(default_factory=list)
110
+ created_at: datetime = field(default_factory=datetime.now)
111
+ pivot_step_id: str | None = None
112
+ metadata: dict[str, Any] = field(default_factory=dict)
113
+
114
+ def add_step(self, step: CompensationPlanStep) -> "CompensationPlan":
115
+ """Add a step to the plan.
116
+
117
+ Args:
118
+ step: Compensation step to add.
119
+
120
+ Returns:
121
+ Self for chaining.
122
+ """
123
+ self.steps.append(step)
124
+ return self
125
+
126
+ def get_execution_order(self) -> list[CompensationPlanStep]:
127
+ """Get steps in execution order based on dependencies.
128
+
129
+ Returns:
130
+ Steps in order of execution.
131
+ """
132
+ # Simple topological sort
133
+ result = []
134
+ remaining = list(self.steps)
135
+ completed = set()
136
+
137
+ while remaining:
138
+ for step in list(remaining):
139
+ deps_satisfied = all(
140
+ dep in completed for dep in step.dependencies
141
+ )
142
+ if deps_satisfied:
143
+ result.append(step)
144
+ completed.add(step.step_id)
145
+ remaining.remove(step)
146
+ break
147
+ else:
148
+ # No progress - might be cycle or missing dep
149
+ result.extend(remaining)
150
+ break
151
+
152
+ return result
153
+
154
+ def get_parallel_groups(self) -> list[list[CompensationPlanStep]]:
155
+ """Get steps grouped for parallel execution.
156
+
157
+ Returns:
158
+ List of step groups that can run in parallel.
159
+ """
160
+ groups = []
161
+ current_group = []
162
+ completed = set()
163
+
164
+ for step in self.get_execution_order():
165
+ # Check if all dependencies are complete
166
+ deps_complete = all(d in completed for d in step.dependencies)
167
+
168
+ if step.can_parallel and deps_complete:
169
+ current_group.append(step)
170
+ else:
171
+ if current_group:
172
+ groups.append(current_group)
173
+ completed.update(s.step_id for s in current_group)
174
+ current_group = []
175
+ groups.append([step])
176
+ completed.add(step.step_id)
177
+
178
+ if current_group:
179
+ groups.append(current_group)
180
+
181
+ return groups
182
+
183
+ def to_dict(self) -> dict[str, Any]:
184
+ """Convert to dictionary for serialization."""
185
+ return {
186
+ "saga_id": self.saga_id,
187
+ "policy": self.policy.value,
188
+ "steps": [
189
+ {
190
+ "step_id": s.step_id,
191
+ "step_name": s.step_name,
192
+ "priority": s.priority.value,
193
+ "strategy": s.strategy,
194
+ "dependencies": s.dependencies,
195
+ "can_parallel": s.can_parallel,
196
+ }
197
+ for s in self.steps
198
+ ],
199
+ "pivot_step_id": self.pivot_step_id,
200
+ "created_at": self.created_at.isoformat(),
201
+ }
202
+
203
+
204
+ class CompensationPlanner:
205
+ """Generates compensation plans for sagas.
206
+
207
+ This class analyzes a saga definition and generates an appropriate
208
+ compensation plan based on the configured policy and step characteristics.
209
+ """
210
+
211
+ def __init__(self, policy: CompensationPolicy = CompensationPolicy.BACKWARD) -> None:
212
+ """Initialize the planner.
213
+
214
+ Args:
215
+ policy: Default compensation policy.
216
+ """
217
+ self._default_policy = policy
218
+
219
+ def create_plan(
220
+ self,
221
+ saga: "SagaDefinition",
222
+ completed_steps: list[str],
223
+ failed_step: str | None = None,
224
+ policy: CompensationPolicy | None = None,
225
+ ) -> CompensationPlan:
226
+ """Create a compensation plan for the saga.
227
+
228
+ Args:
229
+ saga: Saga definition.
230
+ completed_steps: List of completed step IDs.
231
+ failed_step: ID of the failed step (if any).
232
+ policy: Override policy for this plan.
233
+
234
+ Returns:
235
+ Compensation plan.
236
+ """
237
+ effective_policy = policy or self._default_policy
238
+
239
+ plan = CompensationPlan(
240
+ saga_id=saga.saga_id,
241
+ policy=effective_policy,
242
+ )
243
+
244
+ # Find pivot step
245
+ pivot_step = saga.get_pivot_step()
246
+ if pivot_step:
247
+ plan.pivot_step_id = pivot_step.step_id
248
+
249
+ # Get steps to compensate
250
+ steps_to_compensate = self._determine_compensatable_steps(
251
+ saga, completed_steps, failed_step, effective_policy, pivot_step
252
+ )
253
+
254
+ # Build plan based on policy
255
+ if effective_policy == CompensationPolicy.BACKWARD:
256
+ self._build_backward_plan(plan, saga, steps_to_compensate)
257
+ elif effective_policy == CompensationPolicy.FORWARD:
258
+ self._build_forward_plan(plan, saga, completed_steps, failed_step)
259
+ elif effective_policy == CompensationPolicy.SEMANTIC:
260
+ self._build_semantic_plan(plan, saga, steps_to_compensate)
261
+ elif effective_policy == CompensationPolicy.PIVOT:
262
+ self._build_pivot_plan(plan, saga, completed_steps, pivot_step)
263
+ elif effective_policy == CompensationPolicy.COUNTERMEASURE:
264
+ self._build_countermeasure_plan(plan, saga, steps_to_compensate)
265
+ elif effective_policy == CompensationPolicy.PARALLEL:
266
+ self._build_parallel_plan(plan, saga, steps_to_compensate)
267
+ elif effective_policy == CompensationPolicy.SELECTIVE:
268
+ self._build_selective_plan(plan, saga, steps_to_compensate, failed_step)
269
+ elif effective_policy == CompensationPolicy.BEST_EFFORT:
270
+ self._build_best_effort_plan(plan, saga, steps_to_compensate)
271
+
272
+ return plan
273
+
274
+ def _determine_compensatable_steps(
275
+ self,
276
+ saga: "SagaDefinition",
277
+ completed_steps: list[str],
278
+ failed_step: str | None,
279
+ policy: CompensationPolicy,
280
+ pivot_step: "SagaStepDefinition | None",
281
+ ) -> list["SagaStepDefinition"]:
282
+ """Determine which steps need compensation."""
283
+ compensatable = []
284
+
285
+ # Check if we passed the pivot point
286
+ if pivot_step and pivot_step.step_id in completed_steps:
287
+ # Past pivot - no compensation allowed
288
+ logger.info(
289
+ f"Saga passed pivot point at {pivot_step.step_id}, "
290
+ "compensation not possible"
291
+ )
292
+ return []
293
+
294
+ for step in saga.steps:
295
+ # Only compensate completed steps
296
+ if step.step_id not in completed_steps:
297
+ continue
298
+
299
+ # Skip the failed step itself (wasn't completed)
300
+ if step.step_id == failed_step:
301
+ continue
302
+
303
+ # Must have compensation defined
304
+ if not step.has_compensation():
305
+ continue
306
+
307
+ compensatable.append(step)
308
+
309
+ return compensatable
310
+
311
+ def _build_backward_plan(
312
+ self,
313
+ plan: CompensationPlan,
314
+ saga: "SagaDefinition",
315
+ steps: list["SagaStepDefinition"],
316
+ ) -> None:
317
+ """Build backward compensation plan (reverse order)."""
318
+ # Sort by execution order, then reverse
319
+ step_order = {s.step_id: i for i, s in enumerate(saga.steps)}
320
+ sorted_steps = sorted(steps, key=lambda s: step_order.get(s.step_id, 0), reverse=True)
321
+
322
+ prev_step_id = None
323
+ for step in sorted_steps:
324
+ plan_step = CompensationPlanStep(
325
+ step_id=step.step_id,
326
+ step_name=step.name,
327
+ priority=CompensationPriority.NORMAL,
328
+ strategy="backward",
329
+ dependencies=[prev_step_id] if prev_step_id else [],
330
+ action=step.compensation_action or step.compensation_fn,
331
+ )
332
+ plan.add_step(plan_step)
333
+ prev_step_id = step.step_id
334
+
335
+ def _build_forward_plan(
336
+ self,
337
+ plan: CompensationPlan,
338
+ saga: "SagaDefinition",
339
+ completed_steps: list[str],
340
+ failed_step: str | None,
341
+ ) -> None:
342
+ """Build forward recovery plan (try to complete)."""
343
+ # Get remaining steps after failure
344
+ execution_order = saga.get_execution_order()
345
+ failed_index = next(
346
+ (i for i, s in enumerate(execution_order) if s.step_id == failed_step),
347
+ len(execution_order),
348
+ )
349
+
350
+ for step in execution_order[failed_index:]:
351
+ if step.step_id in completed_steps:
352
+ continue
353
+
354
+ # Add as forward recovery step
355
+ plan_step = CompensationPlanStep(
356
+ step_id=step.step_id,
357
+ step_name=step.name,
358
+ priority=CompensationPriority.NORMAL,
359
+ strategy="forward",
360
+ action=step.action,
361
+ metadata={"recovery": True},
362
+ )
363
+ plan.add_step(plan_step)
364
+
365
+ def _build_semantic_plan(
366
+ self,
367
+ plan: CompensationPlan,
368
+ saga: "SagaDefinition",
369
+ steps: list["SagaStepDefinition"],
370
+ ) -> None:
371
+ """Build semantic compensation plan."""
372
+ for step in reversed(steps):
373
+ priority = (
374
+ CompensationPriority.HIGH if step.required else CompensationPriority.NORMAL
375
+ )
376
+ strategy = "semantic" if step.semantic_undo else "backward"
377
+
378
+ plan_step = CompensationPlanStep(
379
+ step_id=step.step_id,
380
+ step_name=step.name,
381
+ priority=priority,
382
+ strategy=strategy,
383
+ action=step.compensation_action or step.compensation_fn,
384
+ metadata={"semantic_undo": step.semantic_undo},
385
+ )
386
+ plan.add_step(plan_step)
387
+
388
+ def _build_pivot_plan(
389
+ self,
390
+ plan: CompensationPlan,
391
+ saga: "SagaDefinition",
392
+ completed_steps: list[str],
393
+ pivot_step: "SagaStepDefinition | None",
394
+ ) -> None:
395
+ """Build compensation plan with pivot transaction support."""
396
+ if pivot_step and pivot_step.step_id in completed_steps:
397
+ # Past pivot - use forward recovery
398
+ plan.policy = CompensationPolicy.FORWARD
399
+ plan.metadata["pivot_passed"] = True
400
+ logger.info("Pivot passed, switching to forward recovery")
401
+ return
402
+
403
+ # Normal backward compensation up to pivot
404
+ compensatable = []
405
+ for step in saga.steps:
406
+ if step.step_id not in completed_steps:
407
+ continue
408
+ if step.is_pivot:
409
+ break
410
+ if step.has_compensation():
411
+ compensatable.append(step)
412
+
413
+ self._build_backward_plan(plan, saga, compensatable)
414
+
415
+ def _build_countermeasure_plan(
416
+ self,
417
+ plan: CompensationPlan,
418
+ saga: "SagaDefinition",
419
+ steps: list["SagaStepDefinition"],
420
+ ) -> None:
421
+ """Build countermeasure compensation plan."""
422
+ for step in saga.steps:
423
+ if not step.is_countermeasure:
424
+ continue
425
+
426
+ plan_step = CompensationPlanStep(
427
+ step_id=step.step_id,
428
+ step_name=step.name,
429
+ priority=CompensationPriority.HIGH,
430
+ strategy="countermeasure",
431
+ action=step.action,
432
+ metadata={"is_countermeasure": True},
433
+ )
434
+ plan.add_step(plan_step)
435
+
436
+ def _build_parallel_plan(
437
+ self,
438
+ plan: CompensationPlan,
439
+ saga: "SagaDefinition",
440
+ steps: list["SagaStepDefinition"],
441
+ ) -> None:
442
+ """Build parallel compensation plan."""
443
+ for step in steps:
444
+ # All steps marked as parallel-capable
445
+ plan_step = CompensationPlanStep(
446
+ step_id=step.step_id,
447
+ step_name=step.name,
448
+ priority=CompensationPriority.NORMAL,
449
+ strategy="parallel",
450
+ action=step.compensation_action or step.compensation_fn,
451
+ can_parallel=True,
452
+ # Dependencies only from step definition
453
+ dependencies=[d.step_id for d in step.dependencies],
454
+ )
455
+ plan.add_step(plan_step)
456
+
457
+ def _build_selective_plan(
458
+ self,
459
+ plan: CompensationPlan,
460
+ saga: "SagaDefinition",
461
+ steps: list["SagaStepDefinition"],
462
+ failed_step: str | None,
463
+ ) -> None:
464
+ """Build selective compensation plan."""
465
+ # Only compensate steps related to the failed step
466
+ if not failed_step:
467
+ return
468
+
469
+ failed_step_def = saga.get_step(failed_step)
470
+ if not failed_step_def:
471
+ return
472
+
473
+ # Find dependent steps
474
+ dependent_ids = set()
475
+ for step in saga.steps:
476
+ for dep in step.dependencies:
477
+ if dep.step_id == failed_step:
478
+ dependent_ids.add(step.step_id)
479
+
480
+ # Compensate only related steps
481
+ for step in reversed(steps):
482
+ is_related = (
483
+ step.step_id in dependent_ids
484
+ or any(d.step_id == failed_step for d in step.dependencies)
485
+ )
486
+
487
+ if is_related and step.has_compensation():
488
+ plan_step = CompensationPlanStep(
489
+ step_id=step.step_id,
490
+ step_name=step.name,
491
+ priority=CompensationPriority.NORMAL,
492
+ strategy="selective",
493
+ action=step.compensation_action or step.compensation_fn,
494
+ )
495
+ plan.add_step(plan_step)
496
+
497
+ def _build_best_effort_plan(
498
+ self,
499
+ plan: CompensationPlan,
500
+ saga: "SagaDefinition",
501
+ steps: list["SagaStepDefinition"],
502
+ ) -> None:
503
+ """Build best-effort compensation plan."""
504
+ for step in reversed(steps):
505
+ plan_step = CompensationPlanStep(
506
+ step_id=step.step_id,
507
+ step_name=step.name,
508
+ priority=CompensationPriority.OPTIONAL,
509
+ strategy="best_effort",
510
+ action=step.compensation_action or step.compensation_fn,
511
+ can_parallel=True, # All can run in parallel
512
+ )
513
+ plan.add_step(plan_step)
514
+
515
+
516
+ # =============================================================================
517
+ # Strategy Implementations
518
+ # =============================================================================
519
+
520
+
521
+ class CompensationStrategyBase(ABC):
522
+ """Base class for compensation strategy implementations."""
523
+
524
+ @abstractmethod
525
+ def execute(
526
+ self,
527
+ plan: CompensationPlan,
528
+ checkpoint_result: "CheckpointResult",
529
+ context: "TransactionContext",
530
+ ) -> list["CompensationResult"]:
531
+ """Execute the compensation plan.
532
+
533
+ Args:
534
+ plan: Compensation plan to execute.
535
+ checkpoint_result: Original checkpoint result.
536
+ context: Transaction context.
537
+
538
+ Returns:
539
+ List of compensation results.
540
+ """
541
+ pass
542
+
543
+
544
+ class SemanticCompensation(CompensationStrategyBase):
545
+ """Semantic compensation strategy.
546
+
547
+ Semantic compensation allows for compensation actions that don't
548
+ strictly undo the original action but provide a semantically
549
+ equivalent outcome.
550
+
551
+ Example:
552
+ - Original: Reserve 10 seats
553
+ - Strict undo: Release 10 seats
554
+ - Semantic: Add 10 seats to waiting list
555
+ """
556
+
557
+ def __init__(
558
+ self,
559
+ fallback_to_strict: bool = True,
560
+ require_acknowledgment: bool = False,
561
+ ) -> None:
562
+ """Initialize semantic compensation.
563
+
564
+ Args:
565
+ fallback_to_strict: Fall back to strict undo if semantic fails.
566
+ require_acknowledgment: Require external acknowledgment.
567
+ """
568
+ self._fallback_to_strict = fallback_to_strict
569
+ self._require_acknowledgment = require_acknowledgment
570
+
571
+ def execute(
572
+ self,
573
+ plan: CompensationPlan,
574
+ checkpoint_result: "CheckpointResult",
575
+ context: "TransactionContext",
576
+ ) -> list["CompensationResult"]:
577
+ """Execute semantic compensation."""
578
+ from truthound.checkpoint.transaction.base import CompensationResult
579
+
580
+ results = []
581
+
582
+ for step in plan.get_execution_order():
583
+ is_semantic = step.metadata.get("semantic_undo", False)
584
+
585
+ try:
586
+ if step.action:
587
+ if callable(step.action):
588
+ result = step.action(checkpoint_result, None, context)
589
+ else:
590
+ result = step.action.execute(checkpoint_result)
591
+
592
+ comp_result = CompensationResult(
593
+ action_name=step.step_name,
594
+ success=True,
595
+ details={"semantic": is_semantic},
596
+ )
597
+ else:
598
+ comp_result = CompensationResult(
599
+ action_name=step.step_name,
600
+ success=False,
601
+ error="No compensation action defined",
602
+ )
603
+
604
+ results.append(comp_result)
605
+
606
+ except Exception as e:
607
+ if self._fallback_to_strict and is_semantic:
608
+ logger.info(f"Semantic compensation failed, trying strict: {e}")
609
+ # Could try strict undo here
610
+ comp_result = CompensationResult(
611
+ action_name=step.step_name,
612
+ success=False,
613
+ error=f"Semantic compensation failed: {e}",
614
+ )
615
+ else:
616
+ comp_result = CompensationResult(
617
+ action_name=step.step_name,
618
+ success=False,
619
+ error=str(e),
620
+ )
621
+ results.append(comp_result)
622
+
623
+ return results
624
+
625
+
626
+ class PivotTransaction(CompensationStrategyBase):
627
+ """Pivot transaction strategy.
628
+
629
+ A pivot transaction is a step in a saga that represents a point
630
+ of no return. Once the pivot succeeds, the saga cannot be
631
+ compensated and must proceed forward.
632
+
633
+ Example:
634
+ - Step 1: Reserve seats (compensatable)
635
+ - Step 2: Charge card (compensatable)
636
+ - Step 3: Issue ticket (PIVOT - irreversible)
637
+ - Step 4: Send confirmation (must complete)
638
+
639
+ If step 4 fails, compensation stops at step 3.
640
+ """
641
+
642
+ def __init__(self, pivot_step_id: str) -> None:
643
+ """Initialize pivot transaction.
644
+
645
+ Args:
646
+ pivot_step_id: ID of the pivot step.
647
+ """
648
+ self._pivot_step_id = pivot_step_id
649
+
650
+ def execute(
651
+ self,
652
+ plan: CompensationPlan,
653
+ checkpoint_result: "CheckpointResult",
654
+ context: "TransactionContext",
655
+ ) -> list["CompensationResult"]:
656
+ """Execute pivot-aware compensation."""
657
+ from truthound.checkpoint.transaction.base import CompensationResult
658
+
659
+ results = []
660
+
661
+ for step in plan.get_execution_order():
662
+ # Stop at pivot
663
+ if step.step_id == self._pivot_step_id:
664
+ logger.info(f"Reached pivot step {step.step_id}, stopping compensation")
665
+ break
666
+
667
+ if step.action:
668
+ try:
669
+ if callable(step.action):
670
+ step.action(checkpoint_result, None, context)
671
+ else:
672
+ step.action.execute(checkpoint_result)
673
+
674
+ results.append(
675
+ CompensationResult(
676
+ action_name=step.step_name,
677
+ success=True,
678
+ )
679
+ )
680
+ except Exception as e:
681
+ results.append(
682
+ CompensationResult(
683
+ action_name=step.step_name,
684
+ success=False,
685
+ error=str(e),
686
+ )
687
+ )
688
+
689
+ return results
690
+
691
+
692
+ class CountermeasureStrategy(CompensationStrategyBase):
693
+ """Countermeasure compensation strategy.
694
+
695
+ Instead of undoing completed actions, countermeasures apply
696
+ corrective actions to handle the failure state.
697
+
698
+ Example:
699
+ - Original failure: Payment declined after inventory reserved
700
+ - Undo: Release inventory (traditional)
701
+ - Countermeasure: Send payment retry notification,
702
+ hold inventory for 24 hours
703
+ """
704
+
705
+ def __init__(
706
+ self,
707
+ countermeasures: dict[str, Callable[..., Any]] | None = None,
708
+ apply_in_order: bool = True,
709
+ ) -> None:
710
+ """Initialize countermeasure strategy.
711
+
712
+ Args:
713
+ countermeasures: Map of step ID to countermeasure function.
714
+ apply_in_order: Apply countermeasures in saga order.
715
+ """
716
+ self._countermeasures = countermeasures or {}
717
+ self._apply_in_order = apply_in_order
718
+
719
+ def add_countermeasure(
720
+ self,
721
+ step_id: str,
722
+ action: Callable[..., Any],
723
+ ) -> "CountermeasureStrategy":
724
+ """Add a countermeasure for a step.
725
+
726
+ Args:
727
+ step_id: Step to apply countermeasure for.
728
+ action: Countermeasure action.
729
+
730
+ Returns:
731
+ Self for chaining.
732
+ """
733
+ self._countermeasures[step_id] = action
734
+ return self
735
+
736
+ def execute(
737
+ self,
738
+ plan: CompensationPlan,
739
+ checkpoint_result: "CheckpointResult",
740
+ context: "TransactionContext",
741
+ ) -> list["CompensationResult"]:
742
+ """Execute countermeasure compensation."""
743
+ from truthound.checkpoint.transaction.base import CompensationResult
744
+
745
+ results = []
746
+
747
+ # Find countermeasure steps
748
+ countermeasure_steps = [
749
+ s for s in plan.steps
750
+ if s.metadata.get("is_countermeasure") or s.step_id in self._countermeasures
751
+ ]
752
+
753
+ for step in countermeasure_steps:
754
+ action = self._countermeasures.get(step.step_id, step.action)
755
+
756
+ if action:
757
+ try:
758
+ if callable(action):
759
+ action(checkpoint_result, None, context)
760
+ else:
761
+ action.execute(checkpoint_result)
762
+
763
+ results.append(
764
+ CompensationResult(
765
+ action_name=step.step_name,
766
+ success=True,
767
+ details={"type": "countermeasure"},
768
+ )
769
+ )
770
+ except Exception as e:
771
+ results.append(
772
+ CompensationResult(
773
+ action_name=step.step_name,
774
+ success=False,
775
+ error=str(e),
776
+ details={"type": "countermeasure"},
777
+ )
778
+ )
779
+
780
+ return results