Arya Bank — data quality & reconciliation

Fictional bank, synthetic data: 1,000 customers, 1,366 accounts, 50,285 transactions for September 2026, with known defects injected on purpose. Checked with SQL rules in DuckDB and Great Expectations, then reconciled against the reporting pipeline. Updated 12 Oct 2026, 00:46 UTC.

Data quality score
98.86
of 100 · worst day 17 Sep (96.18)
Rules exact vs ground truth
12/12
no misses, no false positives
Reconciliation
7/7
source → report checks pass
Pipeline bugs caught
6/6
68/68 tests green on the correct pipeline
Completeness
96.0
Uniqueness
99.7
Validity
98.83
Integrity
99.79
Timeliness
99.96
Consistency
98.88

Failed transaction rows per day

Rows breaking a row-level rule (bad currency, non-positive amount, unknown account, duplicate copy). The 17 Sep spike is the injected feed incident. Rows dated after the cutoff are not shown.

0204060801471013171922252866 · feed incident
Show as table
DateRowsFailedScore
2026-09-011,721799.59
2026-09-021,658299.88
2026-09-031,657699.64
2026-09-041,693699.65
2026-09-051,670899.52
2026-09-061,729899.54
2026-09-071,655799.58
2026-09-081,659499.76
2026-09-091,648399.82
2026-09-101,7071299.3
2026-09-111,630499.75
2026-09-121,694699.65
2026-09-131,704899.53
2026-09-141,716699.65
2026-09-151,668799.58
2026-09-161,645499.76
2026-09-171,7266696.18
2026-09-181,6941199.35
2026-09-191,610799.57
2026-09-201,680799.58
2026-09-211,7071099.41
2026-09-221,592699.62
2026-09-231,695599.71
2026-09-241,6831099.41
2026-09-251,720899.53
2026-09-261,616899.5
2026-09-271,666999.46
2026-09-281,673799.58
2026-09-291,675799.58
2026-09-301,674699.64

Quality rules (SQL)

Each rule is graded against the generator's manifest of injected defects.

RuleDimensionCheckFailedPass ratevs ground truth
UNQ-01UniquenessEach txn_id appears once
transactions
150 / 50,28599.7%✓ exact
150 found / 150 injected
CMP-01CompletenessCustomer has email, phone and KYC status
customers
40 / 1,00096.0%✓ exact
40 found / 40 injected
VAL-01ValidityCurrency is INR or a currency with an FX rate
transactions
60 / 50,28599.88%✓ exact
60 found / 60 injected
VAL-02ValidityAmount is a number greater than zero
transactions
30 / 50,28599.94%✓ exact
30 found / 30 injected
VAL-03ValidityEmail is well formed
customers
25 / 1,00097.5%✓ exact
25 found / 25 injected
VAL-04ValidityPhone is a 10-digit Indian mobile number (starts 6-9)
customers
20 / 1,00098.0%✓ exact
20 found / 20 injected
INT-01IntegrityTransaction belongs to a known account
transactions
25 / 50,28599.95%✓ exact
25 found / 25 injected
INT-02IntegrityAccount's branch exists in the branch master
accounts
5 / 1,36699.63%✓ exact
5 found / 5 injected
TML-01TimelinessTransaction is not dated after the extract cutoff
transactions
20 / 50,28599.96%✓ exact
20 found / 20 injected
CON-01ConsistencySavings account closing balance is not negative
accounts
10 / 1,36699.27%✓ exact
10 found / 10 injected
CON-02ConsistencyClosing balance = opening + credits - debits (successful, valid transactions)
accounts
25 / 1,36698.17%✓ exact
25 found / 25 injected
CON-03ConsistencyCustomers under 18 cannot hold a CURRENT account
customers
8 / 1,00099.2%✓ exact
8 found / 8 injected

Reconciliation: source → report

Expected figures are recomputed from the raw extract with independent SQL, then compared with the pipeline output.

