# 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](/corpus/#how-this-topic-marks-confidence). ## 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](/corpus/quality/checks/#sixteen-shape-checks-on-every-audit) and the [audit surface](/corpus/vocabulary/audit/). 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**). ## Keys 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. ```law relation parcel_fee(parcel: Parcel, amount: Text) { key(parcel); } ``` ## 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](/corpus/vocabulary/languages/) for the status vocabulary. ## Where to go next - The companion page on [modeling vocabulary](/corpus/vocabulary/modeling/) introduces relations. - The companion page on [languages](/corpus/vocabulary/languages/) covers labels and verbalization. - The companion page on the [audit surface](/corpus/vocabulary/audit/) lists the lints that enforce these contracts. - For construct-level detail, see [the Vocabulary construct reference](/constructs/vocabulary/).