Closed world: when silence means "no"
In all previous tutorials a missing fact yielded NEITHER: law stays
silent. That is the right default caution: from the archive not knowing
about your accreditation it does not follow that you have none.
But sometimes it does. The archive keeps the accreditation registry, and keeps it exhaustively: if a person is not in it, she has no accreditation. Not “unknown” but no. That is a legal fact about the registry’s completeness, and it must be declared, not implied.
language "law.core" version "0.2";package tutorial.archive version "0.4.0";namespace "urn:law:tutorial:archive";
entity Person;
relation known_reader(p: Person) kind institutional;relation accredited(p: Person) kind institutional;relation in_researcher_registry(p: Person) kind institutional;relation must_be_escorted(p: Person) kind institutional;Declaring completeness
Section titled “Declaring completeness”closure AccreditationClosure { predicate accredited; domain known_reader; snapshot ARCHIVE_ACCREDITATION_2026; complete_as_of @2026-03-01T00:00:00+00:00; derive_explicit_negative true;}It reads like this: the predicate accredited is exhaustively
described by the ARCHIVE_ACCREDITATION_2026 snapshot as of 1 March
2026, but only for those falling into the known_reader domain.
The four fields carry four different obligations, and none is spare:
| Field | What is declared |
|---|---|
predicate | exactly which predicate is closed: not the package, not the ontology as a whole |
domain | about whom the registry may speak exhaustively |
snapshot | against which source; this is an address, not a word |
complete_as_of | at which moment completeness is claimed: the registry is complete as of a date, not forever |
derive_explicit_negative true means a missing entry produces
a full negative fact, not a mere lookup failure. The difference shows
in the proof: such a negation carries a closure certificate, and the
report states on what ground the system decided the entry is absent.
What the engine answers
Section titled “What the engine answers”| Reader | Facts | accredited |
|---|---|---|
| Ivanova | in domain, entry present | TRUE_ONLY |
| Ivanova | in domain, no entry | FALSE_ONLY |
| visiting researcher | outside domain | NEITHER |
The middle row is what closure is written for. The top and bottom rows
are the same without it.
Closure is local. About those outside the domain the registry says
nothing, and the system answers NEITHER. The engine is not being
cautious here but reads the declaration literally: the archive claimed
completeness about its own readers, not about all people in the world.
The temptation to write domain wider is worth resisting: widening the
domain widens the claim the archive answers for.
Why this belongs in a norm
Section titled “Why this belongs in a norm”Negation in a rule body works only where negation can be established.
rule EscortRequired strict { for p: Person; when in_researcher_registry(p) and not accredited(p); then must_be_escorted(p);}| Reader | Facts | must_be_escorted |
|---|---|---|
| Ivanova | in domain, in researcher registry, no accreditation | TRUE_ONLY |
| visitor | outside domain, in researcher registry | NEITHER |
Without a declared closure this rule would never fire: not accredited(p) requires an established negation, and there is nowhere to
take it from. There is no negation by failure in the core; the silence
of rules remains silence (we saw that in the second tutorial). closure
is the only way to turn a missing entry into a fact, and that way
requires an explicit claim about the source’s completeness.
What it costs
Section titled “What it costs”Closure is a strong claim about the world, and it ages. complete_as_of
fixes a moment; a norm executed at a later date relies on a snapshot
that may be stale. Checking the snapshot’s freshness is the job of the
process around the system, not of the engine: the core executes what was
declared and does not guess when the declaration stopped being true.
Hence the practical rule: closure is declared where completeness has
a holder, an authority obliged to keep the registry and answering
for its completeness. If there is no such authority, NEITHER is the
honest answer, and replacing it with FALSE by declaring completeness
means shifting onto the system a responsibility nobody took.
How law answers “no”
Section titled “How law answers “no””The three tools with which law answers “no” can now be told apart:
| Mechanism | Answer | Ground |
|---|---|---|
| norm with a negative head | FALSE_ONLY | the norm directly forbids |
closure | FALSE_ONLY | the registry is declared complete |
defeater | NEITHER | the ground of application has lapsed |
| none of the above | NEITHER | the input is incomplete |
Next is the test in the language of law: a check a lawyer will read is written in the same language as the norm. After it comes a real act: article 175 of the Social Code of the Republic of Kazakhstan, its source, the content-hash anchor, and reconciliation with the pinned edition.
The exercise for this page is /tutorials/exercise-closed-world/.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.