Books / Constructions / Chapter 1
Part I · Chapter 1
What This Record Is About
Contents of Constructions
Let us start with a small example about water. The OpenStax general chemistry textbook Chemistry 2e explains in section 14.1[^openstax-14-1] that in reactions water can donate a proton to another particle or accept one. Particles capable of playing both roles are called amphiprotic. We will return to that property in the next chapter. For now, take just one piece of information: water can donate a proton.
To begin, it is enough to know that a proton is a positively charged particle. We will not need the details of reactions yet. We will read a ready-made record and work out how it denotes the subject and the property reported about it.
By the end of the chapter you will be able to tell three things apart: what the model’s vocabulary lets us record, what is reported about a particular object, and what question is asked. First we will examine short statements, then assemble them into a checkable example.
Vocabulary: what information can be recorded
The Arxo corpus holds a model of this textbook section. Its vocabulary contains this declaration:
pub entity Species {
label ru unofficial "химическая частица";
label en unofficial "chemical species";
}
The word entity introduces a type of object. Here the type is
called Species: these are the chemical particles the model will
be able to talk about. The curly braces mark the beginning and
the end of the type description.
The two label lines give captions for the reader: ru means
Russian, en means English. The captions let the model present
Species in different languages. unofficial
marks the unofficial status of a caption; by itself the word does
not say whether it was invented by the model’s author or taken
from a source. The pub mark makes the name available to other
packages. We will examine this mechanism in detail in
chapter 16. The caption text is enclosed in quotation marks, and
a semicolon ends the entry.
Declaring a type still reports nothing about water. It introduces a concept we will use in records. Next, two properties that can be ascribed to a particle:
pub relation donates_proton(s: Species) kind empirical {
label ru unofficial "частица отдаёт протон другой частице";
label en unofficial "the species donates a proton to another compound";
}
pub relation accepts_proton(s: Species) kind empirical {
label ru unofficial "частица принимает протон";
label en unofficial "the species accepts a proton";
}
The word relation declares a relation. It can describe a property
of a single object or a link between several. Here each relation
has one place for an object — a single argument.
In the entry s: Species, the letter s denotes that place, and
after the colon comes the required type: a chemical species. So
donates_proton(s) can be read as “species s donates a proton”,
and accepts_proton(s) as “species s accepts a proton”. We will
supply the concrete object later.
The mark kind empirical characterizes the relation as describing
an empirical property of its subject. In our example, such
information will come with the input data. Where a particular
record came from is stated separately; the lone empirical mark
does not establish that.
So far we have a vocabulary: a particle type and two relations. It lets us talk about their properties, but ascribes those properties neither to water nor to any other particle.
All the blocks above are excerpts from the complete file. At its beginning, the language, the package, and the namespace the declarations belong to are named as well. Those lines say where a record belongs. We will examine the package arrangement in chapter 16; the complete source is available at the link[^chapter-1-model].

