Engineering guide · Executed teaching example

Turn a privacy decision into a test that can fail

Deleting a profile is not the same as completing an erasure request. This small example follows a request across two stores, keeps a failed destination visible, and checks what happens on retry and restore.

Settle the privacy decision before automating it

An accountable privacy reviewer must establish whose request this is, which processing and data it covers, whether erasure applies, and which exceptions or retention duties matter. The European Commission describes both erasure grounds and exceptions. It also describes a response without undue delay and, in principle, within one month. That is not a universal “delete every copy within 30 days” engineering rule. Commission guidance on individual requests.

The EDPB's Article 25 guidance asks for effective measures suited to the processing and evidence of their effectiveness. It does not prescribe the two-store architecture or retry strategy below. Final Guidelines 4/2019, paragraphs 13 to 16.

Our fixture begins after the legal and identity questions have been resolved. It uses synthetic data and a fictional product decision, assumed approved only for this teaching scenario. It cannot determine whether a real request should be accepted.

Write the engineering promise separately

Illustrative approved policy: for this eligible request, remove the target subject's rows from the declared profiles and analytics stores. Report completion only when absence has been observed in both live stores. Keep any destination failure unresolved and named. Retrying must preserve other subjects' rows.

The versioned teaching policy records that assumption, four engineering requirements and the exclusions. It is not GDPR text or a record of a real customer's approval.

  1. Define the scope: identify the two destinations and the target subject. Missing a third destination would invalidate a broader completion claim.
  2. Choose the observation: query actual rows after the deletion attempt, independently of the handler's status message.
  3. Specify the failure: if analytics deletion fails, keep the request unresolved even if profile deletion succeeds.
  4. Specify recovery: retry safely. After a restore, reconcile the live state before relying on the previous completion.

The broken handler said “complete” too early

Executed October 3, 2026 with Python 3.14.7 and SQLite 3.53.4. The failure is deliberately injected before the analytics deletion. The observations are real results from this toy fixture.

Target rows remaining in the two declared live stores
Executed scenarioReported stateProfilesAnalytics
Broken handler, analytics failureComplete, incorrectly01
Corrected handler, same failureUnresolved01
Retry after recoveryComplete00
Repeat completed requestComplete00
Reconcile after analytics restoreUnresolved01
Delete the restored live rowComplete00

The unrelated subject retained one row in each live store throughout these observations. The runner's independent SQL queries caught the false completion in the broken handler. All nine checks passed, including that expected detection, retry safety and restore reconciliation. Inspect the full observed JSON.

The repair is small but consequential: collect a result for every declared destination and only then decide whether this live-store request is complete. A successful deletion in the first store cannot stand in for the second store's result.

A restore can invalidate yesterday's completion

The fixture takes an analytics backup before deletion, then restores it after the retry succeeds. An explicit reconciliation call finds the returning target row and reopens the request. A further deletion removes the live row again.

The backup itself still contains the row. The runner checks and reports that exclusion before removing its temporary directory. Here, “complete” describes two live stores at an observation point. It does not mean every copy has been erased, and SQL deletion does not establish physical media sanitization.

A production design needs a reviewed backup and restoration policy, durable request state, concurrent-write handling and an inventory of downstream destinations. This synchronous example has none of those mechanisms. It also does not automate request authentication, recipient communication or deadlines.

Run the same failure yourself

Download the complete fixture ZIP and its SHA-256 digest. It uses Python's standard library, makes no network calls and creates only temporary databases containing synthetic rows.

python3 -m zipfile -e privacy-obligation.zip .
cd privacy-obligation
python3 verify.py
python3 run.py rerun.json

The verifier checks file digests and the saved observation's source hashes. The runner executes the scenarios again and writes a new report, overwriting that output path if it exists. It exits nonzero if any check fails. A digest establishes which files you inspected, not legal sufficiency.

Individual files: deletion handlers, runner and independent checks, file digests and scope and reproduction notes.

Bring one approved obligation and one uncertain outcome

Proof can help connect a reviewed privacy decision to a requirement, its implementation, verification and remaining gaps. This example is ordinary Python, not a native Proof privacy connector or a GDPR compliance assessment.

Bring one approved deletion or retention policy and a failure path your current tests do not explain. Scope an evidence review with Proof to establish what can be observed in your system and which legal or operational decisions remain outside that evidence.

Continue with deriving engineering requirements, evidence freshness and a reviewable verification report.

Primary guidance checked October 3, 2026. The legal sources inform the question; the executed fixture establishes only the behavior and limits described above.