Books / Constructions / Chapter 1

Part I · Chapter 1

What This Record Is About

10 min read

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].

Timur tries to pour water from a jug drawn in a book into an empty glass. Dana holds a real jug of water.

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.

An unperturbed blue circle on thin legs poses for a draughtsman. He erases a square on the easel and corrects the drawing to a circle.

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

  1. Read assertion k12-1 in ordinary words. Name separately the object’s type, its identifier, the relation, and the name of the entry itself.
  2. In a fresh copy of the file, find scenario urn:query:openstax-chem-acids-12-book-water-donation-recorded and change only its question: instead of donates_proton, ask about accepts_proton for the same water. Leave the original assertion and the TRUE_ONLY expectation 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.
  3. 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

Constructions

Contents

You’re reading · Part I

Reading the First Model

Reading settings

Text size
Appearance

Preferences and your reading place are saved only in this browser.