docs← Back to article

Markdown for LLMs

Several packages and a world

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

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

```law
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

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.

```law
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

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.

```law
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`:

```law
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

Three files hold the link between packages, each with its role.

```text
[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

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

The manifest's second import, `calc.tiers`, is a shared tier computer;
about it on [the next page](/tutorials/primitives/). The package's full
composition:

```text
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

A symbol the neighbour does not export. Replace `base_page_rate` in
`CopyFee`'s body with `page_rate`:

```text
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"`:

```text
error LDC-E1110: зависимость "tutorial.city" объявлена версией "0.2.0", а
resolve-контекст предъявил "0.1.0" (§23: canonical build использует exact
version резолвера, и точная версия в тексте закона обязана с ней совпасть)
```

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:

```text
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.

## Next

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](/tutorials/primitives/).