What we talk about: object, name, and record
Aigerim opens the registry Dana sent. In it, two researchers are recorded identically: “Ivanova A. S.”. The first one has two accreditation records: an old one, whose validity has expired, and a new one. About the second there is no such evidence. How can the accreditation of each be answered without attributing one person’s evidence to the other?
Let us start by telling apart the person, her name, and the record about her. Two people may share a name, and one person may correspond to several records. These distinctions must be kept in the model. For that we will compose a vocabulary: declare the object types and the relations with which we will describe people and their accreditation.
The Archive of Veliky Ustin, its registry, and the people in the story are fictional. The whole example is given on this page. If you want to run it right away, go to the “Run” section.
Question: how does a person differ from a record about her?
Section titled “Question: how does a person differ from a record about her?”In this lesson we will treat accreditation as established when a valid accreditation record corresponds to the person. We will check two cases: first two Ivanovas, then two records of one of them. In both cases we need to see which object each piece of evidence concerns.
First, let us write down the expected answers in plain words. We add an error check to them: what happens if a number is given instead of a name?
| Evidence | Expected answer |
|---|---|
| Two Ivanovas; only the first has a valid record | The second one’s accreditation is neither established nor refuted |
| One Ivanova; the old record has expired, the new one is valid | Accreditation established |
| A number given instead of a name | Type error when checking the package |
Matching names give no grounds to treat the second Ivanova as accredited. The old record does not cancel the new one. And a number instead of a name breaks the record form we are about to set in the vocabulary.
Record: vocabulary
Section titled “Record: vocabulary”The first chapter needed the Person type, denoting people. Now we add
a Record type for accreditation records. A record also becomes an
object in its own right: it can be given a status and linked to
a particular person.
For statuses we introduce a RecordStatus enumeration with two values:
Active — the record is valid, Expired — its validity has lapsed.
A parameter of this type takes one of the listed values. The enumeration
itself, however, does not forbid several statements about one record’s
status. Such a restriction would need a separate entry in the model.
language "law.core" version "0.2";package tutorial.archive version "0.1.1";namespace "urn:law:tutorial:archive";
entity Person;entity Record;
enum RecordStatus { Active; Expired }
relation person_name(p: Person, name: Text) kind empirical;relation accreditation_record(r: Record, p: Person) kind institutional;relation record_status(r: Record, s: RecordStatus) kind institutional;relation accredited(p: Person) kind institutional;After each relation name, its parameters are listed in parentheses: what we pass, in which order, and what type each value must be. This description is called a signature.
The person_name relation links a person to her name. The first
parameter has type Person, the second Text, the built-in type for
text. There is an Integer type for whole numbers and a Date type
for dates. The accreditation_record relation links a record to
a person, and record_status a record to its status. The order matters:
in accreditation_record the record comes first, then the person.
The empirical marker on person_name means we describe observed
evidence: which name stands in the registry. The institutional marker
on the other relations points to their link with institutional decisions
and statuses. These markers characterise the meaning of relations; the
concrete source of each piece of evidence must be stated separately.
Now let us write the rule. The variable p denotes the person, r the
record. They are declared by the for p: Person and for r: Record
lines. After when stand two conditions: the record belongs to this
person and has the Active status. When both hold, the rule allows
her accreditation to be established.
rule AccreditedByActiveRecord strict { for p: Person; for r: Record; when accreditation_record(r, p) and record_status(r, Active); then accredited(p);}Note: there is no person_name relation in the rule. Deriving the
conclusion needs the record-to-person link and the record’s status. That
is why matching names alone do not carry accreditation from one Ivanova
to the other.
Run: get the answer
Section titled “Run: get the answer”You will need a copy of the repository and Rust with Cargo installed.
Open a terminal at the repository root and run the commands below.
Run all further commands in the same window: it will keep the paths you
set. As in the first chapter, check will verify the package, and
lower will prepare the program and save it into a temporary directory.
cd engines/lawctutorial_dir=../../docs/tutorialstutorial_page="$tutorial_dir/01-vocabulary.en.law.md"cargo run -q --profile gate -p law-cli -- check \ "$tutorial_page"tutorial_work=$(mktemp -d)cargo run -q --profile gate -p law-cli -- lower \ "$tutorial_page" > "$tutorial_work/program.lawir.json"The first test describes two Ivanovas. Each person is matched with her
own entity_ref: urn:tutorial:ivanova and urn:tutorial:ivanova-2.
Their names are identical, their references differ. By these references
the model tells people apart.
The accreditation record has a reference of its own:
urn:tutorial:rec-2026. We link it only to the first Ivanova and state
the Active status. In the evaluate line we ask about the accreditation
of the second. The expected NEITHER answer means the accreditation is
neither established nor refuted.
test "две Ивановы: имя не склеивает людей" { given { context { decision_time @2026-03-01T09:00:00+05:00; knowledge_time @2026-03-01T09:00:00+05:00; legal_time @2026-03-01; timezone "Asia/Almaty"; } assert person_name( entity_ref("urn:tutorial:ivanova"), "Иванова А. С.") { id "name-1"; origin case_input; } assert person_name( entity_ref("urn:tutorial:ivanova-2"), "Иванова А. С.") { id "name-2"; origin case_input; } assert accreditation_record( entity_ref("urn:tutorial:rec-2026"), entity_ref("urn:tutorial:ivanova")) { id "rec-new"; origin case_input; } assert record_status(entity_ref("urn:tutorial:rec-2026"), Active) { id "status-new"; origin case_input; } } evaluate truth(accredited(entity_ref("urn:tutorial:ivanova-2"))); expect truth_status == NEITHER;}The test name reads: “Two Ivanovas: a shared name does not merge people.”
cargo run -q --profile gate -p law-cli -- test \ "$tutorial_dir/tests/01-vocabulary-two-ivanovas.lawtest" \ --lawtest --program "$tutorial_work/program.lawir.json"A test PASS message confirms the expected NEITHER answer. The input
evidence holds no accreditation record for the second Ivanova. The first
one’s name matches hers, but that is not enough to apply the rule. At the
same time, the missing record does not yet mean the second Ivanova’s
accreditation is refuted.
In the second test we consider one Ivanova and her two records. The old
one, rec-2024, has expired; the new one, rec-2026, is valid. Each
record has its own reference and status, so the rule conditions can be
checked for each of them separately.
test "две записи: считается действующая" { given { context { decision_time @2026-03-01T09:00:00+05:00; knowledge_time @2026-03-01T09:00:00+05:00; legal_time @2026-03-01; timezone "Asia/Almaty"; } assert accreditation_record( entity_ref("urn:tutorial:rec-2024"), entity_ref("urn:tutorial:ivanova")) { id "rec-old"; origin case_input; } assert record_status(entity_ref("urn:tutorial:rec-2024"), Expired) { id "status-old"; origin case_input; } assert accreditation_record( entity_ref("urn:tutorial:rec-2026"), entity_ref("urn:tutorial:ivanova")) { id "rec-new"; origin case_input; } assert record_status(entity_ref("urn:tutorial:rec-2026"), Active) { id "status-new"; origin case_input; } } evaluate truth(accredited(entity_ref("urn:tutorial:ivanova"))); expect truth_status == TRUE_ONLY;}The test name reads: “Two records: the valid one counts.”
cargo run -q --profile gate -p law-cli -- test \ "$tutorial_dir/tests/01-vocabulary-two-records.lawtest" \ --lawtest --program "$tutorial_work/program.lawir.json"cargo run -q --profile gate -p law-cli -- explain \ "$tutorial_dir/tests/01-vocabulary-two-records.lawtest" \ --program "$tutorial_work/program.lawir.json"The test should finish with a test PASS message: accreditation is
established, the answer is TRUE_ONLY. In the explanation, find the
AccreditedByActiveRecord rule and the evidence about the rec-2026
record: whom it belongs to and in which status it is. Together they give
grounds for the conclusion.
The old rec-2024 record does not satisfy the Active condition.
Moreover, our rule has no conclusion of missing accreditation from the
Expired status. So the old record does not refute the result obtained
via the new one. We kept both records and can explain which of them
supports the answer.
Practice: mix up and catch
Section titled “Practice: mix up and catch”Make a copy of the ready-made two-Ivanovas test file
in a temporary directory. In the test command, give the path to
this copy instead of the original file. The prepared program stays
the same.
First change only the question: in the evaluate line replace
ivanova-2 with ivanova. Now we ask about the first Ivanova, who has
a valid record. Before running the test, explain why you expect
TRUE_ONLY, and put that status in the expect line. The test should
pass. You may also change the name in one of the person_name lines:
it will not affect the answer, since the name is not among the rule
conditions.
For the next experiment, again take a copy of the original test with
the question about the second Ivanova and the NEITHER expectation. In
the statement named rec-new, replace the urn:tutorial:ivanova
reference with urn:tutorial:ivanova-2. Now the record belongs to the
second Ivanova. Keep the previous expectation and run the test: it should
finish with FAIL, because the obtained answer became TRUE_ONLY.
The record-to-person link changed, and the conclusion followed it.
Finally, check how a wrong value type is detected. Make a copy of this
page and in the first test replace the "Иванова А. С." text (“Ivanova
A. S.”) with the number 42 without quotes. Run the check command for
the copy. It should report an LDC-E2104 error: an Integer number was
passed, while the name parameter requires Text. The compiler does not
turn a number into a name automatically; such a record must be fixed
before running.
Acceptance: what you can check yourself
Section titled “Acceptance: what you can check yourself”Check that you can repeat both cases and explain the results:
- Matching names do not merge two Ivanovas. In the first case the answer
about the second is
NEITHER, about the firstTRUE_ONLY. - One Ivanova may have two separate records. The valid one lets
accreditation be established: the answer is
TRUE_ONLY. - If the valid record is linked to another person, the answer changes. Changing the name text does not affect the conclusion.
- A number instead of a name gives an
LDC-E2104error when checking the package.
Boundary: what types do not check
Section titled “Boundary: what types do not check”Package checking detects a number where text is required and compares the argument count against the relation declaration. But a typo in a name is still text. A wrong record-to-person link may also be written in a type-correct way. The model will reason over the evidence we passed to it.
Handle entity_ref references with particular care. The type of such
a reference is set by the relation parameter in which it is used. The
words ivanova and rec-2026 inside the reference help us read the
example, but by themselves they do not declare a person or a record.
If in the accreditation_record statement these references are swapped,
the compiler may accept the record: the first argument is used as
a Record, the second as a Person. But then the needed link to
the Active record is lost. So when checking input evidence, it matters
to verify both the argument order and what each reference denotes. This
is examined in more detail
on the vocabulary reference.
We did not compute validity periods here either. The Active and
Expired statuses were given in the input evidence. Checking a status
against dates would need the dates themselves and a matching rule.
Now Aigerim can tell apart two people with the same name and explain which of several records supports the conclusion. To understand the answer, you need to know which object each piece of input evidence speaks about.
In these examples we again obtained TRUE_ONLY and NEITHER. What the
two remaining states mean, and how to work with contradicting statements,
is covered in the lesson
“Four states of support”.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.