Several packages and a world
The archive does not set the copy page rate — the city council adopts it
by its decision. So the archive holds two acts: its own rules and someone
else’s decision, and the archive norm must read the magnitude from the
neighbouring package rather than rewrite it at home. A visible part of
the corpus is arranged so: 57 corpus packages declare
[dependencies], and the budget act with the MRP is the most frequent
dependency (measured 05.09.2026). This page is the first with two
programs instead of one, and the first checked not on the page
itself but on a package in a tree: the practicum tree holds
tutorial.city and tutorial.archive with manifests, a pinned
law.lock, and scenarios, while the page must match it in forms and
execute on its dependencies.
language "law.core" version "0.2";package tutorial.archive version "0.15.0";namespace "urn:law:tutorial:archive";
import tutorial.city version "0.1.0";
entity Person;entity CopyOrder;
relation billing_year(p: Person, year: Integer) kind empirical { key(p); }relation copy_order(o: CopyOrder, p: Person, pages: Integer) kind empirical { key(o); }relation copy_fee(o: CopyOrder, amount: Money) kind institutional { key(o); }Someone else’s act
Section titled “Someone else’s act”The council decision is a separate tutorial.city package with its own
name, namespace, and manifest. Everything the archive may read from it
is marked pub: an unmarked relation does not exist from outside,
and a reference to it is a refusal, not silence.
language "law.core" version "0.2";package tutorial.city version "0.1.0";namespace "urn:law:tutorial:city";
pub relation base_page_rate(year: Integer, amount: Money) kind institutional;pub relation late_fee_unit(year: Integer, amount: Money) kind institutional;
assert base_page_rate(2026, 150 KZT) { id "city-page-rate-2026"; origin source_asserted;}The rate fact lives in the council package itself with the
source_asserted provenance: it is the act’s norm, not case input.
Years are the magnitude’s axis: the consumer names the year explicitly,
and no rate exists for a year the council did not set.
A reference across the boundary
Section titled “A reference across the boundary”The archive norm reads the foreign relation via a qualified
package::symbol reference. The import is declared in the statute text
with an exact version, and the law.toml manifest must match it.
rule CopyFee strict { label ru-KZ unofficial "Плата за копирование: число страниц по ставке города на год выставления счёта"; for o: CopyOrder; for p: Person; for n: Integer; for y: Integer; for rate: Money; when copy_order(o, p, n) and billing_year(p, y) and tutorial.city::base_page_rate(y, rate); then copy_fee(o, n * rate);}The label reads: “Copy fee: page count at the city rate for the billing year”.
| Facts | copy_fee(order1, 1050 KZT) |
|---|---|
| order for 7 pages, billed for 2026 | TRUE_ONLY |
| order for 7 pages, billed for 2025 | NEITHER |
The test from this page, byte for byte; it executes on a merged
world — the page’s CLIR together with the pinned bytes of
tutorial.city:
test "семь страниц по ставке города — 1050" { given { context { decision_time @2026-04-20T09:00:00+05:00; knowledge_time @2026-04-20T09:00:00+05:00; legal_time @2026-04-20; timezone "Asia/Almaty"; } assert billing_year(entity_ref("urn:tutorial:ivanova"), 2026) { id "assert-year"; origin case_input; } assert copy_order(entity_ref("urn:tutorial:order1"), entity_ref("urn:tutorial:ivanova"), 7) { id "assert-order"; origin case_input; } } evaluate truth(copy_fee(entity_ref("urn:tutorial:order1"), 1050 KZT)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED;}The test name reads: “Seven pages at the city rate — 1050.”
Note the test does not feed the rate as a fact: it arrives from the council package together with the world. The table’s second row is a year with no decision: the norm stays silent, and no “default rate” appears at the archive.
Manifest, lock, and dependency bytes
Section titled “Manifest, lock, and dependency bytes”Three files hold the link between packages, each with its role.
[package]name = "tutorial.archive"version = "0.15.0"language = "0.2"namespace = "urn:law:tutorial:archive"
[dependencies]"tutorial.city" = "0.1.0""calc.tiers" = "0.1.0"law.toml is the author’s intent: which packages and versions are needed.
law.lock is this intent resolved into exact versions with the
byte hash of each dependency: the council package’s
contentHash is recorded in the lock, and if the council decision’s
bytes change, the lock goes stale. deps/ holds the
pinned bytes themselves, the dependency’s CLIR; only the generator writes
them, they are not edited by hand.
The compiler needs these three files as a context: lowering
a package with an imports context, where the resolver assembles the
context from the lock and deps. Without a context the compiler refuses —
a foreign head used to lower into an empty predicate
silently, and the rule never fired. Today the lowered CLIR’s
envelope.imports carries the dependencies’ hashes and enters the
program’s semantic hash: the same archive against other council
bytes is another program.
World and program
Section titled “World and program”A case may not carry law: the test receives the program as
a second argument, alongside the test file.
A world is the consumer’s CLIR merged with the dependencies’ CLIR at the
pinned hashes (link_deps): bytes diverging from the lock drop the world
build with LDC-E1104 rather than substituting another rate. A chain
longer than one step — an act importing a package that itself imports
a third — assembles transitively, and each dependency’s pin is verified
against the world participant that declared it (link_deps_transitive).
A merged world is not stored as a dependency: the lock pin counts over a package’s bytes, and a merged world’s bytes differ. Each package gets its own CLIR; a world is assembled per run.
What else lies in the practicum package
Section titled “What else lies in the practicum package”The manifest’s second import, calc.tiers, is a shared tier computer;
about it on the next page. The package’s full
composition:
packs/examples/tutorial/archive/├── law.toml манифест: зависимости, features, [[tests]]├── law.lock разрешение и хэши зависимостей — только генератором├── deps/ закреплённые CLIR зависимостей — только генератором├── package.law импорты, словарь, общие отношения├── 10-tariffs.law плата за копирование и таблица скидок├── 20-late-fee.law плата за просрочку шкалой calc.tiers├── late-fee-cap.lawparam.json потолок платы по датам (A3)├── sources.law провенанс: источник, редакция, фрагменты└── tests/*.lawtest сценарии, объявленные в [[tests]]The tree comments read: “manifest: dependencies, features, [[tests]]”; “resolution and dependency hashes — generator only”; “pinned dependency CLIRs — generator only”; “imports, vocabulary, shared relations”; “copy fee and discount table”; “overdue fee via the calc.tiers scale”; “fee cap by dates (A3)”; “provenance: source, edition, fragments”; “scenarios declared in [[tests]]”.
The practicum package is checked like calc.*
consumers: statics, lock and deps freshness, lowering with a context and
no empty predicates, a merged world, every scenario via both runners, and
byte-identical results. This page is compiled
under the same lock’s context and its test executes on the same world —
the page can diverge from neither the language nor the package.
Compiler refusals
Section titled “Compiler refusals”A symbol the neighbour does not export. Replace base_page_rate in
CopyFee’s body with page_rate:
error LDC-E1105: tutorial.city::page_rate: символ не экспортирован пакетом(§24: межпакетные ссылки — только на `pub`-декларации; экспортировано:base_page_rate, late_fee_unit)The diagnostic reads: ‘symbol not exported by the package (cross-package references only to pub declarations; exported: base_page_rate, late_fee_unit)’.
The statute text’s version mismatched the resolved one. Ask for
tutorial.city version "0.2.0":
error LDC-E1110: зависимость "tutorial.city" объявлена версией "0.2.0", аresolve-контекст предъявил "0.1.0" (§23: canonical build использует exactversion резолвера, и точная версия в тексте закона обязана с ней совпасть)The diagnostic reads: ‘dependency “tutorial.city” is declared version “0.2.0” while the resolve context presented “0.1.0” (the statute text’s exact version must match the resolver’s exact version)’.
A package importing itself:
error LDC-E1102: пакет "tutorial.archive" импортирует сам себя (§23:imports acyclic)The diagnostic reads: ‘package “tutorial.archive” imports itself (imports are acyclic)’.
All three refusals belong to the language under the
practicum context. And one boundary to know: check without
an imports context does not judge dependencies — a green check of
a package with imports says nothing about the linkage. Judge by lowering
with a context.
The rate arrived from someone else’s act; the tiered overdue-fee computation is likewise not worth writing yourself — it is shared computation, already in the tree: shared computation as a dependency.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.