Markdown for LLMs
Vocabulary
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# Vocabulary
**In one sentence:** the vocabulary is everything a package declares before
the first rule: individual types (`entity`), assertion signatures
(`relation`), closed lists (`enum`), named values (`const`), and visibility
(`pub`). The author always takes the vocabulary first: without a declared
name any literal is a `check` rejection, and there is nothing to write a
rule about.
The language specification treats the vocabulary as the package header:
entities, relations, enumerations, constants, and visibility are declared
before the first rule, and every literal is checked against them. The
judgment channel (relations answered by an organ, not by facts) lives on the
[judgment-channel page](/constructs/judgment-channel/).
## 1. When to use and when not to
| Instead | Selection rule |
|---|---|
| `relation` vs an entity field | An `entity { field: Type; }` body holds only internal immutable fields. Everything that changes over time, is contested, or is established by a case is a relation. Criterion: the value arrives as a fact — therefore `relation` |
| `kind empirical` vs `kind institutional` | An observable case fact (measurement, event) is `empirical`; a status or qualification established by law is `institutional`; rule-head-inferred is `derived`. `kind` is metadata, it does not change truth, but its lies are expensive: another’s `kind` confuses the analysis reader |
| `enum` vs an open relation | A closed list (classes, ranks) is an `enum`: members are incomparable with another enumeration (`TYPE_ERROR` at runtime, `LDC-E2122` at `check`), there is no order. An open set is a relation with a parameter |
| `const Name = entity_ref(…)` vs a bare name | An individual gets a name only through `const`: a bare name in term position must resolve to a declaration, otherwise `LDC-E1330`. `registered_in(c, Astana)` without `const Astana` is a rejection, not “a new individual” |
| `key(c)` vs a second rule | A key is an integrity restriction: two tuples with one key projection give issue `KEY_CONFLICT`, the evaluator picks nothing and deletes nothing. The “latest/correct” of the two is not by key but by rule priority or a decision table |
## 2. Minimal example
Package `research.vocabulary.company_registry`: entities, a named individual via
`const`, a rate ceiling via `const Decimal`, an enumeration of classes,
relations with keys, and three strict reader rules:
```law
entity Company { label ru-KZ official "Компания"; }
entity Region { label ru-KZ official "Регион"; }
const CAPITAL: Region = entity_ref("urn:case:research:vocabulary:capital") {
label ru-KZ official "столичный регион";
};
pub const MAX_RATE: Decimal = 25 percent;
enum LicenceClass { first; second; third; }
relation registered_in(c: Company, r: Region) kind institutional { key(c); }
relation licence_class(c: Company, k: LicenceClass) kind institutional { key(c); }
relation rate_applied(c: Company, r: Decimal) kind empirical { key(c); }
rule CapitalCompany strict {
for c: Company;
when registered_in(c, CAPITAL);
then capital_company(c);
}
rule FirstClass strict {
for c: Company;
for k: LicenceClass;
when licence_class(c, k) and k == first;
then first_class(c);
}
```
Case facts: `registered_in(alpha, capital)` with `origin case_input`.
Query: `evaluate truth(capital_company(alpha))`. The `CAPITAL` constant is
dereferenced before evaluation, so the fact about
`entity_ref("urn:case:research:vocabulary:capital")` and the rule about
`CAPITAL` concern one individual.
Actual engine answer:
```text
law test research.vocabulary.company_registry: мир research.vocabulary.company_registry
ok [research.vocabulary.company_registry#authored] tests/01-capital-company.lawtest / urn:query:research-vocabulary-01
ok [research.vocabulary.company_registry#authored] tests/02-first-class.lawtest / urn:query:research-vocabulary-02
итого: 2 проверено, 2 прошли, 0 не прошли, 0 не исполнены; код 0
```
`law engine check` — `check OK`, no warnings. Sensitivity:
`licence_class(alpha, second)` gives `first_class(alpha)` = Not established, not refuted
(the second test): a different enumeration member — the rule
stays silent. An enumeration member is written bare (`second`) — it is the
same node as `LicenceClass.second`.
Second package `research.vocabulary.subtype_key`: a subtype `entity Branch : Company`
and a key. A branch fits the `Company` slot: the `BranchRegion` rule
reads `registered_in(b, r)` through the supertype. Two regions of one branch
give Established plus issue `KEY_CONFLICT`
(`expect issue(KEY_CONFLICT)`); one region — Established without issues,
`law test` — 2/2. Sensitivity: removing
the second fact removes both the conflict and the second support.
## 3. Example by domain
- **Standards:** package `scrum.guide` (Scrum Guide) — `pub enum
DeveloperAccountability` with a label and members (see the
[corpus forms](/constructs/vocabulary/corpus-forms/)): `pub enum` exports the type and every member.
- **Law (sanctions):** package `us.ofac.fifty_percent` (OFAC 50% rule, US sanctions) — subtypes
`entity BlockedPerson : Party` and `entity Entity : Party`:
party roles as subtypes, not flags.
- **Historical law:** package `eng.corpus.statutes_of_apparel_1574` (Statutes of Apparel 1574, England) —
a series of `const …: Rank = entity_ref(…)` with labels: nine
of the corpus’s ten constants are named individuals, not numbers.
- **Finance:** package `us.fnma.selling_income` (FNMA income rules, US) — relations
with `key(src)` and a comment on the honest `KEY_CONFLICT` instead of a
silent pick: a model of documenting a key.
## 4. How the engine answers
Table — actual runs of this section’s teaching packages:
| Facts | Question | Answer | Why |
|---|---|---|---|
| `registered_in(alpha, capital)` | `capital_company(alpha)` | Established | `CAPITAL` dereferenced to the same `entity_ref` |
| `licence_class(alpha, second)` | `first_class(alpha)` | Not established, not refuted | different enumeration member |
| two regions of one branch | `branch_region` | Established + `KEY_CONFLICT` | key violated, facts not deleted |
| one branch region | `branch_region` | Established, issues empty | counterfactual: the key alone declares the conflict |
| `branch_office`, branch `registered_in` | `branch_region` | Established | branch is a company subtype |
- Entity identity is the “nominal type, StableId” pair: one row in
`Company` and in `Region` are different values; no implicit conversions.
- An enumeration member is a value, and it is its identity: the guard `k == first` compares StableIds; dotted, bare, and
qualified spellings are one constant reference.
- A constant through a constant unfolds recursively, in one pre-pass over
the program and the case.
- On the rate value: `20 percent` against the `25 percent` ceiling — in the
case language; the threshold is written as the guard `r <=
MAX_RATE`, there are no const-percents in the corpus. On this section’s
teaching packages a numeric vocabulary guard is not fixed by a run (in
`company-registry` the `WithinCap` rule exists, but there is no test with
`rate_applied`) — the claim of its firing is marked here as “not checked”.
Additionally, further checked behaviours of the earlier edition (not fixed
by a run in these teaching packages):
| Facts | Question | Answer | Why |
|---|---|---|---|
| `registered_in(alpha, north)` | `capital_company(alpha)` | Not established, not refuted | a different individual; the rule stays silent, it does not refuse |
| `rate_applied(alpha, 20 percent)` | `within_cap(alpha)` | Established | rate within `MAX_RATE` |
| `rate_applied(beta, 30 percent)` | `within_cap(beta)` | Not established, not refuted | above the ceiling — the rule stays silent |
| `licence_class(alpha, first)` | `first_class(alpha)` | Established | an enumeration member as a value |
| `licence_class(alpha, first)` | `reliable(alpha)` | Not established, not refuted + `REQUIRES_JUDGMENT` | the judge did not answer: `good_standing` is a judgment channel (the channel itself lives on the [judgment-channel page](/constructs/judgment-channel/)) |
| `risk_level(alpha, high)` | `audit_flag(alpha)` | Established | the dotted spelling `RiskLevel.high` is the same member |
| `registered_in(alpha, capital)` and `(alpha, north)` | `capital_company(alpha)` | Established + `KEY_CONFLICT` | an observation expecting `KEY_CONFLICT` |
## 5. Common mistakes
1. An individual name without declaration — `LDC-E1330` (pitfalls, item 1).
2. A field in a constant’s label block — `LDC-E0201` (pitfalls, item 2).
3. A hard-keyword name (`LDC-E0203`) and arity off-declaration
(`LDC-E2103`) (pitfalls, item 3).
4. A constant type not matching the initializer — `LDC-E2111`;
prose-style percentage and money types are not resolved by the compiler
(pitfalls, item 4).
5. A subtype the wrong way round — `LDC-E2104` (pitfalls, item 5).
6. Members of different enumerations in one guard — `LDC-E2122`
(pitfalls, item 6).
7. A constant through itself — silent `check`, `CYCLIC_CONSTANT` at runtime
(pitfalls, item 7).
## 6. References
- Neighbour pages: [strict rules](/constructs/rule-strict/),
[facts and evidence](/constructs/facts-and-evidence/).
- The first-vocabulary tutorial lives in the [tutorials catalogue](/tutorials/first-package/).
- The judgment channel (`external judgment relation`, `REQUIRES_JUDGMENT`)
lives on the [judgment-channel page](/constructs/judgment-channel/); the syntax is in
section 7 below.
- The pitfalls page lists the diagnostics (`LDC-E1330`, `LDC-E0201`,
`LDC-E0203`, `LDC-E2103`, `LDC-E2111`, `LDC-E2104`, `LDC-E2122`) with wrong
forms and fixes.
## 7. Grammar excerpts
Declaration visibility (who sees the symbol):
```ebnf
top_declaration = { annotation }, [ visibility ], declaration ;
visibility = "pub" | "internal" ;
```
Entity and subtype (the `entity_decl` production):
```ebnf
entity_decl = "entity", identifier,
[ ":", type_ref ],
[ "{", { field_decl | label_item | metadata_item }, "}" ],
[ ";" ] ;
```
Enumeration (the `enum_decl`, `enum_variant` productions; separators —
the `= "string"` form out of slice 0.1 — `LDC-E0206`):
```ebnf
enum_decl = "enum", identifier, "{",
{ label_item },
enum_variant, { enum_variant | label_item },
"}" ;
(* Errata E-0082: разделитель вариантов необязателен и допускает запятую.
Перепись корпуса: 193 варианта записаны через `;`, 98 через `,`; обе
реализации принимают и смешанную запись, и вовсе бессоюзную. Форма
`= string_literal` остаётся ЗАРЕЗЕРВИРОВАННОЙ (вне среза 0.1, LDC-E0206). *)
enum_variant = identifier, [ "=", string_literal ], [ ";" | "," ] ;
```
Constant (the `const_decl` production; after the expression the body
admits only a label):
```ebnf
const_decl = "const", identifier, ":", type_ref,
"=", expression,
( ";" | "{", { label_item }, "}", [ ";" ] ) ;
```
Relation and key (the `relation_decl`, `relation_item`, `relation_kind`
productions):
```ebnf
relation_decl = "relation", identifier,
"(", parameter_list, ")",
[ "kind", relation_kind ],
( ";" | "{", { relation_item }, "}" ) ;
relation_item = "key", "(", identifier,
{ ",", identifier }, ")", ";"
| label_item
| metadata_item ;
relation_kind = "empirical"
| "institutional"
| "evaluative"
| "derived"
| "normative_auxiliary"
| "external" ;
```
Symbol parameters (the `parameter_list`, `parameter` productions):
```ebnf
parameter_list = [ parameter, { ",", parameter }, [ "," ] ] ;
parameter = identifier, ":", type_ref,
[ "{", { label_item }, "}" ] ;
```
Judgment channel: block content (the `external_judgment_item` production;
semantics and behaviour live on the [judgment-channel page](/constructs/judgment-channel/)):
```ebnf
external_judgment_item = "authority", identifier, ";"
| "request_schema", type_ref, ";"
| label_item ;
```