Truthound 3.x Architecture¶
Design Goal¶
Truthound 3.0 replaces a compatibility-oriented 2.x facade with a native zero-config validation platform. The primary design target is not novelty; it is maintainability, exactness, and extensibility under real production pressure.
This redesign draws on four reference systems:
- Great Expectations: suite execution separated from storage and presentation
- Soda: scan planning and backend-aware execution
- Deequ: analyzers, constraints, verification, and metric repositories as distinct concepts
- Pandera: schema-centric validation and lazy data interaction
Architectural Theme¶
Truthound 3.0 is organized around:
- a small kernel
- a first-class
TruthoundContext - deterministic auto-suite synthesis
- exact-by-default validation semantics
- optional namespaces for non-core systems
The public documentation portal also exposes two first-party layers around that kernel plus one additive review namespace:
| Layer | Repository | Responsibility |
|---|---|---|
Truthound Core |
truthound |
data-plane validation kernel, zero-config workspace, result model, reporters, checkpoint runtime, profiling |
Truthound AI |
truthound.ai |
review-layer APIs for proposal compilation, run analysis, approval logs, and controlled apply |
Truthound Orchestration |
truthound-orchestration |
execution integration layer for Airflow, Dagster, Prefect, dbt, Mage, and Kestra |
Truthound Dashboard |
separately distributed console | control-plane for sessions, RBAC, sources, artifacts, incidents, secrets, AI review, and observability |
The main docs site aggregates these boundaries, but aggregation is not the same as flattening them into one undifferentiated platform. The kernel remains the source of truth for execution semantics, while the AI namespace, orchestration layer, and dashboard operate around those semantics instead of replacing them.
Kernel Boundaries¶
Truthound now fixes the internal standard boundary at five packages:
| Package | Role | Representative Types |
|---|---|---|
truthound.core.contracts |
Stable ports and capability contracts | DataAsset, ExecutionBackend, MetricRepository, ArtifactStore, PluginCapability |
truthound.core.suite |
Declarative validation intent | ValidationSuite, CheckSpec, SchemaSpec, EvidencePolicy, SeverityPolicy |
truthound.core.planning |
Compilation from suite to executable plan | ScanPlanner, ScanPlan, PlanStep |
truthound.core.runtime |
Orchestration and failure isolation | ValidationRuntime |
truthound.core.results |
Canonical runtime result model | ValidationRunResult, CheckResult, ExecutionIssue |
The context and checkpoint layers sit beside the kernel rather than inside it:
truthound.contextowns.truthound/, baselines, run artifacts, docs artifacts, and plugin-manager accesstruthound.checkpointorchestrates validation around the canonicalValidationRunResult
The first-party external layers sit outside the kernel as well:
truthound.aicompiles prompts and run evidence into reviewable artifacts while keeping provider/redaction logic outside the kernel hot pathtruthound-orchestrationadapts the kernel into host-native execution environments without redefiningValidationRunResult- the dashboard control-plane consumes validation artifacts and operational state without re-implementing validation execution
Runtime Flow¶
flowchart LR
A["th.check(data)"] --> B["TruthoundContext"]
B --> C["AutoSuiteBuilder / ValidationSuite"]
C --> D["ScanPlanner"]
D --> E["ValidationRuntime"]
E --> F["ValidationRunResult"]
F --> G["RunPresentation"]
G --> H["reporters / validation datadocs"]
F --> I["checkpoint / persistence / docs artifacts"]
The facade remains user-friendly, but orchestration is now explicit and canonical end-to-end.
Ports and Adapters¶
Truthound 3.0 uses a ports-and-adapters interpretation tailored for data validation:
- Ports describe durable contracts such as
DataAsset,ExecutionBackend, and plugin capabilities. - Adapters translate real sources into those ports, for example Polars-backed or SQL-backed assets.
- Planning decides whether a suite should execute sequentially, in parallel, or with SQL pushdown, and which metric work can be fused.
- Runtime executes the compiled plan and isolates validator failures into
ExecutionIssue. - Results remain stable even when execution strategy changes.
This lets Truthound evolve the planner or backend strategy without rewriting the user contract.
TruthoundContext and Zero-Config State¶
TruthoundContext is now the default project boundary. It auto-discovers the project root, creates .truthound/, and owns:
- resolved defaults from
truthound.yamlwhen present - asset catalog fingerprints
- baseline schemas and metric history
- persisted validation runs
- validation-doc artifacts
- plugin manager access
The fixed workspace layout is:
.truthound/config.yaml.truthound/catalog/.truthound/baselines/.truthound/runs/.truthound/docs/.truthound/plugins/
Peripheral Boundaries¶
Peripheral subsystems and first-party layers are intentionally kept outside the kernel while still consuming the same canonical contracts:
- checkpoint orchestration uses
CheckpointResult.validation_runas its in-memory result model - checkpoint formatting helpers use
CheckpointResult.validation_viewrather than reintroducing a second result model - profiler integrations consume suite and result contracts without importing report rendering layers directly
- realtime, ML, and lineage integrations are expected to depend on
truthound.corecontracts or subsystem-local adapters rather than presentation or CLI layers - orchestration layers should preserve the kernel result semantics while translating them into host-native payloads
- AI layers should produce proposals, analyses, approval events, and applied suite records without back-importing
truthound.aiintotruthound.core - dashboard layers should operate on artifacts, ownership, and observability state rather than inventing a second execution model
This keeps outer subsystems extensible without letting them become alternate sources of truth for results or presentation.
Public Contract¶
Truthound 3.0 narrows the public surface and makes it honest:
th.check()returnsValidationRunResultcompareis imported fromtruthound.drift.compare- the root package exports
TruthoundContext,ValidationSuite,CheckSpec,SchemaSpec,ValidationRunResult, andCheckResult - advanced systems move to namespace imports such as
truthound.mlortruthound.realtime
This prevents the public API from drifting away from the real runtime model.
Auto-Suite and Planner Responsibilities¶
When validators=None, Truthound does not run every validator. It invokes a deterministic AutoSuiteBuilder that:
- always includes schema/nullability/type coverage when enough information exists
- adds uniqueness only for key-like columns inferred from profile and naming heuristics
- adds range checks for numeric columns with confident bounds
- avoids expensive probabilistic work unless explicitly eligible
ScanPlanner then owns the execution planning concerns that previously leaked through the API or validator base layer:
- duplicate check accounting
- coarse execution mode selection
- parallel eligibility
- pushdown eligibility
- backend routing metadata
- execution metadata handed off to validator optimization utilities
Metric deduplication and aggregate fusion live below the planner in validator execution utilities and optimization helpers. The planner is intentionally narrow: it should decide how a suite should run, not perform the validation itself.
Runtime Responsibilities¶
ValidationRuntime owns execution semantics:
- validator construction from
CheckSpec - timeout-safe and retry-safe execution
- sequential and parallel orchestration
- pushdown delegation for SQL assets
- conversion of runtime failures into
ExecutionIssue - stable result ordering
- exact-by-default confirmation behavior
This keeps operational concerns out of suite definition and out of validator authoring.
Backend Strategy¶
Truthound 3.0 treats Polars as the reference backend and optimization target:
PolarsBackendis the primary local execution path- SQL pushdown is planner-driven and first-class
- pandas and Spark enter through datasource adapters but are normalized to the same backend contract
Core deterministic checks are exact by default. Sampling or sketches are allowed only for profiling, drift, anomaly detection, or explicitly approximate workloads, and any sketch-triggered failure should be exact-confirmed before the final verdict.
Result Model¶
ValidationRunResult is the canonical output for the 3.0 kernel. It separates:
- aggregate verdicts through
CheckResult - issue evidence through
ValidationIssue - runtime failures through
ExecutionIssue - actual runtime behavior through
execution_mode - planner-selected coarse strategy through
planned_execution_mode
Convenience methods such as render(), write(), and build_docs() live on the result object, but they are lazy-import facades over reporter and datadocs services rather than alternate result models or pure core primitives.
Presentation Boundary¶
Reporter and validation-doc generation now consume the kernel result model directly:
ValidationRunResultis the only canonical reporter inputRunPresentationis the shared immutable projection used by reporters and validation datadocsReporterContextcarries render-time metadata without re-coupling renderers to runtime internalstruthound.stores.results.ValidationResultis now a persistence DTO, not a rendering contract
This preserves one execution model while still allowing multiple output renderers to share aggregation and formatting logic.
Plugin Architecture¶
The plugin platform now has one lifecycle runtime. See the dedicated Plugin Platform document for details, but the key decision is simple:
PluginManageris the real managerEnterprisePluginManageris a capability-driven facade over that manager
The public extension contracts are:
CheckSpecFactoryReporter.render(run_result, *, context)DataAssetProvider- lifecycle hooks over stable kernel contracts only
This removes lifecycle duplication while still allowing security, trust, hot reload, and versioning capabilities to exist as optional services.
Dependency Rule¶
truthound.core must not depend on:
truthound.reporterstruthound.pluginstruthound.datadocstruthound.cli_modules
That rule is enforced by architecture tests and exists to prevent outer layers from re-coupling the kernel.
Reporter and validation-doc layers must also avoid direct imports of truthound.stores.results; storage conversion is allowed only in adapter modules at the edge.
The same rule now applies to peripheral subsystems such as checkpoint, profiler, realtime, ML, and lineage. If they need presentation or persistence behavior, they should go through subsystem adapters rather than import those outer layers directly.
Stability Model¶
Stability is part of the architecture, not a later hardening pass:
- per-check timeout budgets
- isolated exception capture
- deterministic retry behavior
- idempotent persistence of run artifacts
- corrupted baseline/cache quarantine
- stable serialization and ordering
Migration Path¶
Truthound 3.0 is an intentional breaking release:
- remove legacy
Reportassumptions from core runtime - make
TruthoundContextand auto-suite behavior the default path - standardize plugins and reporters on canonical 3.0 contracts
- isolate optional namespaces from the kernel boundary
- ship migration tooling so upgrades are mechanical rather than guesswork
The detailed user-facing changes are summarized in the Migration Guide and recorded in ADR 001, ADR 002, ADR 003, and ADR 004.
Canonical documentation lives in the main MkDocs navigation. Historical paths remain available only through the Legacy Archive and compatibility alias pages.