Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

GDPR walkthrough

A worked compliance knowledge base: a formalizable slice of the EU General Data Protection Regulation (Articles 5, 6, 7, 9, 15, 17, 33), answered by deterministic, auditable deduction.

Source of truth: gdpr.nibli at the repo root. Every verdict quoted below is pinned by the gdpr_* regression tests in nibli-engine/tests/integration.rs, so this page cannot silently drift from the engine. The same corpus ships as the playground preset “GDPR compliance (Ch 19)” — an example KB, not a chapter of any third-party book.

The scenario

EntityRole
AdamData subject; has given consent
AkmesController that suffered a breach
GugliController with no breach (clean control)
KanrekAdam’s health record (special-category data, Art 9)
OrdrekAn ordinary personal-data record

Second-order legal concepts are mapped onto proxy predicates, disclosed in the corpus header:

PredicateReads as
permitted(x)processing of x has a lawful basis (Art 6)
~permitted(x)no lawful basis remains → right to erasure (Art 17)
obligated_by(x, event { P() })x is under a legal obligation that P
permitted(x, event { P() })x has the right that P

Load it in the REPL

:load gdpr.nibli
[Load] Done: 24 asserted, 77 skipped, 0 errors

The 77 skipped lines are comments and blanks. Fact ids are assigned in file order; the consent fact approves(Adam). lands as fact #21 — the corpus deliberately defines the Article 17 rule after the scenario so these ids stay stable (a rule’s position in the file never affects reasoning).

Engine-checked queries

Query by stating a claim with the ? prefix. All verdicts below are asserted by the regression suite against the full loaded corpus:

ClaimVerdictWhy
? permitted(Adam).TRUEConsent is a lawful basis (Art 6(1)(a))
? ~permitted(Adam).FALSEA lawful basis stands, so no erasure right
? permitted(Gugli).FALSEA controller is not a consenting subject — an exhaustive, deduced FALSE
? data(Kanrek).TRUEHealth record → personal data, derived via data(every healthy data).
? obligated_by(Kanrek, event { correct() }).TRUEArt 5 accuracy reaches health data through the category chain
? obligated_by(Kanrek, event { exact() }).TRUESpecial-category data needs a stricter basis (Art 9)
? obligated_by(Ordrek, event { exact() }).FALSEOrdinary data does not
? permitted(Adam, event { data discovers() }).TRUERight of access / DSAR (Art 15)
? permitted(Akmes, event { data discovers() }).FALSEA controller does not acquire the subject’s access right
? obligated_by(Akmes, event { message() }).TRUEBreached controller must notify (Art 33)
? obligated_by(Gugli, event { message() }).FALSENo breach, no notification duty
? obligated_by(Adam, event { removes() }).FALSEConsent present → no erasure obligation (Art 17 rule)

Every FALSE here is a deduced false under the closed-world assumption — the engine exhausted the search — not a shrug. ? also prints a plain-English [Why] summary and the proof tree; see What Nibli guarantees for the verdict contract.

The headline demo. Adam’s only lawful basis is consent (fact #21). Retract it and re-query — both verdicts flip:

:retract 21
[Retract] Fact #21 retracted. KB rebuilt.

? permitted(Adam).
[Query] FALSE

? ~permitted(Adam).
[Query] TRUE

No lawful basis remains, so the right to erasure (Art 17(1)(b)) arises. The erasure verdict is derived by negation-as-failure and its proof carries the naf_dependent flag — the engine discloses that the conclusion rests on an absence. Nothing was edited by hand: the same rules, re-derived over the surviving facts. See Belief revision for the mechanics.

The corpus also stores Article 17 as a rule with a negated restrictor:

obligated_by(every person where ~approves, event { removes() }).

where ~approves compiles to a negation-as-failure check per subject: a consenting person carries no erasure obligation while a non-consenting one does (pinned by gdpr_erasure_rule_is_per_subject and the rule-level belief-revision test).

Honest boundaries

Two scope decisions the corpus makes explicitly, in its own comments:

  • Art 7 (“freely given” consent) is deliberately not encoded. Whether a consent was un-coerced is a case-by-case human judgment — it stays outside the deductive firewall rather than being faked as a rule.
  • The erasure rule keys on ~approves, not ~permitted. The corpus derives a lawful basis from a legal obligation, so a where ~permitted rule would close a negative basis↔obligation cycle — the engine correctly rejects that as unstratifiable at assert time. For Adam, whose only basis is consent, the two formulations coincide, which is why the right can equivalently be queried as ~permitted(Adam).

Try it in the playground

Select “GDPR compliance (Ch 19)” in the playground header dropdown. Its preset queries are exactly the first four claims above: lawful basis? (Art 6) · right to erasure? (Art 17) · a controller is not a consenting person—exhaustive FALSE · health record → personal data (Art 4/9, derived). Proofs render with the curated legal-domain overlay (“has a lawful basis for processing”), never a bare variable.