An assertion about a particular object
Information for a particular situation is gathered into a case. That is what this book calls the dataset we submit to the model. For the first case, a single entry is enough:
assert donates_proton(entity_ref("urn:case:chem:h2o")) { id "k12-1"; origin case_input; }
assert introduces an assertion. After it comes the familiar
relation donates_proton, and in parentheses the object to which
the property is ascribed. The entry entity_ref("urn:case:chem:h2o")
refers to that object by an identifier — a string in quotation marks.
In our example the identifier chosen for water is
urn:case:chem:h2o. The part h2o helps a human recognize what it
refers to, but by itself it tells the model nothing about chemical
properties. What matters for matching records is the whole string.
If the same identifier appears in the question, it will denote
the same object.
The assertion also has a name: k12-1. It stands after id in
the curly braces and lets us refer to a particular entry. In
chapter 4 such references will help us examine the grounds of
an answer. The mark origin case_input means the assertion
came in with the case input data.
So we have recorded: “In this case it is reported that the particle
with the identifier urn:case:chem:h2o donates a proton.” The
vocabulary defined the form of the entry, and the assertion linked
the property to a particular object.
Asking about what was recorded
Now let us ask a question about the same water: is there support for asserting that it donates a proton? Before reading the query, try answering on your own. In the case, that property is named directly.
Here are the question and the expected result — an excerpt from the check scenario:
evaluate truth(donates_proton(entity_ref("urn:case:chem:h2o")));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
evaluate truth(…) asks whether the assertion in parentheses is
supported. Inside, the relation donates_proton and the water
identifier are repeated. The question matches exactly what was
reported in the case.
The expect lines state the expectations against which the
result will be compared. The sign == means an equality
check. TRUE_ONLY means that there is support for the assertion
and no support for its negation. In this case the supporting ground is
entry k12-1. There is no contrary information, nor any rules
deriving the negation of this property here.
The second expectation concerns executing the query: COMPUTED
means the result was computed. That is a separate matter.
In chapter 3 we will examine the four states of support, and
in chapter 9 the questions that call for a human decision.
An expectation does not serve as a ground for the answer. It is needed to check whether the result matched the one we justified in advance.
Information about one object, a question about another
Keep the earlier information: the case records only the property
of water. Now ask about ammonia, denoted in the example by the
identifier urn:case:chem:nh3. Does the model have grounds to
confirm or refute that property for ammonia?
In another scenario the question and the expectations look like this:
evaluate truth(donates_proton(entity_ref("urn:case:chem:nh3")));
expect truth_status == NEITHER;
expect evaluation_status == COMPUTED;
The relation donates_proton is declared for species, so the
question can be asked. But in this case nothing is reported about
ammonia’s ability to donate a proton, and the package’s rules do
not establish it for us. The answer NEITHER means there
are grounds neither for nor against this assertion.
Such a result proves nothing about the chemical properties of ammonia. It shows which grounds are missing from this example. The declared relation lets us ask the question, while a definite answer needs information or an applicable rule.
How to check the example
The question, the input data, and the expectations can be combined into a scenario. The first scenario, about water, looks like this in full:
test "urn:query:openstax-chem-acids-12-book-water-donation-recorded" {
given {
context {
decision_time @2026-09-06T12:00:00Z;
knowledge_time @2026-09-06T12:00:00Z;
legal_time @2026-09-06;
timezone "UTC";
}
assert donates_proton(entity_ref("urn:case:chem:h2o")) { id "k12-1"; origin case_input; }
}
evaluate truth(donates_proton(entity_ref("urn:case:chem:h2o")));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
After test comes the scenario’s name. The given block holds the
input data. Inside it are the familiar assertion and the context —
the context of the question. It sets three time fields and the time
zone. In all the scenarios of the first part these values are the
same and do not change the answers under discussion. We will examine
their roles in detail in chapter 13; for now, leave them as they are.
After given come the already familiar question and expectations.
The outer curly braces join all of this into one scenario. It lives
in a file with other check cases; the excerpt shown does not replace
the complete file or the model itself.
For checking, install @arxo/cli@0.2.4 as described in the prologue and
use this edition’s reader companion. For a routine check of the package,
run from its reader/ directory:
law test corpus/laws/org/openstax/chemistry-acids
law test reads the package’s declared scenarios and pinned dependencies.
For the chapter exercises we also use the lower-level law engine test:
it lets us pair a copied scenario file with a particular prepared program.
Run the following command from the same directory:
law engine test \
corpus/laws/org/openstax/chemistry-acids/tests/openstax-chemistry-acids.lawtest \
--program corpus/clir/openstax-chemistry-acids.lawir.json --imports \
contexts/openstax-chemistry-acids.json
The path before --program points at the scenario file, and the one
after it at the prepared model the scenarios are checked against.
The command runs every scenario in that file. Among the results
there will be a line:
test PASS: urn:query:openstax-chem-acids-12-book-water-donation-recorded
PASS means the result matched the expectations. To check the
difference between a result and an expectation, make a copy of the
scenario file. Only in scenario 12-book-water-donation-recorded,
replace expect truth_status == TRUE_ONLY; with
expect truth_status == FALSE_ONLY;. Run the command again, giving
the copy’s path instead of the first path. Leave the path after
--program unchanged.
Now the modified scenario will produce:
test FAIL: urn:query:openstax-chem-acids-12-book-water-donation-recorded
truth_status == FALSE_ONLY: в документе TRUE_ONLY
Author’s paraphrase of the engine output above (the engine’s text
is in Russian and is quoted verbatim; what follows is the author’s
English retelling): the check expected FALSE_ONLY, but the
document holds TRUE_ONLY.
We changed the expected value, so the check found a mismatch. The answer itself stayed the same: the case still holds the positive entry about water. The check shows us that our expectation does not match the result.

What such a check confirms
The relation donates_proton declares its argument type: Species.
Type checking lets us catch, for example, the use of a variable of
type Solution (a solution) in place of a particle in a rule. It checks that an
entry agrees with the declared vocabulary.
The test scenario serves a different purpose: it compares the result with the expectations. Neither an admissible argument type nor matching expectations certify that the input information is trustworthy. For that, we need to find out who reported it and on what ground. We will return to that topic in chapter 11.
In our first example the answer rested directly on the case’s assertion. In the coming chapters, conclusions drawn by rules will be added to the input information. Each time we will examine which grounds support the answer and what happens when they change.
Try it yourself
- Read assertion
k12-1in ordinary words. Name separately the object’s type, its identifier, the relation, and the name of the entry itself. - In a fresh copy of the file, find scenario
urn:query:openstax-chem-acids-12-book-water-donation-recordedand change only its question: instead ofdonates_proton, ask aboutaccepts_protonfor the same water. Leave the original assertion and theTRUE_ONLYexpectation unchanged at first. Predict the model’s answer and the check’s outcome. After running, explain the mismatch, then write a justified expectation and check the scenario once more. - Find one more single-argument relation in the complete vocabulary. Read its caption and explain what assertion could be recorded with it. The declaration alone does not mean such an assertion is present in your case.
Check your predictions
In the second exercise there is not enough information for an
answer about accepting a proton: the result is NEITHER, and the
old expectation will not match the result. After changing the
expectation to NEITHER, the check will pass.
Now we have a vocabulary, one assertion, and a way to ask about it. In the next chapter we will add a second piece of information about water — the ability to accept a proton — and read the rule that links the two abilities to a new property.
[^openstax-14-1]: OpenStax. Chemistry 2e, §14.1 “Brønsted–Lowry Acids and Bases”. Source on proton transfer between water and ammonia.
[^chapter-1-model]: Complete model vocabulary.
Contents · PDF · EPUB · Original text under CC BY 4.0 · Source-material terms