The false-alarm floor of a cross-table check
Simulate a modelNeeds Python
Problem
A referential-integrity check (every order's customer must exist) assumes both tables are complete at the moment of the check. When they load on different schedules, they are not: an order from a customer who signed up after the last customer load looks orphaned until the next one. That produces a floor of false alarms set by the load schedule, which no threshold can tune away. The fix is to check only rows old enough that their references must have arrived: allowed lateness.
Simulate two loaders. Customers load every L minutes, orders every 10 minutes. Let 2% of orders come from customers who signed up less than 60 minutes earlier. For L in 5, 15, 30, 60, 120 minutes, count how many orders are "orphans" at the moment each order batch arrives. Plot the false-alarm rate against L. Then add "allowed lateness" (only check orders older than L + 10 minutes).
The question. How does the false orphan rate grow with the customer load interval, and what does allowed lateness do to it?
Predict
Expect the rate to fall to about zero with allowed lateness. You should see the floor move with L, and no threshold remove it.
Run it
1Install uv once. It fetches Python and the lab's packages for you.
Terminal curl -LsSf https://astral.sh/uv/install.sh | sh2Get the script. It is the whole lab: read it, then download it.
View the codeHide the code
the-false-alarm-floor-of-a.py # /// script # requires-python = ">=3.10" # /// # Copyright (c) 2026 Aayush Sharma · SPDX-License-Identifier: MIT # https://thedataengineering.com/lab-code/LICENSE.txt """The false-alarm floor of a referential-integrity check. Customers load every L minutes, orders every 10 minutes; 2% of orders come from customers who signed up less than 60 minutes earlier. At each order batch, count orders whose customer is not loaded yet ("orphans"), for L from 5 to 120 minutes. Then allow lateness: check only orders older than L + 10. """ import argparse, json, random p = argparse.ArgumentParser(description=__doc__.splitlines()[0]) p.add_argument("--days", type=int, default=7, help="Simulated days.") p.add_argument("--orders-per-min", type=float, default=50, help="Orders per minute.") p.add_argument("--new-share", type=float, default=0.02, help="Share of orders from customers who signed up in the last hour.") p.add_argument("--loads", type=lambda s: [int(v) for v in s.split(",")], default=[5, 15, 30, 60, 120], help="Customer load intervals L, minutes.") p.add_argument("--seed", type=int, default=0, help="Random seed.") p.add_argument("--json", help="Also write the results to this JSON file.") args = p.parse_args() random.seed(args.seed) minutes = args.days * 1440 orders = [] # (order time, customer signup time) for m in range(minutes): for _ in range(int(args.orders_per_min)): t = m + random.random() signup = t - random.uniform(0, 60) if random.random() < args.new_share else t - random.uniform(60, 60 * 24 * 365) orders.append((t, signup)) rows = [] for L in args.loads: alarms = checked = alarms_late = checked_late = 0 for t, signup in orders: batch_at = (int(t // 10) + 1) * 10 # the order arrives with the next 10-minute batch loaded_until = (batch_at // L) * L # customers loaded as of the last customer load checked += 1; alarms += signup > loaded_until if batch_at - t >= 0: # allowed lateness: check the order once it is L + 10 old check_at = t + L + 10 loaded_then = (check_at // L) * L checked_late += 1; alarms_late += signup > loaded_then rows.append({"L": L, "false_alarm_pct": alarms / checked * 100, "with_lateness_pct": alarms_late / checked_late * 100}) print(f"customers every {L:>3} min: {alarms / checked:6.3%} of orders look orphaned " f"with lateness L + 10: {alarms_late / checked_late:6.3%}") if args.json: with open(args.json, "w") as f: json.dump({"tables": {"loads": rows}}, f)3Run it in the folder you saved it to, with the defaults first. Then change a knob from the table below and run it again.
Terminal uv run the-false-alarm-floor-of-a.py uv run the-false-alarm-floor-of-a.py --help # every knob
| Knob · default | What it changes |
|---|---|
| --days7 | Simulated days. |
| --orders-per-min50 | Orders per minute. |
| --new-share0.02 | Share of orders from customers who signed up in the last hour. |
| --loads5, 15, 30, 60, 120 | Customer load intervals L, minutes. |
| --seed0 | Random seed. |
Our run
Data table
| Customer load interval L (minutes) | Checked on arrival | Checked after L + 10 min |
|---|---|---|
| 5 | 0% | 0% |
| 15 | 0.067% | 0% |
| 30 | 0.214% | 0% |
| 60 | 0.681% | 0% |
| 120 | 1.32% | 0% |
customers every 5 min: 0.000% of orders look orphaned with lateness L + 10: 0.000%
customers every 15 min: 0.067% of orders look orphaned with lateness L + 10: 0.000%
customers every 30 min: 0.214% of orders look orphaned with lateness L + 10: 0.000%
customers every 60 min: 0.681% of orders look orphaned with lateness L + 10: 0.000%
customers every 120 min: 1.315% of orders look orphaned with lateness L + 10: 0.000%What we found
The false-orphan rate rose with the customer load interval, from 0% at 5 minutes to 0.681% at 60 and 1.32% at 120, as expected: every order from a new customer waits for the next customer load. With allowed lateness of L + 10 minutes, the rate was 0% at every interval.
Read it
Every threshold is a classifier and inherits two error types, but this floor is not a threshold problem: it is a timing problem, and its cause is in the load schedule. Check a reference only after the latest time it can legitimately arrive, and the alarms that remain are real.