Books / Constructions / Chapter 2
Part I · Chapter 2
From Two Premises to a Conclusion
Contents of Constructions
In the first chapter we recorded that water can donate a proton and asked about that same ability. The entry itself was enough for the answer. Now let us add a second piece of information and ask about a property that follows from the two together. To derive it, the model will also need a rule linking the two premises to a conclusion.
The textbook[^chapter-2-source] describes water in two roles: in one reaction it donates a proton, in another it accepts one. Let us record both abilities with the familiar relations:
assert donates_proton(entity_ref("urn:case:chem:h2o")) { id "k14-1"; origin case_input; }
assert accepts_proton(entity_ref("urn:case:chem:h2o")) { id "k14-2"; origin case_input; }
Both assertions concern the same object, urn:case:chem:h2o. The assertion names
differ: k14-1 refers to donating a proton, k14-2 to accepting
one. We speak of two abilities of one particle; we do not assert
that it donates and accepts a proton simultaneously in a single
reaction.
A particle capable of playing both roles is called amphiprotic. The vocabulary holds a separate relation for this property:
pub relation amphiprotic(s: Species) kind institutional {
label ru unofficial "частица амфипротна: способна и отдать, и принять протон";
label en unofficial "the species is amphiprotic";
}
The declaration has the familiar form: the name
amphiprotic, one argument of type Species, captions in two
languages. With this relation we can now ask whether water is
amphiprotic. But neither of our two assertions answers it directly.
To get an answer, we need a link between the known abilities
and the new property.
How to record the link
First, put it in ordinary words: if a particle can donate a proton and can accept one, then it is amphiprotic. The two abilities serve as the conditions of the inference. The statements we reason from are called premises; the statement we reach is the conclusion.
In the same vocabulary file this link is recorded by a rule[^chapter-2-rule]:
@source(OS_14_1_AMPHIPROTIC)
pub rule AmphiproticDonatesAndAccepts strict {
label ru unofficial "способная и отдать, и принять протон частица амфипротна (14.1)";
label en unofficial "a species capable of either donating or accepting protons is amphiprotic (14.1)";
for s: Species;
when donates_proton(s) and accepts_proton(s);
then amphiprotic(s);
}
The word rule declares a rule, and AmphiproticDonatesAndAccepts
sets its name. By that name we will be able to recognize the rule
in the explanation and check whether it was applied. The familiar
label lines help read the entry, but the path from premises
to conclusion is set by the for, when, and then lines.
The historical English label says “either donating or accepting”,
which is loose wording: the and in when requires both abilities.
for s: Species; introduces a variable s of type Species. In
the relation declaration we already saw a place for an argument.
The variable acts as a placeholder linking several assertions: in every place marked s,
the same particle must appear. Substitute water, and the
whole rule concerns water. Substitute ammonia, and it concerns ammonia.
when starts the condition. Between the two premises stands and:
both are needed. If water can donate a proton and
ammonia can accept one, that is not enough. You cannot collect two
abilities from different particles and ascribe both to one of them.

