Markdown for LLMs
Closed world: when silence means "no"
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# 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.
```law
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
```law
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
| 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
Negation in a rule body works only where negation can be established.
```law
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
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"
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](/tutorials/writing-tests/):
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/](/tutorials/exercise-closed-world/).