CheckWhat it provesResultExpected / actual
REC-01Every raw row is either loaded or quarantined✓ pass50285 raw rows
50000 loaded + 285 quarantined = 50285
REC-02Each valid transaction is loaded exactly once✓ pass50000 valid transactions
0 missing, 0 unexpected, 0 duplicated
REC-03Quarantine counts per reason match the quality rules✓ passDUPLICATE 150, INVALID_CURRENCY 60, NON_POSITIVE_AMOUNT 30, UNKNOWN_ACCOUNT 25, FUTURE_DATED 20
DUPLICATE 150, FUTURE_DATED 20, INVALID_CURRENCY 60, NON_POSITIVE_AMOUNT 30, UNKNOWN_ACCOUNT 25
REC-04Daily control totals (count, credits, debits) match the source✓ passevery day matches
0 of 30 report days differ
REC-05Every branch-day row matches the source✓ passevery branch-day matches
0 branch-day rows differ (report has 630)
REC-06Computed closing balance per account matches the source ledger✓ passall accounts match
0 accounts differ
REC-07Balance breaks in the report are exactly the known source breaks✓ pass25 accounts (rule CON-02)
25 accounts flagged by report

Planted pipeline bugs

The whole test suite is rerun with one bug switched on at a time. A bug counts as caught when at least one test fails.

BugDefectResultCaught by
PIPE-01Duplicates not removed
A re-sent transaction is counted twice in the daily totals.
✓ caughtUnit, Reconciliation
7 failing tests
PIPE-02FX uses the latest rate for every day
Foreign remittances are converted at the 30 Sep rate instead of the rate on their own date.
✓ caughtUnit, Reconciliation
9 failing tests
PIPE-03Report date taken in UTC, not IST
Payments made between 00:00 and 05:30 IST land on the previous day's report.
✓ caughtUnit, Reconciliation
9 failing tests
PIPE-04Inner join to branch master
Transactions of accounts with an unknown branch vanish without being quarantined.
✓ caughtUnit, Reconciliation
7 failing tests
PIPE-05Failed and reversed payments counted
Totals include money that never moved.
✓ caughtUnit, Reconciliation
9 failing tests
PIPE-06Paise dropped
Amounts are floored to whole rupees before totalling.
✓ caughtUnit, Reconciliation
9 failing tests

Great Expectations

TableColumnExpectationResultUnexpectedSample
transactionstxn_idnot be null✓ pass0
transactionstxn_idbe unique✗ fail300T00042777, T00032241, T00043108
transactionsaccount_idmatch regex✓ pass0
transactionscurrencybe in set✗ fail48usd, usd, RS
transactionscurrencynot be null✗ fail12nan, nan, nan
transactionsamount_numbe between✗ fail300.0, -4991.59, 0.0
transactionsdirectionbe in set✓ pass0
transactionsstatusbe in set✓ pass0
transactionschannelbe in set✓ pass0
transactionstxn_ts_utcbe between✗ fail202026-10-10 13:30:00, 2026-10-06 07:30:00, 2026-10-10 00:30:00
customerscustomer_idbe unique✓ pass0
customersemailnot be null✗ fail14nan, nan, nan
customersemailmatch regex✗ fail25zarna x@example.com, unni@, xavier x@example.com
customersphonenot be null✗ fail13nan, nan, nan
customersphonematch regex✗ fail205987654321, 5987654321, 5987654321
customerskyc_statusnot be null✗ fail13nan, nan, nan
customerskyc_statusbe in set✓ pass0
customersdate_of_birthmatch regex✓ pass0
accountsaccount_idbe unique✓ pass0
accountsaccount_typebe in set✓ pass0
accountsbranch_codebe in set✗ fail5ARYB9999, ARYB9999, ARYB9999
accountscurrencybe in set✓ pass0

Quarantine

Rows the pipeline refused to load, with the reason. Nothing is dropped silently.

ReasonRows
DUPLICATE150
FUTURE_DATED20
INVALID_CURRENCY60
NON_POSITIVE_AMOUNT30
UNKNOWN_ACCOUNT25

Source on GitHub