report.coverage records what each detector examined, at what scale,
and what was skipped or capped and why. Read it alongside findings to
understand which properties were checked. This chapter explains the coverage
vocabulary, the three budget presets, the optional wall-clock deadline, the
overrides that scale the sampled work, and how detector selection appears in
coverage.
The coverage vocabulary¶
report.coverage maps each pass to a status and a human-readable detail
line. There are five statuses:
| Status | Meaning | Typical detail |
|---|---|---|
ran_exact | The pass ran over all rows, no sampling | “6 cards (exact)” |
ran_sampled | The pass ran on a deterministic sample by design | sample size vs table size |
capped | The pass ran but a search cap limited its scope | how many of how many candidates |
skipped | The pass did not run at all | “quick tier”, “deadline reached”, “detector not enabled” |
not_applicable | The pass ran and found nothing to report on | “0 single-column unique, 0 composite” |
A capped pass performed some work but reached a search limit. For
example, the numeric-pair pass screens all pairs and computes detailed
statistics for the strongest 496. A skipped pass did not run. Check the
detail line to see what work supports either status.
The three budgets¶
The budget argument selects one of three presets. Everything exact is
identical across budgets; what changes is the relationship work.
quick | standard | deep | |
|---|---|---|---|
| Column cards, duplicates, keys, sortedness, dates | all exact, full rows | same | same |
| Single-column uniqueness | exact | exact | exact |
| Composite key search | — | pairs, verified up to 16 | pairs and triples, verified up to 24 |
| Functional dependencies | — | LHS size ≤ 2, verified over ≤ 200,000 rows | LHS size ≤ 3, verified over ≤ 500,000 rows |
| Model passes (screening, tables, rules, regimes) | — | ≤ 20,000 encoded rows | ≤ 50,000 encoded rows |
| Numeric pair statistics | — | ≤ 496 pairs over ≤ 20,000 rows | ≤ 2,016 pairs over ≤ 50,000 rows |
quick runs column summaries and basic integrity checks. standard
adds relationship discovery and is the default. deep uses wider
searches and larger samples. The limits and sampling methods are in
Deterministic sampling.
import random
import polars as pl
import onceover
rng = random.Random(3)
n = 15_000
region_id = [rng.randrange(4) for _ in range(n)]
region_name = [["north", "south", "east", "west"][r] for r in region_id]
quantity = [rng.randrange(1, 21) for _ in range(n)]
double_quantity = [2 * q for q in quantity]
x = [rng.uniform(-1, 1) for _ in range(n)]
y = [v * v for v in x]
df = pl.DataFrame({
"order_id": list(range(n)),
"region_id": region_id,
"region_name": region_name,
"quantity": quantity,
"double_quantity": double_quantity,
"x": x,
"y": y,
})
reports = {b: onceover.profile(df, budget=b) for b in ["quick", "standard", "deep"]}
for b, r in reports.items():
measured = sum(1 for f in r.findings
if any(e["basis"] == "measured" for e in f["evidence"]))
print(f"{b:9s} {len(r.findings):3d} findings ({measured} with measured evidence)")quick 11 findings (5 with measured evidence)
standard 36 findings (22 with measured evidence)
deep 36 findings (22 with measured evidence)
quick returns full-data summaries and basic integrity findings.
standard adds relationships; deep uses a wider search but finds the
same structure in this fixture. The coverage table shows which passes
ran at each budget:
from great_tables import GT, loc, style
passes = sorted(set().union(*[set(r.coverage) for r in reports.values()]))
rows = []
for p in passes:
row = {"pass": p}
for b, r in reports.items():
row[b] = r.coverage.get(p, {"status": "—", "detail": ""})["status"]
rows.append(row)
(GT(pl.DataFrame(rows))
.tab_header(title="Pass status by budget", subtitle="15,000 rows × 7 columns")
.tab_options(table_width="100%", table_layout="fixed",
table_font_size="14px", data_row_padding="9px")
.tab_style(style.css("white-space: normal; overflow-wrap: anywhere; line-height: 1.5;"),
loc.body()))Overrides¶
Three keyword arguments scale the sampled work without touching the exact
passes. sample_rows caps the row sample shared by the FD verification, the
encoded matrix, and model fitting. max_predictors caps how many predictors
survive screening per fitted model. max_pairs caps how many numeric pairs
get detailed statistics after screening. Column cards, duplicate detection,
single-column keys, sortedness, dates, and identity residual verification
always examine the full input.
default = onceover.profile(df)
tuned = onceover.profile(df, sample_rows=6_000, max_predictors=8, max_pairs=20)
for pass_name in ["encoding", "functional_dependencies", "dependence_screen"]:
print(f"{pass_name}:")
print(" default:", default.coverage[pass_name]["detail"][:90])
print(" tuned: ", tuned.coverage[pass_name]["detail"][:90])encoding:
default: 15000 rows (15000 of 15000), 7 features (all usable columns; per-model predictor budget 48
tuned: 6000 rows (6000 of 15000), 7 features (all usable columns; per-model predictor budget 8, 0
functional_dependencies:
default: all 4 eligible lhs / 7 eligible rhs columns screened (24 directed pairs over 2048 rows); p
tuned: all 4 eligible lhs / 7 eligible rhs columns screened (24 directed pairs over 2048 rows); p
dependence_screen:
default: 15 of 15 numeric pairs (full); all 15 pairs screened; detailed statistics over 15000 of 15
tuned: 15 of 15 numeric pairs (full); all 15 pairs screened; detailed statistics over 6000 of 150
The tuned run’s coverage shows 6,000-row samples where the default used 15,000 (and would use 20,000 on a larger table). Smaller samples are cheaper but can leave too few rows for model fitting. Check coverage for passes skipped because the sample was too small. Relationships involving rare values may also be missed when those values are absent from the sample.
The deadline¶
An optional wall-clock budget, deadline_seconds, trades completeness for
time. It is checked between passes: whichever pass is running when the
deadline passes still completes, and later passes are skipped and recorded
as "deadline reached" in coverage. Nothing is interrupted mid-computation,
so any reported finding comes from a pass that completed.
The deadline is the single opt-in source of nondeterminism in the package. Without it, the same data and configuration produce byte-identical reports; with it, which passes finish depends on machine speed at that moment. Coverage records the passes skipped after the deadline.
import numpy as np
rng_np = np.random.default_rng(5)
big = pl.DataFrame(
{"id": np.arange(400_000, dtype=np.int64)}
| {f"x{i:02}": rng_np.random(400_000) for i in range(15)}
)
timed = onceover.profile(big, deadline_seconds=1.0)
deadline_skips = {name: info for name, info in timed.coverage.items()
if info["status"] == "skipped"
and "deadline" in info["detail"].lower()}
print("Passes skipped because of the deadline:", len(deadline_skips))
for name, info in deadline_skips.items():
print(f"{name:28s} {info['status']:14s} {info['detail']}")Passes skipped because of the deadline: 7
association_rules skipped deadline reached
dates skipped deadline reached
deadline skipped wall-clock deadline 2.7s reached; later passes skipped
digits skipped deadline reached
expectations skipped deadline reached
predictability_screen skipped deadline reached
regimes skipped deadline reached
On this 400,000-row frame, a one-second deadline may skip later passes
if the preceding work takes long enough. A fast run can finish all enabled
passes before the deadline. A views entry saying detector not enabled
reflects detector selection rather than the deadline. Include coverage
when sharing a report produced under a deadline; it records which passes
completed.
Detector selection¶
Selecting a subset with detectors=[...] marks deselected passes
"detector not enabled". A detector required by a selected detector still
runs, but its coverage line includes “required as a resource; findings not
selected”. Every rule candidate from PRISM or association mining is then
re-counted on a common diagnostic partition; coverage records this check
under rule_evaluation. See Reading findings for detector selection
examples.
Reading coverage in practice¶
If a finding is absent, check its detector’s status.
skippedmeans the pass did not run;cappedmeans it examined only part of its candidate search.ran_exactwith no finding means no property met the pass’s reporting criteria on the full input.For sampled work, read the sample and table sizes in the detail line. Each evidence record also gives
scope.population_rowsandscope.rows_evaluatedfor its own measurement.Before automating an action, check the finding’s
basis, sampling, validation, and pass status. Full-data measurements describe the current table. Validate sampled or model-based results on the data where the action will apply.