docs← Back to article

Markdown for LLMs

Vocabulary

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# 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 ;
```