Vocabulary contracts: kinds, keys, and templates
A vocabulary declaration is a promise to its consumers. This page covers the three ways authors sharpen that promise: relation kinds, keys, and predicate templates. All three are checked by tooling (S).
No commands are needed to follow this page. Each claim carries a status in words with a letter mark; the full legend is on the topic index.
Relation kinds
Section titled “Relation kinds”Every relation may declare a kind — optional metadata saying where its rows come from (S). The vocabulary is closed: six values exist, and anything else is refused at compile time.
Intent — what each value promises:
empirical— rows observed in the world, submitted by the case.institutional— rows constituted by records: holdings, recorded kinds, registrations. The lab fixtures mark the holding link and the recorded parcel kind this way.evaluative— rows whose content is a judgment call: standards such as reasonable, good faith, or substantial.derived— rows produced by rules.normative_auxiliary— helper rows computed on the way to a normative conclusion.external— rows owned by an outside system rather than by the case or the rules.
Mechanical checks — what tooling enforces, by name. The compiler rejects unknown kinds outright. The structural catalog adds two questions and three lints over the content channels.
The producers question lists the rules that feed a predicate. The
readers question lists the rules, norms, and constraints that consume
it.
| Problem | Lint that catches it |
|---|---|
| Evaluative content is submitted as a case fact, with no producer rule and no judgment channel | evaluative-fact-without-producer |
| An evaluative standard is computed only from non-evaluative premises | evaluative-head-from-nonevaluative-body |
| A rule head is filled by an aggregate, but the relation declares no key | aggregate-head-without-key |
Which configuration runs the lints: running them requires a source
checkout (I). In the full checkout build, the audit command runs all
sixteen catalog lints over a fresh snapshot as its form section. The
public release also has law audit, but it ships no lint catalog, so
its audit reports that section as not_run. See Sixteen shape
checks on every
audit and
the audit surface.
Usage contract — what authors sign. Submit case facts only through empirical or institutional relations; give every derived relation a rule producer — a derived relation with no producer is a modeling gap; route evaluative content through a producer or the judgment channel, never as a bare case assertion; and when the kind is omitted, promise nothing — readers must inspect the producers and readers themselves before trusting the rows.
The judgment channel itself is a separate construct, not a kind:
external judgment relation declares a decision input with a named
authority, and it is that declaration — not any kind value — that
carries decisions made by a named body (S).
A key(...) annotation names the parameters that functionally determine
a relation’s remaining parameters (S). Keys matter most for
aggregation: when a rule head is filled by an aggregate, the relation
must declare the key the aggregate groups by, otherwise the submitted
and recomputed values can both hold at once. A dedicated lint,
aggregate-head-without-key, catches exactly that shape (S).
When two different values arrive for the same key, evaluation does not
pick one silently: both stay true and the result reports KEY_CONFLICT
(S). Treat a key conflict as a modeling signal — either the key is
too narrow or the two producers disagree and a priority is missing.
relation parcel_fee(parcel: Parcel, amount: Text) { key(parcel);}Predicate templates
Section titled “Predicate templates”Relations with labels can carry a template "…{param}…" that shows how
to verbalize the predicate with its parameters filled in (S). The
template is total: every parameter must appear at least once, and the
compiler reports a template that names an unknown parameter or omits a
known one. Answer rendering uses templates to turn derived rows back
into readable sentences.
Templates live on relation labels only, and they follow the same multilingual status rules as labels themselves — see the companion page on languages for the status vocabulary.
Where to go next
Section titled “Where to go next”- The companion page on modeling vocabulary introduces relations.
- The companion page on languages covers labels and verbalization.
- The companion page on the audit surface lists the lints that enforce these contracts.
- For construct-level detail, see the Vocabulary construct reference.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.