Skip to content
docs
Arxo ↗

A package in the corpus: manifest, scenarios, provenance, and checks

For LLMs5 sections

The archive package already does everything the corpus does: it imports a foreign act and a computer, holds an A3 parameter, executes on a merged world. What remains is what turns it into a package in a tree rather than a set of files: a manifest with catalogue metadata, declared scenarios, source provenance, and registration in checks. This page is matched by the whole practicum package, and the checks compare its forms against that package’s files.

Arxo Law
language "law.core" version "0.2";
package tutorial.archive version "0.15.0";
namespace "urn:law:tutorial:archive";
source ARCHIVE_RULES {
kind municipal_act;
jurisdiction VELIKY_USTIN;
number "2026-14";
}
edition ARCHIVE_RULES_2026_RU of ARCHIVE_RULES {
language ru;
officiality official;
adopted @2026-01-15;
in_force [@2026-02-01, infinity);
}
fragment ARCHIVE_RULES_P9 in ARCHIVE_RULES_2026_RU {
kind paragraph;
locator "paragraph/9";
text ru official """Плата за просрочку возврата исчисляется за каждый день просрочки и не может
превышать установленного потолка.
""";
}

The quoted fragment reads: “Overdue-return fees accrue per overdue day and may not exceed the set cap.”

The corpus layout convention is closed: a package holds a manifest, package.law only for the shared, normative modules, A3 sidecars, sources.law, and subdirectories from a closed list — tests/, sources/, deps/, i18n/, resources/calendars/… The linter marks an off-list directory with a remark, and the checks reject it.

Output
packs/examples/tutorial/archive/
├── law.toml [package], [dependencies], [features], [[tests]]
├── law.lock, deps/ только генератором
├── package.law импорты, словарь, общие отношения
├── 10-tariffs.law модуль: плата за копирование
├── 20-late-fee.law модуль: плата за просрочку
├── late-fee-cap.lawparam.json A3-параметр
├── sources.law провенанс
└── tests/
├── tariffs.lawtest
└── late-fee.lawtest

The tree comments read: “generator only”; “imports, vocabulary, shared relations”; “module: copy fee”; “module: overdue fee”; “A3 parameter”; “provenance”.

The layout leaves one fork — how to cut normative modules — and answers it: by source units, not by construction types. For the archive these are two rule chapters; for a real act modules follow articles and chapters, and the module name names them.

Output
[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"
[features]
enabled = ["law.params/0.1"]
semanticLayer = "L1"
[[tests]]
family = "tutorial_archive"
suites = ["tests/tariffs.lawtest", "tests/late-fee.lawtest"]
world = ["tutorial.archive", "tutorial.city", "calc.tiers"]

The headers in every .law file must match the manifest — else LDC-E1109. [features] switches A3 surfaces on: an unknown or partially implemented feature is rejected by the compiler, not silently skipped. [[tests]] declares the package’s scenarios: the family serves as the run and ratchet unit, suites lists the files, world names the program — the consumer first, then dependencies. No separate module is needed to register scenarios: a file in tests/ named by no suite drops the checks, as does a suite naming a nonexistent file.

What the practicum manifest lacks is a [metadata] section. It describes the act: title, jurisdiction, publisher, status, fidelity to source. For a real corpus package it is mandatory and reconciled against source declarations:

Output
[metadata]
title = "Гражданский кодекс РК (Особенная часть, 409-I): срез — конкурсные обязательства и публичное обещание вознаграждения (ст. 910—912)"
primarySource = "GK_RK_OSOBENNAYA"
jurisdiction = "KZ"
instrument = "code"
sourceFidelity = "pinned_unofficial_copy"
issuer = "Парламент Республики Казахстан"
legalStatus = "in_force"
verifiedAgainstSource = false

The title reads: “Civil Code of RK (Special Part, 409-I): slice — competition obligations and public reward promises (art. 910–912)”; the issuer reads “Parliament of the Republic of Kazakhstan”.

jurisdiction and instrument derive from sources.law, and the checks reconcile them literally; issuer, legalStatus, verifiedAgainstSource derive from nowhere — the author writes them and justifies them in a comment. A teaching package must not carry [metadata] for the same reason calc.* lacks it: substituting a jurisdiction would declare the example law. It does not enter the semantic hash — it is catalogue, not semantics.

sources.law works as the package’s “lockfile”: it names the source, the edition with its validity window, and fragments with locator and text. Rule @source anchors and A3-value anchors point at fragments; for a real act a fragment carries the pinned bytes’ content_hash, and the checks verify it twice — by address and by content, as in the pinned edition tutorial. The fictional archive has nothing to pin, and no materialization_status is declared: the page honestly says there is no source instead of faking one.

A new file does not enter checks by itself. A corpus package is registered across the registries list: in the CLIR generator’s lowered-acts list, a regression family and its ratchet, scenario manifests, labels and overlays. The practicum has one registry: it sees every law.toml under the practicum tree and does with it what corpus checks do with a calc.* consumer:

Output
$ python3 verify/ci/gates/release/check_tutorial_practicum.py --only archive
archive (потребитель): lock/deps свежие, понижен с контекстом без пустых
предикатов, слитый мир 140 узлов, 10 тестов сходятся у lawc и lawref,
байтово идентичны 10/10
check_tutorial_practicum: OK — пакетов 1

The report reads: “archive (consumer): lock/deps fresh, lowered with a context without empty predicates, merged world of 140 nodes, 10 tests agree between both runners, byte-identical 10/10”.

Three rules without which a package counts broken even when check is green:

  • generated files are edited only by the generator — law.lock, deps/, CLIR; a hand edit is caught by hash reconciliation (--regen is the only path);
  • a promised outcome is a scenario, not a comment: a package without tests/*.lawtest prints as unverified and drops the checks;
  • two implementations agree byte-wise: both runners execute every scenario, and the reference evaluation document equals the engine’s output. A discrepancy is a qualifying blocker, not a reason to fit one side to the other.

No heavy runs are needed for one package’s sake: narrowing by package restricts the work to the act and its dependency closure.

The author track ends here: from the first rule to a checked package. Next are tracks for other readers: how to ask law via MCP, how to embed the engine in an application, how to verify someone else’s formalisation, and how to evolve the language itself.

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

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