A package in the corpus: manifest, scenarios, provenance, and checks
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.
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.”
Layout
Section titled “Layout”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.
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.lawtestThe 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.
Manifest
Section titled “Manifest”[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:
[metadata]title = "Гражданский кодекс РК (Особенная часть, 409-I): срез — конкурсные обязательства и публичное обещание вознаграждения (ст. 910—912)"primarySource = "GK_RK_OSOBENNAYA"jurisdiction = "KZ"instrument = "code"sourceFidelity = "pinned_unofficial_copy"issuer = "Парламент Республики Казахстан"legalStatus = "in_force"verifiedAgainstSource = falseThe 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.
Provenance
Section titled “Provenance”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.
Checks
Section titled “Checks”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:
$ python3 verify/ci/gates/release/check_tutorial_practicum.py --only archivearchive (потребитель): lock/deps свежие, понижен с контекстом без пустыхпредикатов, слитый мир 140 узлов, 10 тестов сходятся у lawc и lawref,байтово идентичны 10/10check_tutorial_practicum: OK — пакетов 1The 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 (--regenis the only path); - a promised outcome is a scenario, not a comment: a package without
tests/*.lawtestprints 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.