# 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. ```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." ## 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. ```text 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. ## Manifest ```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" [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: ```text [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. ## 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](/tutorials/pinned-edition/). 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 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: ```text $ 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. ## Next 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.