Verification
Masking is a claim. Verification is a check.
After the masking rules run, the engine scans the candidate for data that still looks like a person: addresses, card numbers, national identifiers, names in free text. If it finds anything, nothing is published. If it finds nothing, it signs a statement of what it scanned and what it found, and that statement is what makes the version branchable.
copy ──> mask ──> scan ──> attestation ──> golden │ └── anything found: nothing is publishedWhy the check is separate from the rules
Section titled “Why the check is separate from the rules”Because the rules are written by people. A column added last month has no rule,
a rule can name the wrong column, and a notes field can hold an address
somebody pasted into it. A masking pass that ran successfully proves the rules
ran, not that the data is safe.
Verification is the part that can say no.
Nothing branches an unverified golden
Section titled “Nothing branches an unverified golden”AF-MSK-001 The golden gv_20260826120000_a1b2c3d4 has no valid verificationattestation and cannot be branched. Next: Run 'af golden verify gv_...'; a golden is branchable only once verification has passed.This is enforced in every provider rather than in a checklist. It is the product’s central promise: an environment cannot contain unmasked production data, because the only thing an environment can branch is a golden, and a golden is not a golden until the scan passed.
The conformance suite every provider runs has a behaviour for exactly this, so a provider written outside this repository is held to it too.
When the scan finds something
Section titled “When the scan finds something”AF-MSK-002 Verification found data matching card number in orders.notes. Next: Add a masking rule for orders.notes and refresh the golden. The value itself is never printed.The value is never printed, and it is never written to a log, an artifact, or a CI annotation. A finding that quoted the data would publish it in the output of the job that caught it.
Add a rule and refresh:
rules: - table: orders column: notes transform: free_text why: "customers paste anything into this field"If the column genuinely holds no personal data and the detector is wrong, say so explicitly rather than deleting the check:
- table: orders column: notes transform: preserve why: "internal fulfilment codes, never free text from a customer"preserve is the exemption, and why is what makes it reviewable. An
exemption with no sentence beside it is a decision nobody can check later, and
af mask plan prints the sentence next to the column so it is read.
The attestation
Section titled “The attestation”A signed statement: which version, which rules, which detectors ran, how many rows and columns were scanned, and what was found. It is stored with the golden so anyone holding an environment can read what was checked without asking the engine.
With the Neon provider it lives in the branch itself:
SELECT version, rules_hash, created_at, attestation FROM _antifailure.golden;It is signed so that “this data was scanned” is a claim you can check rather than one you have to take on trust.