Skip to content
docs
Arxo ↗

Vocabulary first

For LLMs11 sections

The vocabulary is everything a package declares before the first rule: object types, relation signatures, closed lists, named values, and visibility. Without a declared name there is nothing to write a rule about: any literal outside the vocabulary is a rejection at check time. This stage sits between inventory and construct choice. Inventory says which content units to formalize, vocabulary says what the model talks about, and only then do rules say what follows.

  • Name one object type per durable thing the act reasons about, not per mention in the text. The running example needs three: employer, employee, and insurance contract.
  • Separate four things the act text blurs: the object, its stable id, its human name, and the record about it. Two people may share a name, and one person may own several records. Identity is the reference, never the text.
  • Give each claim its record: one relation tuple per claim, with the parameter order fixed once in the signature.
  • Put roles where they belong: a capacity inside a relationship is a relation parameter, while a standing party kind may deserve its own object type.
  • Close what is closed: statuses and classes with a fixed membership become enumerations; open sets stay relations with a parameter.
  • Date the events: occurrences that happen at a time take a date argument. The four modeled articles of the running example carry no time parameters, so no date column appears there.
  • Mark the kind of every relation: observed case facts are empirical, statuses the law establishes are institutional, rule-head conclusions are derived. Kind is metadata and never changes truth, but a wrong kind misleads every later reader.
  • State reuse up front: export shared names, require explicit local imports, and declare dependencies. The running example declares explicit local imports and no dependencies.
  • Object type versus relation: anything that changes over time, is contested, or arrives as a case fact is a relation, never a built-in field.
  • Closed list versus open relation: fixed membership goes in an enumeration, whose members refuse comparison with another enumeration; open sets stay relations.
  • Key or silent duplicates: a key turns two tuples under one projection into an explicit conflict the reader must resolve, instead of a silent pick.
  • Named individual versus bare name: an individual gets its name only through a declared constant; a bare name that resolves to nothing is a rejection.
  • Empirical versus institutional for each relation, decided by meaning: observed versus established by law.

The artifact is a vocabulary review: every declared object type and relation with its shape and a verdict. The table below is the review for the running example at the source snapshot; a fresh package writes the same table for its own names before drafting rules. (The accepted candidate adds the insured-sum and minimum-wage inputs plus the premium-base and R1 relations — see the worked example below.)

NameShapeVerdict
Employer, Employeeobject typeskeep: the parties of every modeled article
InsuranceContractobject typekeep with a note: declared, but no relation or rule in the four modeled articles touches it
employer_has_employeeempirical link, employer and employeekeep: the duty condition reads it
professional_risk_classempirical, employer and integer class, key on employerkeep: one class per employer, enforced by the key
annual_payrollempirical, employer and money amount, key on employerkeep: one payroll figure per employer
employment_accident_contract_concludedempirical flag on employerkeep with a note: declared, but no rule in the four modeled articles reads it
capacity_loss_percentempirical, worker and integer percent, key on workerkeep: the payout condition reads it
insurance_payment_overdueempirical, worker with unpaid amount and day countkeep: the penalty rule reads it
employer_must_insure_employeesinstitutional duty on employerkeep: derived by the Article Eight rule
insurance_tariffinstitutional rate on employerkeep: derived by the tariff rules
insurance_premium_dueinstitutional amount on employerkeep: derived by the premium rule
insurance_payout_dueinstitutional flag on workerkeep: derived by the payout rule
insurance_payout_barredinstitutional flag on workerkeep with a note: declared, but no rule produces it; the act states who is paid, and silence stays silence
late_payment_penalty_dueinstitutional amount on workerkeep: derived by the penalty rule

[Source snapshot]: the employer accident insurance package, version 0.1.0, language 0.2, with zero dependencies and explicit local imports. Source EAI_EDITION, materialization PINNED_UNOFFICIAL_COPY (Adilet API copy retrieved 2026-09-13, sha256 pinned, local copy in pkg). Three object types carry the parties; six empirical relations carry the case facts with keys on the employer and the worker where duplicates would be ambiguous; six institutional relations carry what the law establishes. Article Eight derives the employer duty from the employment link. Article Seventeen derives the tariff from the risk class and the premium from payroll times rate. Article Nineteen derives payout from the loss percent. Article Nine derives the penalty from the overdue amount and the day count. Three declarations stay unread or unproduced by any rule; each is noted in the review rather than silently kept.

[Accepted candidate]: eight empirical relations (adding the insured sum and the minimum wage as case inputs) and eight institutional relations (adding the premium base amount and the R1 reimbursement conclusion). The premium base reads the insured sum, not payroll — and annual_payroll becomes the fourth rule-unread declaration: cases still assert it, but no premium rule touches it since finding EAI-R3.

Two classic failures open this stage. Merging distinct objects that share a name lets one person’s record speak for another; matching names never carry a conclusion across. A wrong-typed literal written into the package — a number where a rule head needs text — fails the static check with LDC-E2104, before any question is asked. A wrong-typed fact fed with a case fails one layer later, at case input validation, not at package check. The subtler failure is trusting types too far: a typo is still text, and a wrong but well-typed link still reasons. Types check form, never truth — and each layer catches only its own mistakes, as the calculations page states for the runtime layer.

The stage is done when the package check passes with no warnings and every case literal resolves against the vocabulary. Observed run with tool version law 0.1.0, semantics law.core/0.2:

Output
law engine check corpus/laws/kz/laws/employee-accident-insurance
check OK: corpus/laws/kz/laws/employee-accident-insurance

Criterion: the check line reads OK, and re-running it after any vocabulary edit keeps it so. An undeclared name must fail here, never at question time; a mistyped case value fails at input validation, and a mistyped runtime operation fails when the question runs — the three layers are named on the calculations page. The suite for the running example passes seven of seven; its full output is shown in the next stage.

Vocabulary fixes form, not truth or completeness. Unused declarations warn nobody by themselves, which is why the review notes them explicitly. A missing relation is found only when a rule or a question needs it, so the review is re-read at every later stage.

Continue with Choosing a construct, which picks the rule shape for each vocabulary item.

Documentation for Arxo. Writings — blog.arxo.io.

Anonymous visit counts on stats.arxo.io, no cookies.