Checking each record on its own, so one file cannot fill gaps in another.
scoped-audit.py · output · proof · check · try it in the playground
An auditor has two separate records. The approved record says Alice is an editor and that she gave consent. The incomplete record says Bob is an editor, and nothing else.
Within each record, which editors gave consent, and which need review? A consent written in one record must not count for another.
Each record is a graph: a bundle of simple statements (triples, written
triple(Subject, Property, Value)), kept as one piece of data.
fact(
context('approved', graph([triple('alice', 'role', 'editor'), triple('alice', 'consent', 'yes')])),
)
fact(context('incomplete', graph([triple('bob', 'role', 'editor')])))
implies(
context(Context, Graph)
& includes(Graph, triple(Person, 'consent', 'yes')),
consented(Context, Person),
)
implies(
context(Context, Graph)
& includes(Graph, triple(Person, 'role', 'editor'))
& ~includes(Graph, triple(Person, 'consent', 'yes')),
needs_review(Context, Person),
)
Both rules look inside one graph. ~ means “it is not the case that”.
consented('approved', 'alice')
needs_review('incomplete', 'bob')
Alice consented in the approved record. Bob is an editor in the incomplete record with no consent there, so he needs review.
For Bob:
[triple('bob', 'role', 'editor')] —
fact 2.Verdict: checked_with_obligations. 10 steps, 1 on trust.
Note how small the trusted part is: it is scoped to one record, not “nothing anywhere”.
python -m peye examples/scoped-audit.py
python -m peye --proof examples/scoped-audit.py
Add triple('bob', 'consent', 'yes') to Bob’s graph, so it reads
graph([triple('bob', 'role', 'editor'), triple('bob', 'consent', 'yes')]): the review
disappears and consented('incomplete', 'bob') appears instead.
Keeping records separate keeps audits honest. Each conclusion says which record it came from, and the one “not found” claim is limited to that record.