Part 2. Why Banking Data Requires Specifications
Banking data tolerates "roughly correct" especially poorly. In a web feature, an error is often visible to the user. In a data product, an error can look like a normal table: rows exist, fields exist, tests are green, but the meaning is already broken. That is why the banking domain is convenient for learning SDD Data: it forces you to explicitly write promises, constraints, and evidence.
Where the Risk Is Higher Than Usual
In our educational bank, we are interested in five risk classes:
- PII and direct identifiers;
- payments and risk signals;
- data access consents;
- credit portfolio and delinquency;
- reporting and reproducibility of calculations.
Each risk class requires not only SQL, but also a verifiable rule. "Do not disclose personal data" is too broad. A workable rule sounds like this: models/marts/ contains no pii_email, phone, passport_number, or other direct identifier columns, and a reviewer checks this before release.
Why dbt Tests Are Not Enough
dbt tests catch not_null, unique, accepted values, and some custom invariants well. But they do not know that customer_360 is promised as "one
row per customer" unless you wrote that down in the specification. They do not know that adding product_code changes the consumer contract. They do not know that risk_flag is an educational signal, not a final credit scoring decision.
That is why SDD Data has several layers:
- dbt tests check the form and part of the facts;
- ODCS captures the technical contract;
- ODPS describes the data product and the consumer;
- the model specification describes the grain and acceptance facts;
- the reviewer report ties a change to the promises.
Example of a Bad Specification
Build a customer mart for analysts. Add useful fields about accounts and
transactions. Check data quality.
Problems:
- grain is not specified;
- it is not said whether PII may be disclosed;
- "useful fields" are not defined;
- there is no SLA or data freshness;
- "data quality" is not turned into facts;
- there is no owner who accepts drift.
A Good Version
Data product: customer_360.
Consumer: analysts of the customer portfolio and branch network.
Mart: mart_customer_360.
Granularity: one row per `customer_id`.
PII: the mart contains no direct PII.
Data freshness: 24 hours.
Required facts: `customer_id` unique/not_null, `total_balance_rub` not_null,
`risk_event_count_7d` is present, the check for the forbidden direct PII list passes.
Such a specification does not solve the whole product, but it sets boundaries the agent should not have to guess.
Analysis for the Reader
The banking example is chosen not for drama. It is convenient because almost every assumption has consequences. In an online store, a faulty mart can also cause harm, but in a bank even educational entities immediately force you to ask: is it allowed to show this field, who has the right to change the methodology, how do you prove reproducibility, what will happen to the report further down the chain. These questions discipline the reader better than an abstract sales example.
It is especially important to distinguish "the table was built" from "the data can be used." A green dbt build says the graph is executable and the stated checks passed. It does not say the correct granularity was chosen. It does not know that a single mart must not mix a customer and an account. It does not see that a field looks like a scoring output, while in fact it is an educational flag from the source. This is not a shortcoming of dbt; it is the boundary of the tool.
It is useful for the reader to practice on bad specifications. A bad specification usually sounds confident: "build a useful mart", "add quality", "account for the risks." It contains few explicit mistakes, because it promises almost nothing. A good specification, on the contrary, looks narrower. It says: one row per customer, direct PII is forbidden, freshness is 24 hours, required fields are these, checks are these. Narrowness here is not a weakness, but a way to make the work verifiable.
In this chapter it is important not to memorize a list of banking risks, but to get used to the question "how will this be proven?". If a rule cannot be turned into a command, a SQL query, a manual reviewer step, or human confirmation, it is not yet ready for the agent. A good agent should not guess what "correct" means; it should be given a criterion by which its work can be rejected.
Practice
Take one mart from the README and write three risks for it: grain, PII, and contract drift. For each risk, formulate not a slogan, but a verifiable rule. If the rule cannot be verified, rewrite it down to a command or a manual reviewer step.
Minimum Output
After the chapter, create a short note:
# Notes on Data Risks
## PII
## Grain
## Freshness
## Contract Drift
## Human Confirmations
Fill in one rule per section. If a rule cannot be verified, rewrite it as a command, SQL, a schema review, or human confirmation.
Typical Mistake
Writing in AGENTS.md: "comply with banking requirements." For the agent this is almost useless. It needs concrete prohibitions, allowed input models, contract fields, and checks.
Review Questions
- Why does a green
dbt buildnot prove the correctness of a data product? - Which defect is more dangerous: a syntactic SQL error or an unnoticed change of grain?
- Where is it better to record the PII policy: in chat, in a SQL comment, or in a specification?