then starts the conclusion. Here it is amphiprotic(s): the very
particle for which both conditions hold is amphiprotic. The rule
lets us derive a new assertion while keeping the link to the
premises.
The mark strict means the rule is strict: when the condition
holds, it yields the conclusion with no exception clause. That is
a property of the rule in the model. By itself it does not certify
that the information we recorded in the case is trustworthy. We
will look at rules with exceptions later, in chapter 8.
Above the rule stands @source(OS_14_1_AMPHIPROTIC). It is a
reference to the textbook’s fixed fragment, which the package names
this way. The fragment first describes water’s two roles, then
introduces the term “amphiprotic”. The formal entry expresses that
link through two conditions. We will return to how source references
are arranged in chapter 12; for now what matters is that the ground
for recording the rule can be found and read.
The new relation has one more feature to explain: kind institutional
instead of the familiar kind empirical. In this vocabulary the
first two abilities describe empirical properties, while
amphiproticity is presented as a property established by an
accepted definition. Here the institutional mark does not mean
belonging to an institution.
But a relation-kind mark alone concludes nothing. In our scenario
the abilities are reported by assertions with origin case_input,
and amphiproticity is obtained by an explicitly recorded rule. To
understand where a particular piece of information came from, look
at those entries and the links between them, not only at kind.
Checking the conclusion
Take scenario 14 from the same check set[^chapter-2-tests] we worked with in the first chapter. Here it is shown in full; the file’s other scenarios and header are not included in the excerpt.
test "urn:query:openstax-chem-acids-14-book-water-both-roles-amphiprotic" {
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 "k14-1"; origin case_input; }
assert accepts_proton(entity_ref("urn:case:chem:h2o")) { id "k14-2"; origin case_input; }
}
evaluate truth(amphiprotic(entity_ref("urn:case:chem:h2o")));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
expect applied(AmphiproticDonatesAndAccepts);
}
The scenario’s structure is as before. given sets the context and
the input assertions, evaluate records the question, expect the
expected results. The time fields are left as in the first chapter;
at this stage we change only the information and the question.
Let us trace the path to the answer. The case holds both premises
for water. The rule links them to amphiproticity. In this scenario
there is a ground for such an assertion and no ground against it,
so we expect TRUE_ONLY. As before, COMPUTED means the answer
was computed.
The last line adds a new check:
expect applied(AmphiproticDonatesAndAccepts);.
It checks that an application of the named rule appears in the result’s supporting
graph: the linked record of assertions and inferences behind the answer. That is a useful complement to checking the answer itself:
now we also expect a particular line of reasoning. At the same
time, applied does not assert that the rule was the only possible
ground. The explanation will show which entries took part in its application.
From the reader companion directory you can repeat the first chapter’s command:
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
It will check the whole file. Among the results there will be a line:
test PASS: urn:query:openstax-chem-acids-14-book-water-both-roles-amphiprotic
This command uses the model shipped with the reader companion.
The path after --program points to the prepared model used to compute the answers.
Where the answer came from
For a separate analysis, make a copy of the check file and save it
in the reader companion directory under the name water.lawtest. Keep in it
the three opening language, package, namespace lines and only
the test block of scenario 14 shown above. The explanation command
needs a single scenario so it is clear which answer to unpack.
The companion’s question preparer supplies the pinned import context and
asks the public compiler to prepare the case and question. It makes no
decision about the answer; explain then computes and displays its grounds.
Run from the same root:
chapter2_explain=$(mktemp -d)
python3 reader_tools/prepare_question.py water.lawtest \
--program corpus/clir/openstax-chemistry-acids.lawir.json --imports \
contexts/openstax-chemistry-acids.json --out "$chapter2_explain"
law engine explain "$chapter2_explain"
The explain command shows what the answer rests on. Its output is
below; the long rule-application identifier is shortened with an
ellipsis.
the species is amphiprotic(h2o): TRUE_ONLY
rule_application the species is amphiprotic(h2o)
(urn:proof:apply:AmphiproticDonatesAndAccepts:f103e243…)
assertion the species donates a proton to another compound(h2o)
(urn:proof:assert:urn:openstax:clir:chemistry-acids#k14-1)
assertion the species accepts a proton(h2o)
(urn:proof:assert:urn:openstax:clir:chemistry-acids#k14-2)
This output uses the vocabulary’s English captions. The first line
reports the answer about water’s amphiproticity. Below it sits
a rule_application, the application of the rule named
AmphiproticDonatesAndAccepts. Further below, indented further, are
two assertions: the input assertions k14-1 and k14-2. Their
names let us return to the particular entries in the case.
In the first chapter the answer rested on a single assertion. Now one more step has appeared between the input information and the answer. We can show not only the resulting property, but the rule that produced it, together with both premises.
When one piece of information is missing
Remove the entry about accepting a proton. In the check set, this case corresponds to scenario 15:
test "urn:query:openstax-chem-acids-15-book-water-one-role-no-conclusion" {
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 "k15-1"; origin case_input; }
}
evaluate truth(amphiprotic(entity_ref("urn:case:chem:h2o")));
expect truth_status == NEITHER;
expect evaluation_status == COMPUTED;
}
Something is still known about water: it can donate a proton. But
the question is about amphiproticity, and that conclusion needs
both abilities. One premise is present, the other is not, so the
rule under discussion does not apply. In this scenario there is no
other ground for an answer for or against amphiproticity either.
The result is NEITHER.
Compare with the first chapter. There we asked about ammonia, about
which the case held no assertions at all. Now there is an entry
about water, but it is not enough to answer the new question. Both
cases produced NEITHER, though the input information differed.
The missing premise did not turn into a negative conclusion. To assert that water is not amphiprotic would take a ground against that property. Mere silence about accepting a proton is not enough for such a conclusion.
The direction of the rule
The entry when …; then …; sets a direction: from the conditions
to the conclusion. The rule under discussion lets us conclude
amphiproticity from the two abilities. It does not license the reverse
move.
If only amphiprotic for water is recorded in the case, this rule
will not derive the abilities to donate and accept
protons by reasoning backwards. Although the definition connects all three properties, the
formal entry expresses one particular transition. When reading
a rule, distinguish what we understand from the definition from the
conclusion recorded in the model.
That is why in our scenario it matters to keep exactly the two input abilities. If the property we seek is reported in advance, the answer can rest on that entry, and we will no longer test whether the two premises suffice to derive it by rule.
Try it yourself
For each exercise, take a fresh copy of water.lawtest with
scenario 14. Run it with the test command, substituting the
copy’s name for the full set’s path; the model after --program
stays the same. First predict the result, then compare it with the
one obtained.
- Swap the two assertions inside
given. Will the answer and the rule’s application change? Check this without changing the expectations. - Delete assertion
k14-1, keeping only the ability to accept a proton. Keep the question and the expectations at first. Which two checks should find a mismatch? After running, explain why and correct the expectations for the new case. - Keep both lines, but in assertion
k14-2replaceurn:case:chem:h2owithurn:case:chem:nh3. Still ask about water’s amphiproticity. Are the two entries now enough for the conclusion? First check the old expectations, then write new ones and justify them through the variables.
Check your predictions
In the first exercise both premises survive, and the check passes.
In the second and third the answer is NEITHER: either one ability
is missing, or the abilities belong to different objects. The old
TRUE_ONLY and applied(AmphiproticDonatesAndAccepts) expectations
fail. For the revised cases, replace the expected status with
NEITHER and drop the expectation that this rule is applied; keep
COMPUTED. Checks with such expectations will pass. We will learn
how to express the absence of an application with a separate check
later.
Now we can follow a short inference: find the two premises, make sure they concern one particle, and trace the transition to the conclusion. The next step is to work out what changes when an ability is not merely unmentioned but explicitly recorded as negated.
[^chapter-2-source]: OpenStax. Chemistry 2e, §14.1 “Brønsted–Lowry Acids and Bases”.
Textbook: water’s two roles and amphiproticity.
The fixed fragment OS_14_1_AMPHIPROTIC is in the sources file.
[^chapter-2-rule]: Complete vocabulary and the AmphiproticDonatesAndAccepts rule.
[^chapter-2-tests]: Complete check set, scenarios 14 and 15.
Contents · PDF · EPUB · Original text under CC BY 4.0 · Source-material terms