patrol_dbt
Checks a dbt model's table for data-quality incidents across daily partitions, tests proposed fixes against control totals, and reports which are safe to auto-fix or need escalation.
Instructions
Check the table behind a dbt model for data-quality incidents and say which are safe to fix.
A patrol checks every daily partition of the fact table for duplicate keys, duplicate rows, missing
partitions, rows that point to no reference record, null spikes, and row counts or amounts that do not
match the source's control totals. For each problem it proposes a fix, tests that fix on a copy against
the control totals, and decides: "auto-fixed" (proven and low risk), "no action needed" (checked, the
data is right) or "escalate" (a person must decide).
Use this after `dbt build` or `dbt run`, before trusting or publishing a date-partitioned model. It
finds the model's table from dbt's manifest, connects the way the project's profile says (DuckDB and
Snowflake targets are supported), and takes the column mapping from the model's `meta: dataranger:`
block unless you pass columns here. Use patrol_snowflake or patrol_duckdb for tables that are not dbt
models, and patrol_files for CSV or Parquet exports.
Behavior: reads target/manifest.json, dbt_project.yml and profiles.yml; it does not run dbt. It then
runs three SELECT statements and nothing else, so neither the warehouse nor the dbt project is
modified. On Snowflake it selects only the mapped columns for the last `days` days. The only side
effect is writing four report files to out_dir: dashboard.html, audit.jsonl, incidents.csv and
fixed_version.csv (the proposed corrected table, for review). Fails with a readable error if the
manifest is missing (run dbt first), a model is unknown, the target type is not supported, or a
mapped column does not exist.
Returns the counts (incidents, auto_fixed, no_action_needed, escalate), needs_a_person (the escalated
incidents), all_incidents (partition, problems, decision, proposed_fix, residual for each) and
outputs (paths to the report files). Pass outputs.folder and a partition to get_incident for the
full evidence behind one decision. Tell the user about every escalated incident.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"project_dir": "<project_dir>",
"model": "<model>"
},
"name": "patrol_dbt"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| key | No | Primary key column of the fact model. Omit to use meta.dataranger.key, or txn_id. | |
| date | No | Date column the fact model is partitioned by; the control totals need the same column. Omit to use meta.dataranger.date, or txn_date. | |
| days | No | Read only the last N days of the fact table and control totals (today counts as day one). Use at least 30 so the checks have a baseline. Pass null to read the whole table, which can be slow and costly. | |
| model | Yes | Name of the dbt fact model to check, for example fct_payments. A seed, snapshot, or a source written as source_name.table_name also works. | |
| amount | No | Numeric amount column of the fact model. Omit to use meta.dataranger.amount, or amount. | |
| target | No | dbt target to read from, for example prod. Omit for the profile's default target. | |
| out_dir | No | Folder to write the report files into. Created if missing; report files already there are overwritten. Omit to use a new temporary folder; its path comes back in outputs.folder. | |
| ref_key | No | Key column of the reference model. Omit to use meta.dataranger.ref_key, or customer_id. | |
| segment | No | Column that splits each day into segments, such as channel; the control totals need the same column. Omit to use meta.dataranger.segment, or channel. | |
| category | No | Optional categorical column of the fact model. Omit to use meta.dataranger.category, or none. | |
| ref_model | No | dbt model of the reference table that fact rows point to, for example dim_customers. Omit if the fact model's meta.dataranger block sets ref_model. | |
| reference | No | Fact column that points to the reference model. Omit to use meta.dataranger.reference, or customer_id. | |
| threshold | No | Gate threshold: the largest relative gap to the control totals that a verified fix may leave and still be marked auto-fixed (0.01 = 1%). Lower is stricter. Omit for the benchmark-calibrated default, 0.0135. | |
| project_dir | Yes | Path to the dbt project folder, the one that holds dbt_project.yml. It must have been built or parsed, so target/manifest.json exists. | |
| profiles_dir | No | Folder that holds profiles.yml. Omit to look in DBT_PROFILES_DIR, the project folder, then ~/.dbt. | |
| manifest_model | No | dbt model holding the source system's control totals: one row per date and segment ('*' = whole day) with n and amount. Omit if the fact model's meta.dataranger block sets manifest_model. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | ||
| table | Yes | ||
| outputs | Yes | ||
| escalate | Yes | ||
| incidents | Yes | ||
| auto_fixed | Yes | ||
| rows_checked | Yes | ||
| all_incidents | Yes | ||
| gate_threshold | Yes | ||
| needs_a_person | Yes | ||
| no_action_needed | Yes |