<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/feed-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:podcast="https://podcastindex.org/namespace/1.0" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <atom:link rel="self" href="https://feeds.dzone.com/data"/>
    <atom:link rel="hub" href="https://feedpress.superfeedr.com/"/>
    <title>DZone Data Zone</title>
    <link>https://dzone.com/data</link>
    <description>Recent posts in Data on DZone.com</description>
    <item>
      <title>The Role of Multi-Agent AI in Optimizing Warehouse Logistics</title>
      <link>https://feeds.dzone.com/link/23559/17379710/multi-agent-ai-optimizing-warehouse-logistics</link>
      <description><![CDATA[<p dir="ltr">A <a href="https://dzone.com/articles/multi-agent-ai-ddd-event-storming">multi-agent AI system</a> is comprised of several independent but cooperating agents who are working towards a common goal through interaction with one another.</p>
<p dir="ltr">In warehouse logistics, different types of agents can be represented as:</p><img src="https://feeds.dzone.com/link/23559/17379710.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 13 Jul 2026 19:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3653852</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19027502&amp;w=600"/>
      <dc:creator>Lilly Gracia</dc:creator>
    </item>
    <item>
      <title>Building Reliable Async Processing Pipelines Using Temporal</title>
      <link>https://feeds.dzone.com/link/23559/17379519/building-async-pipelines-using-temporal</link>
      <description><![CDATA[<p>Asynchronous processing pipelines are a cornerstone of modern distributed systems, but wiring them together reliably can be complex. A typical pipeline built with queues or message brokers requires custom retry logic, dead-letter queues, cron recovery jobs, and database status flags to ensure every step eventually succeeds.&nbsp;</p>
<p>Temporal replaces this heavy plumbing with durable workflows. In a <a href="https://dzone.com/articles/temporal-workflow-design-patterns">Temporal workflow</a>, the business logic of the pipeline is written as ordinary sequential code, yet it executes reliably across failures. The platform persists every state transition and step so that if a worker crashes or a network blip occurs, execution resumes exactly where it left off.&nbsp;</p><img src="https://feeds.dzone.com/link/23559/17379519.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 13 Jul 2026 13:00:06 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3654791</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19088013&amp;w=600"/>
      <dc:creator>Akhil Madineni</dc:creator>
    </item>
    <item>
      <title>Exploring A Few Java 25 Language Enhancements</title>
      <link>https://feeds.dzone.com/link/23559/17376159/java-25-language-enhancements</link>
      <description><![CDATA[<p>Although Java 26 was released in mid-March this year, Java 25 is the latest LTS version available, and thus I chose to focus my attention on it in the first place.</p>
<p>Irrespective of whether certain Java 25 language improvements are still available as preview features or not, this article briefly outlines a few. The main purpose is to first make the developers aware that Java is continuously refined and evolved by its API contributors and secondly, to raise the curiosity and interest of exploring these enhancements in detail.</p><img src="https://feeds.dzone.com/link/23559/17376159.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 10 Jul 2026 14:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3642504</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19084116&amp;w=600"/>
      <dc:creator>Horatiu Dan</dc:creator>
    </item>
    <item>
      <title>Getting Started With RabbitMQ in Spring Boot</title>
      <link>https://feeds.dzone.com/link/23559/17375023/rabbitmq-spring-boot</link>
      <description><![CDATA[<p>RabbitMQ is an enterprise-grade open-source messaging and streaming broker. In this blog, you will learn some basic concepts of RabbitMQ and how to use it in a Spring Boot application. Enjoy!</p>
<h2>Introduction</h2>
<p>Before diving into the programmatic details, first some concepts need to be explained. Do realize that in this blog, only the surface is scratched from what is possible with RabbitMQ. A detailed overview can be found in the <a href="https://www.rabbitmq.com/tutorials" rel="noopener noreferrer" target="_blank">official RabbitMQ documentation</a>.</p><img src="https://feeds.dzone.com/link/23559/17375023.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 08 Jul 2026 17:00:03 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3665897</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19083484&amp;w=600"/>
      <dc:creator>Gunter Rotsaert</dc:creator>
    </item>
    <item>
      <title>Building Production-Grade Delta Lake Pipelines With Apache Spark on Databricks</title>
      <link>https://feeds.dzone.com/link/23559/17374986/production-grade-data-late-pipelines</link>
      <description><![CDATA[<h2>Why Delta Lake?</h2>
<p>Apache Parquet on cloud storage was a great first step for <a href="https://dzone.com/articles/data-lake-warehouse-or-lakehouse">data lakes</a> — but it left engineers dealing with a painful set of problems in production:</p>
<ul>
 <li><strong>No ACID transactions</strong> — concurrent reads/writes could corrupt data silently</li>
 <li><strong>Schema drift</strong> — nothing stopped upstream systems from changing column types</li>
 <li><strong>No deletes or updates</strong> — GDPR compliance meant rewriting entire partitions</li>
 <li><strong>Painful failure recovery</strong> — half-written data after a job crash became your problem</li>
</ul>
<p>Delta Lake solves all of this by sitting on top of Parquet and adding a transaction log (<code>_delta_log/</code>) that records every operation atomically. On Databricks, Delta is the default table format, deeply integrated with Apache Spark, Auto Optimize, and the Photon execution engine.</p><img src="https://feeds.dzone.com/link/23559/17374986.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 08 Jul 2026 14:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3662913</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19081615&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>A Step-by-Step Guide to Implementing Columnar Tables in SQL Server</title>
      <link>https://feeds.dzone.com/link/23559/17374535/sql-server-columnar-tables</link>
      <description><![CDATA[<p>Columnar storage was introduced in SQL Server 2016 as part of the SQL Server 2016 In-Memory OLTP feature. It is specifically designed for data warehousing and analytical workloads, where large amounts of data need to be scanned, aggregated, or analyzed efficiently.&nbsp;</p>
<p>Columnar storage stores data in a column-wise format rather than the traditional row-wise storage, offering significant performance benefits for read-heavy operations such as reporting and analytics.</p><img src="https://feeds.dzone.com/link/23559/17374535.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 07 Jul 2026 17:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3537817</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19080266&amp;w=600"/>
      <dc:creator>arvind toorpu</dc:creator>
    </item>
    <item>
      <title>Building a Mortgage Agent With FRED Data, FastAPI, and LLM Tool Calling</title>
      <link>https://feeds.dzone.com/link/23559/17374464/mortgage-agent-with-fred-data-fastapi-llm-tool</link>
      <description><![CDATA[<p data-pm-slice="1 1 []">If you have ever tried to build a “mortgage rates today” feature, you have probably landed on the same fork in the road I did. Consumer finance sites publish attractive numbers, but those pages are editorial HTML, not APIs. Layout changes break scrapers, terms of use are unclear, and it is hard to explain what statistic you are actually showing. For a developer project meant to be forked on GitHub, that path is a dead end.</p>
<p>I wanted something smaller and more honest: national 30-year and 15-year fixed benchmarks from a source economists already cite, plus a separate surface where first-time buyers could ask basic questions without handing over sensitive data. The result is US Homes Mortgage Agent, an open-source FastAPI application with two clear jobs. One page shows macro rates and a chart. Another page hosts a conversational assistant that is grounded in the same data and in plain Python math.</p><img src="https://feeds.dzone.com/link/23559/17374464.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 07 Jul 2026 13:00:07 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3658597</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19080198&amp;w=600"/>
      <dc:creator>Sushma Kukkadapu</dc:creator>
    </item>
    <item>
      <title>How to Build a Production-Ready RAG Pipeline With Vector DBs</title>
      <link>https://feeds.dzone.com/link/23559/17374071/production-rag-pipeline</link>
      <description><![CDATA[<p dir="ltr">The adoption of retrieval-augmented generation (RAG) from research papers to production systems has been rapid. Those who tried it in 2023 are now deploying it at scale for enterprise search, internal knowledge bases, and customer-facing assistants. However, a lot is still between a working prototype RAG and one that can withstand traffic on the road, using real data, and real modes of failure.</p>
<p dir="ltr">This article explains what this gap is, how to plug it, and where most production pipelines fail.</p><img src="https://feeds.dzone.com/link/23559/17374071.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 06 Jul 2026 19:15:01 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3663121</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19078882&amp;w=600"/>
      <dc:creator>Mark Saxon</dc:creator>
    </item>
    <item>
      <title>Parquet vs Lance: How Storage Layout Changes the Read Path</title>
      <link>https://feeds.dzone.com/link/23559/17373955/parquet-vs-lance-how-storage-layout-changes-the-re-1</link>
      <description><![CDATA[<p dir="ltr">Apache Parquet became the default format for analytical data because it matched the read path of analytical engines. Queries scanned large parts of a dataset, often across a small set of columns, and Parquet was built to support that efficiently. Row groups, column pages, and compression all work well when the goal is to maximize scan throughput.</p>
<p dir="ltr">That model still fits a large part of analytics. But it starts to break down when queries read small subsets of data, especially when those reads are repeated. At that point, the cost is no longer dominated by scanning. It depends on how much data the reader must process before it can return the result. That is where comparing <a href="https://parquet.apache.org/docs/" rel="noopener noreferrer" target="_blank">Parquet</a> with <a href="https://lance.org/guide/read_and_write/" rel="noopener noreferrer" target="_blank">Lance</a> becomes useful; the difference is not just in file format, but in the read path itself. The <a href="https://arxiv.org/pdf/2504.15247" rel="noopener noreferrer" target="_blank">Lance paper</a> frames this problem well by focusing on how structural encoding affects random access and scan performance.</p><img src="https://feeds.dzone.com/link/23559/17373955.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 06 Jul 2026 16:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3654634</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19078861&amp;w=600"/>
      <dc:creator>Hitarth Trivedi</dc:creator>
    </item>
    <item>
      <title>Azure Databricks for Scalable MLOps and Feature Engineering With Apache Spark, Delta Lake, and MLflow</title>
      <link>https://feeds.dzone.com/link/23559/17373871/azure-databricks-mlops</link>
      <description><![CDATA[<p>Raw data doesn't win model competitions. Features do. And when your raw data is tens of billions of rows sitting across multiple sources, you can't afford to run pandas in a notebook and call it a day.</p>
<p>In this tutorial, I'll walk through building a production-grade feature engineering pipeline on <a href="https://dzone.com/articles/azure-databricks-best-practices-for-a-developer">Azure Databricks</a> using:</p><img src="https://feeds.dzone.com/link/23559/17373871.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 06 Jul 2026 14:00:03 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3663565</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19076762&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>From Polling to PubSub: Building an Asynchronous OPC UA Stack in Python</title>
      <link>https://feeds.dzone.com/link/23559/17372372/async-opc-ua-python</link>
      <description><![CDATA[<p data-path-to-node="8">Industrial control systems are generating more data than ever before, but the Python tooling used to process this telemetry often encounters severe performance constraints. Traditional OPC UA libraries are built around synchronous, polling-based Client and Server architectures. When industrial networks scale to thousands of sensors broadcasting high-frequency data, these synchronous Python implementations choke. To handle this modern many-to-many topology, developers need a native Publisher and Subscriber solution that does not block the execution thread while waiting for network packets.</p>
<p data-path-to-node="9">For Python developers unfamiliar with industrial protocols, OPC UA PubSub (IEC 62541-14) is a standard that decouples data producers from consumers by allowing devices to broadcast telemetry via stateless middleware like UDP Multicast. For industrial engineers new to Python concurrency, <code data-index-in-node="288" data-path-to-node="9">asyncio</code> is a standard library that uses an event loop to handle thousands of simultaneous network operations concurrently without the heavy overhead of traditional threading.</p><img src="https://feeds.dzone.com/link/23559/17372372.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 03 Jul 2026 18:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3663572</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19077404&amp;w=600"/>
      <dc:creator>Harshith Narasimhan Srivatsa</dc:creator>
    </item>
    <item>
      <title>Real-Time AI Feature Engineering With Spark Structured Streaming and Databricks Feature Store</title>
      <link>https://feeds.dzone.com/link/23559/17371845/real-time-ai-features-spark-databricks</link>
      <description><![CDATA[<h2>The Feature Engineering Problem</h2>
<p>Feature engineering is where most ML projects silently fail in production. Not because the model is wrong — but because the features the model sees at training time are different from the features it sees at inference time. This is called training-serving skew, and it's the #1 silent killer of ML systems.</p>
<p>Three specific failure modes cause it:</p><img src="https://feeds.dzone.com/link/23559/17371845.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 02 Jul 2026 18:00:05 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3662916</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19077381&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>Dead Letter Queue Patterns in Apache Flink: Handling Poison Messages Without Stopping Your Stream</title>
      <link>https://feeds.dzone.com/link/23559/17371675/flink-dlq-patterns</link>
      <description><![CDATA[<div data-theme="light">
 <p>Streaming systems usually fail in one of two ways:</p>
 <ul>
  <li><strong>Loudly</strong>, when infrastructure breaks</li>
  <li><strong>Quietly</strong>, when one bad record keeps replaying until the pipeline is effectively dead</li>
 </ul>
 <p>The second failure mode is more dangerous because it often starts with something small: malformed JSON, an unexpected schema change, a missing required field, or a downstream timeout that was never handled correctly.</p><img src="https://feeds.dzone.com/link/23559/17371675.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 02 Jul 2026 13:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659522</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19049222&amp;w=600"/>
      <dc:creator>Rohit Muthyala</dc:creator>
    </item>
    <item>
      <title>Apache Spark Query Optimization on Databricks: Catalyst, AQE, and Photon Engine</title>
      <link>https://feeds.dzone.com/link/23559/17371635/spark-query-optimization</link>
      <description><![CDATA[<h2>Why Query Optimization Matters</h2>
<p>A Spark query written by a human and a Spark query executed by the engine are often very different things. The gap between them — the <em>optimization</em> — is what separates a job that runs in 3 minutes from one that runs in 3 hours on identical hardware.</p>
<p>Databricks compounds Spark's native Catalyst optimizer with two additional layers:</p><img src="https://feeds.dzone.com/link/23559/17371635.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 02 Jul 2026 12:00:07 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3662915</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19075064&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>Fine-Tuning LLMs at Scale With Databricks MLflow and Spark</title>
      <link>https://feeds.dzone.com/link/23559/17370486/llm-finetuning-databricks</link>
      <description><![CDATA[<h2>Why Fine-Tune on Databricks?</h2>
<p>General-purpose LLMs like Llama 3, Mistral, or Falcon are impressive out of the box — but they underperform on domain-specific tasks: medical coding, legal clause extraction, internal support ticket classification, and financial report summarization. Fine-tuning adapts a pre-trained model's weights to your domain using your proprietary labeled data.</p>
<p>Doing this <em>at scale</em> introduces real engineering challenges:</p><img src="https://feeds.dzone.com/link/23559/17370486.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 30 Jun 2026 17:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3662914</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19073096&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>A Low-Latency Routing Pattern for Multiple Small Language Models</title>
      <link>https://feeds.dzone.com/link/23559/17370393/low-latency-llm-routing</link>
      <description><![CDATA[<p>A multi-SLM platform creates value only when specialization does not <span style="margin: 0px; padding: 0px;">introduce</span>&nbsp;a new latency tier. Small language models are inexpensive enough to dedicate to focused work such as&nbsp;<span style="margin: 0px; padding: 0px;">extraction</span>, code handling, safety filtering, or short-form reasoning, but that advantage disappears if model selection itself becomes expensive. Research on LLM routing shows that query difficulty varies enough for model choice to materially affect efficiency and quality, and modern serving stacks expose enough control over routing, batching, and cache locality to turn that insight into an operational design rather than an academic one. In practice, the routing layer has to behave like a tiny data-plane decision engine, not like another inference hop.</p>
<h2>Why Multiple SLMs Need Routing</h2>
<p>A single small model rarely gives the best latency-quality trade-off for every prompt type. Short structured requests, such as JSON extraction and classification, differ sharply from code repair, and both differ again from prompts that need broader reasoning. RouteLLM describes routing as assigning simpler queries to weaker models and reserving stronger models for harder cases, while FrugalGPT reports that a learned cascade can preserve strong-model quality with very large cost reductions. Although those papers evaluate broader LLM portfolios, the underlying lesson transfers cleanly to a fleet of small specialized models: heterogeneity in request shape makes heterogeneity in model choice economically and operationally rational.&nbsp;</p><img src="https://feeds.dzone.com/link/23559/17370393.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 30 Jun 2026 14:00:01 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659884</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19073084&amp;w=600"/>
      <dc:creator>Akhil Madineni</dc:creator>
    </item>
    <item>
      <title>A Fully Self‑Contained Text Embedding Service in C#</title>
      <link>https://feeds.dzone.com/link/23559/17370284/a-fully-selfcontained-text-embedding-service-in-c</link>
      <description><![CDATA[<p>Modern semantic search, <span style="margin: 0px; padding: 0px;">retrieval-augmented generation (RAG) pipelines, and large-scale recommendation models heavily rely on&nbsp;<strong>embeddings</strong>&nbsp;— transformations</span>&nbsp;of natural language text into dense numeric representations called vectors. These embeddings position semantically related text in nearby regions of vector space. It enables similarity computation through distant metrices such as Cosine similarity or Euclidean distance. Cloud-hosted services like OpenAI has <code>text-embedding-ada-002</code> provide high-quality vector encodings.&nbsp;</p>
<p>But it comes with API keys, network latency, and per-token usage costs. In contrast, <code>LocalEmbeddingService</code> does all the computation within hosted process, no GPUs, no outbound requests, no model files to manage.&nbsp;</p><img src="https://feeds.dzone.com/link/23559/17370284.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 30 Jun 2026 12:00:07 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3660979</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19073075&amp;w=600"/>
      <dc:creator>Mangesh Walimbe</dc:creator>
    </item>
    <item>
      <title>Wayland Compositor Debugging in C++: Hunting Null Pointer Crashes in the Display Stack</title>
      <link>https://feeds.dzone.com/link/23559/17368749/wayland-compositor-debugging</link>
      <description><![CDATA[<p>The bug looked simple. Resume from sleep, the screen flashes, the display server segfaults. About one in twelve resumes. The device, a Yocto-based industrial Linux box, ARM64, running a custom Wayland compositor on top of wlroots, would log nothing useful, drop to a black screen, and require a reboot. The customer’s complaint was three lines long. The fix took eleven weeks.</p>
<p>This article is what I learned, in the order I learned it, debugging a null pointer dereference inside a Wayland compositor’s lifecycle. It’s specific to wlroots and a custom compositor based on it, but most of the techniques transfer to any C++ system at this layer.</p><img src="https://feeds.dzone.com/link/23559/17368749.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 26 Jun 2026 18:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3658547</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19064643&amp;w=600"/>
      <dc:creator>Rajasekhar sunkara</dc:creator>
    </item>
    <item>
      <title>Data Pipeline Observability: Why Your AI Model Fails in Production</title>
      <link>https://feeds.dzone.com/link/23559/17368707/why-ai-model-fails-in-production</link>
      <description><![CDATA[<h2 data-anchor="the3amincidentthatchangedeverything" data-slate-node="element" data-slug="the3amincidentthatchangedeverything3"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The 3:00 AM Incident That Changed Everything</span></span></span></h2>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">It was a Tuesday morning when the alerts started firing. Our recommendation engine, the one that drives 30% of our revenue, had tanked. Accuracy dropped from 94% to 58% overnight. The data science team immediately blamed the model. They started tweaking hyperparameters, re-training on new data, and running diagnostics. Nothing worked.&nbsp;</span></span></span>
</div>
<div data-slate-node="element">
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">I got pulled into the war room at 3:00 AM. The first thing I asked wasn't "What's wrong with the model?" It was "What changed in the data pipeline?"</span></span></span>
</div>
<div data-slate-node="element">
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Turns out, everything.</span></span></span>
 <br>
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">A vendor had pushed a schema change upstream. A field that used to be required became optional. Null values started flowing through our pipeline. Our feature engineering code didn't handle nulls gracefully; it just propagated them downstream. By the time the data reached the model, 40% of our feature vectors were corrupted.</span></span></span>
 <br>
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The model wasn't broken. The data was.</span></span></span>
 <br>
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">We spent six hours manually rolling back the schema change, re-running the pipeline, and restoring service. The incident report was brutal: "Lack of data validation caught a breaking change too late."</span></span></span>
</div>
<div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjAzJTIwQU0lMjBJbmNpZGVudCUyMFRoYXQlMjBDaGFuZ2VkJTIwRXZlcnl0aGluZyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySXQlMjB3YXMlMjBhJTIwVHVlc2RheSUyMG1vcm5pbmclMjB3aGVuJTIwdGhlJTIwYWxlcnRzJTIwc3RhcnRlZCUyMGZpcmluZy4lMjBPdXIlMjByZWNvbW1lbmRhdGlvbiUyMGVuZ2luZSVFMiU4MCU5NHRoZSUyMG9uZSUyMHRoYXQlMjBkcml2ZXMlMjAzMCUyNSUyMG9mJTIwb3VyJTIwcmV2ZW51ZSVFMiU4MCU5NGhhZCUyMHRhbmtlZC4lMjBBY2N1cmFjeSUyMGRyb3BwZWQlMjBmcm9tJTIwOTQlMjUlMjB0byUyMDU4JTI1JTIwb3Zlcm5pZ2h0LiUyMFRoZSUyMGRhdGElMjBzY2llbmNlJTIwdGVhbSUyMGltbWVkaWF0ZWx5JTIwYmxhbWVkJTIwdGhlJTIwbW9kZWwuJTIwVGhleSUyMHN0YXJ0ZWQlMjB0d2Vha2luZyUyMGh5cGVycGFyYW1ldGVycyUyQyUyMHJlLXRyYWluaW5nJTIwb24lMjBuZXclMjBkYXRhJTJDJTIwcnVubmluZyUyMGRpYWdub3N0aWNzLiUyME5vdGhpbmclMjB3b3JrZWQuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJJJTIwZ290JTIwcHVsbGVkJTIwaW50byUyMHRoZSUyMHdhciUyMHJvb20lMjBhdCUyMDMlMjBBTS4lMjBUaGUlMjBmaXJzdCUyMHRoaW5nJTIwSSUyMGFza2VkJTIwd2Fzbid0JTIwJTVDJTIyV2hhdCdzJTIwd3JvbmclMjB3aXRoJTIwdGhlJTIwbW9kZWwlM0YlNUMlMjIlMjBJdCUyMHdhcyUyMCU1QyUyMldoYXQlMjBjaGFuZ2VkJTIwaW4lMjB0aGUlMjBkYXRhJTIwcGlwZWxpbmUlM0YlNUMlMjIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlR1cm5zJTIwb3V0JTJDJTIwZXZlcnl0aGluZy4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkElMjB2ZW5kb3IlMjBoYWQlMjBwdXNoZWQlMjBhJTIwc2NoZW1hJTIwY2hhbmdlJTIwdXBzdHJlYW0uJTIwQSUyMGZpZWxkJTIwdGhhdCUyMHVzZWQlMjB0byUyMGJlJTIwcmVxdWlyZWQlMjBiZWNhbWUlMjBvcHRpb25hbC4lMjBOdWxsJTIwdmFsdWVzJTIwc3RhcnRlZCUyMGZsb3dpbmclMjB0aHJvdWdoJTIwb3VyJTIwcGlwZWxpbmUuJTIwT3VyJTIwZmVhdHVyZSUyMGVuZ2luZWVyaW5nJTIwY29kZSUyMGRpZG4ndCUyMGhhbmRsZSUyMG51bGxzJTIwZ3JhY2VmdWxseSVFMiU4MCU5NGl0JTIwanVzdCUyMHByb3BhZ2F0ZWQlMjB0aGVtJTIwZG93bnN0cmVhbS4lMjBCeSUyMHRoZSUyMHRpbWUlMjB0aGUlMjBkYXRhJTIwcmVhY2hlZCUyMHRoZSUyMG1vZGVsJTJDJTIwNDAlMjUlMjBvZiUyMG91ciUyMGZlYXR1cmUlMjB2ZWN0b3JzJTIwd2VyZSUyMGNvcnJ1cHRlZC4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoZSUyMG1vZGVsJTIwd2Fzbid0JTIwYnJva2VuLiUyMFRoZSUyMGRhdGElMjB3YXMuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJXZSUyMHNwZW50JTIwc2l4JTIwaG91cnMlMjBtYW51YWxseSUyMHJvbGxpbmclMjBiYWNrJTIwdGhlJTIwc2NoZW1hJTIwY2hhbmdlJTJDJTIwcmUtcnVubmluZyUyMHRoZSUyMHBpcGVsaW5lJTJDJTIwYW5kJTIwcmVzdG9yaW5nJTIwc2VydmljZS4lMjBUaGUlMjBpbmNpZGVudCUyMHJlcG9ydCUyMHdhcyUyMGJydXRhbCUzQSUyMCU1QyUyMkxhY2slMjBvZiUyMGRhdGElMjB2YWxpZGF0aW9uJTIwY2F1Z2h0JTIwYSUyMGJyZWFraW5nJTIwY2hhbmdlJTIwdG9vJTIwbGF0ZS4lNUMlMjIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoYXQncyUyMHdoZW4lMjBJJTIwcmVhbGl6ZWQlMjB3ZSUyMG5lZWRlZCUyMG9ic2VydmFiaWxpdHklMjBpbiUyMG91ciUyMGRhdGElMjBwaXBlbGluZSUyQyUyMG5vdCUyMGp1c3QlMjBpbiUyMG91ciUyMG1vZGVscy4lMjIlN0QlNUQlN0QlNUQ=">
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">That's when I realized we needed&nbsp;</span></span></span><a href="https://dzone.com/articles/introduction-to-the-four-pillars-of-observability"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">observability</span></span></span></a><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;in our data pipeline, not just in our models.</span></span></span>
  <br>
  <br>
 </div>
 <h2 data-anchor="theproblem%3Adataqualityisinvisibleuntilitbreaks" data-slate-node="element" data-slug="theproblem%3Adataqualityisinvisibleuntilitbreaks12"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Problem: Data Quality is Invisible Until It Breaks</span></span></span></h2>
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's the uncomfortable truth about data pipelines: they fail silently.</span></span></span>
  <br>
  <br>
 </div>
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Your ETL job completes successfully. Your Spark cluster finishes transformations. Your data warehouse loads without errors. Everything looks green in the monitoring dashboard. But the data itself? Garbage in, garbage out.</span></span></span>
  <br>
  <br>
 </div>
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">There are three categories of failures that break AI models in production:</span></span></span>
  <br>
  <br>
 </div>
 <ul>
  <li>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>Missing Values:</strong></span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>&nbsp;</strong>A source system stops populating a field. Your pipeline doesn't validate it. The model gets NaN values it never saw during training. Predictions become random noise.</span></span></span>
   </div></li>
  <li>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>Schema Changes:</strong></span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>&nbsp;</strong>An upstream team adds a new column, renames an existing one, or changes data types. Your pipeline doesn't expect these changes. Either it crashes, or worse, it silently maps data to the wrong columns.</span></span></span>
   </div></li>
  <li>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>Distribution Shifts:</strong></span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>&nbsp;</strong>The statistical properties of your data change. A field that was always between 0 and 100 suddenly has values of 50,000. Your model's scaling assumptions break. Predictions become nonsensical.</span></span></span>
   </div></li>
 </ul>
 <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBQcm9ibGVtJTNBJTIwRGF0YSUyMFF1YWxpdHklMjBpcyUyMEludmlzaWJsZSUyMFVudGlsJTIwSXQlMjBCcmVha3MlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkhlcmUncyUyMHRoZSUyMHVuY29tZm9ydGFibGUlMjB0cnV0aCUyMGFib3V0JTIwZGF0YSUyMHBpcGVsaW5lcyUzQSUyMHRoZXklMjBmYWlsJTIwc2lsZW50bHkuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJZb3VyJTIwRVRMJTIwam9iJTIwY29tcGxldGVzJTIwc3VjY2Vzc2Z1bGx5LiUyMFlvdXIlMjBTcGFyayUyMGNsdXN0ZXIlMjBmaW5pc2hlcyUyMHRyYW5zZm9ybWF0aW9ucy4lMjBZb3VyJTIwZGF0YSUyMHdhcmVob3VzZSUyMGxvYWRzJTIwd2l0aG91dCUyMGVycm9ycy4lMjBFdmVyeXRoaW5nJTIwbG9va3MlMjBncmVlbiUyMGluJTIwdGhlJTIwbW9uaXRvcmluZyUyMGRhc2hib2FyZC4lMjBCdXQlMjB0aGUlMjBkYXRhJTIwaXRzZWxmJTNGJTIwR2FyYmFnZSUyMGluJTJDJTIwZ2FyYmFnZSUyMG91dC4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoZXJlJTIwYXJlJTIwdGhyZWUlMjBjYXRlZ29yaWVzJTIwb2YlMjBmYWlsdXJlcyUyMHRoYXQlMjBicmVhayUyMEFJJTIwbW9kZWxzJTIwaW4lMjBwcm9kdWN0aW9uJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJNaXNzaW5nJTIwVmFsdWVzJTNBJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIwQSUyMHNvdXJjZSUyMHN5c3RlbSUyMHN0b3BzJTIwcG9wdWxhdGluZyUyMGElMjBmaWVsZC4lMjBZb3VyJTIwcGlwZWxpbmUlMjBkb2Vzbid0JTIwdmFsaWRhdGUlMjBpdC4lMjBUaGUlMjBtb2RlbCUyMGdldHMlMjBOYU4lMjB2YWx1ZXMlMjBpdCUyMG5ldmVyJTIwc2F3JTIwZHVyaW5nJTIwdHJhaW5pbmcuJTIwUHJlZGljdGlvbnMlMjBiZWNvbWUlMjByYW5kb20lMjBub2lzZS4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlNjaGVtYSUyMENoYW5nZXMlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBBbiUyMHVwc3RyZWFtJTIwdGVhbSUyMGFkZHMlMjBhJTIwbmV3JTIwY29sdW1uJTJDJTIwcmVuYW1lcyUyMGFuJTIwZXhpc3RpbmclMjBvbmUlMkMlMjBvciUyMGNoYW5nZXMlMjBkYXRhJTIwdHlwZXMuJTIwWW91ciUyMHBpcGVsaW5lJTIwZG9lc24ndCUyMGV4cGVjdCUyMHRoZXNlJTIwY2hhbmdlcy4lMjBFaXRoZXIlMjBpdCUyMGNyYXNoZXMlMkMlMjBvciUyMHdvcnNlJTJDJTIwaXQlMjBzaWxlbnRseSUyMG1hcHMlMjBkYXRhJTIwdG8lMjB0aGUlMjB3cm9uZyUyMGNvbHVtbnMuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJEaXN0cmlidXRpb24lMjBTaGlmdHMlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBUaGUlMjBzdGF0aXN0aWNhbCUyMHByb3BlcnRpZXMlMjBvZiUyMHlvdXIlMjBkYXRhJTIwY2hhbmdlLiUyMEElMjBmaWVsZCUyMHRoYXQlMjB3YXMlMjBhbHdheXMlMjBiZXR3ZWVuJTIwMCUyMGFuZCUyMDEwMCUyMHN1ZGRlbmx5JTIwaGFzJTIwdmFsdWVzJTIwb2YlMjA1MCUyQzAwMC4lMjBZb3VyJTIwbW9kZWwncyUyMHNjYWxpbmclMjBhc3N1bXB0aW9ucyUyMGJyZWFrLiUyMFByZWRpY3Rpb25zJTIwYmVjb21lJTIwbm9uc2Vuc2ljYWwuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJOb25lJTIwb2YlMjB0aGVzZSUyMHNob3clMjB1cCUyMGluJTIwdHJhZGl0aW9uYWwlMjBpbmZyYXN0cnVjdHVyZSUyMG1vbml0b3JpbmcuJTIwWW91ciUyMENQVSUyMGlzJTIwZmluZS4lMjBNZW1vcnklMjBpcyUyMGZpbmUuJTIwTmV0d29yayUyMGlzJTIwZmluZS4lMjBCdXQlMjB5b3VyJTIwZGF0YSUyMGlzJTIwb24lMjBmaXJlLiUyMiU3RCU1RCU3RCU1RA==">
  <div data-slate-node="element">
   <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">None of these show up in traditional infrastructure monitoring. Your CPU is fine. Memory is fine. Network is fine. But your data is on fire.</span></span></span>
  </div>
  <h2 data-anchor="thesolution%3Aobservabilityateverylayer" data-slate-node="element" data-slug="thesolution%3Aobservabilityateverylayer21"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Solution: Observability at Every Layer</span></span></span></h2>
  <div data-slate-node="element">
   <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">I started building a three-layer observability framework using dbt, Great Expectations, and custom validation logic. The goal was simple: catch data quality issues before they reach the model.</span></span></span>
  </div>
  <h3 data-anchor="layer1%3Adbttests(thefirstlineofdefense)" data-slate-node="element" data-slug="layer1%3Adbttests(thefirstlineofdefense)23"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Layer 1: dbt Tests (The First Line of Defense)</span></span></span></h3>
  <div data-slate-node="element">
   <a href="https://dzone.com/articles/dbt-false-failures"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">dbt tests</span></span></span></a><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;are your cheapest, fastest way to catch obvious data quality issues. They run after every transformation and fail the entire pipeline if something's wrong.</span></span></span>
  </div>
  <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBTb2x1dGlvbiUzQSUyME9ic2VydmFiaWxpdHklMjBhdCUyMEV2ZXJ5JTIwTGF5ZXIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkklMjBzdGFydGVkJTIwYnVpbGRpbmclMjBhJTIwdGhyZWUtbGF5ZXIlMjBvYnNlcnZhYmlsaXR5JTIwZnJhbWV3b3JrJTIwdXNpbmclMjBkYnQlMkMlMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyQyUyMGFuZCUyMGN1c3RvbSUyMHZhbGlkYXRpb24lMjBsb2dpYy4lMjBUaGUlMjBnb2FsJTIwd2FzJTIwc2ltcGxlJTNBJTIwY2F0Y2glMjBkYXRhJTIwcXVhbGl0eSUyMGlzc3VlcyUyMGJlZm9yZSUyMHRoZXklMjByZWFjaCUyMHRoZSUyMG1vZGVsLiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJoZWFkaW5nJTIyJTJDJTIybGV2ZWwlMjIlM0EzJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyTGF5ZXIlMjAxJTNBJTIwZGJ0JTIwVGVzdHMlMjAoVGhlJTIwRmlyc3QlMjBMaW5lJTIwb2YlMjBEZWZlbnNlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyZGJ0JTIwdGVzdHMlMjBhcmUlMjB5b3VyJTIwY2hlYXBlc3QlMkMlMjBmYXN0ZXN0JTIwd2F5JTIwdG8lMjBjYXRjaCUyMG9idmlvdXMlMjBkYXRhJTIwcXVhbGl0eSUyMGlzc3Vlcy4lMjBUaGV5JTIwcnVuJTIwYWZ0ZXIlMjBldmVyeSUyMHRyYW5zZm9ybWF0aW9uJTIwYW5kJTIwZmFpbCUyMHRoZSUyMGVudGlyZSUyMHBpcGVsaW5lJTIwaWYlMjBzb21ldGhpbmcncyUyMHdyb25nLiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySGVyZSdzJTIwd2hhdCUyMHdlJTIwaW1wbGVtZW50ZWQlM0ElMjIlN0QlNUQlN0QlNUQ=">
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's what we implemented:</span></span></span>
   </div>
   <div class="codeMirror-wrapper" contenteditable="false">
    <div contenteditable="false">
     <div class="codeHeader">
      <div class="nameLanguage">
       SQL
      </div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
     </div>
     <div class="codeMirror-code--wrapper" data-code="-- models/staging/stg_user_events.yml
version: 2

models:
  - name: stg_user_events
    columns:
      - name: user_id
        tests:
          - not_null
          - unique
      - name: event_timestamp
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: &quot;event_timestamp <= current_timestamp()&quot;
      - name: event_value
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: &quot;event_value > 0&quot;" data-lang="text/x-sql">
      <pre><code lang="text/x-sql">-- models/staging/stg_user_events.yml
version: 2

models:
  - name: stg_user_events
    columns:
      - name: user_id
        tests:
          - not_null
          - unique
      - name: event_timestamp
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: "event_timestamp &lt;= current_timestamp()"
      - name: event_value
        tests:
          - not_null
          - dbt_utils.expression_is_true:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; expression: "event_value &gt; 0"</code></pre>
     </div>
    </div>
   </div>
   <div data-slate-node="element">
    <br>
   </div>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">These tests are simple but powerful. They catch:</span></span></span>
   </div>
   <ul>
    <li>Missing required fields (<code>not_null</code>)</li>
    <li>Duplicate records (unique)</li>
    <li>Impossible values (<code>event_timestamp</code> in the future)</li>
    <li>Out-of-range values (negative prices)</li>
   </ul>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">We run these tests on every dbt run. If any test fails, the pipeline stops. No data reaches the model. No silent corruption.</span></span></span>
    <br>
    <br>
   </div>
   <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGVzZSUyMHRlc3RzJTIwYXJlJTIwc2ltcGxlJTIwYnV0JTIwcG93ZXJmdWwuJTIwVGhleSUyMGNhdGNoJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyTWlzc2luZyUyMHJlcXVpcmVkJTIwZmllbGRzJTIwKG5vdF9udWxsKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkR1cGxpY2F0ZSUyMHJlY29yZHMlMjAodW5pcXVlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkltcG9zc2libGUlMjB2YWx1ZXMlMjAoZXZlbnRfdGltZXN0YW1wJTIwaW4lMjB0aGUlMjBmdXR1cmUpJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyT3V0LW9mLXJhbmdlJTIwdmFsdWVzJTIwKG5lZ2F0aXZlJTIwcHJpY2VzKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2UlMjBydW4lMjB0aGVzZSUyMHRlc3RzJTIwb24lMjBldmVyeSUyMGRidCUyMHJ1bi4lMjBJZiUyMGFueSUyMHRlc3QlMjBmYWlscyUyQyUyMHRoZSUyMHBpcGVsaW5lJTIwc3RvcHMuJTIwTm8lMjBkYXRhJTIwcmVhY2hlcyUyMHRoZSUyMG1vZGVsLiUyME5vJTIwc2lsZW50JTIwY29ycnVwdGlvbi4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoZSUyMGJlYXV0eSUyMG9mJTIwZGJ0JTIwdGVzdHMlMjBpcyUyMHRoYXQlMjB0aGV5J3JlJTIwdmVyc2lvbi1jb250cm9sbGVkJTJDJTIwZG9jdW1lbnRlZCUyQyUyMGFuZCUyMHBhcnQlMjBvZiUyMHlvdXIlMjB0cmFuc2Zvcm1hdGlvbiUyMGNvZGUuJTIwV2hlbiUyMGElMjBzY2hlbWElMjBjaGFuZ2UlMjBoYXBwZW5zJTJDJTIweW91JTIwdXBkYXRlJTIwdGhlJTIwdGVzdCUyQyUyMGNvbW1pdCUyMGl0JTJDJTIwYW5kJTIwZXZlcnlvbmUlMjBrbm93cyUyMHdoYXQlMjBjaGFuZ2VkLiUyMiU3RCU1RCU3RCU1RA==">
    <div data-slate-node="element">
     <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The beauty of dbt tests is that they're version-controlled, documented, and part of your transformation code. When a schema change happens, you update the test, commit it, and everyone knows what changed.</span></span></span>
     <br>
     <br>
    </div>
    <h3 data-anchor="layer2%3Agreatexpectations(thestatisticalvalidator)" data-slate-node="element" data-slug="layer2%3Agreatexpectations(thestatisticalvalidator)34"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Layer 2: Great Expectations (The Statistical Validator)</span></span></span></h3>
    <div data-slate-node="element">
     <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">dbt tests catch structural issues. Great Expectations catches statistical anomalies, the subtle shifts that break models.</span></span></span>
     <br>
     <br>
    </div>
    <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTMlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJMYXllciUyMDIlM0ElMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMChUaGUlMjBTdGF0aXN0aWNhbCUyMFZhbGlkYXRvciklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMmRidCUyMHRlc3RzJTIwY2F0Y2glMjBzdHJ1Y3R1cmFsJTIwaXNzdWVzLiUyMEdyZWF0JTIwRXhwZWN0YXRpb25zJTIwY2F0Y2hlcyUyMHN0YXRpc3RpY2FsJTIwYW5vbWFsaWVzJUUyJTgwJTk0dGhlJTIwc3VidGxlJTIwc2hpZnRzJTIwdGhhdCUyMGJyZWFrJTIwbW9kZWxzLiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySGVyZSdzJTIwYSUyMHJlYWwlMjBzY2VuYXJpbyUzQSUyMG91ciUyMHVzZXJfYWdlJTIwY29sdW1uJTIwaGFkJTIwYSUyMGRpc3RyaWJ1dGlvbiUyMG9mJTIwMTgtNjUlMjBmb3IlMjB0d28lMjB5ZWFycy4lMjBUaGVuJTIwb25lJTIwZGF5JTJDJTIwd2UlMjBzdGFydGVkJTIwZ2V0dGluZyUyMGFnZXMlMjBvZiUyMDIwMCUyQyUyMDUwMCUyQyUyMDEwMDAuJTIwQSUyMGRhdGElMjBlbnRyeSUyMGJ1ZyUyMHVwc3RyZWFtLiUyMGRidCUyMHRlc3RzJTIwd291bGRuJ3QlMjBjYXRjaCUyMHRoaXMlMjBiZWNhdXNlJTIwdGhlJTIwdmFsdWVzJTIwYXJlJTIwdGVjaG5pY2FsbHklMjB2YWxpZCUyMGludGVnZXJzLiUyMEJ1dCUyMEdyZWF0JTIwRXhwZWN0YXRpb25zJTIwd291bGQuJTIyJTdEJTVEJTdEJTVE">
     <div data-slate-node="element">
      <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's a real scenario: our <code>user_age</code> column had a distribution of 18-65 for two years. Then one day, we started getting ages of 200, 500, 1000. A data entry bug upstream. dbt tests wouldn't catch this because the values are technically valid integers. But Great Expectations would.</span></span></span>
     </div>
     <div class="codeMirror-wrapper" contenteditable="false">
      <div contenteditable="false">
       <div class="codeHeader">
        <div class="nameLanguage">
         Python
        </div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
       </div>
       <div class="codeMirror-code--wrapper" data-code="# great_expectations/expectations/user_events_expectations.py
from great_expectations.core.batch import RuntimeBatchRequest
from great_expectations.data_context import DataContext

context = DataContext()
suite = context.create_expectation_suite(
    expectation_suite_name=&quot;user_events_suite&quot;,
    overwrite_existing=True
)

validator = context.get_validator(
    batch_request=RuntimeBatchRequest(
        datasource_name=&quot;my_spark_datasource&quot;,
        data_connector_name=&quot;default_runtime_data_connector&quot;,
        data_asset_name=&quot;user_events&quot;
    ),
    expectation_suite_name=&quot;user_events_suite&quot;
)

# Expect user_age to be between 18 and 120
validator.expect_column_values_to_be_between(
    column=&quot;user_age&quot;,
    min_value=18,
    max_value=120
)

# Expect event_value to have a mean between 50 and 200
validator.expect_column_mean_to_be_between(
    column=&quot;event_value&quot;,
    min_value=50,
    max_value=200
)

# Expect less than 5% missing values in critical columns
validator.expect_column_values_to_not_be_null(
    column=&quot;user_id&quot;,
    mostly=0.95
)

# Expect the distribution to match historical patterns
validator.expect_column_kl_divergence_from_list(
    column=&quot;event_type&quot;,
    partition_object={&quot;event_type&quot;: [&quot;click&quot;, &quot;view&quot;, &quot;purchase&quot;]},
    threshold=0.1
)

validator.save_expectation_suite(discard_failed_expectations=False)" data-lang="text/x-python">
        <pre><code lang="text/x-python"># great_expectations/expectations/user_events_expectations.py
from great_expectations.core.batch import RuntimeBatchRequest
from great_expectations.data_context import DataContext

context = DataContext()
suite = context.create_expectation_suite(
    expectation_suite_name="user_events_suite",
    overwrite_existing=True
)

validator = context.get_validator(
    batch_request=RuntimeBatchRequest(
        datasource_name="my_spark_datasource",
        data_connector_name="default_runtime_data_connector",
        data_asset_name="user_events"
    ),
    expectation_suite_name="user_events_suite"
)

# Expect user_age to be between 18 and 120
validator.expect_column_values_to_be_between(
    column="user_age",
    min_value=18,
    max_value=120
)

# Expect event_value to have a mean between 50 and 200
validator.expect_column_mean_to_be_between(
    column="event_value",
    min_value=50,
    max_value=200
)

# Expect less than 5% missing values in critical columns
validator.expect_column_values_to_not_be_null(
    column="user_id",
    mostly=0.95
)

# Expect the distribution to match historical patterns
validator.expect_column_kl_divergence_from_list(
    column="event_type",
    partition_object={"event_type": ["click", "view", "purchase"]},
    threshold=0.1
)

validator.save_expectation_suite(discard_failed_expectations=False)</code></pre>
       </div>
      </div>
     </div>
     <div data-slate-node="element">
      <br>
     </div>
     <div data-slate-node="element">
      <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Great Expectations runs after dbt tests. It validates:</span></span></span>
     </div>
     <ul>
      <li>Value ranges (age between 18 and 120)</li>
      <li>Statistical properties (mean event value between 50 and 200)</li>
      <li>Null rates (less than 5% missing in critical columns)</li>
      <li>Distribution shifts (<code>event_type</code> distribution matches historical patterns)</li>
     </ul>
     <div data-slate-node="element">
      <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">If Great Expectations detects an anomaly, it alerts us. We investigate before the data reaches the model.</span></span></span>
     </div>
     <h3 data-anchor="layer3%3Acustomvalidation(thedomainexpert)" data-slate-node="element" data-slug="layer3%3Acustomvalidation(thedomainexpert)44"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Layer 3: Custom Validation (The Domain Expert)</span></span></span></h3>
     <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMHJ1bnMlMjBhZnRlciUyMGRidCUyMHRlc3RzLiUyMEl0JTIwdmFsaWRhdGVzJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyVmFsdWUlMjByYW5nZXMlMjAoYWdlJTIwYmV0d2VlbiUyMDE4JTIwYW5kJTIwMTIwKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlN0YXRpc3RpY2FsJTIwcHJvcGVydGllcyUyMChtZWFuJTIwZXZlbnQlMjB2YWx1ZSUyMGJldHdlZW4lMjA1MCUyMGFuZCUyMDIwMCklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIybGlzdEl0ZW0lMjIlMkMlMjJvcmRlcmVkJTIyJTNBZmFsc2UlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJOdWxsJTIwcmF0ZXMlMjAobGVzcyUyMHRoYW4lMjA1JTI1JTIwbWlzc2luZyUyMGluJTIwY3JpdGljYWwlMjBjb2x1bW5zKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkRpc3RyaWJ1dGlvbiUyMHNoaWZ0cyUyMChldmVudF90eXBlJTIwZGlzdHJpYnV0aW9uJTIwbWF0Y2hlcyUyMGhpc3RvcmljYWwlMjBwYXR0ZXJucyklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMklmJTIwR3JlYXQlMjBFeHBlY3RhdGlvbnMlMjBkZXRlY3RzJTIwYW4lMjBhbm9tYWx5JTJDJTIwaXQlMjBhbGVydHMlMjB1cy4lMjBXZSUyMGludmVzdGlnYXRlJTIwYmVmb3JlJTIwdGhlJTIwZGF0YSUyMHJlYWNoZXMlMjB0aGUlMjBtb2RlbC4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyaGVhZGluZyUyMiUyQyUyMmxldmVsJTIyJTNBMyUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkxheWVyJTIwMyUzQSUyMEN1c3RvbSUyMFZhbGlkYXRpb24lMjAoVGhlJTIwRG9tYWluJTIwRXhwZXJ0KSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyZGJ0JTIwYW5kJTIwR3JlYXQlMjBFeHBlY3RhdGlvbnMlMjBhcmUlMjBnZW5lcmljLiUyMFlvdXIlMjBkb21haW4lMjBpcyUyMHNwZWNpZmljLiUyMFdlJTIwYWRkZWQlMjBjdXN0b20lMjB2YWxpZGF0aW9uJTIwbG9naWMlMjB0aGF0JTIwdW5kZXJzdGFuZHMlMjBvdXIlMjBidXNpbmVzcy4lMjIlN0QlNUQlN0QlNUQ=">
      <div data-slate-node="element">
       <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">dbt and Great Expectations are generic. Your domain is specific. We added custom validation logic that understands our business.</span></span></span>
      </div>
      <div class="codeMirror-wrapper newest" contenteditable="false">
       <div contenteditable="false">
        <div class="codeHeader">
         <div class="nameLanguage">
          Python
         </div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
        </div>
        <div class="codeMirror-code--wrapper" data-code="# pipelines/validation/custom_validators.py
import pandas as pd
from datetime import datetime, timedelta

def validate_feature_engineering(df: pd.DataFrame) -> dict:
    &quot;&quot;&quot;
    Custom validation for features before they reach the model.
    Returns a dict of validation results.
    &quot;&quot;&quot;
    results = {}
    
    # Validate 1: Feature completeness
    # We need at least 95% of features populated
    feature_cols = [col for col in df.columns if col.startswith('feature_')]
    null_rate = df[feature_cols].isnull().sum().sum() / (len(df) * len(feature_cols))
    results['feature_completeness'] = {
        'passed': null_rate < 0.05,
        'null_rate': null_rate,
        'threshold': 0.05
    }
    
    # Validate 2: Feature scaling
    # After normalization, features should be roughly between -3 and 3 (3 sigma)
    for col in feature_cols:
        max_val = df[col].max()
        min_val = df[col].min()
        results[f'{col}_scaling'] = {
            'passed': max_val < 10 and min_val > -10,
            'max': max_val,
            'min': min_val
        }
    
    # Validate 3: Temporal consistency
    # Events should be recent (within last 30 days)
    if 'event_date' in df.columns:
        df['event_date'] = pd.to_datetime(df['event_date'])
        days_old = (datetime.now() - df['event_date'].max()).days
        results['temporal_freshness'] = {
            'passed': days_old < 30,
            'days_old': days_old,
            'threshold_days': 30
        }
    
    # Validate 4: Business logic
    # Revenue should always be positive
    if 'revenue' in df.columns:
        negative_revenue = (df['revenue'] < 0).sum()
        results['business_logic_revenue'] = {
            'passed': negative_revenue == 0,
            'negative_count': negative_revenue
        }
    
    return results

def validate_and_alert(df: pd.DataFrame, validation_results: dict) -> bool:
    &quot;&quot;&quot;
    Check all validations and alert if any fail.
    Returns True if all pass, False otherwise.
    &quot;&quot;&quot;
    all_passed = True
    
    for check_name, check_result in validation_results.items():
        if not check_result['passed']:
            all_passed = False
            print(f&quot;ALERT: {check_name} failed&quot;)
            print(f&quot;Details: {check_result}&quot;)
            # Send to monitoring system (Datadog, New Relic, etc.)
            # send_alert(check_name, check_result)
    
    return all_passed" data-lang="text/x-python">
         <pre><code lang="text/x-python"># pipelines/validation/custom_validators.py
import pandas as pd
from datetime import datetime, timedelta

def validate_feature_engineering(df: pd.DataFrame) -&gt; dict:
    """
    Custom validation for features before they reach the model.
    Returns a dict of validation results.
    """
    results = {}
    
    # Validate 1: Feature completeness
    # We need at least 95% of features populated
    feature_cols = [col for col in df.columns if col.startswith('feature_')]
    null_rate = df[feature_cols].isnull().sum().sum() / (len(df) * len(feature_cols))
    results['feature_completeness'] = {
        'passed': null_rate &lt; 0.05,
        'null_rate': null_rate,
        'threshold': 0.05
    }
    
    # Validate 2: Feature scaling
    # After normalization, features should be roughly between -3 and 3 (3 sigma)
    for col in feature_cols:
        max_val = df[col].max()
        min_val = df[col].min()
        results[f'{col}_scaling'] = {
            'passed': max_val &lt; 10 and min_val &gt; -10,
            'max': max_val,
            'min': min_val
        }
    
    # Validate 3: Temporal consistency
    # Events should be recent (within last 30 days)
    if 'event_date' in df.columns:
        df['event_date'] = pd.to_datetime(df['event_date'])
        days_old = (datetime.now() - df['event_date'].max()).days
        results['temporal_freshness'] = {
            'passed': days_old &lt; 30,
            'days_old': days_old,
            'threshold_days': 30
        }
    
    # Validate 4: Business logic
    # Revenue should always be positive
    if 'revenue' in df.columns:
        negative_revenue = (df['revenue'] &lt; 0).sum()
        results['business_logic_revenue'] = {
            'passed': negative_revenue == 0,
            'negative_count': negative_revenue
        }
    
    return results

def validate_and_alert(df: pd.DataFrame, validation_results: dict) -&gt; bool:
    """
    Check all validations and alert if any fail.
    Returns True if all pass, False otherwise.
    """
    all_passed = True
    
    for check_name, check_result in validation_results.items():
        if not check_result['passed']:
            all_passed = False
            print(f"ALERT: {check_name} failed")
            print(f"Details: {check_result}")
            # Send to monitoring system (Datadog, New Relic, etc.)
            # send_alert(check_name, check_result)
    
&nbsp; &nbsp; return all_passed</code></pre>
        </div>
       </div>
      </div>
      <div data-slate-node="element">
       <br>
      </div>
      <div data-slate-node="element">
       <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">This custom validation runs after Great Expectations. It checks:</span></span></span>
      </div>
      <ul>
       <li>Feature completeness (95% of features populated)</li>
       <li>Feature scaling (normalized features in the expected range)</li>
       <li>Temporal freshness (data is recent)</li>
       <li>Business logic (revenue is positive)</li>
      </ul>
      <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGlzJTIwY3VzdG9tJTIwdmFsaWRhdGlvbiUyMHJ1bnMlMjBhZnRlciUyMEdyZWF0JTIwRXhwZWN0YXRpb25zLiUyMEl0JTIwY2hlY2tzJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyRmVhdHVyZSUyMGNvbXBsZXRlbmVzcyUyMCg5NSUyNSUyMG9mJTIwZmVhdHVyZXMlMjBwb3B1bGF0ZWQpJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyRmVhdHVyZSUyMHNjYWxpbmclMjAobm9ybWFsaXplZCUyMGZlYXR1cmVzJTIwaW4lMjBleHBlY3RlZCUyMHJhbmdlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRlbXBvcmFsJTIwZnJlc2huZXNzJTIwKGRhdGElMjBpcyUyMHJlY2VudCklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIybGlzdEl0ZW0lMjIlMkMlMjJvcmRlcmVkJTIyJTNBZmFsc2UlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJCdXNpbmVzcyUyMGxvZ2ljJTIwKHJldmVudWUlMjBpcyUyMHBvc2l0aXZlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySWYlMjBhbnklMjBjaGVjayUyMGZhaWxzJTJDJTIwd2UlMjBibG9jayUyMHRoZSUyMHBpcGVsaW5lJTIwYW5kJTIwYWxlcnQlMjB0aGUlMjB0ZWFtLiUyMiU3RCU1RCU3RCU1RA==">
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">If any check fails, we block the pipeline and alert the team.</span></span></span>
       </div>
       <h2 data-anchor="therealworldgotchaswediscovered" data-slate-node="element" data-slug="therealworldgotchaswediscovered54"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Real-World Gotchas We Discovered</span></span></span></h2>
       <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 1: Validation Overhead</span></span></span></h3>
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Running dbt tests, Great Expectations, and custom validation on every pipeline run adds latency. We went from 15-minute runs to 25-minute runs. The trade-off was worth it (catching one data quality issue saved us more time than we lost), but you need to plan for it.</span></span></span>
       </div>
       <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 2: False Positives</span></span></span></h3>
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Great Expectations' distribution shift detection is sensitive. Legitimate business changes (a marketing campaign causing a spike in <code>user_age</code> distribution) triggered false alerts. We had to tune thresholds carefully and add context to alerts.</span></span></span>
       </div>
       <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 3: Schema Changes Are Sneaky</span></span></span></h3>
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">A vendor added a new column to an upstream table. Our pipeline didn't break; it just ignored the new column. But the data science team expected it. We added schema validation to catch new columns and alert us.</span></span></span>
       </div>
       <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBSZWFsLVdvcmxkJTIwR290Y2hhcyUyMFdlJTIwRGlzY292ZXJlZCUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyR290Y2hhJTIwMSUzQSUyMFZhbGlkYXRpb24lMjBPdmVyaGVhZCUyMiUyQyUyMmJvbGQlMjIlM0F0cnVlJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJpc0JyZWFrJTIyJTNBdHJ1ZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMiUyMiU3RCU1RCU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjJSdW5uaW5nJTIwZGJ0JTIwdGVzdHMlMkMlMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyQyUyMGFuZCUyMGN1c3RvbSUyMHZhbGlkYXRpb24lMjBvbiUyMGV2ZXJ5JTIwcGlwZWxpbmUlMjBydW4lMjBhZGRzJTIwbGF0ZW5jeS4lMjBXZSUyMHdlbnQlMjBmcm9tJTIwMTUtbWludXRlJTIwcnVucyUyMHRvJTIwMjUtbWludXRlJTIwcnVucy4lMjBUaGUlMjB0cmFkZS1vZmYlMjB3YXMlMjB3b3J0aCUyMGl0JTIwKGNhdGNoaW5nJTIwb25lJTIwZGF0YSUyMHF1YWxpdHklMjBpc3N1ZSUyMHNhdmVkJTIwdXMlMjBtb3JlJTIwdGltZSUyMHRoYW4lMjB3ZSUyMGxvc3QpJTJDJTIwYnV0JTIweW91JTIwbmVlZCUyMHRvJTIwcGxhbiUyMGZvciUyMGl0LiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyR290Y2hhJTIwMiUzQSUyMEZhbHNlJTIwUG9zaXRpdmVzJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmlzQnJlYWslMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIyJTdEJTVEJTdEJTJDJTdCJTIydGV4dCUyMiUzQSUyMkdyZWF0JTIwRXhwZWN0YXRpb25zJyUyMGRpc3RyaWJ1dGlvbiUyMHNoaWZ0JTIwZGV0ZWN0aW9uJTIwaXMlMjBzZW5zaXRpdmUuJTIwTGVnaXRpbWF0ZSUyMGJ1c2luZXNzJTIwY2hhbmdlcyUyMChhJTIwbWFya2V0aW5nJTIwY2FtcGFpZ24lMjBjYXVzaW5nJTIwYSUyMHNwaWtlJTIwaW4lMjB1c2VyX2FnZSUyMGRpc3RyaWJ1dGlvbiklMjB0cmlnZ2VyZWQlMjBmYWxzZSUyMGFsZXJ0cy4lMjBXZSUyMGhhZCUyMHRvJTIwdHVuZSUyMHRocmVzaG9sZHMlMjBjYXJlZnVsbHklMjBhbmQlMjBhZGQlMjBjb250ZXh0JTIwdG8lMjBhbGVydHMuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJHb3RjaGElMjAzJTNBJTIwU2NoZW1hJTIwQ2hhbmdlcyUyMEFyZSUyMFNuZWFreSUyMiUyQyUyMmJvbGQlMjIlM0F0cnVlJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJpc0JyZWFrJTIyJTNBdHJ1ZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMiUyMiU3RCU1RCU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjJBJTIwdmVuZG9yJTIwYWRkZWQlMjBhJTIwbmV3JTIwY29sdW1uJTIwdG8lMjBhbiUyMHVwc3RyZWFtJTIwdGFibGUuJTIwT3VyJTIwcGlwZWxpbmUlMjBkaWRuJ3QlMjBicmVhayVFMiU4MCU5NGl0JTIwanVzdCUyMGlnbm9yZWQlMjB0aGUlMjBuZXclMjBjb2x1bW4uJTIwQnV0JTIwdGhlJTIwZGF0YSUyMHNjaWVuY2UlMjB0ZWFtJTIwZXhwZWN0ZWQlMjBpdC4lMjBXZSUyMGFkZGVkJTIwc2NoZW1hJTIwdmFsaWRhdGlvbiUyMHRvJTIwY2F0Y2glMjBuZXclMjBjb2x1bW5zJTIwYW5kJTIwYWxlcnQlMjB1cy4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkdvdGNoYSUyMDQlM0ElMjBOdWxsJTIwSGFuZGxpbmclMjBWYXJpZXMlMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyaXNCcmVhayUyMiUzQXRydWUlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyUHl0aG9uJTIwdHJlYXRzJTIwbnVsbCUyMGFzJTIwTm9uZS4lMjBTUUwlMjB0cmVhdHMlMjBpdCUyMGFzJTIwTlVMTC4lMjBTcGFyayUyMHRyZWF0cyUyMGl0JTIwYXMlMjBudWxsLiUyMFdoZW4lMjBkYXRhJTIwZmxvd3MlMjBiZXR3ZWVuJTIwc3lzdGVtcyUyQyUyMG51bGxzJTIwZ2V0JTIwbG9zdCUyMG9yJTIwbWlzaW50ZXJwcmV0ZWQuJTIwV2UlMjBoYWQlMjB0byUyMHN0YW5kYXJkaXplJTIwbnVsbCUyMGhhbmRsaW5nJTIwYWNyb3NzJTIwdGhlJTIwZW50aXJlJTIwcGlwZWxpbmUuJTIyJTdEJTVEJTdEJTVE">
        <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 4: Null Handling Varies</span></span></span></h3>
        <div data-slate-node="element">
         <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Python treats null as None. SQL treats it as NULL. Spark treats it as null. When data flows between systems, nulls get lost or misinterpreted. We had to standardize null handling across the entire pipeline.</span></span></span>
        </div>
        <h2 data-anchor="theframework%3Aadecisionmatrix" data-slate-node="element" data-slug="theframework%3Aadecisionmatrix60"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Framework: A Decision Matrix</span></span></span></h2>
        <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBGcmFtZXdvcmslM0ElMjBBJTIwRGVjaXNpb24lMjBNYXRyaXglMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkhlcmUncyUyMGhvdyUyMHdlJTIwZGVjaWRlJTIwd2hpY2glMjB2YWxpZGF0aW9uJTIwbGF5ZXIlMjB0byUyMHVzZSUzQSUyMiU3RCU1RCU3RCU1RA==">
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's how we decide which validation layer to use:</span></span></span>
         </div>
         <div class="table-responsive" style="border: none;">
          <table style="width: auto; max-width: 100%; table-layout: fixed; display: table;" width="auto">
           <tbody>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Issue Type</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Caught By</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Example</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Action</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Missing required field</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">dbt tests</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">user_id is null</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Fail pipeline immediately</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Duplicate records</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">dbt tests</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Same user_id appears twice</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Fail pipeline immediately</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Impossible values</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">dbt tests</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">event_timestamp in future</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Fail pipeline immediately</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Out-of-range values</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Great Expectations</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">age &gt; 150</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, fail if severe</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Distribution shift</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Great Expectations</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">event_value mean changes 50%</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, continue if acceptable</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Business logic violation</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Custom validation</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">revenue is negative</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, fail</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Schema change</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Custom validation</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">New column added upstream</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, update tests</td>
            </tr>
           </tbody>
          </table>
         </div>
         <h2 data-anchor="theresults%3Afromchaostoconfidence" data-slate-node="element" data-slug="theresults%3Afromchaostoconfidence64"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Results: From Chaos to Confidence</span></span></span></h2>
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">After implementing this three-layer framework:</span></span></span>
         </div>
         <ul>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Incident reduction:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;We went from 2-3 data quality incidents per month to 0 in six months.</span></span></span></li>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Time to resolution:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;When issues do occur, we catch them within minutes instead of hours.</span></span></span></li>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Model stability:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Model accuracy stopped fluctuating. It's now consistently 93-95%.</span></span></span></li>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Team confidence:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Data scientists trust the data. Engineers trust the pipeline.</span></span></span></li>
         </ul>
         <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBSZXN1bHRzJTNBJTIwRnJvbSUyMENoYW9zJTIwdG8lMjBDb25maWRlbmNlJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJBZnRlciUyMGltcGxlbWVudGluZyUyMHRoaXMlMjB0aHJlZS1sYXllciUyMGZyYW1ld29yayUzQSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkluY2lkZW50JTIwcmVkdWN0aW9uJTNBJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIwV2UlMjB3ZW50JTIwZnJvbSUyMDItMyUyMGRhdGElMjBxdWFsaXR5JTIwaW5jaWRlbnRzJTIwcGVyJTIwbW9udGglMjB0byUyMDAlMjBpbiUyMHNpeCUyMG1vbnRocyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRpbWUlMjB0byUyMHJlc29sdXRpb24lM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBXaGVuJTIwaXNzdWVzJTIwZG8lMjBvY2N1ciUyQyUyMHdlJTIwY2F0Y2glMjB0aGVtJTIwd2l0aGluJTIwbWludXRlcyUyMGluc3RlYWQlMjBvZiUyMGhvdXJzJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyTW9kZWwlMjBzdGFiaWxpdHklM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBNb2RlbCUyMGFjY3VyYWN5JTIwc3RvcHBlZCUyMGZsdWN0dWF0aW5nLiUyMEl0J3MlMjBub3clMjBjb25zaXN0ZW50bHklMjA5My05NSUyNSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRlYW0lMjBjb25maWRlbmNlJTNBJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIwRGF0YSUyMHNjaWVudGlzdHMlMjB0cnVzdCUyMHRoZSUyMGRhdGEuJTIwRW5naW5lZXJzJTIwdHJ1c3QlMjB0aGUlMjBwaXBlbGluZSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyVGhlJTIwYmVzdCUyMHBhcnQlM0YlMjBXZSUyMGNhdWdodCUyMHRoZSUyMHNjaGVtYSUyMGNoYW5nZSUyMGluY2lkZW50JTIwYmVmb3JlJTIwaXQlMjBoYXBwZW5lZC4lMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMGRldGVjdGVkJTIwdGhlJTIwZGlzdHJpYnV0aW9uJTIwc2hpZnQlMkMlMjB3ZSUyMGludmVzdGlnYXRlZCUyQyUyMGZvdW5kJTIwdGhlJTIwdXBzdHJlYW0lMjBjaGFuZ2UlMkMlMjBhbmQlMjBjb29yZGluYXRlZCUyMHdpdGglMjB0aGUlMjB2ZW5kb3IlMjB0ZWFtJTIwYmVmb3JlJTIwYW55JTIwZGF0YSUyMHJlYWNoZWQlMjBwcm9kdWN0aW9uLiUyMiU3RCU1RCU3RCU1RA==">
          <div data-slate-node="element">
           <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The best part? We caught the schema change incident before it happened. Great Expectations detected the distribution shift, we investigated, found the upstream change, and coordinated with the vendor team before any data reached production.</span></span></span>
          </div>
          <h2 data-anchor="gettingstarted%3Atheminimalviableobservability" data-slate-node="element" data-slug="gettingstarted%3Atheminimalviableobservability72"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Getting Started: The Minimal Viable Observability</span></span></span></h2>
          <div data-slate-node="element">
           <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">You don't need to implement everything at once. Start here:</span></span></span>
          </div>
          <ol>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 1:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Add dbt tests for not_null and unique on critical columns.</span></span></span></li>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 1:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Add dbt tests for not_null and unique on critical columns.</span></span></span></li>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 1:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Add dbt tests for not_null and unique on critical columns.</span></span></span></span></span></span></li>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 4:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Set up alerting so you're notified when validations fail.</span></span></span></span></span></span></span></span></span></li>
          </ol>
          <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJHZXR0aW5nJTIwU3RhcnRlZCUzQSUyMFRoZSUyME1pbmltYWwlMjBWaWFibGUlMjBPYnNlcnZhYmlsaXR5JTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJZb3UlMjBkb24ndCUyMG5lZWQlMjB0byUyMGltcGxlbWVudCUyMGV2ZXJ5dGhpbmclMjBhdCUyMG9uY2UuJTIwU3RhcnQlMjBoZXJlJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQXRydWUlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJXZWVrJTIwMSUzQSUyMiUyQyUyMmJvbGQlMjIlM0F0cnVlJTdEJTJDJTdCJTIydGV4dCUyMiUzQSUyMiUyMEFkZCUyMGRidCUyMHRlc3RzJTIwZm9yJTIwbm90X251bGwlMjBhbmQlMjB1bmlxdWUlMjBvbiUyMGNyaXRpY2FsJTIwY29sdW1ucyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2VlayUyMDIlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBBZGQlMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMGZvciUyMHZhbHVlJTIwcmFuZ2VzJTIwb24lMjBudW1lcmljJTIwY29sdW1ucyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2VlayUyMDMlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBBZGQlMjBjdXN0b20lMjB2YWxpZGF0aW9uJTIwZm9yJTIweW91ciUyMHNwZWNpZmljJTIwYnVzaW5lc3MlMjBsb2dpYyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2VlayUyMDQlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBTZXQlMjB1cCUyMGFsZXJ0aW5nJTIwc28lMjB5b3UncmUlMjBub3RpZmllZCUyMHdoZW4lMjB2YWxpZGF0aW9ucyUyMGZhaWwlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoYXQncyUyMGl0LiUyMFlvdSUyMG5vdyUyMGhhdmUlMjBvYnNlcnZhYmlsaXR5JTIwaW4lMjB5b3VyJTIwZGF0YSUyMHBpcGVsaW5lLiUyMiU3RCU1RCU3RCU1RA==">
           <div data-slate-node="element">
            <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">That's it. You now have observability in your data pipeline.</span></span></span>
           </div>
          </div>
         </div>
         <h2 data-anchor="conclusion%3Aobservabilitysavesmodels" data-slate-node="element" data-slug="conclusion%3Aobservabilitysavesmodels80"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Conclusion: Observability Saves Models</span></span></span></h2>
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Your AI model isn't failing because it's bad. It's failing because the data feeding it is bad. And you won't know the data is bad until you look.</span></span></span>
         </div>
         <div data-slate-node="element">
          <br>
         </div>
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The best models in the world can't save you from garbage data. But good observability can. dbt tests, Great Expectations, and custom validation aren't fun. They don't make it into conference talks. But they'll save your production system at 3:00 AM.</span></span></span>
         </div>
         <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJDb25jbHVzaW9uJTNBJTIwT2JzZXJ2YWJpbGl0eSUyMFNhdmVzJTIwTW9kZWxzJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJZb3VyJTIwQUklMjBtb2RlbCUyMGlzbid0JTIwZmFpbGluZyUyMGJlY2F1c2UlMjBpdCdzJTIwYmFkLiUyMEl0J3MlMjBmYWlsaW5nJTIwYmVjYXVzZSUyMHRoZSUyMGRhdGElMjBmZWVkaW5nJTIwaXQlMjBpcyUyMGJhZC4lMjBBbmQlMjB5b3UlMjB3b24ndCUyMGtub3clMjB0aGUlMjBkYXRhJTIwaXMlMjBiYWQlMjB1bnRpbCUyMHlvdSUyMGxvb2suJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBiZXN0JTIwbW9kZWxzJTIwaW4lMjB0aGUlMjB3b3JsZCUyMGNhbid0JTIwc2F2ZSUyMHlvdSUyMGZyb20lMjBnYXJiYWdlJTIwZGF0YS4lMjBCdXQlMjBnb29kJTIwb2JzZXJ2YWJpbGl0eSUyMGNhbi4lMjBkYnQlMjB0ZXN0cyUyQyUyMEdyZWF0JTIwRXhwZWN0YXRpb25zJTJDJTIwYW5kJTIwY3VzdG9tJTIwdmFsaWRhdGlvbiUyMGFyZW4ndCUyMHNleHkuJTIwVGhleSUyMGRvbid0JTIwbWFrZSUyMGl0JTIwaW50byUyMGNvbmZlcmVuY2UlMjB0YWxrcy4lMjBCdXQlMjB0aGV5J2xsJTIwc2F2ZSUyMHlvdXIlMjBwcm9kdWN0aW9uJTIwc3lzdGVtJTIwYXQlMjAzJTIwQU0uJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJTdGFydCUyMHNtYWxsLiUyMFRlc3QlMjBlYXJseS4lMjBWYWxpZGF0ZSUyMG9mdGVuLiUyMiU3RCU1RCU3RCU1RA==">
          <div data-slate-node="element">
           <br>
          </div>
          <div data-slate-node="element">
           <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Start small. Test early. Validate often.</span></span></span>
          </div>
         </div>
        </div>
       </div>
      </div>
     </div>
    </div>
   </div>
  </div>
 </div>
</div></p><img src="https://feeds.dzone.com/link/23559/17368707.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 26 Jun 2026 16:00:05 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3643570</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19061479&amp;w=600"/>
      <dc:creator>Abhilash Rao Mesala</dc:creator>
    </item>
    <item>
      <title>Building High‑Precision Vector Search for Document Retrieval on Databricks</title>
      <link>https://feeds.dzone.com/link/23559/17368687/databricks-vector-search</link>
      <description><![CDATA[<p>For years, search technology meant one thing: type in a keyword, and the system goes hunting for an exact match. That works fine for product SKUs or error codes, but it falls apart the moment someone asks a real question. If your knowledge base is full of manuals, support tickets, transcripts, and reports, a person searching for "why does the machine shut down during startup" shouldn't have to guess the exact phrase the original author used.</p>
<p>This is the gap that vector search closes. Instead of matching words, it matches meaning. And on <a href="https://dzone.com/articles/databricks-101-an-introductory-guide">Databricks</a>, building this kind of system is more accessible than most teams expect, once you understand the moving pieces.</p><img src="https://feeds.dzone.com/link/23559/17368687.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 26 Jun 2026 15:00:01 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659711</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19059073&amp;w=600"/>
      <dc:creator>Ramesh Bellamkonda</dc:creator>
    </item>
  </channel>
</rss>
