Module 8: Project Kioskos Reliability And Governance System
Running the full gate against a clean day
Description
Lesson 4 confirmed half this module's promise: run_full_gate() precisely catches S04's incident's six real problems. This lesson confirms the other half, the one no earlier module in this guide could test yet — each worked exclusively on the broken file: what happens when the complete system runs on a file that has no problem at all? If the answer were "it also finds something," the complete system would be useless — it would be indistinguishable from an alarm that always goes off, no matter what's on the other side of the door.
Connection to the module. Lesson 4 ran the gate on what's broken. This lesson runs it, with no change at all, on what's clean. The comparison between both runs — 6 failures versus 0 — is this whole module's central evidence, and it closes the thread lesson 1 opened: a trust system isn't one that always says no, it's one that distinguishes.
An analogy: the same guard, now with a legitimate key
A security guard who sounds the alarm every time someone approaches the door — regardless of whether the person has a legitimate key or not — isn't protecting anything; they're training the whole building to ignore them. The real proof a security system works isn't just that it reacts to an intruder — lesson 4 already confirmed that — it's that it lets through, with no alarm at all, the person who does have the right to enter. This lesson hands that same guard — run_full_gate(), with not a single line changed — a legitimate key: a real day of Kiosko sales, from the usual stores, at the usual prices. If the guard sounds the alarm anyway, the problem isn't the door — it's the guard.
The material: rebuilding a clean day from S01-S03
Why "rebuilt," not "invented"
No value in this new file gets chosen at random. Each one comes, directly, from data eight earlier guides in this ecosystem already confirmed reliable:
| Clean-day element | Where it comes from |
|---|---|
Stores: S01, S02, S03 | Kiosko's three original stores — deliberately with no S04, the store under suspicion |
Products: P001-P004 | dim_product's complete catalog, with no invented product |
Prices: 0.55/1.20/0.75/4.50 | Exactly REFERENCE_PRICES, the baseline calculated in module 5 over the canonical week's 40 rows |
Row count: 8 | The same order of magnitude as a typical canonical-week day (Monday 2026-08-03 had 8 real orders) |
order_ts: 2026-08-15, between 08:05 and 09:48 | Within the SLA's 24-hour window, counted backward from PIPELINE_RUN_AT |
What to expect (verified with no code run, just arithmetic): the file has to respect two simultaneous constraints for check_freshness() to report PASS with sla_hours=24 and run_at="2026-08-16T09:00:00" — the most recent order_ts can't be earlier than 2026-08-15T09:00:00, and it has to be earlier than or equal to PIPELINE_RUN_AT (the file can't have a future date). Save this file exactly as it is, four lines fewer than S04 on purpose — a normal day, not an incident:
order_id,store_id,product_id,quantity,unit_price,order_ts
ORD-9601,S01,P001,3,0.55,2026-08-15T08:05:00
ORD-9602,S02,P002,2,1.20,2026-08-15T08:20:00
ORD-9603,S03,P003,1,0.75,2026-08-15T08:35:00
ORD-9604,S01,P004,1,4.50,2026-08-15T08:50:00
ORD-9605,S02,P001,4,0.55,2026-08-15T09:05:00
ORD-9606,S03,P002,2,1.20,2026-08-15T09:20:00
ORD-9607,S01,P003,2,0.75,2026-08-15T09:35:00
ORD-9608,S02,P004,1,4.50,2026-08-15T09:48:00
Eight lines, new order_ids (ORD-9601 through ORD-9608, continuing the numbering after S04, with no collision with any earlier order_id in this guide), the three original stores spread with no special pattern, every unit_price copied exactly from REFERENCE_PRICES (P001=0.55, P002=1.20, P003=0.75, P004=4.50, with no variation), every product_id within dim_product, no repeated order_id, no negative or null quantity, no empty unit_price. The latest order_ts is 2026-08-15T09:48:00.
Loading it into kiosko.duckdb
# load_clean_day.py
import duckdb
con = duckdb.connect("kiosko.duckdb")
con.execute("""
CREATE OR REPLACE TABLE orders_clean_day AS
SELECT * FROM read_csv('orders_2026-08-15.csv', header=True,
columns={
'order_id': 'VARCHAR', 'store_id': 'VARCHAR', 'product_id': 'VARCHAR',
'quantity': 'BIGINT', 'unit_price': 'DOUBLE', 'order_ts': 'TIMESTAMP'
})
""")
row_count = con.sql("SELECT COUNT(*) FROM orders_clean_day").fetchone()[0]
print(f"Rows loaded into orders_clean_day: {row_count}")
What to expect.
Rows loaded into orders_clean_day: 8
Worked example: the same run_full_gate(), with no change at all
# run_clean_day.py
import duckdb
import pandera
import polars as pl
from kiosko_trust import (
PIPELINE_RUN_AT, REFERENCE_PRICES, contract_to_pandera_schema, gate_failure_count,
load_contract, run_full_gate,
)
con = duckdb.connect("kiosko.duckdb")
dim_product_df = con.sql("SELECT * FROM dim_product").pl()
clean_day_df = con.sql("SELECT * FROM orders_clean_day").pl()
contract = load_contract("orders_contract.yaml")
schema = contract_to_pandera_schema(contract)
print(f"Rows read from orders_clean_day: {clean_day_df.height}\n")
gate_results = run_full_gate(
clean_day_df, dim_product_df, REFERENCE_PRICES, schema,
run_at=PIPELINE_RUN_AT, sla_hours=contract.sla.freshness_hours,
min_rows=contract.sla.row_count.min, max_rows=contract.sla.row_count.max,
)
print("=== run_full_gate() on orders_2026-08-15.csv (clean day) ===")
for r in gate_results:
print(f" [{r['status']}] {r['check']:<14} {r['detail']}")
failures = gate_failure_count(gate_results)
print(f"\nFailures: {failures} of {len(gate_results)} checks")
assert failures == 0, f"expected 0 failures, got {failures}"
print("assert failures == 0 -> OK")
What to expect (verified by actually running python3 run_clean_day.py, with kiosko.duckdb containing orders_clean_day and dim_product, pandera==0.32.1):
Rows read from orders_clean_day: 8
=== run_full_gate() on orders_2026-08-15.csv (clean day) ===
[PASS] completeness no rows
[PASS] uniqueness no rows
[PASS] validity no rows
[PASS] consistency every product_id exists in dim_product
[PASS] accuracy every price is within the baseline
[PASS] freshness 23.2h of 24h SLA
[PASS] volume 8 rows, range [5, 20]
Failures: 0 of 7 checks
assert failures == 0 -> OK
Seven PASS, no exception at all. freshness passes by a deliberately tight margin — 23.2 of 24 SLA hours, not a comfortable round number like 1 hour — so this result is a real test of check_freshness()'s arithmetic, not a coincidence where any file from the last month would have passed the same way. volume passes with 8 rows, comfortably within [5, 20], the same range the contract already declared for a new store's first file. And the five row-level checks — completeness, uniqueness, validity, consistency, accuracy — find not a single row with problems, because, unlike S04, this file got built exactly so it wouldn't have any.
Compare this result, line by line, against lesson 4: the same seven check names, the same order, the exact same function running underneath — and yet, a completely opposite result. That is, precisely, the evidence this module needed: the same gate, run with no change at all, produces a different verdict because the data is different, not because the system has a bias toward saying yes or toward saying no.
Table: the complete comparison, S04 versus the clean day
| Check | S04 (orders_2026-08-14.csv) | Clean day (orders_2026-08-15.csv) |
|---|---|---|
| completeness | FAIL (ORD-9503) | PASS |
| uniqueness | FAIL (ORD-9502 x2) | PASS |
| validity | FAIL (ORD-9507) | PASS |
| consistency | FAIL (ORD-9508) | PASS |
| accuracy | FAIL (ORD-9509) | PASS |
| freshness | FAIL (47.58h of 24h) | PASS (23.2h of 24h) |
| volume | PASS (12 rows) | PASS (8 rows) |
| Total failures | 6 of 7 | 0 of 7 |
| Rows in quarantine | 6 of 12 | 0 of 8 (no need to run quarantine()) |
Diagram: the same system, two inputs, two verdicts
flowchart TD
G["run_full_gate()\nthe SAME function, no change at all"]
A["orders_2026-08-14.csv\nS04, the incident"] --> G
B["orders_2026-08-15.csv\nS01-S03, clean day"] --> G
G --> R1["6 of 7 FAIL\n-> quarantine() + raise_alert()"]
G --> R2["0 of 7 FAIL\n-> the file continues the pipeline\nwith no friction at all"]
Going deeper: what if the gate were too permissive?
It's worth asking the uncomfortable question before accepting this result as good: does 0 failures prove the system is precise, or could it be proving the system just doesn't detect almost anything? The answer doesn't live in this lesson alone — it lives in lessons 4 and 5's combination. If run_full_gate() were too permissive (say, if check_price_baseline()'s tolerance were miscalibrated, as module 5, lesson 7 warned), the result on S04 would have also been optimistic, and lesson 4 would have revealed it with a failure count lower than 6. The fact lesson 4 did catch the six real problems, with the exact calibration module 5 already validated, is what gives this lesson's 0 credibility — an overly permissive system would have failed in both directions, not just one. This lesson's Exercise 1 lets you verify this yourself, by deliberately breaking the clean day.
Common mistakes
Thinking 0 of 7 FAIL means the system "found nothing because it doesn't know how to look." What happens: someone, used to the four earlier lessons' results always showing some failure, interprets a clean result as suspicious — "is there really no problem, or is the system missing it?" Why it happens: after seven modules focused almost exclusively on finding problems, a result with none feels, by contrast, untrustworthy. How to spot it: review this lesson's Going deeper section — this 0's credibility doesn't come from this lesson alone, it comes from the same function, with no change at all, having found S04's six real problems in the earlier lesson. How to fix it: always evaluate a detection system with both kinds of evidence — does it catch what's wrong? does it let through what's right? — never with just one. This lesson exists, specifically, to complete that evaluation's second half.
Modifying the clean day "to make it look more like S04" by adding a row with a minor problem. What happens: someone, wanting this example to be "more realistic," adds a row with some imperfect detail — a slightly high quantity, an out-of-order timestamp — thinking no real sales day is perfect. Why it happens: the intuition that "real data always has something wrong" is, generally, reasonable — but it confuses this file's specific purpose. How to spot it: review this lesson's "Why rebuilt, not invented" section — every value in this file has a reason traceable to already-confirmed Kiosko data; adding an arbitrary imperfection would break that traceability. How to fix it: this lesson's clean day has a specific, deliberate pedagogical purpose — demonstrating the system generates no false alarms on genuinely correct data —, not simulating the whole spectrum of variability a real Kiosko day could have. If you want to explore what happens when the clean day does have a problem, this lesson's Exercise 1 does it in a controlled way, measuring exactly the effect of one change at a time.
Exercises
Exercise 1 — Break the clean day on purpose, with a single change, and confirm the gate reacts. Change ORD-9601's unit_price from 0.55 to 5.50 (a single-digit error, ten times the real price), reload orders_clean_day into kiosko.duckdb, and run run_clean_day.py again. Confirm how many failures you see now, and in which check.
See solution
With ORD-9601 at 5.50 instead of 0.55, the result goes from 0 to 1 failure, exclusively in accuracy: deviation = |5.50 - 0.55| / 0.55 = 9.0, far above tolerance=0.5. The other six checks stay at PASS with no change. This exercise confirms, with direct evidence, the question this lesson's Going deeper section raised: the gate does react to a real problem when it appears, even in a file that until then was perfectly clean — the original 0 wasn't the result of a system that doesn't know how to detect anything, it was the correct result for genuinely correct data.
Exercise 2 — Calculate, with no code run, what check_freshness()'s result would be if the clean day's latest order_ts were 2026-08-15T08:00:00 instead of 2026-08-15T09:48:00. Using check_freshness()'s formula (hours_since_latest = (run_at - latest_ts) / 3600), calculate the exact number and determine whether it would stay at PASS or turn to FAIL.
See solution
run_at = 2026-08-16T09:00:00, latest_ts = 2026-08-15T08:00:00. The difference is exactly 25 hours (1 day plus 1 hour). With sla_hours=24, 25 > 24, so the result would be FAIL, not PASS — a margin of just one hour determines the entire verdict. This calculation confirms why this lesson chose 09:48:00 as the latest order_ts, instead of a more comfortable number: it demonstrates check_freshness() has no hidden tolerance margin at all — the boundary between PASS and FAIL is exactly sla_hours, not a fraction of an hour more.
Exercise 3 — Argue whether it would be reasonable to build a third file, "an average day with a single minor problem," to test the gate in an intermediate zone between S04 (6 failures) and the clean day (0 failures). In 2-3 sentences, considering what this lesson's Exercise 1 already demonstrated, argue whether a third scenario like that would add new evidence.
See solution
It wouldn't add qualitatively new evidence, though it could be useful as an additional practice exercise: this lesson's Exercise 1 already demonstrated, with a single controlled change, that the gate reacts proportionally — one problem produces one failure, not six — so an "intermediate" file would simply confirm the same behavior with a different combination of broken and clean rows, revealing no principle lessons 4 and 5's two runs (plus Exercise 1) haven't already covered. Keeping exactly two runs — the two extremes, 6 and 0 — has the pedagogical value of isolating the central question with maximum clarity: does the system distinguish between "everything wrong" and "everything right"? A third intermediate point would be good personal practice, but not a requirement for answering that question with sufficient evidence.
Summary and next step
In this lesson you ran run_full_gate(), with no change at all, on a file completely different from lesson 4's: a clean, 8-row day, rebuilt with data already confirmed reliable from Kiosko's canonical week. The result — 0 failures out of 7 checks — completes the evidence this module needed: the same system that precisely caught S04's six real problems generates no false alarm on data that really is fine.
Before moving on you should be able to: explain why every value in the clean day comes from already-confirmed Kiosko data, not invented numbers; and describe what would happen if run_full_gate() reported some failure on this file (Exercise 1 already showed you the answer with a concrete case).
Lesson 6 changes topic: it publishes the complete system's governance layer — LINEAGE_MAP, generate_catalog(), ACCESS_POLICY, mask_pii() — which applies equally over S04, over the clean day, and over any future Kiosko file, no matter the seven checks' result.
Resources
- Module 5, lesson 4, of this same guide — the exact source of
REFERENCE_PRICES, the baseline this clean day reproduces with no variation at all.src/guides/data-reliability-and-governance-guide/workbook/module-05-accuracy-and-deterministic-anomaly-detection/en/04-building-a-price-baseline-from-kioskos-clean-week.md. In English. - Module 6, lesson 3, of this same guide — the exact source of why the "now" reference has to be a fixed constant, the basis for why this lesson chose
2026-08-15carefully.src/guides/data-reliability-and-governance-guide/workbook/module-06-freshness-volume-and-lineage/en/03-a-fixed-reference-clock-never-datetime-now.md. In English. - This guide's DESIGN.
src/guides/data-reliability-and-governance-guide/DISENO.md. In Spanish.