Skip to content

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 published

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.

AF-MSK-001 The golden gv_20260826120000_a1b2c3d4 has no valid verification
attestation 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.

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:

masking.yaml
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.

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.

Related: masking, goldens.