Referential Integrity Checks
data_quality.validate_rows is strictly intra-row, single-table — its
unique rule only dedupes within one batch. There was no parent/child
foreign-key check across two loaded tables, no composite-key uniqueness, and no
standalone accepted-values / row-count assertion. This adds those dbt-style
generic checks over rows already loaded by load_rows / query_sqlite.
Pure standard library (collections); imports no PySide6. Every function
is pure (rows in, report out), so it is fully deterministic in CI.
Headless API
from je_auto_control import (
check_foreign_key, check_unique_key, check_accepted_values,
check_row_count, load_rows,
)
orders = load_rows("orders.csv")
users = load_rows("users.csv")
fk = check_foreign_key(orders, "user_id", users, "id") # {ok, violations, missing}
pk = check_unique_key(orders, ["region", "id"]) # {ok, duplicates}
av = check_accepted_values(orders, "status", ["open", "closed"])
rc = check_row_count(orders, minimum=1) # {ok, count}
check_foreign_key flags non-null child values absent from the parent column
(dbt relationships). check_unique_key reports duplicate single or
composite keys. check_accepted_values lists non-null values outside the
allowed set. check_row_count verifies the count falls within optional
minimum / maximum bounds. Each returns an ok flag plus details.
Executor commands
AC_check_foreign_key, AC_check_unique_key, AC_check_accepted_values,
and AC_check_row_count each take JSON rows (and a column / key / allowed
list) and return the report. All are exposed as MCP tools
(ac_check_*) and as Script Builder commands under Data.